1 24 package org.ofbiz.minilang.method.otherops; 25 26 import java.math.BigDecimal ; 27 import java.text.DecimalFormat ; 28 import java.util.HashMap ; 29 import java.util.Iterator ; 30 import java.util.List ; 31 import java.util.Map ; 32 33 import org.ofbiz.base.util.Debug; 34 import org.ofbiz.base.util.UtilValidate; 35 import org.ofbiz.base.util.UtilXml; 36 import org.ofbiz.minilang.SimpleMethod; 37 import org.ofbiz.minilang.method.ContextAccessor; 38 import org.ofbiz.minilang.method.MethodContext; 39 import org.ofbiz.minilang.method.MethodOperation; 40 import org.w3c.dom.Element ; 41 42 49 public class Calculate extends MethodOperation { 50 51 public static final String module = Calculate.class.getName(); 52 53 public static final BigDecimal ZERO = new BigDecimal (0.0); 54 public static final int TYPE_DOUBLE = 1; 55 public static final int TYPE_FLOAT = 2; 56 public static final int TYPE_LONG = 3; 57 public static final int TYPE_INTEGER = 4; 58 public static final int TYPE_STRING = 5; 59 public static final int TYPE_BIG_DECIMAL = 6; 60 61 ContextAccessor mapAcsr; 62 ContextAccessor fieldAcsr; 63 String decimalScaleString; 64 String decimalFormatString; 65 String typeString; 66 String roundingModeString; 67 Calculate.SubCalc calcops[]; 68 69 public Calculate(Element element, SimpleMethod simpleMethod) { 70 super(element, simpleMethod); 71 mapAcsr = new ContextAccessor(element.getAttribute("map-name")); 72 fieldAcsr = new ContextAccessor(element.getAttribute("field-name")); 73 74 decimalScaleString = element.getAttribute("decimal-scale"); 75 decimalFormatString = element.getAttribute("decimal-format"); 76 typeString = element.getAttribute("type"); 77 roundingModeString = element.getAttribute("rounding-mode"); 78 79 List calcopElements = UtilXml.childElementList(element); 80 calcops = new Calculate.SubCalc[calcopElements.size()]; 81 Iterator calcopIter = calcopElements.iterator(); 82 int i = 0; 83 84 while (calcopIter.hasNext()) { 85 Element calcopElement = (Element ) calcopIter.next(); 86 String nodeName = calcopElement.getNodeName(); 87 88 if ("calcop".equals(nodeName)) { 89 calcops[i] = new Calculate.CalcOp(calcopElement); 90 } else if ("number".equals(nodeName)) { 91 calcops[i] = new Calculate.NumberOp(calcopElement); 92 } else { 93 Debug.logError("Error: calculate operation with type " + nodeName, module); 94 } 95 i++; 97 } 98 } 99 100 public boolean exec(MethodContext methodContext) { 101 String typeString = methodContext.expandString(this.typeString); 102 int type; 103 if ("Double".equals(typeString)) { 104 type = Calculate.TYPE_DOUBLE; 105 } else if ("Float".equals(typeString)) { 106 type = Calculate.TYPE_FLOAT; 107 } else if ("Long".equals(typeString)) { 108 type = Calculate.TYPE_LONG; 109 } else if ("Integer".equals(typeString)) { 110 type = Calculate.TYPE_INTEGER; 111 } else if ("String".equals(typeString)) { 112 type = Calculate.TYPE_STRING; 113 } else if ("BigDecimal".equals(typeString)) { 114 type = Calculate.TYPE_BIG_DECIMAL; 115 } else { 116 type = Calculate.TYPE_DOUBLE; 117 } 118 119 String roundingModeString = methodContext.expandString(this.roundingModeString); 120 int roundingMode; 121 if ("Ceiling".equals(roundingModeString)) { 122 roundingMode = BigDecimal.ROUND_CEILING; 123 } else if ("Floor".equals(roundingModeString)) { 124 roundingMode = BigDecimal.ROUND_FLOOR; 125 } else if ("Up".equals(roundingModeString)) { 126 roundingMode = BigDecimal.ROUND_UP; 127 } else if ("Down".equals(roundingModeString)) { 128 roundingMode = BigDecimal.ROUND_DOWN; 129 } else if ("HalfUp".equals(roundingModeString)) { 130 roundingMode = BigDecimal.ROUND_HALF_UP; 131 } else if ("HalfDown".equals(roundingModeString)) { 132 roundingMode = BigDecimal.ROUND_HALF_DOWN; 133 } else if ("HalfEven".equals(roundingModeString)) { 134 roundingMode = BigDecimal.ROUND_HALF_EVEN; 135 } else if ("Unnecessary".equals(roundingModeString)) { 136 roundingMode = BigDecimal.ROUND_UNNECESSARY; 137 } else { 138 roundingMode = BigDecimal.ROUND_HALF_EVEN; 140 } 141 142 String decimalScaleString = methodContext.expandString(this.decimalScaleString); 143 int decimalScale = 2; 144 if (UtilValidate.isNotEmpty(decimalScaleString)) { 145 decimalScale = Integer.valueOf(decimalScaleString).intValue(); 146 } 147 148 String decimalFormatString = methodContext.expandString(this.decimalFormatString); 149 DecimalFormat df = null; 150 if (UtilValidate.isNotEmpty(decimalFormatString)) { 151 df = new DecimalFormat (decimalFormatString); 152 } 153 154 BigDecimal resultValue = ZERO; 155 resultValue = resultValue.setScale(decimalScale, roundingMode); 156 for (int i = 0; i < calcops.length; i++) { 157 resultValue = resultValue.add(calcops[i].calcValue(methodContext, decimalScale, roundingMode)); 158 } 160 resultValue = resultValue.setScale(decimalScale, roundingMode); 161 162 177 178 Object resultObj = null; 179 switch (type) { 180 case TYPE_DOUBLE: 181 resultObj = new Double (resultValue.doubleValue()); 182 break; 183 case TYPE_FLOAT: 184 resultObj = new Float (resultValue.floatValue()); 185 break; 186 case TYPE_LONG: 187 resultValue = resultValue.setScale(0, roundingMode); 188 resultObj = new Long (resultValue.longValue()); 189 break; 190 case TYPE_INTEGER: 191 resultValue = resultValue.setScale(0, roundingMode); 192 resultObj = new Integer (resultValue.intValue()); 193 break; 194 case TYPE_STRING: 195 if (df != null && resultValue.compareTo(ZERO) > 0) { 197 resultObj = df.format(resultValue); 198 } else { 199 resultObj = resultValue.toString(); 200 } 201 break; 202 case TYPE_BIG_DECIMAL: 203 resultObj = resultValue; 204 break; 205 } 206 207 if (!mapAcsr.isEmpty()) { 208 Map toMap = (Map ) mapAcsr.get(methodContext); 209 if (toMap == null) { 210 if (Debug.verboseOn()) Debug.logVerbose("Map not found with name " + mapAcsr + ", creating new map", module); 211 toMap = new HashMap (); 212 mapAcsr.put(methodContext, toMap); 213 } 214 fieldAcsr.put(toMap, resultObj, methodContext); 215 } else { 216 fieldAcsr.put(methodContext, resultObj); 217 } 218 219 return true; 220 } 221 222 public String rawString() { 223 return "<calculate field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>"; 225 } 226 public String expandedString(MethodContext methodContext) { 227 return this.rawString(); 229 } 230 231 protected static interface SubCalc { 232 public BigDecimal calcValue(MethodContext methodContext, int scale, int roundingMode); 233 } 234 235 protected static class NumberOp implements SubCalc { 236 String valueStr; 237 238 public NumberOp(Element element) { 239 valueStr = element.getAttribute("value"); 240 } 241 242 public BigDecimal calcValue(MethodContext methodContext, int scale, int roundingMode) { 243 String valueStr = methodContext.expandString(this.valueStr); 244 BigDecimal value; 245 try { 246 value = new BigDecimal (valueStr); 247 value = value.setScale(scale, roundingMode); 248 } catch (Exception e) { 249 Debug.logError(e, "Could not parse the number string: " + valueStr, module); 250 throw new IllegalArgumentException ("Could not parse the number string: " + valueStr); 251 } 252 253 return value; 255 } 256 257 } 258 259 protected static class CalcOp implements SubCalc { 260 public static final int OPERATOR_ADD = 1; 261 public static final int OPERATOR_SUBTRACT = 2; 262 public static final int OPERATOR_MULTIPLY = 3; 263 public static final int OPERATOR_DIVIDE = 4; 264 public static final int OPERATOR_NEGATIVE = 5; 265 266 ContextAccessor mapAcsr; 267 ContextAccessor fieldAcsr; 268 String operatorStr; 269 Calculate.SubCalc calcops[]; 270 271 public CalcOp(Element element) { 272 mapAcsr = new ContextAccessor(element.getAttribute("map-name")); 273 fieldAcsr = new ContextAccessor(element.getAttribute("field-name")); 274 operatorStr = element.getAttribute("operator"); 275 276 List calcopElements = UtilXml.childElementList(element); 277 calcops = new Calculate.SubCalc[calcopElements.size()]; 278 Iterator calcopIter = calcopElements.iterator(); 279 int i = 0; 280 281 while (calcopIter.hasNext()) { 282 Element calcopElement = (Element ) calcopIter.next(); 283 String nodeName = calcopElement.getNodeName(); 284 285 if ("calcop".equals(calcopElement.getNodeName())) { 286 calcops[i] = new Calculate.CalcOp(calcopElement); 287 } else if ("number".equals(calcopElement.getNodeName())) { 288 calcops[i] = new Calculate.NumberOp(calcopElement); 289 } else { 290 Debug.logError("Error: calculate operation unknown with type " + nodeName, module); 291 } 292 i++; 294 } 295 } 296 297 public BigDecimal calcValue(MethodContext methodContext, int scale, int roundingMode) { 298 String operatorStr = methodContext.expandString(this.operatorStr); 299 int operator = CalcOp.OPERATOR_ADD; 300 if ("get".equals(operatorStr)) { 301 operator = CalcOp.OPERATOR_ADD; 302 } else if ("add".equals(operatorStr)) { 303 operator = CalcOp.OPERATOR_ADD; 304 } else if ("subtract".equals(operatorStr)) { 305 operator = CalcOp.OPERATOR_SUBTRACT; 306 } else if ("multiply".equals(operatorStr)) { 307 operator = CalcOp.OPERATOR_MULTIPLY; 308 } else if ("divide".equals(operatorStr)) { 309 operator = CalcOp.OPERATOR_DIVIDE; 310 } else if ("negative".equals(operatorStr)) { 311 operator = CalcOp.OPERATOR_NEGATIVE; 312 } 313 314 BigDecimal resultValue = ZERO; 315 resultValue = resultValue.setScale(scale, roundingMode); 316 boolean isFirst = true; 317 318 if (!fieldAcsr.isEmpty()) { 320 Object fieldObj = null; 321 322 if (!mapAcsr.isEmpty()) { 323 Map fromMap = (Map ) mapAcsr.get(methodContext); 324 if (fromMap == null) { 325 if (Debug.verboseOn()) Debug.logVerbose("Map not found with name " + mapAcsr + ", creating new map", module); 326 fromMap = new HashMap (); 327 mapAcsr.put(methodContext, fromMap); 328 } 329 fieldObj = fieldAcsr.get(fromMap, methodContext); 330 } else { 331 fieldObj = fieldAcsr.get(methodContext); 332 } 333 334 if (fieldObj != null) { 335 if (fieldObj instanceof Double ) { 336 resultValue = new BigDecimal (((Double ) fieldObj).doubleValue()); 337 } else if (fieldObj instanceof Long ) { 338 resultValue = BigDecimal.valueOf(((Long ) fieldObj).longValue()); 339 } else if (fieldObj instanceof Float ) { 340 resultValue = new BigDecimal (((Float ) fieldObj).floatValue()); 341 } else if (fieldObj instanceof Integer ) { 342 resultValue = BigDecimal.valueOf(((Integer ) fieldObj).longValue()); 343 } else if (fieldObj instanceof String ) { 344 resultValue = new BigDecimal ((String ) fieldObj); 345 } else if (fieldObj instanceof BigDecimal ) { 346 resultValue = (BigDecimal ) fieldObj; 347 } 348 if (operator == OPERATOR_NEGATIVE) resultValue = resultValue.negate(); 349 isFirst = false; 350 } else { 351 if (Debug.infoOn()) Debug.logInfo("Field not found with field-name " + fieldAcsr + ", and map-name " + mapAcsr + "using a default of 0", module); 352 } 353 } 354 355 for (int i = 0; i < calcops.length; i++) { 356 if (isFirst) { 357 resultValue = calcops[i].calcValue(methodContext, scale, roundingMode); 358 if (operator == OPERATOR_NEGATIVE) resultValue = resultValue.negate(); 359 isFirst = false; 360 } else { 361 switch (operator) { 362 case OPERATOR_ADD: 363 resultValue = resultValue.add(calcops[i].calcValue(methodContext, scale, roundingMode)); 364 break; 365 case OPERATOR_SUBTRACT: 366 case OPERATOR_NEGATIVE: 367 resultValue = resultValue.subtract(calcops[i].calcValue(methodContext, scale, roundingMode)); 368 break; 369 case OPERATOR_MULTIPLY: 370 resultValue = resultValue.multiply(calcops[i].calcValue(methodContext, scale, roundingMode)); 371 break; 372 case OPERATOR_DIVIDE: 373 resultValue = resultValue.divide(calcops[i].calcValue(methodContext, scale, roundingMode), scale, roundingMode); 374 break; 375 } 376 } 377 } 379 return resultValue; 381 } 382 } 383 } 384 | Popular Tags |