001: /*
002: * $Id: Calculate.java,v 1.1 2003/08/17 06:06:13 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: */
024: package org.ofbiz.minilang.method.otherops;
025:
026: import java.util.*;
027:
028: import org.w3c.dom.*;
029: import org.ofbiz.base.util.*;
030: import org.ofbiz.minilang.*;
031: import org.ofbiz.minilang.method.*;
032:
033: /**
034: * Calculates a result based on nested calcops.
035: *
036: * @author <a href="mailto:jonesde@ofbiz.org">David E. Jones</a>
037: * @version $Revision: 1.1 $
038: * @since 2.0
039: */
040: public class Calculate extends MethodOperation {
041:
042: public static final String module = Calculate.class.getName();
043:
044: public static final int TYPE_DOUBLE = 1;
045: public static final int TYPE_FLOAT = 2;
046: public static final int TYPE_LONG = 3;
047: public static final int TYPE_INTEGER = 4;
048: public static final int TYPE_STRING = 5;
049:
050: ContextAccessor mapAcsr;
051: ContextAccessor fieldAcsr;
052: String typeString;
053: Calculate.SubCalc calcops[];
054:
055: public Calculate(Element element, SimpleMethod simpleMethod) {
056: super (element, simpleMethod);
057: mapAcsr = new ContextAccessor(element.getAttribute("map-name"));
058: fieldAcsr = new ContextAccessor(element
059: .getAttribute("field-name"));
060:
061: typeString = element.getAttribute("type");
062:
063: List calcopElements = UtilXml.childElementList(element, null);
064: calcops = new Calculate.SubCalc[calcopElements.size()];
065: Iterator calcopIter = calcopElements.iterator();
066: int i = 0;
067:
068: while (calcopIter.hasNext()) {
069: Element calcopElement = (Element) calcopIter.next();
070: String nodeName = calcopElement.getNodeName();
071:
072: if ("calcop".equals(nodeName)) {
073: calcops[i] = new Calculate.CalcOp(calcopElement);
074: } else if ("number".equals(nodeName)) {
075: calcops[i] = new Calculate.NumberOp(calcopElement);
076: } else {
077: Debug.logError("Error: calculate operation with type "
078: + nodeName, module);
079: }
080: // Debug.logInfo("Added operation type " + nodeName + " in position " + i, module);
081: i++;
082: }
083: }
084:
085: public boolean exec(MethodContext methodContext) {
086: String typeString = methodContext.expandString(this .typeString);
087: int type;
088: if ("Double".equals(typeString)) {
089: type = Calculate.TYPE_DOUBLE;
090: } else if ("Float".equals(typeString)) {
091: type = Calculate.TYPE_FLOAT;
092: } else if ("Long".equals(typeString)) {
093: type = Calculate.TYPE_LONG;
094: } else if ("Integer".equals(typeString)) {
095: type = Calculate.TYPE_INTEGER;
096: } else if ("String".equals(typeString)) {
097: type = Calculate.TYPE_STRING;
098: } else {
099: type = Calculate.TYPE_DOUBLE;
100: }
101:
102: double resultValue = 0;
103:
104: for (int i = 0; i < calcops.length; i++) {
105: resultValue += calcops[i].calcValue(methodContext);
106: // Debug.logInfo("main total so far: " + resultValue, module);
107: }
108:
109: Object resultObj = null;
110:
111: switch (type) {
112: case TYPE_DOUBLE:
113: resultObj = new Double(resultValue);
114: break;
115: case TYPE_FLOAT:
116: resultObj = new Float(resultValue);
117: break;
118: case TYPE_LONG:
119: resultObj = new Long(Math.round(resultValue));
120: break;
121: case TYPE_INTEGER:
122: resultObj = new Integer((int) Math.round(resultValue));
123: break;
124: case TYPE_STRING:
125: resultObj = new Double(resultValue).toString();
126: break;
127: }
128:
129: if (!mapAcsr.isEmpty()) {
130: Map toMap = (Map) mapAcsr.get(methodContext);
131: if (toMap == null) {
132: if (Debug.verboseOn())
133: Debug.logVerbose("Map not found with name "
134: + mapAcsr + ", creating new map", module);
135: toMap = new HashMap();
136: mapAcsr.put(methodContext, toMap);
137: }
138: fieldAcsr.put(toMap, resultObj, methodContext);
139: } else {
140: fieldAcsr.put(methodContext, resultObj);
141: }
142:
143: return true;
144: }
145:
146: protected static interface SubCalc {
147: public double calcValue(MethodContext methodContext);
148: }
149:
150: protected static class NumberOp implements SubCalc {
151: String valueStr;
152:
153: public NumberOp(Element element) {
154: valueStr = element.getAttribute("value");
155: }
156:
157: public double calcValue(MethodContext methodContext) {
158: String valueStr = methodContext.expandString(this .valueStr);
159: double value;
160: try {
161: value = Double.parseDouble(valueStr);
162: } catch (Exception e) {
163: Debug.logError(e, "Could not parse the number string: "
164: + valueStr, module);
165: throw new IllegalArgumentException(
166: "Could not parse the number string: "
167: + valueStr);
168: }
169:
170: // Debug.logInfo("calcValue number: " + value, module);
171: return value;
172: }
173:
174: }
175:
176: protected static class CalcOp implements SubCalc {
177: public static final int OPERATOR_ADD = 1;
178: public static final int OPERATOR_SUBTRACT = 2;
179: public static final int OPERATOR_MULTIPLY = 3;
180: public static final int OPERATOR_DIVIDE = 4;
181: public static final int OPERATOR_NEGATIVE = 5;
182:
183: ContextAccessor mapAcsr;
184: ContextAccessor fieldAcsr;
185: String operatorStr;
186: Calculate.SubCalc calcops[];
187:
188: public CalcOp(Element element) {
189: mapAcsr = new ContextAccessor(element
190: .getAttribute("map-name"));
191: fieldAcsr = new ContextAccessor(element
192: .getAttribute("field-name"));
193: operatorStr = element.getAttribute("operator");
194:
195: List calcopElements = UtilXml.childElementList(element,
196: null);
197: calcops = new Calculate.SubCalc[calcopElements.size()];
198: Iterator calcopIter = calcopElements.iterator();
199: int i = 0;
200:
201: while (calcopIter.hasNext()) {
202: Element calcopElement = (Element) calcopIter.next();
203: String nodeName = calcopElement.getNodeName();
204:
205: if ("calcop".equals(calcopElement.getNodeName())) {
206: calcops[i] = new Calculate.CalcOp(calcopElement);
207: } else if ("number".equals(calcopElement.getNodeName())) {
208: calcops[i] = new Calculate.NumberOp(calcopElement);
209: } else {
210: Debug.logError(
211: "Error: calculate operation unknown with type "
212: + nodeName, module);
213: }
214: // Debug.logInfo("Added operation type " + nodeName + " in position " + i, module);
215: i++;
216: }
217: }
218:
219: public double calcValue(MethodContext methodContext) {
220: String operatorStr = methodContext
221: .expandString(this .operatorStr);
222: int operator = CalcOp.OPERATOR_ADD;
223: if ("get".equals(operatorStr)) {
224: operator = CalcOp.OPERATOR_ADD;
225: } else if ("add".equals(operatorStr)) {
226: operator = CalcOp.OPERATOR_ADD;
227: } else if ("subtract".equals(operatorStr)) {
228: operator = CalcOp.OPERATOR_SUBTRACT;
229: } else if ("multiply".equals(operatorStr)) {
230: operator = CalcOp.OPERATOR_MULTIPLY;
231: } else if ("divide".equals(operatorStr)) {
232: operator = CalcOp.OPERATOR_DIVIDE;
233: } else if ("negative".equals(operatorStr)) {
234: operator = CalcOp.OPERATOR_NEGATIVE;
235: }
236:
237: double resultValue = 0;
238: boolean isFirst = true;
239:
240: // if a fieldAcsr was specified, get the field from the map or result and use it as the initial value
241: if (!fieldAcsr.isEmpty()) {
242: Object fieldObj = null;
243:
244: if (!mapAcsr.isEmpty()) {
245: Map fromMap = (Map) mapAcsr.get(methodContext);
246: if (fromMap == null) {
247: if (Debug.verboseOn())
248: Debug.logVerbose("Map not found with name "
249: + mapAcsr + ", creating new map",
250: module);
251: fromMap = new HashMap();
252: mapAcsr.put(methodContext, fromMap);
253: }
254: fieldObj = fieldAcsr.get(fromMap, methodContext);
255: } else {
256: fieldObj = fieldAcsr.get(methodContext);
257: }
258:
259: if (fieldObj != null) {
260: if (fieldObj instanceof Double) {
261: resultValue = ((Double) fieldObj).doubleValue();
262: } else if (fieldObj instanceof Long) {
263: resultValue = (double) ((Long) fieldObj)
264: .longValue();
265: } else if (fieldObj instanceof Float) {
266: resultValue = (double) ((Float) fieldObj)
267: .floatValue();
268: } else if (fieldObj instanceof Integer) {
269: resultValue = (double) ((Integer) fieldObj)
270: .intValue();
271: } else if (fieldObj instanceof String) {
272: resultValue = Double.valueOf((String) fieldObj)
273: .doubleValue();
274: }
275: if (operator == OPERATOR_NEGATIVE)
276: resultValue = -resultValue;
277: isFirst = false;
278: } else {
279: if (Debug.infoOn())
280: Debug.logInfo(
281: "Field not found with field-name "
282: + fieldAcsr + ", and map-name "
283: + mapAcsr
284: + "using a default of 0",
285: module);
286: }
287: }
288:
289: for (int i = 0; i < calcops.length; i++) {
290: if (isFirst) {
291: resultValue = calcops[i].calcValue(methodContext);
292: if (operator == OPERATOR_NEGATIVE)
293: resultValue = -resultValue;
294: isFirst = false;
295: } else {
296: switch (operator) {
297: case OPERATOR_ADD:
298: resultValue += calcops[i]
299: .calcValue(methodContext);
300: break;
301: case OPERATOR_SUBTRACT:
302: case OPERATOR_NEGATIVE:
303: resultValue -= calcops[i]
304: .calcValue(methodContext);
305: break;
306: case OPERATOR_MULTIPLY:
307: resultValue *= calcops[i]
308: .calcValue(methodContext);
309: break;
310: case OPERATOR_DIVIDE:
311: resultValue /= calcops[i]
312: .calcValue(methodContext);
313: break;
314: }
315: }
316: // Debug.logInfo("sub total so far: " + resultValue, module);
317: }
318: // Debug.logInfo("calcValue calcop: " + resultValue + "(field=" + fieldAcsr + ", map=" + mapAcsr + ")", module);
319: return resultValue;
320: }
321: }
322: }
|