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/05/06 02:43:59 UTC

svn commit: r1334536 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/conditional/While.java src/org/ofbiz/minilang/method/envops/IterateMap.java src/org/ofbiz/minilang/method/envops/Loop.java

Author: adrianc
Date: Sun May  6 00:43:58 2012
New Revision: 1334536

URL: http://svn.apache.org/viewvc?rev=1334536&view=rev
Log:
Overhauled Mini-language <iterate-map>, <loop>, and <while> elements.

Modified:
    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/conditional/While.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/IterateMap.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Loop.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=1334536&r1=1334535&r2=1334536&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
+++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Sun May  6 00:43:58 2012
@@ -3415,19 +3415,19 @@ under the License.
         </xs:annotation>
         <xs:complexType>
             <xs:group minOccurs="0" maxOccurs="unbounded" ref="AllOperations" />
-            <xs:attribute type="xs:string" name="entry" use="required">
+            <xs:attribute type="xs:string" name="list" use="required">
                 <xs:annotation>
                     <xs:documentation>
-                        The name of the environment field that will contain each entry in the list.
+                        The name of the environment field that contains the list to iterate over.
                         &lt;br/&gt;&lt;br/&gt;
                         Required. Attribute type: expression.
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
-            <xs:attribute type="xs:string" name="list" use="required">
+            <xs:attribute type="xs:string" name="entry" use="required">
                 <xs:annotation>
                     <xs:documentation>
-                        The name of the environment field that contains the list to iterate over.
+                        The name of the environment field that will contain each entry in the list.
                         &lt;br/&gt;&lt;br/&gt;
                         Required. Attribute type: expression.
                     </xs:documentation>
@@ -3438,77 +3438,84 @@ under the License.
     <xs:element name="iterate-map" substitutionGroup="ControlOperations">
         <xs:annotation>
             <xs:documentation>
-                The operations contained by the iterate-map tag will be executed for each of the entries in the map.
-                It will run all of the operations underneath the iterate-map-element for each of the entries in the given map,
-                setting the key for that entry and the key name variable, and the value for that entry and the value variable.
-
-                This tag can contain any of the simple-method operations, including the conditional/if operations.
-
-                Any simple-method operation can be nested under the iterate-map tag.
+                The operations contained in the iterate-map element will be executed for each of the entries in the list,
+                and will make the current entry key/value pair available in the environment by the names specified.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:group minOccurs="0" maxOccurs="unbounded" ref="AllOperations"/>
-            <xs:attributeGroup ref="attlist.iterate-map"/>
+            <xs:group minOccurs="0" maxOccurs="unbounded" ref="AllOperations" />
+            <xs:attribute type="xs:string" name="map" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the environment field that contains the map to iterate over.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="key" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the environment field that will contain the map entry key.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="value" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the environment field that will contain the map entry value.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.iterate-map">
-        <xs:attribute type="xs:string" name="key" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the variable to put the key.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="value" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the variable to put the value in.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="map" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the map to use.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="loop" substitutionGroup="ControlOperations">
         <xs:annotation>
             <xs:documentation>
-                Loop, rather than iterating over some sort of a structure,
-                will simply loop a certain number of times. The
-                number of times to loop is specified in the count attribute,
-                and it will put the current count in the field attribute,
-                or in the variable named by the field attribute. So if you
-                want to loop ten times you say count=ten, and
-                field=count for example. First time through count will
-                be zero; last time through count will be nine.
+                The operations contained in the loop element will be executed repeatedly until the specified count is reached.
+                The current count value is available in the environment by the name specified.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:group minOccurs="0" maxOccurs="unbounded" ref="AllOperations"/>
-            <xs:attributeGroup ref="attlist.loop"/>
+            <xs:group minOccurs="0" maxOccurs="unbounded" ref="AllOperations" />
+            <xs:attribute type="xs:string" name="count" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The number of times to loop.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute types: constant, expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="field">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the environment field that will contain the current count.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+        </xs:complexType>
+    </xs:element>
+    <xs:element name="while" substitutionGroup="ControlOperations">
+        <xs:annotation>
+            <xs:documentation>
+                The operations contained in the while element will be executed as long as its condition element
+                evaluates to true.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element ref="condition" />
+                <xs:element ref="then" />
+            </xs:sequence>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.loop">
-        <xs:attribute type="xs:string" name="count" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Number of times to loop.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="field" use="optional">
-            <xs:annotation>
-                <xs:documentation>
-                    Current count is put in the field attribute.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="check-errors" substitutionGroup="ControlOperations">
         <xs:annotation>
             <xs:documentation>
@@ -3682,34 +3689,6 @@ under the License.
             </xs:sequence>
         </xs:complexType>
     </xs:element>
-    <xs:element name="while" substitutionGroup="IfOtherOperations">
-        <xs:annotation>
-            <xs:documentation>
-                While loop operation, uses the same condition element as the if operation.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element ref="condition">
-                    <xs:annotation>
-                        <xs:documentation>
-                            A simple element with no attributes that contains the condition that will be evaluated to determine which sub-operations to execute.
-                            To combine the other if operations documented below the and, or, xor, and notelements can be used.
-                            The and, or, and xor elements can contain as many general if operations and modifier/combination elements (ie and, or, xor, and not).
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:element>
-                <xs:element ref="then">
-                    <xs:annotation>
-                        <xs:documentation>
-                            The then element is used to contain operations that will run if the condition evaluate to true.
-                            A then tag must be included, but can be empty.
-                        </xs:documentation>
-                    </xs:annotation>
-                </xs:element>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
     <xs:element name="condition">
         <xs:annotation>
             <xs:documentation>

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/conditional/While.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/conditional/While.java?rev=1334536&r1=1334535&r2=1334536&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/conditional/While.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/conditional/While.java Sun May  6 00:43:58 2012
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.minilang.MiniLangException;
+import org.ofbiz.minilang.MiniLangValidate;
 import org.ofbiz.minilang.SimpleMethod;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
@@ -33,13 +34,17 @@ import org.w3c.dom.Element;
 /**
  * Continually processes sub-ops while the condition remains true
  */
-public class While extends MethodOperation {
+public final class While extends MethodOperation {
 
-    Conditional condition;
-    List<MethodOperation> thenSubOps;
+    private final Conditional condition;
+    private final List<MethodOperation> thenSubOps;
 
     public While(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.childElements(simpleMethod, element, "condition", "then");
+            MiniLangValidate.requiredChildElements(simpleMethod, element, "condition", "then");
+        }
         Element conditionElement = UtilXml.firstChildElement(element, "condition");
         Element conditionChildElement = UtilXml.firstChildElement(conditionElement);
         this.condition = ConditionalFactory.makeConditional(conditionChildElement, simpleMethod);
@@ -49,9 +54,6 @@ public class While extends MethodOperati
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        // if conditions fails, always return true;
-        // if a sub-op returns false return false and stop, otherwise drop though loop and
-        // return true
         while (condition.checkCondition(methodContext)) {
             try {
                 for (MethodOperation methodOperation : thenSubOps) {

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/IterateMap.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/IterateMap.java?rev=1334536&r1=1334535&r2=1334536&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/IterateMap.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/IterateMap.java Sun May  6 00:43:58 2012
@@ -23,9 +23,12 @@ import java.util.List;
 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.MiniLangRuntimeException;
+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.ofbiz.minilang.method.envops.Break.BreakElementException;
@@ -35,51 +38,57 @@ import org.w3c.dom.Element;
 /**
  * Process sub-operations for each entry in the map
  */
-public class IterateMap extends MethodOperation {
+public final class IterateMap extends MethodOperation {
 
     public static final String module = IterateMap.class.getName();
 
-    ContextAccessor<Object> keyAcsr;
-    ContextAccessor<Map<? extends Object, ? extends Object>> mapAcsr;
-    List<MethodOperation> subOps;
-    ContextAccessor<Object> valueAcsr;
+    private final FlexibleMapAccessor<Object> keyFma;
+    private final FlexibleMapAccessor<Map<? extends Object, ? extends Object>> mapFma;
+    private final List<MethodOperation> subOps;
+    private final FlexibleMapAccessor<Object> valueFma;
 
     public IterateMap(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        this.keyAcsr = new ContextAccessor<Object>(element.getAttribute("key"), element.getAttribute("key-name"));
-        this.valueAcsr = new ContextAccessor<Object>(element.getAttribute("value"), element.getAttribute("value-name"));
-        this.mapAcsr = new ContextAccessor<Map<? extends Object, ? extends Object>>(element.getAttribute("map"), element.getAttribute("map-name"));
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "key", "map", "value");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "key", "map", "value");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "key", "map", "value");
+        }
+        this.keyFma = FlexibleMapAccessor.getInstance(element.getAttribute("key"));
+        this.mapFma = FlexibleMapAccessor.getInstance(element.getAttribute("map"));
+        this.valueFma = FlexibleMapAccessor.getInstance(element.getAttribute("value"));
         this.subOps = Collections.unmodifiableList(SimpleMethod.readOperations(element, simpleMethod));
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        if (mapAcsr.isEmpty()) {
-            Debug.logWarning("No map-name specified in iterate tag, doing nothing: " + rawString(), module);
-            return true;
+        if (mapFma.isEmpty()) {
+            throw new MiniLangRuntimeException("No map specified.", this);
         }
-        Object oldKey = keyAcsr.get(methodContext);
-        Object oldValue = valueAcsr.get(methodContext);
+        Object oldKey = keyFma.get(methodContext.getEnvMap());
+        Object oldValue = valueFma.get(methodContext.getEnvMap());
         if (oldKey != null) {
-            Debug.logWarning("In iterate-map the key had a non-null value before entering the loop for the operation: " + this.rawString(), module);
+            if (Debug.verboseOn())
+                Debug.logVerbose("In iterate-map the key had a non-null value before entering the loop for the operation: " + this, module);
         }
         if (oldValue != null) {
-            Debug.logWarning("In iterate-map the value had a non-null value before entering the loop for the operation: " + this.rawString(), module);
+            if (Debug.verboseOn())
+                Debug.logVerbose("In iterate-map the value had a non-null value before entering the loop for the operation: " + this, module);
         }
-        Map<? extends Object, ? extends Object> theMap = mapAcsr.get(methodContext);
+        Map<? extends Object, ? extends Object> theMap = mapFma.get(methodContext.getEnvMap());
         if (theMap == null) {
-            if (Debug.infoOn())
-                Debug.logInfo("Map not found with name " + mapAcsr + ", doing nothing: " + rawString(), module);
+            if (Debug.verboseOn())
+                Debug.logVerbose("Map not found with name " + mapFma + ", doing nothing: " + this, module);
             return true;
         }
         if (theMap.size() == 0) {
             if (Debug.verboseOn())
-                Debug.logVerbose("Map with name " + mapAcsr + " has zero entries, doing nothing: " + rawString(), module);
+                Debug.logVerbose("Map with name " + mapFma + " has zero entries, doing nothing: " + this, module);
             return true;
         }
         for (Map.Entry<? extends Object, ? extends Object> theEntry : theMap.entrySet()) {
-            keyAcsr.put(methodContext, theEntry.getKey());
-            valueAcsr.put(methodContext, theEntry.getValue());
+            keyFma.put(methodContext.getEnvMap(), theEntry.getKey());
+            valueFma.put(methodContext.getEnvMap(), theEntry.getValue());
             try {
                 for (MethodOperation methodOperation : subOps) {
                     if (!methodOperation.exec(methodContext)) {
@@ -101,8 +110,7 @@ public class IterateMap extends MethodOp
 
     @Override
     public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
     public List<MethodOperation> getSubOps() {
@@ -111,7 +119,23 @@ public class IterateMap extends MethodOp
 
     @Override
     public String rawString() {
-        return "<iterate-map map-name=\"" + this.mapAcsr + "\" key=\"" + this.keyAcsr + "\" value=\"" + this.valueAcsr + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<iterate-map ");
+        if (!this.mapFma.isEmpty()) {
+            sb.append("map=\"").append(this.mapFma).append("\" ");
+        }
+        if (!this.keyFma.isEmpty()) {
+            sb.append("key=\"").append(this.keyFma).append("\" ");
+        }
+        if (!this.valueFma.isEmpty()) {
+            sb.append("value=\"").append(this.valueFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
     public static final class IterateMapFactory implements Factory<IterateMap> {

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Loop.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Loop.java?rev=1334536&r1=1334535&r2=1334536&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Loop.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/Loop.java Sun May  6 00:43:58 2012
@@ -21,10 +21,12 @@ package org.ofbiz.minilang.method.envops
 import java.util.Collections;
 import java.util.List;
 
-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.MiniLangRuntimeException;
+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.ofbiz.minilang.method.envops.Break.BreakElementException;
@@ -34,40 +36,40 @@ import org.w3c.dom.Element;
 /**
  * Loop
  */
-public class Loop extends MethodOperation {
+public final class Loop extends MethodOperation {
 
     public static final String module = Loop.class.getName();
 
-    protected String countStr;
-    protected ContextAccessor<Integer> fieldAcsr;
-    protected List<MethodOperation> subOps;
+    private final FlexibleStringExpander countFse;
+    private final FlexibleMapAccessor<Integer> fieldFma;
+    private final List<MethodOperation> subOps;
 
     public Loop(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        this.fieldAcsr = new ContextAccessor<Integer>(element.getAttribute("field"));
-        this.countStr = element.getAttribute("count");
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "count", "field");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "count");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "count", "field");
+        }
+        this.countFse = FlexibleStringExpander.getInstance(element.getAttribute("count"));
+        this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
         this.subOps = Collections.unmodifiableList(SimpleMethod.readOperations(element, simpleMethod));
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        String countStrExp = methodContext.expandString(this.countStr);
+        String countStr = this.countFse.expandString(methodContext.getEnvMap());
         int count = 0;
         try {
-            Double ctDbl = Double.valueOf(countStrExp);
-            if (ctDbl != null) {
-                count = ctDbl.intValue();
-            }
+            count = Double.valueOf(countStr).intValue();
         } catch (NumberFormatException e) {
-            Debug.logError(e, module);
-            return false;
+            throw new MiniLangRuntimeException("Error while converting \"" + countStr + "\" to a number: " + e.getMessage(), this);
         }
         if (count < 0) {
-            Debug.logWarning("Unable to execute loop operation because the count variable is negative: " + rawString(), module);
-            return false;
+            throw new MiniLangRuntimeException("Unable to execute loop operation because the count is negative: " + countStr, this);
         }
         for (int i = 0; i < count; i++) {
-            fieldAcsr.put(methodContext, i);
+            this.fieldFma.put(methodContext.getEnvMap(), i);
             try {
                 for (MethodOperation methodOperation : subOps) {
                     if (!methodOperation.exec(methodContext)) {
@@ -89,7 +91,7 @@ public class Loop extends MethodOperatio
 
     @Override
     public String expandedString(MethodContext methodContext) {
-        return this.rawString();
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
     public List<MethodOperation> getSubOps() {
@@ -98,7 +100,20 @@ public class Loop extends MethodOperatio
 
     @Override
     public String rawString() {
-        return "<loop field=\"" + this.fieldAcsr + "\" count=\"" + this.countStr + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<loop ");
+        if (!this.countFse.isEmpty()) {
+            sb.append("count=\"").append(this.countFse).append("\" ");
+        }
+        if (!this.fieldFma.isEmpty()) {
+            sb.append("field=\"").append(this.fieldFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
     public static final class LoopFactory implements Factory<Loop> {