KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > minilang > method > otherops > Calculate


1 /*
2  * $Id: Calculate.java 7043 2006-03-22 08:11:05Z jonesde $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.minilang.method.otherops;
25
26 import java.math.BigDecimal JavaDoc;
27 import java.text.DecimalFormat JavaDoc;
28 import java.util.HashMap JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
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 JavaDoc;
41
42 /**
43  * Calculates a result based on nested calcops.
44  *
45  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
46  * @version $Rev: 7043 $
47  * @since 2.0
48  */

49 public class Calculate extends MethodOperation {
50     
51     public static final String JavaDoc module = Calculate.class.getName();
52     
53     public static final BigDecimal JavaDoc ZERO = new BigDecimal JavaDoc(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 JavaDoc decimalScaleString;
64     String JavaDoc decimalFormatString;
65     String JavaDoc typeString;
66     String JavaDoc roundingModeString;
67     Calculate.SubCalc calcops[];
68
69     public Calculate(Element JavaDoc 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 JavaDoc calcopElements = UtilXml.childElementList(element);
80         calcops = new Calculate.SubCalc[calcopElements.size()];
81         Iterator JavaDoc calcopIter = calcopElements.iterator();
82         int i = 0;
83
84         while (calcopIter.hasNext()) {
85             Element JavaDoc calcopElement = (Element JavaDoc) calcopIter.next();
86             String JavaDoc 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             // Debug.logInfo("Added operation type " + nodeName + " in position " + i, module);
96
i++;
97         }
98     }
99
100     public boolean exec(MethodContext methodContext) {
101         String JavaDoc 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 JavaDoc 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             // default to HalfEven, reduce cumulative errors
139
roundingMode = BigDecimal.ROUND_HALF_EVEN;
140         }
141
142         String JavaDoc decimalScaleString = methodContext.expandString(this.decimalScaleString);
143         int decimalScale = 2;
144         if (UtilValidate.isNotEmpty(decimalScaleString)) {
145             decimalScale = Integer.valueOf(decimalScaleString).intValue();
146         }
147         
148         String JavaDoc decimalFormatString = methodContext.expandString(this.decimalFormatString);
149         DecimalFormat JavaDoc df = null;
150         if (UtilValidate.isNotEmpty(decimalFormatString)) {
151             df = new DecimalFormat JavaDoc(decimalFormatString);
152         }
153         
154         BigDecimal JavaDoc 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             // Debug.logInfo("main total so far: " + resultValue, module);
159
}
160         resultValue = resultValue.setScale(decimalScale, roundingMode);
161         
162         /* the old thing that did conversion to string and back, may want to use somewhere sometime...:
163          * for now just doing the setScale above (before and after calc ops)
164         try {
165             resultValue = new BigDecimal(df.format(resultValue));
166         } catch (ParseException e) {
167             String errorMessage = "Unable to format [" + formatString + "] result [" + resultValue + "]";
168             Debug.logError(e, errorMessage, module);
169             if (methodContext.getMethodType() == MethodContext.EVENT) {
170                 methodContext.putEnv(simpleMethod.getEventErrorMessageName(), errorMessage);
171             } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
172                 methodContext.putEnv(simpleMethod.getServiceErrorMessageName(), errorMessage);
173             }
174             return false;
175         }
176         */

177         
178         Object JavaDoc resultObj = null;
179         switch (type) {
180         case TYPE_DOUBLE:
181             resultObj = new Double JavaDoc(resultValue.doubleValue());
182             break;
183         case TYPE_FLOAT:
184             resultObj = new Float JavaDoc(resultValue.floatValue());
185             break;
186         case TYPE_LONG:
187             resultValue = resultValue.setScale(0, roundingMode);
188             resultObj = new Long JavaDoc(resultValue.longValue());
189             break;
190         case TYPE_INTEGER:
191             resultValue = resultValue.setScale(0, roundingMode);
192             resultObj = new Integer JavaDoc(resultValue.intValue());
193             break;
194         case TYPE_STRING:
195             // run the decimal-formatting
196
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 JavaDoc toMap = (Map JavaDoc) 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 JavaDoc();
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 JavaDoc rawString() {
223         // TODO: add all attributes and other info
224
return "<calculate field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>";
225     }
226     public String JavaDoc expandedString(MethodContext methodContext) {
227         // TODO: something more than a stub/dummy
228
return this.rawString();
229     }
230
231     protected static interface SubCalc {
232         public BigDecimal JavaDoc calcValue(MethodContext methodContext, int scale, int roundingMode);
233     }
234
235     protected static class NumberOp implements SubCalc {
236         String JavaDoc valueStr;
237
238         public NumberOp(Element JavaDoc element) {
239             valueStr = element.getAttribute("value");
240         }
241
242         public BigDecimal JavaDoc calcValue(MethodContext methodContext, int scale, int roundingMode) {
243             String JavaDoc valueStr = methodContext.expandString(this.valueStr);
244             BigDecimal JavaDoc value;
245             try {
246                 value = new BigDecimal JavaDoc(valueStr);
247                 value = value.setScale(scale, roundingMode);
248             } catch (Exception JavaDoc e) {
249                 Debug.logError(e, "Could not parse the number string: " + valueStr, module);
250                 throw new IllegalArgumentException JavaDoc("Could not parse the number string: " + valueStr);
251             }
252             
253             // Debug.logInfo("calcValue number: " + value, module);
254
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 JavaDoc operatorStr;
269         Calculate.SubCalc calcops[];
270
271         public CalcOp(Element JavaDoc 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 JavaDoc calcopElements = UtilXml.childElementList(element);
277             calcops = new Calculate.SubCalc[calcopElements.size()];
278             Iterator JavaDoc calcopIter = calcopElements.iterator();
279             int i = 0;
280
281             while (calcopIter.hasNext()) {
282                 Element JavaDoc calcopElement = (Element JavaDoc) calcopIter.next();
283                 String JavaDoc 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                 // Debug.logInfo("Added operation type " + nodeName + " in position " + i, module);
293
i++;
294             }
295         }
296
297         public BigDecimal JavaDoc calcValue(MethodContext methodContext, int scale, int roundingMode) {
298             String JavaDoc 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 JavaDoc resultValue = ZERO;
315             resultValue = resultValue.setScale(scale, roundingMode);
316             boolean isFirst = true;
317
318             // if a fieldAcsr was specified, get the field from the map or result and use it as the initial value
319
if (!fieldAcsr.isEmpty()) {
320                 Object JavaDoc fieldObj = null;
321
322                 if (!mapAcsr.isEmpty()) {
323                     Map JavaDoc fromMap = (Map JavaDoc) 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 JavaDoc();
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 JavaDoc) {
336                         resultValue = new BigDecimal JavaDoc(((Double JavaDoc) fieldObj).doubleValue());
337                     } else if (fieldObj instanceof Long JavaDoc) {
338                         resultValue = BigDecimal.valueOf(((Long JavaDoc) fieldObj).longValue());
339                     } else if (fieldObj instanceof Float JavaDoc) {
340                         resultValue = new BigDecimal JavaDoc(((Float JavaDoc) fieldObj).floatValue());
341                     } else if (fieldObj instanceof Integer JavaDoc) {
342                         resultValue = BigDecimal.valueOf(((Integer JavaDoc) fieldObj).longValue());
343                     } else if (fieldObj instanceof String JavaDoc) {
344                         resultValue = new BigDecimal JavaDoc((String JavaDoc) fieldObj);
345                     } else if (fieldObj instanceof BigDecimal JavaDoc) {
346                         resultValue = (BigDecimal JavaDoc) 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                 // Debug.logInfo("sub total so far: " + resultValue, module);
378
}
379             // Debug.logInfo("calcValue calcop: " + resultValue + "(field=" + fieldAcsr + ", map=" + mapAcsr + ")", module);
380
return resultValue;
381         }
382     }
383 }
384
Popular Tags