You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2012/04/27 00:40:23 UTC

svn commit: r1331137 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java src/org/ofbiz/minilang/method/envops/Now.java src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Author: adrianc
Date: Thu Apr 26 22:40:22 2012
New Revision: 1331137

URL: http://svn.apache.org/viewvc?rev=1331137&view=rev
Log:
Added new attribute "memory-model" to the Mini-language <call-simple-method> element. Code cleanup and validation in FieldToResult.java. Improved validation in Now.java.

Modified:
    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Modified: ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd?rev=1331137&r1=1331136&r2=1331137&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
+++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Thu Apr 26 22:40:22 2012
@@ -918,33 +918,64 @@ under the License.
     <xs:element name="call-simple-method" substitutionGroup="CallOperations">
         <xs:annotation>
             <xs:documentation>
-                The call-simple-method tag calls another simple-method in the same context as the current one.
-                In other words the called simple-method will have the same environment as the calling simple-method,
-                including all environment fields, and either the event or service objects that the calling simple-method was called with.
+                Calls another simple-method in the same context as the current one.
+                The called simple-method will have the same environment as the calling simple-method,
+                including all environment fields, and either the event or service objects
+                that the calling simple-method was called
+                with.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.call-simple-method"/>
+            <xs:sequence>
+                <xs:element ref="result-to-field" minOccurs="0" maxOccurs="unbounded">
+                    <xs:annotation>
+                        <xs:documentation>
+                            Used when memory-model=&quot;function&quot;. Copies the called method fields
+                            to the calling method fields.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:element>
+            </xs:sequence>
+            <xs:attribute type="xs:string" name="method-name" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the simple-method to execute in the specified xml-resource,
+                        or in the current XML file if no xml-resource is specified.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="xml-resource">
+                <xs:annotation>
+                    <xs:documentation>
+                        The full path and filename on the classpath of the XML file which contains an external simple-method to execute.
+                        This is only required if a simple-method in a different file is desired.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="memory-model">
+                <xs:annotation>
+                    <xs:documentation>
+                        The memory model to use. In an &quot;inline&quot; memory model, fields declared or modified in the called method
+                        will be reflected back to the calling method - as if the called method was inline. In a &quot;function&quot; memory
+                        model, fields declared or modified in the called method are local to the called method - they are not
+                        reflected back to the calling method.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:token">
+                        <xs:enumeration value="inline" />
+                        <xs:enumeration value="function" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.call-simple-method">
-        <xs:attribute type="xs:string" name="xml-resource">
-            <xs:annotation>
-                <xs:documentation>
-                    The full path and filename on the classpath of the XML file which contains an external simple-method to execute.
-                    This is only required if a simple-method in a different file is desired.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="method-name" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    The name of the simple-method to execute in the specified xml-resource,
-                    or in the current XML file if no xml-resource is specified.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <!-- Operations to call Java methods and create Java objects -->
     <xs:element name="call-object-method" substitutionGroup="CallOperations">
         <xs:annotation>
@@ -1265,26 +1296,43 @@ under the License.
             <xs:annotation><xs:documentation>The name of the session attribute to use. Defaults to the value of field attribute</xs:documentation></xs:annotation>
         </xs:attribute>
     </xs:attributeGroup>
-    <!-- Service specific operations -->
-    <xs:element name="field-to-result" substitutionGroup="ServiceOperations">
+    <xs:element name="field-to-result" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
-                The field-to-result tag copies a field from a map to the specified service result field.
-                The tag is only used when the simple-method is called as a service, it is ignored otherwise.
+                Copies a field to a service OUT attribute.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.field-to-result"/>
+            <xs:attribute name="field" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the field to copy from. The source of the assignment.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:string">
+                        <xs:minLength value="1" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
+            <xs:attribute name="result-name">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the result field to set. The target of the assignment.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:string">
+                        <xs:minLength value="1" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.field-to-result">
-        <xs:attribute type="xs:string" name="field" use="required">
-            <xs:annotation><xs:documentation>The name (key) of the map field to use.</xs:documentation></xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="result-name">
-            <xs:annotation><xs:documentation>The name of the result Map name/key to use. Defaults to the value of field attribute.</xs:documentation></xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <!-- Environment specific operations -->
     <xs:element name="map-to-map" substitutionGroup="EnvOperations">
         <xs:annotation>
@@ -4436,6 +4484,8 @@ under the License.
                 <xs:annotation>
                     <xs:documentation>
                         The field data type. Defaults to java.sql.Timestamp.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
                     </xs:documentation>
                 </xs:annotation>
                 <xs:simpleType>

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java?rev=1331137&r1=1331136&r2=1331137&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java Thu Apr 26 22:40:22 2012
@@ -18,117 +18,151 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.callops;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
+import javolution.util.FastMap;
+
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.minilang.MiniLangException;
+import org.ofbiz.minilang.MiniLangRuntimeException;
+import org.ofbiz.minilang.MiniLangValidate;
 import org.ofbiz.minilang.SimpleMethod;
+import org.ofbiz.minilang.ValidationException;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.w3c.dom.Element;
 
 /**
- * An operation that calls a simple method in the same, or from another, file
+ * Invokes a Mini-language simple method.
  */
-public class CallSimpleMethod extends MethodOperation {
+public final class CallSimpleMethod extends MethodOperation {
 
     public static final String module = CallSimpleMethod.class.getName();
 
-    String methodName;
-    String xmlResource;
+    private final String methodName;
+    private final String xmlResource;
+    private final String memoryModel;
+    private final List<ResultToField> resultToFieldList;
 
     public CallSimpleMethod(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "method-name", "xml-resource", "memory-model");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "method-name");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "method-name", "xml-resource", "memory-model");
+            MiniLangValidate.childElements(simpleMethod, element, "result-to-field");
+        }
         this.methodName = element.getAttribute("method-name");
         this.xmlResource = element.getAttribute("xml-resource");
+        this.memoryModel = element.getAttribute("memory-model");
+        List<? extends Element> resultToFieldElements = UtilXml.childElementList(element, "result-to-field");
+        if (UtilValidate.isNotEmpty(resultToFieldElements)) {
+            if (!"function".equals(this.memoryModel)) {
+                MiniLangValidate.handleError("Inline memory model cannot include <result-to-field> elements.", simpleMethod, element);
+            }
+            List<ResultToField> resultToFieldList = new ArrayList<ResultToField>(resultToFieldElements.size());
+            for (Element resultToFieldElement : resultToFieldElements) {
+                resultToFieldList.add(new ResultToField(resultToFieldElement, simpleMethod));
+            }
+            this.resultToFieldList = resultToFieldList;
+        } else {
+            this.resultToFieldList = null;
+        }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        if (UtilValidate.isNotEmpty(this.methodName)) {
-            String methodName = methodContext.expandString(this.methodName);
-            String xmlResource = methodContext.expandString(this.xmlResource);
-            SimpleMethod simpleMethodToCall = null;
-            try {
-                simpleMethodToCall = getSimpleMethodToCall(methodContext.getLoader());
-            } catch (MiniLangException e) {
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [error getting methods from resource: " + e.getMessage() + "]";
-                Debug.logError(e, errMsg, module);
-                methodContext.setErrorReturn(errMsg, simpleMethod);
-                return false;
+        if (UtilValidate.isEmpty(this.methodName)) {
+            throw new MiniLangRuntimeException("method-name attribute is empty", this);
+        }
+        SimpleMethod simpleMethodToCall = null;
+        if (UtilValidate.isEmpty(this.xmlResource)) {
+            simpleMethodToCall = this.simpleMethod.getSimpleMethodInSameFile(methodName);
+        } else {
+            Map<String, SimpleMethod> simpleMethods = SimpleMethod.getSimpleMethods(this.xmlResource, methodContext.getLoader());
+            simpleMethodToCall = simpleMethods.get(this.methodName);
+        }
+        if (simpleMethodToCall == null) {
+            throw new MiniLangRuntimeException("Could not find <simple-method name=\"" + this.methodName + "\"> in XML document " + this.xmlResource, this);
+        }
+        MethodContext localContext = methodContext;
+        if ("function".equals(this.memoryModel)) {
+            Map<String, Object> localEnv = FastMap.newInstance();
+            localEnv.putAll(methodContext.getEnvMap());
+            localEnv.remove(this.simpleMethod.getEventResponseCodeName());
+            localEnv.remove(this.simpleMethod.getServiceResponseMessageName());
+            localContext = new MethodContext(localEnv, methodContext.getLoader(), methodContext.getMethodType());
+        }
+        String returnVal = simpleMethodToCall.exec(localContext);
+        if (Debug.verboseOn())
+            Debug.logVerbose("Called simple-method named [" + this.methodName + "] in resource [" + this.xmlResource + "], returnVal is [" + returnVal + "]", module);
+        if (simpleMethodToCall.getDefaultErrorCode().equals(returnVal)) {
+            if (methodContext.getMethodType() == MethodContext.EVENT) {
+                methodContext.putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
+            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+                methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
             }
-            if (simpleMethodToCall == null) {
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process, could not find SimpleMethod " + methodName + " in XML document in resource: " + xmlResource;
-                methodContext.setErrorReturn(errMsg, simpleMethod);
+            return false;
+        }
+        if (methodContext.getMethodType() == MethodContext.EVENT) {
+            // FIXME: This doesn't make sense. We are comparing the called method's response code with this method's
+            // response code. Since response codes are configurable per method, this code will fail.
+            String responseCode = (String) localContext.getEnv(this.simpleMethod.getEventResponseCodeName());
+            if (this.simpleMethod.getDefaultErrorCode().equals(responseCode)) {
+                Debug.logWarning("Got error [" + responseCode + "] calling inline simple-method named [" + this.methodName + "] in resource [" + this.xmlResource + "], message is " + methodContext.getEnv(this.simpleMethod.getEventErrorMessageName()), module);
                 return false;
             }
-            String returnVal = simpleMethodToCall.exec(methodContext);
-            if (Debug.verboseOn())
-                Debug.logVerbose("Called inline simple-method named [" + methodName + "] in resource [" + xmlResource + "], returnVal is [" + returnVal + "]", module);
-            if (returnVal != null && returnVal.equals(simpleMethodToCall.getDefaultErrorCode())) {
-                // in this case just set the error code just in case it hasn't already
-                // been set, the error messages will already be in place...
-                if (methodContext.getMethodType() == MethodContext.EVENT) {
-                    methodContext.putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
-                } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
-                    methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
-                }
+        } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+            // FIXME: This doesn't make sense. We are comparing the called method's response message with this method's
+            // response message. Since response messages are configurable per method, this code will fail.
+            String responseMessage = (String) localContext.getEnv(this.simpleMethod.getServiceResponseMessageName());
+            if (this.simpleMethod.getDefaultErrorCode().equals(responseMessage)) {
+                Debug.logWarning("Got error [" + responseMessage + "] calling inline simple-method named [" + this.methodName + "] in resource [" + this.xmlResource + "], message is " + methodContext.getEnv(this.simpleMethod.getServiceErrorMessageName()) + ", and the error message list is: "
+                        + methodContext.getEnv(this.simpleMethod.getServiceErrorMessageListName()), module);
                 return false;
             }
-            // if the response code/message is error, if so show the error and return
-            // false
-            if (methodContext.getMethodType() == MethodContext.EVENT) {
-                String responseCode = (String) methodContext.getEnv(simpleMethod.getEventResponseCodeName());
-                if (responseCode != null && responseCode.equals(simpleMethod.getDefaultErrorCode())) {
-                    Debug.logWarning("Got error [" + responseCode + "] calling inline simple-method named [" + methodName + "] in resource [" + xmlResource + "], message is " + methodContext.getEnv(simpleMethod.getEventErrorMessageName()), module);
-                    return false;
-                }
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
-                String resonseMessage = (String) methodContext.getEnv(simpleMethod.getServiceResponseMessageName());
-                if (resonseMessage != null && resonseMessage.equals(simpleMethod.getDefaultErrorCode())) {
-                    Debug.logWarning("Got error [" + resonseMessage + "] calling inline simple-method named [" + methodName + "] in resource [" + xmlResource + "], message is " + methodContext.getEnv(simpleMethod.getServiceErrorMessageName()) + ", and the error message list is: "
-                            + methodContext.getEnv(simpleMethod.getServiceErrorMessageListName()), module);
-                    return false;
+        }
+        if ("function".equals(this.memoryModel) && this.resultToFieldList != null) {
+            Map<String, Object> results = localContext.getResults();
+            if (results != null) {
+                for (ResultToField resultToField : this.resultToFieldList) {
+                    resultToField.exec(methodContext.getEnvMap(), results);
                 }
             }
-        } else {
-            String errMsg = "ERROR in call-simple-method: methodName was missing; not running simpleMethod";
-            Debug.logError(errMsg, module);
-            methodContext.setErrorReturn(errMsg, simpleMethod);
-            return false;
         }
         return true;
     }
 
     @Override
     public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
-    public String getMethodName() {
-        return this.methodName;
-    }
-
-    public SimpleMethod getSimpleMethodToCall(ClassLoader loader) throws MiniLangException {
-        SimpleMethod simpleMethodToCall = null;
-        if (UtilValidate.isEmpty(xmlResource)) {
-            simpleMethodToCall = this.simpleMethod.getSimpleMethodInSameFile(methodName);
-        } else {
-            Map<String, SimpleMethod> simpleMethods = SimpleMethod.getSimpleMethods(xmlResource, loader);
-            simpleMethodToCall = simpleMethods.get(methodName);
-        }
-        return simpleMethodToCall;
-    }
-
-    public String getXmlResource() {
-        return this.xmlResource;
+    @Override
+    public String rawString() {
+        return toString();
     }
 
     @Override
-    public String rawString() {
-        return "<call-simple-method xml-resource=\"" + this.xmlResource + "\" method-name=\"" + this.methodName + "\" />";
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<call-simple-method ");
+        if (this.methodName.length() > 0) {
+            sb.append("method-name=\"").append(this.methodName).append("\" ");
+        }
+        if (this.xmlResource.length() > 0) {
+            sb.append("xml-resource=\"").append(this.xmlResource).append("\" ");
+        }
+        if (this.memoryModel.length() > 0) {
+            sb.append("memory-model=\"").append(this.memoryModel).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
     public static final class CallSimpleMethodFactory implements Factory<CallSimpleMethod> {
@@ -140,4 +174,33 @@ public class CallSimpleMethod extends Me
             return "call-simple-method";
         }
     }
+
+    private final class ResultToField {
+
+        private final FlexibleMapAccessor<Object> fieldFma;
+        private final FlexibleMapAccessor<Object> resultNameFma;
+
+        private ResultToField(Element element, SimpleMethod simpleMethod) throws ValidationException {
+            if (MiniLangValidate.validationOn()) {
+                MiniLangValidate.attributeNames(simpleMethod, element, "result-name", "field");
+                MiniLangValidate.requiredAttributes(simpleMethod, element, "result-name");
+                MiniLangValidate.expressionAttributes(simpleMethod, element, "result-name", "field");
+                MiniLangValidate.noChildElements(simpleMethod, element);
+            }
+            this.resultNameFma = FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
+            String fieldAttribute = element.getAttribute("field");
+            if (fieldAttribute.length() == 0) {
+                this.fieldFma = this.resultNameFma;
+            } else {
+                this.fieldFma = FlexibleMapAccessor.getInstance(fieldAttribute);
+            }
+        }
+
+        private void exec(Map<String, Object> context, Map<String, Object> results) throws MiniLangException {
+            Object value = this.resultNameFma.get(results);
+            if (value != null) {
+                this.fieldFma.put(context, value);
+            }
+        }
+    }
 }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java?rev=1331137&r1=1331136&r2=1331137&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java Thu Apr 26 22:40:22 2012
@@ -47,6 +47,8 @@ public final class Now extends MethodOpe
         if (MiniLangValidate.validationOn()) {
             MiniLangValidate.attributeNames(simpleMethod, element, "field", "type");
             MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "field");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "type");
             MiniLangValidate.noChildElements(simpleMethod, element);
         }
         this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java?rev=1331137&r1=1331136&r2=1331137&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java Thu Apr 26 22:40:22 2012
@@ -18,70 +18,72 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.serviceops;
 
-import java.util.Map;
-
-import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.minilang.MiniLangException;
+import org.ofbiz.minilang.MiniLangValidate;
 import org.ofbiz.minilang.SimpleMethod;
-import org.ofbiz.minilang.method.ContextAccessor;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.w3c.dom.Element;
 
 /**
- * Copies a map field to a Service result entry
+ * Copies a field to a service OUT attribute.
  */
-public class FieldToResult extends MethodOperation {
+public final class FieldToResult extends MethodOperation {
 
     public static final String module = FieldToResult.class.getName();
 
-    ContextAccessor<Object> fieldAcsr;
-    ContextAccessor<Map<String, ? extends Object>> mapAcsr;
-    ContextAccessor<Object> resultAcsr;
+    private final FlexibleMapAccessor<Object> fieldFma;
+    private final FlexibleMapAccessor<Object> resultFma;
 
     public FieldToResult(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported
-        mapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("map-name"));
-        fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name"));
-        resultAcsr = new ContextAccessor<Object>(element.getAttribute("result-name"), fieldAcsr.toString());
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "field", "result-name");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "result-name");
+            MiniLangValidate.noChildElements(simpleMethod, element);
+        }
+        this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
+        String resultNameAttribute = element.getAttribute("result-name");
+        if (resultNameAttribute.length() == 0) {
+            this.resultFma = this.fieldFma;
+        } else {
+            this.resultFma = FlexibleMapAccessor.getInstance(resultNameAttribute);
+        }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        // only run this if it is in an SERVICE context
-        if (methodContext.getMethodType() == MethodContext.SERVICE) {
-            Object fieldVal = null;
-            if (!mapAcsr.isEmpty()) {
-                Map<String, ? extends Object> fromMap = mapAcsr.get(methodContext);
-                if (fromMap == null) {
-                    Debug.logWarning("Map not found with name " + mapAcsr, module);
-                    return true;
-                }
-                fieldVal = fieldAcsr.get(fromMap, methodContext);
-            } else {
-                // no map name, try the env
-                fieldVal = fieldAcsr.get(methodContext);
-            }
-            if (fieldVal == null) {
-                Debug.logWarning("Field value not found with name " + fieldAcsr + " in Map with name " + mapAcsr, module);
-                return true;
-            }
-            resultAcsr.put(methodContext.getResults(), fieldVal, methodContext);
+        Object fieldVal = this.fieldFma.get(methodContext.getEnvMap());
+        if (fieldVal != null) {
+            this.resultFma.put(methodContext.getResults(), fieldVal);
         }
         return true;
     }
 
     @Override
     public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
     @Override
     public String rawString() {
-        // TODO: add all attributes and other info
-        return "<field-to-result field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<now ");
+        if (!this.fieldFma.isEmpty()) {
+            sb.append("field=\"").append(this.fieldFma).append("\" ");
+        }
+        if (!this.resultFma.isEmpty()) {
+            sb.append("result-name=\"").append(this.resultFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
     public static final class FieldToResultFactory implements Factory<FieldToResult> {



Re: svn commit: r1331137 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java src/org/ofbiz/minilang/method/envops/Now.java src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Posted by Adrian Crum <ad...@sandglass-software.com>.
Fixed rev 1331247.

-Adrian

On 4/27/2012 7:43 AM, Jacques Le Roux wrote:
> Hi Adrian,
>
> This is blocking trunk demo, please fix or revert
>
> Thanks
>
> Jacques
>
> From: <ad...@apache.org>
>> Author: adrianc
>> Date: Thu Apr 26 22:40:22 2012
>> New Revision: 1331137
>>
>> URL: http://svn.apache.org/viewvc?rev=1331137&view=rev
>> Log:
>> Added new attribute "memory-model" to the Mini-language 
>> <call-simple-method> element. Code cleanup and validation in 
>> FieldToResult.java. Improved validation in Now.java.
>>
>> Modified:
>>    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
>>    
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
>>    
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
>>    
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java
>>
>> Modified: ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
>> URL: 
>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd?rev=1331137&r1=1331136&r2=1331137&view=diff
>> ============================================================================== 
>>
>> --- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
>> +++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Thu Apr 
>> 26 22:40:22 2012
>> @@ -918,33 +918,64 @@ under the License.
>> <xs:element name="call-simple-method" 
>> substitutionGroup="CallOperations">
>> <xs:annotation>
>> <xs:documentation>
>> -                The call-simple-method tag calls another 
>> simple-method in the same context as the current one.
>> -                In other words the called simple-method will have 
>> the same environment as the calling simple-method,
>> -                including all environment fields, and either the 
>> event or service objects that the calling simple-method was called with.
>> +                Calls another simple-method in the same context as 
>> the current one.
>> +                The called simple-method will have the same 
>> environment as the calling simple-method,
>> +                including all environment fields, and either the 
>> event or service objects
>> +                that the calling simple-method was called
>> +                with.
>> </xs:documentation>
>> </xs:annotation>
>> <xs:complexType>
>> - <xs:attributeGroup ref="attlist.call-simple-method"/>
>> + <xs:sequence>
>> + <xs:element ref="result-to-field" minOccurs="0" maxOccurs="unbounded">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                            Used when 
>> memory-model=&quot;function&quot;. Copies the called method fields
>> +                            to the calling method fields.
>> + </xs:documentation>
>> + </xs:annotation>
>> + </xs:element>
>> + </xs:sequence>
>> + <xs:attribute type="xs:string" name="method-name" use="required">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                        The name of the simple-method to execute in 
>> the specified xml-resource,
>> +                        or in the current XML file if no 
>> xml-resource is specified.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Required. Attribute type: constant.
>> + </xs:documentation>
>> + </xs:annotation>
>> + </xs:attribute>
>> + <xs:attribute type="xs:string" name="xml-resource">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                        The full path and filename on the classpath 
>> of the XML file which contains an external simple-method to execute.
>> +                        This is only required if a simple-method in 
>> a different file is desired.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Optional. Attribute type: constant.
>> + </xs:documentation>
>> + </xs:annotation>
>> + </xs:attribute>
>> + <xs:attribute name="memory-model">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                        The memory model to use. In an 
>> &quot;inline&quot; memory model, fields declared or modified in the 
>> called method
>> +                        will be reflected back to the calling method 
>> - as if the called method was inline. In a &quot;function&quot; memory
>> +                        model, fields declared or modified in the 
>> called method are local to the called method - they are not
>> +                        reflected back to the calling method.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Optional. Attribute type: constant.
>> + </xs:documentation>
>> + </xs:annotation>
>> + <xs:simpleType>
>> + <xs:restriction base="xs:token">
>> + <xs:enumeration value="inline" />
>> + <xs:enumeration value="function" />
>> + </xs:restriction>
>> + </xs:simpleType>
>> + </xs:attribute>
>> </xs:complexType>
>> </xs:element>
>> - <xs:attributeGroup name="attlist.call-simple-method">
>> - <xs:attribute type="xs:string" name="xml-resource">
>> - <xs:annotation>
>> - <xs:documentation>
>> -                    The full path and filename on the classpath of 
>> the XML file which contains an external simple-method to execute.
>> -                    This is only required if a simple-method in a 
>> different file is desired.
>> - </xs:documentation>
>> - </xs:annotation>
>> - </xs:attribute>
>> - <xs:attribute type="xs:string" name="method-name" use="required">
>> - <xs:annotation>
>> - <xs:documentation>
>> -                    The name of the simple-method to execute in the 
>> specified xml-resource,
>> -                    or in the current XML file if no xml-resource is 
>> specified.
>> - </xs:documentation>
>> - </xs:annotation>
>> - </xs:attribute>
>> - </xs:attributeGroup>
>> <!-- Operations to call Java methods and create Java objects -->
>> <xs:element name="call-object-method" 
>> substitutionGroup="CallOperations">
>> <xs:annotation>
>> @@ -1265,26 +1296,43 @@ under the License.
>> <xs:annotation><xs:documentation>The name of the session attribute to 
>> use. Defaults to the value of field 
>> attribute</xs:documentation></xs:annotation>
>> </xs:attribute>
>> </xs:attributeGroup>
>> - <!-- Service specific operations -->
>> - <xs:element name="field-to-result" 
>> substitutionGroup="ServiceOperations">
>> + <xs:element name="field-to-result" substitutionGroup="EnvOperations">
>> <xs:annotation>
>> <xs:documentation>
>> -                The field-to-result tag copies a field from a map to 
>> the specified service result field.
>> -                The tag is only used when the simple-method is 
>> called as a service, it is ignored otherwise.
>> +                Copies a field to a service OUT attribute.
>> </xs:documentation>
>> </xs:annotation>
>> <xs:complexType>
>> - <xs:attributeGroup ref="attlist.field-to-result"/>
>> + <xs:attribute name="field" use="required">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                        The name of the field to copy from. The 
>> source of the assignment.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Required. Attribute type: expression.
>> + </xs:documentation>
>> + </xs:annotation>
>> + <xs:simpleType>
>> + <xs:restriction base="xs:string">
>> + <xs:minLength value="1" />
>> + </xs:restriction>
>> + </xs:simpleType>
>> + </xs:attribute>
>> + <xs:attribute name="result-name">
>> + <xs:annotation>
>> + <xs:documentation>
>> +                        The name of the result field to set. The 
>> target of the assignment.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Optional. Attribute type: expression.
>> + </xs:documentation>
>> + </xs:annotation>
>> + <xs:simpleType>
>> + <xs:restriction base="xs:string">
>> + <xs:minLength value="1" />
>> + </xs:restriction>
>> + </xs:simpleType>
>> + </xs:attribute>
>> </xs:complexType>
>> </xs:element>
>> - <xs:attributeGroup name="attlist.field-to-result">
>> - <xs:attribute type="xs:string" name="field" use="required">
>> - <xs:annotation><xs:documentation>The name (key) of the map field to 
>> use.</xs:documentation></xs:annotation>
>> - </xs:attribute>
>> - <xs:attribute type="xs:string" name="result-name">
>> - <xs:annotation><xs:documentation>The name of the result Map 
>> name/key to use. Defaults to the value of field 
>> attribute.</xs:documentation></xs:annotation>
>> - </xs:attribute>
>> - </xs:attributeGroup>
>> <!-- Environment specific operations -->
>> <xs:element name="map-to-map" substitutionGroup="EnvOperations">
>> <xs:annotation>
>> @@ -4436,6 +4484,8 @@ under the License.
>> <xs:annotation>
>> <xs:documentation>
>>                         The field data type. Defaults to 
>> java.sql.Timestamp.
>> + &lt;br/&gt;&lt;br/&gt;
>> +                        Optional. Attribute type: constant.
>> </xs:documentation>
>> </xs:annotation>
>> <xs:simpleType>
>>
>> Modified: 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
>> URL: 
>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java?rev=1331137&r1=1331136&r2=1331137&view=diff
>> ============================================================================== 
>>
>> --- 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java 
>> (original)
>> +++ 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java 
>> Thu Apr 26 22:40:22 2012
>> @@ -18,117 +18,151 @@
>>  *******************************************************************************/ 
>>
>> package org.ofbiz.minilang.method.callops;
>>
>> +import java.util.ArrayList;
>> +import java.util.List;
>> import java.util.Map;
>>
>> +import javolution.util.FastMap;
>> +
>> import org.ofbiz.base.util.Debug;
>> import org.ofbiz.base.util.UtilValidate;
>> +import org.ofbiz.base.util.UtilXml;
>> +import org.ofbiz.base.util.collections.FlexibleMapAccessor;
>> +import org.ofbiz.base.util.string.FlexibleStringExpander;
>> import org.ofbiz.minilang.MiniLangException;
>> +import org.ofbiz.minilang.MiniLangRuntimeException;
>> +import org.ofbiz.minilang.MiniLangValidate;
>> import org.ofbiz.minilang.SimpleMethod;
>> +import org.ofbiz.minilang.ValidationException;
>> import org.ofbiz.minilang.method.MethodContext;
>> import org.ofbiz.minilang.method.MethodOperation;
>> import org.w3c.dom.Element;
>>
>> /**
>> - * An operation that calls a simple method in the same, or from 
>> another, file
>> + * Invokes a Mini-language simple method.
>>  */
>> -public class CallSimpleMethod extends MethodOperation {
>> +public final class CallSimpleMethod extends MethodOperation {
>>
>>     public static final String module = 
>> CallSimpleMethod.class.getName();
>>
>> -    String methodName;
>> -    String xmlResource;
>> +    private final String methodName;
>> +    private final String xmlResource;
>> +    private final String memoryModel;
>> +    private final List<ResultToField> resultToFieldList;
>>
>>     public CallSimpleMethod(Element element, SimpleMethod 
>> simpleMethod) throws MiniLangException {
>>         super(element, simpleMethod);
>> +        if (MiniLangValidate.validationOn()) {
>> +            MiniLangValidate.attributeNames(simpleMethod, element, 
>> "method-name", "xml-resource", "memory-model");
>> +            MiniLangValidate.requiredAttributes(simpleMethod, 
>> element, "method-name");
>> +            MiniLangValidate.constantAttributes(simpleMethod, 
>> element, "method-name", "xml-resource", "memory-model");
>> +            MiniLangValidate.childElements(simpleMethod, element, 
>> "result-to-field");
>> +        }
>>         this.methodName = element.getAttribute("method-name");
>>         this.xmlResource = element.getAttribute("xml-resource");
>> +        this.memoryModel = element.getAttribute("memory-model");
>> +        List<? extends Element> resultToFieldElements = 
>> UtilXml.childElementList(element, "result-to-field");
>> +        if (UtilValidate.isNotEmpty(resultToFieldElements)) {
>> +            if (!"function".equals(this.memoryModel)) {
>> +                MiniLangValidate.handleError("Inline memory model 
>> cannot include <result-to-field> elements.", simpleMethod, element);
>> +            }
>> +            List<ResultToField> resultToFieldList = new 
>> ArrayList<ResultToField>(resultToFieldElements.size());
>> +            for (Element resultToFieldElement : 
>> resultToFieldElements) {
>> +                resultToFieldList.add(new 
>> ResultToField(resultToFieldElement, simpleMethod));
>> +            }
>> +            this.resultToFieldList = resultToFieldList;
>> +        } else {
>> +            this.resultToFieldList = null;
>> +        }
>>     }
>>
>>     @Override
>>     public boolean exec(MethodContext methodContext) throws 
>> MiniLangException {
>> -        if (UtilValidate.isNotEmpty(this.methodName)) {
>> -            String methodName = 
>> methodContext.expandString(this.methodName);
>> -            String xmlResource = 
>> methodContext.expandString(this.xmlResource);
>> -            SimpleMethod simpleMethodToCall = null;
>> -            try {
>> -                simpleMethodToCall = 
>> getSimpleMethodToCall(methodContext.getLoader());
>> -            } catch (MiniLangException e) {
>> -                String errMsg = "ERROR: Could not complete the " + 
>> simpleMethod.getShortDescription() + " process [error getting methods 
>> from resource: " + e.getMessage() + "]";
>> -                Debug.logError(e, errMsg, module);
>> -                methodContext.setErrorReturn(errMsg, simpleMethod);
>> -                return false;
>> +        if (UtilValidate.isEmpty(this.methodName)) {
>> +            throw new MiniLangRuntimeException("method-name 
>> attribute is empty", this);
>> +        }
>> +        SimpleMethod simpleMethodToCall = null;
>> +        if (UtilValidate.isEmpty(this.xmlResource)) {
>> +            simpleMethodToCall = 
>> this.simpleMethod.getSimpleMethodInSameFile(methodName);
>> +        } else {
>> +            Map<String, SimpleMethod> simpleMethods = 
>> SimpleMethod.getSimpleMethods(this.xmlResource, 
>> methodContext.getLoader());
>> +            simpleMethodToCall = simpleMethods.get(this.methodName);
>> +        }
>> +        if (simpleMethodToCall == null) {
>> +            throw new MiniLangRuntimeException("Could not find 
>> <simple-method name=\"" + this.methodName + "\"> in XML document " + 
>> this.xmlResource, this);
>> +        }
>> +        MethodContext localContext = methodContext;
>> +        if ("function".equals(this.memoryModel)) {
>> +            Map<String, Object> localEnv = FastMap.newInstance();
>> +            localEnv.putAll(methodContext.getEnvMap());
>> +            
>> localEnv.remove(this.simpleMethod.getEventResponseCodeName());
>> +            
>> localEnv.remove(this.simpleMethod.getServiceResponseMessageName());
>> +            localContext = new MethodContext(localEnv, 
>> methodContext.getLoader(), methodContext.getMethodType());
>> +        }
>> +        String returnVal = simpleMethodToCall.exec(localContext);
>> +        if (Debug.verboseOn())
>> +            Debug.logVerbose("Called simple-method named [" + 
>> this.methodName + "] in resource [" + this.xmlResource + "], 
>> returnVal is [" + returnVal + "]", module);
>> +        if 
>> (simpleMethodToCall.getDefaultErrorCode().equals(returnVal)) {
>> +            if (methodContext.getMethodType() == MethodContext.EVENT) {
>> +                
>> methodContext.putEnv(simpleMethod.getEventResponseCodeName(), 
>> simpleMethod.getDefaultErrorCode());
>> +            } else if (methodContext.getMethodType() == 
>> MethodContext.SERVICE) {
>> +                
>> methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), 
>> simpleMethod.getDefaultErrorCode());
>>             }
>> -            if (simpleMethodToCall == null) {
>> -                String errMsg = "ERROR: Could not complete the " + 
>> simpleMethod.getShortDescription() + " process, could not find 
>> SimpleMethod " + methodName + " in XML document in resource: " + 
>> xmlResource;
>> -                methodContext.setErrorReturn(errMsg, simpleMethod);
>> +            return false;
>> +        }
>> +        if (methodContext.getMethodType() == MethodContext.EVENT) {
>> +            // FIXME: This doesn't make sense. We are comparing the 
>> called method's response code with this method's
>> +            // response code. Since response codes are configurable 
>> per method, this code will fail.
>> +            String responseCode = (String) 
>> localContext.getEnv(this.simpleMethod.getEventResponseCodeName());
>> +            if 
>> (this.simpleMethod.getDefaultErrorCode().equals(responseCode)) {
>> +                Debug.logWarning("Got error [" + responseCode + "] 
>> calling inline simple-method named [" + this.methodName + "] in 
>> resource [" + this.xmlResource + "], message is " + 
>> methodContext.getEnv(this.simpleMethod.getEventErrorMessageName()), 
>> module);
>>                 return false;
>>             }
>> -            String returnVal = simpleMethodToCall.exec(methodContext);
>> -            if (Debug.verboseOn())
>> -                Debug.logVerbose("Called inline simple-method named 
>> [" + methodName + "] in resource [" + xmlResource + "], returnVal is 
>> [" + returnVal + "]", module);
>> -            if (returnVal != null && 
>> returnVal.equals(simpleMethodToCall.getDefaultErrorCode())) {
>> -                // in this case just set the error code just in case 
>> it hasn't already
>> -                // been set, the error messages will already be in 
>> place...
>> -                if (methodContext.getMethodType() == 
>> MethodContext.EVENT) {
>> -                    
>> methodContext.putEnv(simpleMethod.getEventResponseCodeName(), 
>> simpleMethod.getDefaultErrorCode());
>> -                } else if (methodContext.getMethodType() == 
>> MethodContext.SERVICE) {
>> -                    
>> methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), 
>> simpleMethod.getDefaultErrorCode());
>> -                }
>> +        } else if (methodContext.getMethodType() == 
>> MethodContext.SERVICE) {
>> +            // FIXME: This doesn't make sense. We are comparing the 
>> called method's response message with this method's
>> +            // response message. Since response messages are 
>> configurable per method, this code will fail.
>> +            String responseMessage = (String) 
>> localContext.getEnv(this.simpleMethod.getServiceResponseMessageName());
>> +            if 
>> (this.simpleMethod.getDefaultErrorCode().equals(responseMessage)) {
>> +                Debug.logWarning("Got error [" + responseMessage + 
>> "] calling inline simple-method named [" + this.methodName + "] in 
>> resource [" + this.xmlResource + "], message is " + 
>> methodContext.getEnv(this.simpleMethod.getServiceErrorMessageName()) 
>> + ", and the error message list is: "
>> +                        + 
>> methodContext.getEnv(this.simpleMethod.getServiceErrorMessageListName()), 
>> module);
>>                 return false;
>>             }
>> -            // if the response code/message is error, if so show the 
>> error and return
>> -            // false
>> -            if (methodContext.getMethodType() == MethodContext.EVENT) {
>> -                String responseCode = (String) 
>> methodContext.getEnv(simpleMethod.getEventResponseCodeName());
>> -                if (responseCode != null && 
>> responseCode.equals(simpleMethod.getDefaultErrorCode())) {
>> -                    Debug.logWarning("Got error [" + responseCode + 
>> "] calling inline simple-method named [" + methodName + "] in 
>> resource [" + xmlResource + "], message is " + 
>> methodContext.getEnv(simpleMethod.getEventErrorMessageName()), module);
>> -                    return false;
>> -                }
>> -            } else if (methodContext.getMethodType() == 
>> MethodContext.SERVICE) {
>> -                String resonseMessage = (String) 
>> methodContext.getEnv(simpleMethod.getServiceResponseMessageName());
>> -                if (resonseMessage != null && 
>> resonseMessage.equals(simpleMethod.getDefaultErrorCode())) {
>> -                    Debug.logWarning("Got error [" + resonseMessage 
>> + "] calling inline simple-method named [" + methodName + "] in 
>> resource [" + xmlResource + "], message is " + 
>> methodContext.getEnv(simpleMethod.getServiceErrorMessageName()) + ", 
>> and the error message list is: "
>> -                            + 
>> methodContext.getEnv(simpleMethod.getServiceErrorMessageListName()), 
>> module);
>> -                    return false;
>> +        }
>> +        if ("function".equals(this.memoryModel) && 
>> this.resultToFieldList != null) {
>> +            Map<String, Object> results = localContext.getResults();
>> +            if (results != null) {
>> +                for (ResultToField resultToField : 
>> this.resultToFieldList) {
>> +                    resultToField.exec(methodContext.getEnvMap(), 
>> results);
>>                 }
>>             }
>> -        } else {
>> -            String errMsg = "ERROR in call-simple-method: methodName 
>> was missing; not running simpleMethod";
>> -            Debug.logError(errMsg, module);
>> -            methodContext.setErrorReturn(errMsg, simpleMethod);
>> -            return false;
>>         }
>>         return true;
>>     }
>>
>>     @Override
>>     public String expandedString(MethodContext methodContext) {
>> -        // TODO: something more than a stub/dummy
>> -        return this.rawString();
>> +        return FlexibleStringExpander.expandString(toString(), 
>> methodContext.getEnvMap());
>>     }
>>
>> -    public String getMethodName() {
>> -        return this.methodName;
>> -    }
>> -
>> -    public SimpleMethod getSimpleMethodToCall(ClassLoader loader) 
>> throws MiniLangException {
>> -        SimpleMethod simpleMethodToCall = null;
>> -        if (UtilValidate.isEmpty(xmlResource)) {
>> -            simpleMethodToCall = 
>> this.simpleMethod.getSimpleMethodInSameFile(methodName);
>> -        } else {
>> -            Map<String, SimpleMethod> simpleMethods = 
>> SimpleMethod.getSimpleMethods(xmlResource, loader);
>> -            simpleMethodToCall = simpleMethods.get(methodName);
>> -        }
>> -        return simpleMethodToCall;
>> -    }
>> -
>> -    public String getXmlResource() {
>> -        return this.xmlResource;
>> +    @Override
>> +    public String rawString() {
>> +        return toString();
>>     }
>>
>>     @Override
>> -    public String rawString() {
>> -        return "<call-simple-method xml-resource=\"" + 
>> this.xmlResource + "\" method-name=\"" + this.methodName + "\" />";
>> +    public String toString() {
>> +        StringBuilder sb = new StringBuilder("<call-simple-method ");
>> +        if (this.methodName.length() > 0) {
>> +            
>> sb.append("method-name=\"").append(this.methodName).append("\" ");
>> +        }
>> +        if (this.xmlResource.length() > 0) {
>> +            
>> sb.append("xml-resource=\"").append(this.xmlResource).append("\" ");
>> +        }
>> +        if (this.memoryModel.length() > 0) {
>> +            
>> sb.append("memory-model=\"").append(this.memoryModel).append("\" ");
>> +        }
>> +        sb.append("/>");
>> +        return sb.toString();
>>     }
>>
>>     public static final class CallSimpleMethodFactory implements 
>> Factory<CallSimpleMethod> {
>> @@ -140,4 +174,33 @@ public class CallSimpleMethod extends Me
>>             return "call-simple-method";
>>         }
>>     }
>> +
>> +    private final class ResultToField {
>> +
>> +        private final FlexibleMapAccessor<Object> fieldFma;
>> +        private final FlexibleMapAccessor<Object> resultNameFma;
>> +
>> +        private ResultToField(Element element, SimpleMethod 
>> simpleMethod) throws ValidationException {
>> +            if (MiniLangValidate.validationOn()) {
>> +                MiniLangValidate.attributeNames(simpleMethod, 
>> element, "result-name", "field");
>> +                MiniLangValidate.requiredAttributes(simpleMethod, 
>> element, "result-name");
>> +                MiniLangValidate.expressionAttributes(simpleMethod, 
>> element, "result-name", "field");
>> +                MiniLangValidate.noChildElements(simpleMethod, 
>> element);
>> +            }
>> +            this.resultNameFma = 
>> FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
>> +            String fieldAttribute = element.getAttribute("field");
>> +            if (fieldAttribute.length() == 0) {
>> +                this.fieldFma = this.resultNameFma;
>> +            } else {
>> +                this.fieldFma = 
>> FlexibleMapAccessor.getInstance(fieldAttribute);
>> +            }
>> +        }
>> +
>> +        private void exec(Map<String, Object> context, Map<String, 
>> Object> results) throws MiniLangException {
>> +            Object value = this.resultNameFma.get(results);
>> +            if (value != null) {
>> +                this.fieldFma.put(context, value);
>> +            }
>> +        }
>> +    }
>> }
>>
>> Modified: 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
>> URL: 
>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java?rev=1331137&r1=1331136&r2=1331137&view=diff
>> ============================================================================== 
>>
>> --- 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java 
>> (original)
>> +++ 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java 
>> Thu Apr 26 22:40:22 2012
>> @@ -47,6 +47,8 @@ public final class Now extends MethodOpe
>>         if (MiniLangValidate.validationOn()) {
>>             MiniLangValidate.attributeNames(simpleMethod, element, 
>> "field", "type");
>>             MiniLangValidate.requiredAttributes(simpleMethod, 
>> element, "field");
>> +            MiniLangValidate.expressionAttributes(simpleMethod, 
>> element, "field");
>> +            MiniLangValidate.constantAttributes(simpleMethod, 
>> element, "type");
>>             MiniLangValidate.noChildElements(simpleMethod, element);
>>         }
>>         this.fieldFma = 
>> FlexibleMapAccessor.getInstance(element.getAttribute("field"));
>>
>> Modified: 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java
>> URL: 
>> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java?rev=1331137&r1=1331136&r2=1331137&view=diff
>> ============================================================================== 
>>
>> --- 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java 
>> (original)
>> +++ 
>> ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java 
>> Thu Apr 26 22:40:22 2012
>> @@ -18,70 +18,72 @@
>>  *******************************************************************************/ 
>>
>> package org.ofbiz.minilang.method.serviceops;
>>
>> -import java.util.Map;
>> -
>> -import org.ofbiz.base.util.Debug;
>> +import org.ofbiz.base.util.collections.FlexibleMapAccessor;
>> +import org.ofbiz.base.util.string.FlexibleStringExpander;
>> import org.ofbiz.minilang.MiniLangException;
>> +import org.ofbiz.minilang.MiniLangValidate;
>> import org.ofbiz.minilang.SimpleMethod;
>> -import org.ofbiz.minilang.method.ContextAccessor;
>> import org.ofbiz.minilang.method.MethodContext;
>> import org.ofbiz.minilang.method.MethodOperation;
>> import org.w3c.dom.Element;
>>
>> /**
>> - * Copies a map field to a Service result entry
>> + * Copies a field to a service OUT attribute.
>>  */
>> -public class FieldToResult extends MethodOperation {
>> +public final class FieldToResult extends MethodOperation {
>>
>>     public static final String module = FieldToResult.class.getName();
>>
>> -    ContextAccessor<Object> fieldAcsr;
>> -    ContextAccessor<Map<String, ? extends Object>> mapAcsr;
>> -    ContextAccessor<Object> resultAcsr;
>> +    private final FlexibleMapAccessor<Object> fieldFma;
>> +    private final FlexibleMapAccessor<Object> resultFma;
>>
>>     public FieldToResult(Element element, SimpleMethod simpleMethod) 
>> throws MiniLangException {
>>         super(element, simpleMethod);
>> -        // the schema for this element now just has the "field" 
>> attribute, though the old "field-name" and "map-name" pair is still 
>> supported
>> -        mapAcsr = new ContextAccessor<Map<String, ? extends 
>> Object>>(element.getAttribute("map-name"));
>> -        fieldAcsr = new 
>> ContextAccessor<Object>(element.getAttribute("field"), 
>> element.getAttribute("field-name"));
>> -        resultAcsr = new 
>> ContextAccessor<Object>(element.getAttribute("result-name"), 
>> fieldAcsr.toString());
>> +        if (MiniLangValidate.validationOn()) {
>> +            MiniLangValidate.attributeNames(simpleMethod, element, 
>> "field", "result-name");
>> +            MiniLangValidate.requiredAttributes(simpleMethod, 
>> element, "field");
>> +            MiniLangValidate.expressionAttributes(simpleMethod, 
>> element, "field", "result-name");
>> +            MiniLangValidate.noChildElements(simpleMethod, element);
>> +        }
>> +        this.fieldFma = 
>> FlexibleMapAccessor.getInstance(element.getAttribute("field"));
>> +        String resultNameAttribute = 
>> element.getAttribute("result-name");
>> +        if (resultNameAttribute.length() == 0) {
>> +            this.resultFma = this.fieldFma;
>> +        } else {
>> +            this.resultFma = 
>> FlexibleMapAccessor.getInstance(resultNameAttribute);
>> +        }
>>     }
>>
>>     @Override
>>     public boolean exec(MethodContext methodContext) throws 
>> MiniLangException {
>> -        // only run this if it is in an SERVICE context
>> -        if (methodContext.getMethodType() == MethodContext.SERVICE) {
>> -            Object fieldVal = null;
>> -            if (!mapAcsr.isEmpty()) {
>> -                Map<String, ? extends Object> fromMap = 
>> mapAcsr.get(methodContext);
>> -                if (fromMap == null) {
>> -                    Debug.logWarning("Map not found with name " + 
>> mapAcsr, module);
>> -                    return true;
>> -                }
>> -                fieldVal = fieldAcsr.get(fromMap, methodContext);
>> -            } else {
>> -                // no map name, try the env
>> -                fieldVal = fieldAcsr.get(methodContext);
>> -            }
>> -            if (fieldVal == null) {
>> -                Debug.logWarning("Field value not found with name " 
>> + fieldAcsr + " in Map with name " + mapAcsr, module);
>> -                return true;
>> -            }
>> -            resultAcsr.put(methodContext.getResults(), fieldVal, 
>> methodContext);
>> +        Object fieldVal = this.fieldFma.get(methodContext.getEnvMap());
>> +        if (fieldVal != null) {
>> +            this.resultFma.put(methodContext.getResults(), fieldVal);
>>         }
>>         return true;
>>     }
>>
>>     @Override
>>     public String expandedString(MethodContext methodContext) {
>> -        // TODO: something more than a stub/dummy
>> -        return this.rawString();
>> +        return FlexibleStringExpander.expandString(toString(), 
>> methodContext.getEnvMap());
>>     }
>>
>>     @Override
>>     public String rawString() {
>> -        // TODO: add all attributes and other info
>> -        return "<field-to-result field-name=\"" + this.fieldAcsr + 
>> "\" map-name=\"" + this.mapAcsr + "\"/>";
>> +        return toString();
>> +    }
>> +
>> +    @Override
>> +    public String toString() {
>> +        StringBuilder sb = new StringBuilder("<now ");
>> +        if (!this.fieldFma.isEmpty()) {
>> +            sb.append("field=\"").append(this.fieldFma).append("\" ");
>> +        }
>> +        if (!this.resultFma.isEmpty()) {
>> +            
>> sb.append("result-name=\"").append(this.resultFma).append("\" ");
>> +        }
>> +        sb.append("/>");
>> +        return sb.toString();
>>     }
>>
>>     public static final class FieldToResultFactory implements 
>> Factory<FieldToResult> {
>>
>>

Re: svn commit: r1331137 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java src/org/ofbiz/minilang/method/envops/Now.java src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Posted by Jacques Le Roux <ja...@les7arts.com>.
Hi Adrian,

This is blocking trunk demo, please fix or revert

Thanks

Jacques

From: <ad...@apache.org>
> Author: adrianc
> Date: Thu Apr 26 22:40:22 2012
> New Revision: 1331137
>
> URL: http://svn.apache.org/viewvc?rev=1331137&view=rev
> Log:
> Added new attribute "memory-model" to the Mini-language <call-simple-method> element. Code cleanup and validation in 
> FieldToResult.java. Improved validation in Now.java.
>
> Modified:
>    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
>    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
>    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
>    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java
>
> Modified: ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd?rev=1331137&r1=1331136&r2=1331137&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
> +++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Thu Apr 26 22:40:22 2012
> @@ -918,33 +918,64 @@ under the License.
>     <xs:element name="call-simple-method" substitutionGroup="CallOperations">
>         <xs:annotation>
>             <xs:documentation>
> -                The call-simple-method tag calls another simple-method in the same context as the current one.
> -                In other words the called simple-method will have the same environment as the calling simple-method,
> -                including all environment fields, and either the event or service objects that the calling simple-method was 
> called with.
> +                Calls another simple-method in the same context as the current one.
> +                The called simple-method will have the same environment as the calling simple-method,
> +                including all environment fields, and either the event or service objects
> +                that the calling simple-method was called
> +                with.
>             </xs:documentation>
>         </xs:annotation>
>         <xs:complexType>
> -            <xs:attributeGroup ref="attlist.call-simple-method"/>
> +            <xs:sequence>
> +                <xs:element ref="result-to-field" minOccurs="0" maxOccurs="unbounded">
> +                    <xs:annotation>
> +                        <xs:documentation>
> +                            Used when memory-model=&quot;function&quot;. Copies the called method fields
> +                            to the calling method fields.
> +                        </xs:documentation>
> +                    </xs:annotation>
> +                </xs:element>
> +            </xs:sequence>
> +            <xs:attribute type="xs:string" name="method-name" use="required">
> +                <xs:annotation>
> +                    <xs:documentation>
> +                        The name of the simple-method to execute in the specified xml-resource,
> +                        or in the current XML file if no xml-resource is specified.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Required. Attribute type: constant.
> +                    </xs:documentation>
> +                </xs:annotation>
> +            </xs:attribute>
> +            <xs:attribute type="xs:string" name="xml-resource">
> +                <xs:annotation>
> +                    <xs:documentation>
> +                        The full path and filename on the classpath of the XML file which contains an external simple-method to 
> execute.
> +                        This is only required if a simple-method in a different file is desired.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Optional. Attribute type: constant.
> +                    </xs:documentation>
> +                </xs:annotation>
> +            </xs:attribute>
> +            <xs:attribute name="memory-model">
> +                <xs:annotation>
> +                    <xs:documentation>
> +                        The memory model to use. In an &quot;inline&quot; memory model, fields declared or modified in the called 
> method
> +                        will be reflected back to the calling method - as if the called method was inline. In a 
> &quot;function&quot; memory
> +                        model, fields declared or modified in the called method are local to the called method - they are not
> +                        reflected back to the calling method.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Optional. Attribute type: constant.
> +                    </xs:documentation>
> +                </xs:annotation>
> +                <xs:simpleType>
> +                    <xs:restriction base="xs:token">
> +                        <xs:enumeration value="inline" />
> +                        <xs:enumeration value="function" />
> +                    </xs:restriction>
> +                </xs:simpleType>
> +            </xs:attribute>
>         </xs:complexType>
>     </xs:element>
> -    <xs:attributeGroup name="attlist.call-simple-method">
> -        <xs:attribute type="xs:string" name="xml-resource">
> -            <xs:annotation>
> -                <xs:documentation>
> -                    The full path and filename on the classpath of the XML file which contains an external simple-method to 
> execute.
> -                    This is only required if a simple-method in a different file is desired.
> -                </xs:documentation>
> -            </xs:annotation>
> -        </xs:attribute>
> -        <xs:attribute type="xs:string" name="method-name" use="required">
> -            <xs:annotation>
> -                <xs:documentation>
> -                    The name of the simple-method to execute in the specified xml-resource,
> -                    or in the current XML file if no xml-resource is specified.
> -                </xs:documentation>
> -            </xs:annotation>
> -        </xs:attribute>
> -    </xs:attributeGroup>
>     <!-- Operations to call Java methods and create Java objects -->
>     <xs:element name="call-object-method" substitutionGroup="CallOperations">
>         <xs:annotation>
> @@ -1265,26 +1296,43 @@ under the License.
>             <xs:annotation><xs:documentation>The name of the session attribute to use. Defaults to the value of field 
> attribute</xs:documentation></xs:annotation>
>         </xs:attribute>
>     </xs:attributeGroup>
> -    <!-- Service specific operations -->
> -    <xs:element name="field-to-result" substitutionGroup="ServiceOperations">
> +    <xs:element name="field-to-result" substitutionGroup="EnvOperations">
>         <xs:annotation>
>             <xs:documentation>
> -                The field-to-result tag copies a field from a map to the specified service result field.
> -                The tag is only used when the simple-method is called as a service, it is ignored otherwise.
> +                Copies a field to a service OUT attribute.
>             </xs:documentation>
>         </xs:annotation>
>         <xs:complexType>
> -            <xs:attributeGroup ref="attlist.field-to-result"/>
> +            <xs:attribute name="field" use="required">
> +                <xs:annotation>
> +                    <xs:documentation>
> +                        The name of the field to copy from. The source of the assignment.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Required. Attribute type: expression.
> +                    </xs:documentation>
> +                </xs:annotation>
> +                <xs:simpleType>
> +                    <xs:restriction base="xs:string">
> +                        <xs:minLength value="1" />
> +                    </xs:restriction>
> +                </xs:simpleType>
> +            </xs:attribute>
> +            <xs:attribute name="result-name">
> +                <xs:annotation>
> +                    <xs:documentation>
> +                        The name of the result field to set. The target of the assignment.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Optional. Attribute type: expression.
> +                    </xs:documentation>
> +                </xs:annotation>
> +                <xs:simpleType>
> +                    <xs:restriction base="xs:string">
> +                        <xs:minLength value="1" />
> +                    </xs:restriction>
> +                </xs:simpleType>
> +            </xs:attribute>
>         </xs:complexType>
>     </xs:element>
> -    <xs:attributeGroup name="attlist.field-to-result">
> -        <xs:attribute type="xs:string" name="field" use="required">
> -            <xs:annotation><xs:documentation>The name (key) of the map field to use.</xs:documentation></xs:annotation>
> -        </xs:attribute>
> -        <xs:attribute type="xs:string" name="result-name">
> -            <xs:annotation><xs:documentation>The name of the result Map name/key to use. Defaults to the value of field 
> attribute.</xs:documentation></xs:annotation>
> -        </xs:attribute>
> -    </xs:attributeGroup>
>     <!-- Environment specific operations -->
>     <xs:element name="map-to-map" substitutionGroup="EnvOperations">
>         <xs:annotation>
> @@ -4436,6 +4484,8 @@ under the License.
>                 <xs:annotation>
>                     <xs:documentation>
>                         The field data type. Defaults to java.sql.Timestamp.
> +                        &lt;br/&gt;&lt;br/&gt;
> +                        Optional. Attribute type: constant.
>                     </xs:documentation>
>                 </xs:annotation>
>                 <xs:simpleType>
>
> Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java?rev=1331137&r1=1331136&r2=1331137&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java (original)
> +++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java Thu Apr 26 22:40:22 2012
> @@ -18,117 +18,151 @@
>  *******************************************************************************/
> package org.ofbiz.minilang.method.callops;
>
> +import java.util.ArrayList;
> +import java.util.List;
> import java.util.Map;
>
> +import javolution.util.FastMap;
> +
> import org.ofbiz.base.util.Debug;
> import org.ofbiz.base.util.UtilValidate;
> +import org.ofbiz.base.util.UtilXml;
> +import org.ofbiz.base.util.collections.FlexibleMapAccessor;
> +import org.ofbiz.base.util.string.FlexibleStringExpander;
> import org.ofbiz.minilang.MiniLangException;
> +import org.ofbiz.minilang.MiniLangRuntimeException;
> +import org.ofbiz.minilang.MiniLangValidate;
> import org.ofbiz.minilang.SimpleMethod;
> +import org.ofbiz.minilang.ValidationException;
> import org.ofbiz.minilang.method.MethodContext;
> import org.ofbiz.minilang.method.MethodOperation;
> import org.w3c.dom.Element;
>
> /**
> - * An operation that calls a simple method in the same, or from another, file
> + * Invokes a Mini-language simple method.
>  */
> -public class CallSimpleMethod extends MethodOperation {
> +public final class CallSimpleMethod extends MethodOperation {
>
>     public static final String module = CallSimpleMethod.class.getName();
>
> -    String methodName;
> -    String xmlResource;
> +    private final String methodName;
> +    private final String xmlResource;
> +    private final String memoryModel;
> +    private final List<ResultToField> resultToFieldList;
>
>     public CallSimpleMethod(Element element, SimpleMethod simpleMethod) throws MiniLangException {
>         super(element, simpleMethod);
> +        if (MiniLangValidate.validationOn()) {
> +            MiniLangValidate.attributeNames(simpleMethod, element, "method-name", "xml-resource", "memory-model");
> +            MiniLangValidate.requiredAttributes(simpleMethod, element, "method-name");
> +            MiniLangValidate.constantAttributes(simpleMethod, element, "method-name", "xml-resource", "memory-model");
> +            MiniLangValidate.childElements(simpleMethod, element, "result-to-field");
> +        }
>         this.methodName = element.getAttribute("method-name");
>         this.xmlResource = element.getAttribute("xml-resource");
> +        this.memoryModel = element.getAttribute("memory-model");
> +        List<? extends Element> resultToFieldElements = UtilXml.childElementList(element, "result-to-field");
> +        if (UtilValidate.isNotEmpty(resultToFieldElements)) {
> +            if (!"function".equals(this.memoryModel)) {
> +                MiniLangValidate.handleError("Inline memory model cannot include <result-to-field> elements.", simpleMethod, 
> element);
> +            }
> +            List<ResultToField> resultToFieldList = new ArrayList<ResultToField>(resultToFieldElements.size());
> +            for (Element resultToFieldElement : resultToFieldElements) {
> +                resultToFieldList.add(new ResultToField(resultToFieldElement, simpleMethod));
> +            }
> +            this.resultToFieldList = resultToFieldList;
> +        } else {
> +            this.resultToFieldList = null;
> +        }
>     }
>
>     @Override
>     public boolean exec(MethodContext methodContext) throws MiniLangException {
> -        if (UtilValidate.isNotEmpty(this.methodName)) {
> -            String methodName = methodContext.expandString(this.methodName);
> -            String xmlResource = methodContext.expandString(this.xmlResource);
> -            SimpleMethod simpleMethodToCall = null;
> -            try {
> -                simpleMethodToCall = getSimpleMethodToCall(methodContext.getLoader());
> -            } catch (MiniLangException e) {
> -                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [error getting 
> methods from resource: " + e.getMessage() + "]";
> -                Debug.logError(e, errMsg, module);
> -                methodContext.setErrorReturn(errMsg, simpleMethod);
> -                return false;
> +        if (UtilValidate.isEmpty(this.methodName)) {
> +            throw new MiniLangRuntimeException("method-name attribute is empty", this);
> +        }
> +        SimpleMethod simpleMethodToCall = null;
> +        if (UtilValidate.isEmpty(this.xmlResource)) {
> +            simpleMethodToCall = this.simpleMethod.getSimpleMethodInSameFile(methodName);
> +        } else {
> +            Map<String, SimpleMethod> simpleMethods = SimpleMethod.getSimpleMethods(this.xmlResource, methodContext.getLoader());
> +            simpleMethodToCall = simpleMethods.get(this.methodName);
> +        }
> +        if (simpleMethodToCall == null) {
> +            throw new MiniLangRuntimeException("Could not find <simple-method name=\"" + this.methodName + "\"> in XML document " 
> + this.xmlResource, this);
> +        }
> +        MethodContext localContext = methodContext;
> +        if ("function".equals(this.memoryModel)) {
> +            Map<String, Object> localEnv = FastMap.newInstance();
> +            localEnv.putAll(methodContext.getEnvMap());
> +            localEnv.remove(this.simpleMethod.getEventResponseCodeName());
> +            localEnv.remove(this.simpleMethod.getServiceResponseMessageName());
> +            localContext = new MethodContext(localEnv, methodContext.getLoader(), methodContext.getMethodType());
> +        }
> +        String returnVal = simpleMethodToCall.exec(localContext);
> +        if (Debug.verboseOn())
> +            Debug.logVerbose("Called simple-method named [" + this.methodName + "] in resource [" + this.xmlResource + "], 
> returnVal is [" + returnVal + "]", module);
> +        if (simpleMethodToCall.getDefaultErrorCode().equals(returnVal)) {
> +            if (methodContext.getMethodType() == MethodContext.EVENT) {
> +                methodContext.putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
> +            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
> +                methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
>             }
> -            if (simpleMethodToCall == null) {
> -                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process, could not find 
> SimpleMethod " + methodName + " in XML document in resource: " + xmlResource;
> -                methodContext.setErrorReturn(errMsg, simpleMethod);
> +            return false;
> +        }
> +        if (methodContext.getMethodType() == MethodContext.EVENT) {
> +            // FIXME: This doesn't make sense. We are comparing the called method's response code with this method's
> +            // response code. Since response codes are configurable per method, this code will fail.
> +            String responseCode = (String) localContext.getEnv(this.simpleMethod.getEventResponseCodeName());
> +            if (this.simpleMethod.getDefaultErrorCode().equals(responseCode)) {
> +                Debug.logWarning("Got error [" + responseCode + "] calling inline simple-method named [" + this.methodName + "] 
> in resource [" + this.xmlResource + "], message is " + methodContext.getEnv(this.simpleMethod.getEventErrorMessageName()), 
> module);
>                 return false;
>             }
> -            String returnVal = simpleMethodToCall.exec(methodContext);
> -            if (Debug.verboseOn())
> -                Debug.logVerbose("Called inline simple-method named [" + methodName + "] in resource [" + xmlResource + "], 
> returnVal is [" + returnVal + "]", module);
> -            if (returnVal != null && returnVal.equals(simpleMethodToCall.getDefaultErrorCode())) {
> -                // in this case just set the error code just in case it hasn't already
> -                // been set, the error messages will already be in place...
> -                if (methodContext.getMethodType() == MethodContext.EVENT) {
> -                    methodContext.putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
> -                } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
> -                    methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
> -                }
> +        } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
> +            // FIXME: This doesn't make sense. We are comparing the called method's response message with this method's
> +            // response message. Since response messages are configurable per method, this code will fail.
> +            String responseMessage = (String) localContext.getEnv(this.simpleMethod.getServiceResponseMessageName());
> +            if (this.simpleMethod.getDefaultErrorCode().equals(responseMessage)) {
> +                Debug.logWarning("Got error [" + responseMessage + "] calling inline simple-method named [" + this.methodName + 
> "] in resource [" + this.xmlResource + "], message is " + methodContext.getEnv(this.simpleMethod.getServiceErrorMessageName()) + 
> ", and the error message list is: "
> +                        + methodContext.getEnv(this.simpleMethod.getServiceErrorMessageListName()), module);
>                 return false;
>             }
> -            // if the response code/message is error, if so show the error and return
> -            // false
> -            if (methodContext.getMethodType() == MethodContext.EVENT) {
> -                String responseCode = (String) methodContext.getEnv(simpleMethod.getEventResponseCodeName());
> -                if (responseCode != null && responseCode.equals(simpleMethod.getDefaultErrorCode())) {
> -                    Debug.logWarning("Got error [" + responseCode + "] calling inline simple-method named [" + methodName + "] in 
> resource [" + xmlResource + "], message is " + methodContext.getEnv(simpleMethod.getEventErrorMessageName()), module);
> -                    return false;
> -                }
> -            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
> -                String resonseMessage = (String) methodContext.getEnv(simpleMethod.getServiceResponseMessageName());
> -                if (resonseMessage != null && resonseMessage.equals(simpleMethod.getDefaultErrorCode())) {
> -                    Debug.logWarning("Got error [" + resonseMessage + "] calling inline simple-method named [" + methodName + "] 
> in resource [" + xmlResource + "], message is " + methodContext.getEnv(simpleMethod.getServiceErrorMessageName()) + ", and the 
> error message list is: "
> -                            + methodContext.getEnv(simpleMethod.getServiceErrorMessageListName()), module);
> -                    return false;
> +        }
> +        if ("function".equals(this.memoryModel) && this.resultToFieldList != null) {
> +            Map<String, Object> results = localContext.getResults();
> +            if (results != null) {
> +                for (ResultToField resultToField : this.resultToFieldList) {
> +                    resultToField.exec(methodContext.getEnvMap(), results);
>                 }
>             }
> -        } else {
> -            String errMsg = "ERROR in call-simple-method: methodName was missing; not running simpleMethod";
> -            Debug.logError(errMsg, module);
> -            methodContext.setErrorReturn(errMsg, simpleMethod);
> -            return false;
>         }
>         return true;
>     }
>
>     @Override
>     public String expandedString(MethodContext methodContext) {
> -        // TODO: something more than a stub/dummy
> -        return this.rawString();
> +        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
>     }
>
> -    public String getMethodName() {
> -        return this.methodName;
> -    }
> -
> -    public SimpleMethod getSimpleMethodToCall(ClassLoader loader) throws MiniLangException {
> -        SimpleMethod simpleMethodToCall = null;
> -        if (UtilValidate.isEmpty(xmlResource)) {
> -            simpleMethodToCall = this.simpleMethod.getSimpleMethodInSameFile(methodName);
> -        } else {
> -            Map<String, SimpleMethod> simpleMethods = SimpleMethod.getSimpleMethods(xmlResource, loader);
> -            simpleMethodToCall = simpleMethods.get(methodName);
> -        }
> -        return simpleMethodToCall;
> -    }
> -
> -    public String getXmlResource() {
> -        return this.xmlResource;
> +    @Override
> +    public String rawString() {
> +        return toString();
>     }
>
>     @Override
> -    public String rawString() {
> -        return "<call-simple-method xml-resource=\"" + this.xmlResource + "\" method-name=\"" + this.methodName + "\" />";
> +    public String toString() {
> +        StringBuilder sb = new StringBuilder("<call-simple-method ");
> +        if (this.methodName.length() > 0) {
> +            sb.append("method-name=\"").append(this.methodName).append("\" ");
> +        }
> +        if (this.xmlResource.length() > 0) {
> +            sb.append("xml-resource=\"").append(this.xmlResource).append("\" ");
> +        }
> +        if (this.memoryModel.length() > 0) {
> +            sb.append("memory-model=\"").append(this.memoryModel).append("\" ");
> +        }
> +        sb.append("/>");
> +        return sb.toString();
>     }
>
>     public static final class CallSimpleMethodFactory implements Factory<CallSimpleMethod> {
> @@ -140,4 +174,33 @@ public class CallSimpleMethod extends Me
>             return "call-simple-method";
>         }
>     }
> +
> +    private final class ResultToField {
> +
> +        private final FlexibleMapAccessor<Object> fieldFma;
> +        private final FlexibleMapAccessor<Object> resultNameFma;
> +
> +        private ResultToField(Element element, SimpleMethod simpleMethod) throws ValidationException {
> +            if (MiniLangValidate.validationOn()) {
> +                MiniLangValidate.attributeNames(simpleMethod, element, "result-name", "field");
> +                MiniLangValidate.requiredAttributes(simpleMethod, element, "result-name");
> +                MiniLangValidate.expressionAttributes(simpleMethod, element, "result-name", "field");
> +                MiniLangValidate.noChildElements(simpleMethod, element);
> +            }
> +            this.resultNameFma = FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
> +            String fieldAttribute = element.getAttribute("field");
> +            if (fieldAttribute.length() == 0) {
> +                this.fieldFma = this.resultNameFma;
> +            } else {
> +                this.fieldFma = FlexibleMapAccessor.getInstance(fieldAttribute);
> +            }
> +        }
> +
> +        private void exec(Map<String, Object> context, Map<String, Object> results) throws MiniLangException {
> +            Object value = this.resultNameFma.get(results);
> +            if (value != null) {
> +                this.fieldFma.put(context, value);
> +            }
> +        }
> +    }
> }
>
> Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java?rev=1331137&r1=1331136&r2=1331137&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java (original)
> +++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Now.java Thu Apr 26 22:40:22 2012
> @@ -47,6 +47,8 @@ public final class Now extends MethodOpe
>         if (MiniLangValidate.validationOn()) {
>             MiniLangValidate.attributeNames(simpleMethod, element, "field", "type");
>             MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
> +            MiniLangValidate.expressionAttributes(simpleMethod, element, "field");
> +            MiniLangValidate.constantAttributes(simpleMethod, element, "type");
>             MiniLangValidate.noChildElements(simpleMethod, element);
>         }
>         this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
>
> Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java
> URL: 
> http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java?rev=1331137&r1=1331136&r2=1331137&view=diff
> ==============================================================================
> --- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java (original)
> +++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/serviceops/FieldToResult.java Thu Apr 26 22:40:22 2012
> @@ -18,70 +18,72 @@
>  *******************************************************************************/
> package org.ofbiz.minilang.method.serviceops;
>
> -import java.util.Map;
> -
> -import org.ofbiz.base.util.Debug;
> +import org.ofbiz.base.util.collections.FlexibleMapAccessor;
> +import org.ofbiz.base.util.string.FlexibleStringExpander;
> import org.ofbiz.minilang.MiniLangException;
> +import org.ofbiz.minilang.MiniLangValidate;
> import org.ofbiz.minilang.SimpleMethod;
> -import org.ofbiz.minilang.method.ContextAccessor;
> import org.ofbiz.minilang.method.MethodContext;
> import org.ofbiz.minilang.method.MethodOperation;
> import org.w3c.dom.Element;
>
> /**
> - * Copies a map field to a Service result entry
> + * Copies a field to a service OUT attribute.
>  */
> -public class FieldToResult extends MethodOperation {
> +public final class FieldToResult extends MethodOperation {
>
>     public static final String module = FieldToResult.class.getName();
>
> -    ContextAccessor<Object> fieldAcsr;
> -    ContextAccessor<Map<String, ? extends Object>> mapAcsr;
> -    ContextAccessor<Object> resultAcsr;
> +    private final FlexibleMapAccessor<Object> fieldFma;
> +    private final FlexibleMapAccessor<Object> resultFma;
>
>     public FieldToResult(Element element, SimpleMethod simpleMethod) throws MiniLangException {
>         super(element, simpleMethod);
> -        // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is 
> still supported
> -        mapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("map-name"));
> -        fieldAcsr = new ContextAccessor<Object>(element.getAttribute("field"), element.getAttribute("field-name"));
> -        resultAcsr = new ContextAccessor<Object>(element.getAttribute("result-name"), fieldAcsr.toString());
> +        if (MiniLangValidate.validationOn()) {
> +            MiniLangValidate.attributeNames(simpleMethod, element, "field", "result-name");
> +            MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
> +            MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "result-name");
> +            MiniLangValidate.noChildElements(simpleMethod, element);
> +        }
> +        this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
> +        String resultNameAttribute = element.getAttribute("result-name");
> +        if (resultNameAttribute.length() == 0) {
> +            this.resultFma = this.fieldFma;
> +        } else {
> +            this.resultFma = FlexibleMapAccessor.getInstance(resultNameAttribute);
> +        }
>     }
>
>     @Override
>     public boolean exec(MethodContext methodContext) throws MiniLangException {
> -        // only run this if it is in an SERVICE context
> -        if (methodContext.getMethodType() == MethodContext.SERVICE) {
> -            Object fieldVal = null;
> -            if (!mapAcsr.isEmpty()) {
> -                Map<String, ? extends Object> fromMap = mapAcsr.get(methodContext);
> -                if (fromMap == null) {
> -                    Debug.logWarning("Map not found with name " + mapAcsr, module);
> -                    return true;
> -                }
> -                fieldVal = fieldAcsr.get(fromMap, methodContext);
> -            } else {
> -                // no map name, try the env
> -                fieldVal = fieldAcsr.get(methodContext);
> -            }
> -            if (fieldVal == null) {
> -                Debug.logWarning("Field value not found with name " + fieldAcsr + " in Map with name " + mapAcsr, module);
> -                return true;
> -            }
> -            resultAcsr.put(methodContext.getResults(), fieldVal, methodContext);
> +        Object fieldVal = this.fieldFma.get(methodContext.getEnvMap());
> +        if (fieldVal != null) {
> +            this.resultFma.put(methodContext.getResults(), fieldVal);
>         }
>         return true;
>     }
>
>     @Override
>     public String expandedString(MethodContext methodContext) {
> -        // TODO: something more than a stub/dummy
> -        return this.rawString();
> +        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
>     }
>
>     @Override
>     public String rawString() {
> -        // TODO: add all attributes and other info
> -        return "<field-to-result field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>";
> +        return toString();
> +    }
> +
> +    @Override
> +    public String toString() {
> +        StringBuilder sb = new StringBuilder("<now ");
> +        if (!this.fieldFma.isEmpty()) {
> +            sb.append("field=\"").append(this.fieldFma).append("\" ");
> +        }
> +        if (!this.resultFma.isEmpty()) {
> +            sb.append("result-name=\"").append(this.resultFma).append("\" ");
> +        }
> +        sb.append("/>");
> +        return sb.toString();
>     }
>
>     public static final class FieldToResultFactory implements Factory<FieldToResult> {
>
> 

Re: Fwd: svn commit: r1331137 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java src/org/ofbiz/minilang/method/envops/Now.java src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Posted by Adrian Crum <ad...@sandglass-software.com>.
Done, rev 1331259.

-Adrian

On 4/27/2012 6:06 AM, Jacopo Cappellato wrote:
> Hi Adrian,
>
> I am wondering if, instead of "memory-model", the name "scope" (or similar) would be a better fit.
>
> Jacopo
>
>
> Begin forwarded message:
>
>> Added new attribute "memory-model" to the Mini-language<call-simple-method>  element.

Fwd: svn commit: r1331137 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/callops/CallSimpleMethod.java src/org/ofbiz/minilang/method/envops/Now.java src/org/ofbiz/minilang/method/serviceops/FieldToResult.java

Posted by Jacopo Cappellato <ja...@hotwaxmedia.com>.
Hi Adrian,

I am wondering if, instead of "memory-model", the name "scope" (or similar) would be a better fit.

Jacopo


Begin forwarded message:

> Added new attribute "memory-model" to the Mini-language <call-simple-method> element.