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/06/13 08:04:49 UTC

svn commit: r1349646 [1/2] - in /ofbiz/trunk/framework/minilang: dtd/ src/META-INF/services/ src/org/ofbiz/minilang/method/envops/

Author: adrianc
Date: Wed Jun 13 06:04:49 2012
New Revision: 1349646

URL: http://svn.apache.org/viewvc?rev=1349646&view=rev
Log:
Overhauled Mini-language <order-map-list>, <set-calendar>, <string-append>, <string-to-list>, <to-string> elements. Added a format attribute to the <set> element - to be used for type conversions. Also removed deprecated StringToField class.

The overhaul includes: removing unnecessary object creation, make the class thread-safe, add syntax validation, and misc code cleanups.

Removed:
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToField.java
Modified:
    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
    ofbiz/trunk/framework/minilang/src/META-INF/services/org.ofbiz.minilang.method.MethodOperation$Factory
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringToList.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/ToString.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=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
+++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Wed Jun 13 06:04:49 2012
@@ -1418,7 +1418,7 @@ under the License.
             <xs:documentation>
                 Copies a map to another map. Does nothing if the source map does not exist.
                 If a target map is not specified, the source map is copied to the current
-                envirnment (memory space).
+                environment (memory space).
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
@@ -1501,18 +1501,27 @@ under the License.
         </xs:complexType>
     </xs:element>
     <xs:element name="order-map-list" substitutionGroup="EnvOperations">
-        <xs:annotation><xs:documentation>Sort a List containing Maps: order by fields names given in order-by sub-element.</xs:documentation>
+        <xs:annotation>
+            <xs:documentation>
+                Sorts a list of maps. Maps are sorted by the keys specified in the order-by sub-elements.
+                Does nothing if the list is not found.
+            </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:sequence><xs:element maxOccurs="unbounded" ref="order-by"/></xs:sequence>
-            <xs:attributeGroup ref="attlist.order-map-list"/>
+            <xs:sequence>
+                <xs:element maxOccurs="unbounded" ref="order-by" />
+            </xs:sequence>
+            <xs:attribute type="xs:string" name="list" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Name of the field containing the list to be sorted.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.order-map-list">
-        <xs:attribute type="xs:string" name="list" use="required">
-            <xs:annotation><xs:documentation>Name of the list to be sorted.</xs:documentation></xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="set" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
@@ -1544,7 +1553,7 @@ under the License.
                     <xs:documentation>
                         A constant value, or a constant that includes an expression. The source of the assignment.
                         &lt;br/&gt;&lt;br/&gt;
-                        Required if the from-field attribute is empty. Attribute type: constant+expr.
+                        Required if the from attribute is empty. Attribute type: constant+expr.
                         Defaults to java.lang.String data type.
                     </xs:documentation>
                 </xs:annotation>
@@ -1559,7 +1568,7 @@ under the License.
             <xs:attribute type="xs:string" name="default">
                 <xs:annotation>
                     <xs:documentation>
-                        A default value that is used when the from-field attribute evaluates to null or empty.
+                        A default value that is used when the from attribute evaluates to null or empty.
                         &lt;br/&gt;&lt;br/&gt;
                         Optional. Attribute types: constant, ${expression}.
                     </xs:documentation>
@@ -1574,10 +1583,19 @@ under the License.
                     </xs:documentation>
                 </xs:annotation>
             </xs:attribute>
+            <xs:attribute type="xs:string" name="format">
+                <xs:annotation>
+                    <xs:documentation>
+                        Format to be used for object type conversion. Used when the type attribute is not empty.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
             <xs:attribute name="set-if-null" type="booleanConst">
                 <xs:annotation>
                     <xs:documentation>
-                        Controls if the target field can be set to null when the from-field attribute evaluates to null.
+                        Controls if the target field can be set to null when the from attribute evaluates to null.
                         Defaults to "false".
                         &lt;br/&gt;&lt;br/&gt;
                         Optional. Attribute type: constant.
@@ -1599,158 +1617,150 @@ under the License.
     <xs:element name="string-append" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
-                NOTE: the prefix and suffix will only be used IFF the current string and the string to be appended are both not empty.
-
-                So if the field does not exist then it will create a new field with this string value.
-                If it does exist then it will append this string value to the end.
+                Performs string concatenation and formatting. The operation starts by applying
+                an argument list (if found) to the string attribute value, the result is
+                prepended by the prefix attribute value, and the suffix attribute value is
+                appended to the result. If the string specified in the field attribute exists,
+                the final result is appended to it, else the field is set to the final result.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.string-append"/>
+            <xs:attribute type="xs:string" name="field" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The target of the string concatention.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The string to append to the field named in the field attribute.
+                        This can be a formatting string that is used with the argument list
+                        specified in the arg-list attribute.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="arg-list">
+                <xs:annotation>
+                    <xs:documentation>
+                        An argument list to be used with a formatting string.
+                        The argument list is applied to the string attribute value.
+                        Does nothing if the argument list is not found.
+                        See the java.text.MessageFormat class for more information.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="prefix">
+                <xs:annotation>
+                    <xs:documentation>
+                        A string that will be prepended to the string attribute value.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="suffix">
+                <xs:annotation>
+                    <xs:documentation>
+                        A string that will be appended to the string attribute value.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.string-append">
-        <xs:attribute type="xs:string" name="field" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    The field that you want string-append to operate on.
-                    This is the target field where the value will be put, and this is the string to append to that field.
-
-                    So if the field does not exist then it will create a new field with this string value.
-                    If it does exist then it will append this string value to the end.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="string" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    The string to append to the field named in field-name.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="arg-list">
-            <xs:annotation>
-                <xs:documentation>
-                    arg-list-name is used to insert values from a list into
-                    the string using the object in the standard Java library
-                    that does this sort of string expression with a { } brackets
-                    and a number, no dollar sign.
-
-                    This pattern of the arg-list-name with the prefix and
-                    suffix is something form the early days which is still
-                    supported, but the best thing to do here is just use the
-                    flexible string expander which is far more flexible and
-                    powerful. So you can have the prefix variables to expand
-                    and everything all mixed into one string.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="prefix">
-            <xs:annotation>
-                <xs:documentation>
-                    Used in conjunction with arg-list-name.
-                    String that will be prepended to the string,
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="suffix">
-            <xs:annotation>
-                <xs:documentation>
-                    Used in conjunction with arg-list-name.
-                    String that will be appended to the string,
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="string-to-list" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
-                Take a string literally that can also have a flexible string expander and such in it,
-                and it will add it to a list.
-
-                Note that you can have an arg-listname for using the standard
-                Java style argument list where you have in the source
-                string numbers inside of { } brackets that represent the
-                number the index in the argument list to insert at that point.
+                Adds a string to a list of strings. Deprecated - use the set element.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.string-to-list"/>
+            <xs:attribute type="xs:string" name="string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The string to add to the list specified in the list attribute.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="list" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        List to add the string to. If the list does not exist, one will be created.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="arg-list">
+                <xs:annotation>
+                    <xs:documentation>
+                        An argument list to be used with a formatting string.
+                        The argument list is applied to the string attribute value.
+                        Does nothing if the argument list is not found.
+                        See the java.text.MessageFormat class for more information.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="message-field">
+                <xs:annotation>
+                    <xs:documentation>
+                        To insert a message above a field (used in conjunction with @fieldErrors FTL macro)
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.string-to-list">
-        <xs:attribute type="xs:string" name="string" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    String to add to the list named in list-name.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="list" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    List to add string to.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="arg-list">
-            <xs:annotation>
-                <xs:documentation>
-                    arg-list-name is used to insert values from a list into
-                    the string using the object in the standard Java library
-                    that does this sort of string expresison with a { } brackets
-                    and a number, no dollar sign.
-
-                    This pattern of the arg-list-name with the prefix and
-                    suffix is something form the early days which is still
-                    supported, but the best thing to do here is just use the
-                    flexible string expander which is far more flexible and
-                    powerful. So you can have the prefix variables to expand
-                    and everything all mixed into one string.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="message-field">
-            <xs:annotation>
-                <xs:documentation>
-                    To insert a message above a field (used in conjunction with @fieldErrors FTL macro)
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="to-string" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
-                The to-string tag converts the Object in the specified field to a String, putting the string in the same field.
+                Converts an object to a string. Deprecated - use the set element.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.to-string"/>
+            <xs:attribute type="xs:string" name="field" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        The name of the field containing the object to convert.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="format">
+                <xs:annotation>
+                    <xs:documentation>
+                        Format to use for the conversion.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="numeric-padding">
+                <xs:annotation>
+                    <xs:documentation>
+                        Left-pad the string with the specified number of zeroes.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.to-string">
-        <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="format">
-            <xs:annotation>
-                <xs:documentation>
-                    Format based on the type of the object (date,number, etc.).
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="numeric-padding">
-            <xs:annotation>
-                <xs:documentation>
-                    Padding to use if a numeric object is used.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="clear-field" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
@@ -4381,193 +4391,204 @@ under the License.
             </xs:annotation>
         </xs:attribute>
     </xs:attributeGroup>
-    <xs:element name="set-calendar" substitutionGroup="OtherOperations">
+    <xs:element name="set-calendar" substitutionGroup="EnvOperations">
         <xs:annotation>
             <xs:documentation>
-                The set-calendar tag allows to set a date "field" from another "from-field" date field type
-                or directly from a value using at least one adjuster to modify the from-field date.
-                The type of fields or value is Timestamp.
-
-                Again you can use the flexible string expander here, the ${} syntax and such. It can also do a type conversion,
-                so going from whatever type the source data is in, which would be a string value or whatever the variable
-                type is for a from field, it can convert that to any ofthese types before setting it in the target field.
-
-                You can also specify a default value in the case that the value evaluates to an empty string or the from-field is
-                null or empty. Then the default-value will be used.
-
-                Adjuster years, months, days, hours, minutes, seconds and millis use integers optionally precedeed by + or -
-                Period-align-start and period-align-end allows to align on end or start of a period.
-
-                You may specify a locale or a time-zone else the respective default request value is used.
+                Adjusts a Timestamp by a specified time duration.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.set-calendar"/>
+            <xs:attribute ref="field" />
+            <xs:attribute type="xs:string" name="from-field">
+                <xs:annotation>
+                    <xs:documentation>
+                        Deprecated - use the from attribute.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="from">
+                <xs:annotation>
+                    <xs:documentation>
+                        An expression or script that returns an object or null. The source of the assignment.
+                        &lt;br/&gt;&lt;br/&gt;
+                        A script must be prefixed with the script language followed by a colon (":").
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required if the value attribute is empty. Attribute types: expression, script.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="value">
+                <xs:annotation>
+                    <xs:documentation>
+                        A constant value, or a constant that includes an expression. The source of the assignment.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required if the from attribute is empty. Attribute type: constant+expr.
+                        Defaults to java.lang.String data type.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="default-value">
+                <xs:annotation>
+                    <xs:documentation>
+                        Deprecated - use the default attribute.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="default">
+                <xs:annotation>
+                    <xs:documentation>
+                        A default value that is used when the from attribute evaluates to null or empty.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="set-if-null" type="booleanConst">
+                <xs:annotation>
+                    <xs:documentation>
+                        Controls if the target field can be set to null when the from attribute evaluates to null.
+                        Defaults to "false".
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="set-if-empty" type="booleanConst">
+                <xs:annotation>
+                    <xs:documentation>
+                        Controls if the target field can be set to an empty value. The meaning of "empty" depends on the Java data type.
+                        Defaults to "true".
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="years">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of year(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="months">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of month(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="days">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of days(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="hours">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of hour(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="minutes">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of minute(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="seconds">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of second(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="millis">
+                <xs:annotation>
+                    <xs:documentation>
+                        Add (optionally using +) or subtract (using -) a number of milli-second(s).
+                        If an expression is used, it should evaluate to an integer.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="period-align-start">
+                <xs:annotation>
+                    <xs:documentation>
+                        Align the adjusted date to the start of a period.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:token">
+                        <xs:enumeration value="year" />
+                        <xs:enumeration value="month" />
+                        <xs:enumeration value="week" />
+                        <xs:enumeration value="day" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
+            <xs:attribute name="period-align-end">
+                <xs:annotation>
+                    <xs:documentation>
+                        Align the adjusted date to the end of a period.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:token">
+                        <xs:enumeration value="year" />
+                        <xs:enumeration value="month" />
+                        <xs:enumeration value="week" />
+                        <xs:enumeration value="day" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="locale">
+                <xs:annotation>
+                    <xs:documentation>
+                        A locale value (eg: en). The locale selects the calendar to be used for the adjustment.
+                        Defaults to the environment locale.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute type="xs:string" name="time-zone">
+                <xs:annotation>
+                    <xs:documentation>
+                        A time zone value (eg: GMT).
+                        Defaults to the environment time zone.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute types: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.set-calendar">
-        <xs:attribute type="xs:string" name="field" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the field to copy value to.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="from-field">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the field to copy value from.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="value">
-            <xs:annotation>
-                <xs:documentation>
-                    Simple value to copy in field.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="default-value">
-            <xs:annotation>
-                <xs:documentation>
-                    Default value to copy in field if value evaluates to an empty string or the from-field is null or empty.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="set-if-null" default="false">
-            <xs:annotation>
-                <xs:documentation>
-                    Specifies whether or not to set fields that are null or empty.
-                    Defaults to true.
-                </xs:documentation>
-            </xs:annotation>
-            <xs:simpleType>
-                <xs:restriction base="xs:token">
-                    <xs:enumeration value="true"/>
-                    <xs:enumeration value="false"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute name="set-if-empty" default="true">
-            <xs:annotation>
-                <xs:documentation>
-                    If the source value, either from a value or from a field, is empty, and
-                    empty-string an empty list or a null value.
-                    In this case it's set to true.
-
-                    If you don't want to set, if you want it to
-                    leave the target field alone when the source is empty,
-                    then you need to set this to false.
-                </xs:documentation>
-            </xs:annotation>
-            <xs:simpleType>
-                <xs:restriction base="xs:token">
-                    <xs:enumeration value="true"/>
-                    <xs:enumeration value="false"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="years">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of year(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="months">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of month(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="days">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of days(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="hours">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of hour(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="minutes">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of minute(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="seconds">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of second(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="millis">
-            <xs:annotation>
-                <xs:documentation>
-                    Add (optionally using +) or subtract (using -) a number of milli-second(s).
-                    If an expression is used, it should evaluate to an integer.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="period-align-start">
-            <xs:annotation>
-                <xs:documentation>
-                    Align the returned date to the start of the chosen adjustment between year, month, week or day.
-                </xs:documentation>
-            </xs:annotation>
-            <xs:simpleType>
-                <xs:restriction base="xs:token">
-                    <xs:enumeration value="year"/>
-                    <xs:enumeration value="month"/>
-                    <xs:enumeration value="week"/>
-                    <xs:enumeration value="day"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute name="period-align-end">
-            <xs:annotation>
-                <xs:documentation>
-                    Align the returned date to the end of the chosen adjustment between year, month, week or day.
-                </xs:documentation>
-            </xs:annotation>
-            <xs:simpleType>
-                <xs:restriction base="xs:token">
-                    <xs:enumeration value="year"/>
-                    <xs:enumeration value="month"/>
-                    <xs:enumeration value="week"/>
-                    <xs:enumeration value="day"/>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="locale">
-            <xs:annotation>
-                <xs:documentation>
-                    A locale value (eg: en)
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="time-zone">
-            <xs:annotation>
-                <xs:documentation>
-                    a time zone value (eg: GMT)
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <!--
         ======================================================
         ========== The Simple Map Processor Section ==========

Modified: ofbiz/trunk/framework/minilang/src/META-INF/services/org.ofbiz.minilang.method.MethodOperation$Factory
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/META-INF/services/org.ofbiz.minilang.method.MethodOperation%24Factory?rev=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/META-INF/services/org.ofbiz.minilang.method.MethodOperation$Factory (original)
+++ ofbiz/trunk/framework/minilang/src/META-INF/services/org.ofbiz.minilang.method.MethodOperation$Factory Wed Jun 13 06:04:49 2012
@@ -86,7 +86,6 @@ org.ofbiz.minilang.method.envops.OrderMa
 org.ofbiz.minilang.method.envops.SetCalendar$SetCalendarFactory
 org.ofbiz.minilang.method.envops.SetOperation$SetOperationFactory
 org.ofbiz.minilang.method.envops.StringAppend$StringAppendFactory
-org.ofbiz.minilang.method.envops.StringToField$StringToFieldFactory
 org.ofbiz.minilang.method.envops.StringToList$StringToListFactory
 org.ofbiz.minilang.method.envops.ToString$ToStringFactory
 org.ofbiz.minilang.method.envops.While$WhileFactory

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java?rev=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/OrderMapList.java Wed Jun 13 06:04:49 2012
@@ -18,73 +18,93 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.envops;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import javolution.util.FastList;
-
-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.collections.MapComparator;
+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.w3c.dom.Element;
 
 /**
- * Copies an environment field to a list
+ * Implements the &lt;order-map-list&gt; element.
  */
-public class OrderMapList extends MethodOperation {
-
-    public static final String module = FieldToList.class.getName();
+public final class OrderMapList extends MethodOperation {
 
-    protected ContextAccessor<List<Map<Object, Object>>> listAcsr;
-    protected MapComparator mc;
-    protected List<FlexibleMapAccessor<String>> orderByAcsrList = FastList.newInstance();
+    private final FlexibleMapAccessor<List<Map<Object, Object>>> listFma;
+    private final MapComparator mc;
 
     public OrderMapList(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        listAcsr = new ContextAccessor<List<Map<Object, Object>>>(element.getAttribute("list"), element.getAttribute("list-name"));
-        for (Element orderByElement : UtilXml.childElementList(element, "order-by")) {
-            FlexibleMapAccessor<String> fma = FlexibleMapAccessor.getInstance(UtilValidate.isNotEmpty(orderByElement.getAttribute("field")) ? orderByElement.getAttribute("field") : orderByElement.getAttribute("field-name"));
-            this.orderByAcsrList.add(fma);
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "list");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "list");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "list");
+            MiniLangValidate.childElements(simpleMethod, element, "order-by");
+            MiniLangValidate.requiredChildElements(simpleMethod, element, "order-by");
+        }
+        listFma = FlexibleMapAccessor.getInstance(element.getAttribute("list"));
+        List<? extends Element> orderByElements = UtilXml.childElementList(element, "order-by");
+        if (orderByElements.size() > 0) {
+            ArrayList<FlexibleMapAccessor<String>> orderByList = new ArrayList<FlexibleMapAccessor<String>>(orderByElements.size());
+            for (Element orderByElement : orderByElements) {
+                FlexibleMapAccessor<String> fma = FlexibleMapAccessor.getInstance(orderByElement.getAttribute("field"));
+                orderByList.add(fma);
+            }
+            mc = new MapComparator(orderByList);
+        } else {
+            mc = null;
         }
-        this.mc = new MapComparator(this.orderByAcsrList);
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        List<Map<Object, Object>> orderList = listAcsr.get(methodContext);
-        if (orderList == null) {
-            if (Debug.infoOn())
-                Debug.logInfo("List not found with name " + listAcsr + ", not ordering/sorting list.", module);
-            return true;
+        if (mc == null) {
+            throw new MiniLangRuntimeException("order-by sub-elements not found.", this);
+        }
+        List<Map<Object, Object>> orderList = listFma.get(methodContext.getEnvMap());
+        if (orderList != null) {
+            Collections.sort(orderList, mc);
         }
-        Collections.sort(orderList, mc);
         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() {
-        return "<order-map-list list-name=\"" + this.listAcsr + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<order-map-list ");
+        sb.append("list=\"").append(this.listFma).append("\" />");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;order-map-list&gt; element.
+     */
     public static final class OrderMapListFactory implements Factory<OrderMapList> {
+        @Override
         public OrderMapList createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new OrderMapList(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "order-map-list";
         }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java?rev=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetCalendar.java Wed Jun 13 06:04:49 2012
@@ -24,12 +24,16 @@ import java.util.TimeZone;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.ObjectType;
+import org.ofbiz.base.util.Scriptlet;
+import org.ofbiz.base.util.StringUtil;
 import org.ofbiz.base.util.UtilDateTime;
+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.MiniLangUtil;
+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;
@@ -37,90 +41,144 @@ import org.w3c.dom.Element;
 import com.ibm.icu.util.Calendar;
 
 /**
- * Adjust a Timestamp by a specified time.
+ * Implements the &lt;set-calendar&gt; element.
  */
-public class SetCalendar extends MethodOperation {
+public final class SetCalendar extends MethodOperation {
 
     public static final String module = SetCalendar.class.getName();
 
-    protected FlexibleStringExpander daysExdr;
-    protected FlexibleStringExpander defaultExdr;
-    protected ContextAccessor<Timestamp> field;
-    protected ContextAccessor<Object> fromField;
-    protected FlexibleStringExpander hoursExdr;
-    protected FlexibleStringExpander localeExdr;
-    protected FlexibleStringExpander millisExdr;
-    protected FlexibleStringExpander minutesExdr;
-    protected FlexibleStringExpander monthsExdr;
-    protected FlexibleStringExpander periodAlignEnd;
-    protected FlexibleStringExpander periodAlignStart;
-    protected FlexibleStringExpander secondsExdr;
-    protected boolean setIfEmpty; // default to true
-    protected boolean setIfNull; // default to false
-    protected FlexibleStringExpander timeZoneExdr;
-    protected FlexibleStringExpander valueExdr;
-    protected FlexibleStringExpander yearsExdr;
+    // This method is needed only during the v1 to v2 transition
+    private static boolean autoCorrect(Element element) {
+        boolean elementModified = false;
+        // Correct deprecated default-value attribute
+        String defaultAttr = element.getAttribute("default-value");
+        if (defaultAttr.length() > 0) {
+            element.setAttribute("default", defaultAttr);
+            element.removeAttribute("default-value");
+            elementModified = true;
+        }
+        // Correct deprecated from-field attribute
+        String fromAttr = element.getAttribute("from-field");
+        if (fromAttr.length() > 0) {
+            element.setAttribute("from", fromAttr);
+            element.removeAttribute("from-field");
+            elementModified = true;
+        }
+        // Correct value attribute expression that belongs in from attribute
+        String valueAttr = element.getAttribute("value").trim();
+        if (valueAttr.startsWith("${") && valueAttr.endsWith("}")) {
+            valueAttr = valueAttr.substring(2, valueAttr.length() - 1);
+            if (!valueAttr.contains("${")) {
+                element.setAttribute("from", valueAttr);
+                element.removeAttribute("value");
+                elementModified = true;
+            }
+        }
+        return elementModified;
+    }
+
+    private final FlexibleStringExpander daysFse;
+    private final FlexibleStringExpander defaultFse;
+    private final FlexibleMapAccessor<Object> fieldFma;
+    private final FlexibleMapAccessor<Object> fromFma;
+    private final FlexibleStringExpander hoursFse;
+    private final FlexibleStringExpander localeFse;
+    private final FlexibleStringExpander millisFse;
+    private final FlexibleStringExpander minutesFse;
+    private final FlexibleStringExpander monthsFse;
+    private final FlexibleStringExpander periodAlignEnd;
+    private final FlexibleStringExpander periodAlignStart;
+    private final FlexibleStringExpander secondsFse;
+    private final boolean setIfEmpty;
+    private final boolean setIfNull;
+    private final Scriptlet scriptlet;
+    private final FlexibleStringExpander timeZoneFse;
+    private final FlexibleStringExpander valueFse;
+    private final FlexibleStringExpander yearsFse;
 
     public SetCalendar(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        this.field = new ContextAccessor<Timestamp>(element.getAttribute("field"));
-        this.fromField = new ContextAccessor<Object>(element.getAttribute("from-field"));
-        this.valueExdr = FlexibleStringExpander.getInstance(element.getAttribute("value"));
-        this.defaultExdr = FlexibleStringExpander.getInstance(element.getAttribute("default-value"));
-        this.yearsExdr = FlexibleStringExpander.getInstance(element.getAttribute("years"));
-        this.monthsExdr = FlexibleStringExpander.getInstance(element.getAttribute("months"));
-        this.daysExdr = FlexibleStringExpander.getInstance(element.getAttribute("days"));
-        this.hoursExdr = FlexibleStringExpander.getInstance(element.getAttribute("hours"));
-        this.minutesExdr = FlexibleStringExpander.getInstance(element.getAttribute("minutes"));
-        this.secondsExdr = FlexibleStringExpander.getInstance(element.getAttribute("seconds"));
-        this.millisExdr = FlexibleStringExpander.getInstance(element.getAttribute("millis"));
-        this.periodAlignStart = FlexibleStringExpander.getInstance(element.getAttribute("period-align-start"));
-        this.periodAlignEnd = FlexibleStringExpander.getInstance(element.getAttribute("period-align-end"));
-        this.localeExdr = FlexibleStringExpander.getInstance(element.getAttribute("locale"));
-        this.timeZoneExdr = FlexibleStringExpander.getInstance(element.getAttribute("time-zone"));
-        // default to false, anything but true is false
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.deprecatedAttribute(simpleMethod, element, "from-field", "replace with \"from\"");
+            MiniLangValidate.deprecatedAttribute(simpleMethod, element, "default-value", "replace with \"default\"");
+            MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "set-if-null", "set-if-empty",
+                    "years", "months", "days", "hours", "minutes", "seconds", "millis", "period-align-start", "period-align-end", "locale", "time-zone");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
+            MiniLangValidate.requireAnyAttribute(simpleMethod, element, "from", "value");
+            MiniLangValidate.constantPlusExpressionAttributes(simpleMethod, element, "value");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "set-if-null", "set-if-empty");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "from", "from-field");
+            MiniLangValidate.noChildElements(simpleMethod, element);
+        }
+        boolean elementModified = autoCorrect(element);
+        if (elementModified && MiniLangUtil.autoCorrectOn()) {
+            MiniLangUtil.flagDocumentAsCorrected(element);
+        }
+        this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
+        String fromAttribute = element.getAttribute("from");
+        if (MiniLangUtil.containsScript(fromAttribute)) {
+            this.scriptlet = new Scriptlet(StringUtil.convertOperatorSubstitutions(fromAttribute));
+            this.fromFma = FlexibleMapAccessor.getInstance(null);
+        } else {
+            this.scriptlet = null;
+            this.fromFma = FlexibleMapAccessor.getInstance(fromAttribute);
+        }
+        this.valueFse = FlexibleStringExpander.getInstance(element.getAttribute("value"));
+        if (!fromAttribute.isEmpty() && !this.valueFse.isEmpty()) {
+            throw new IllegalArgumentException("Cannot include both a from attribute and a value attribute in a <set-calendar> element.");
+        }
+        this.defaultFse = FlexibleStringExpander.getInstance(element.getAttribute("default"));
         this.setIfNull = "true".equals(element.getAttribute("set-if-null"));
-        // default to true, anything but false is true
         this.setIfEmpty = !"false".equals(element.getAttribute("set-if-empty"));
-        if (!this.fromField.isEmpty() && !this.valueExdr.isEmpty()) {
-            throw new IllegalArgumentException("Cannot specify a from-field [" + element.getAttribute("from-field") + "] and a value [" + element.getAttribute("value") + "] on the set-calendar action in a screen widget");
-        }
+        this.yearsFse = FlexibleStringExpander.getInstance(element.getAttribute("years"));
+        this.monthsFse = FlexibleStringExpander.getInstance(element.getAttribute("months"));
+        this.daysFse = FlexibleStringExpander.getInstance(element.getAttribute("days"));
+        this.hoursFse = FlexibleStringExpander.getInstance(element.getAttribute("hours"));
+        this.minutesFse = FlexibleStringExpander.getInstance(element.getAttribute("minutes"));
+        this.secondsFse = FlexibleStringExpander.getInstance(element.getAttribute("seconds"));
+        this.millisFse = FlexibleStringExpander.getInstance(element.getAttribute("millis"));
+        this.periodAlignStart = FlexibleStringExpander.getInstance(element.getAttribute("period-align-start"));
+        this.periodAlignEnd = FlexibleStringExpander.getInstance(element.getAttribute("period-align-end"));
+        this.localeFse = FlexibleStringExpander.getInstance(element.getAttribute("locale"));
+        this.timeZoneFse = FlexibleStringExpander.getInstance(element.getAttribute("time-zone"));
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
         Object newValue = null;
-        if (!this.fromField.isEmpty()) {
-            newValue = this.fromField.get(methodContext);
-            if (Debug.verboseOn())
-                Debug.logVerbose("In screen getting value for field from [" + this.fromField.toString() + "]: " + newValue, module);
-        } else if (!this.valueExdr.isEmpty()) {
-            newValue = methodContext.expandString(this.valueExdr);
-        }
-        // If newValue is still empty, use the default value
-        if (ObjectType.isEmpty(newValue) && !this.defaultExdr.isEmpty()) {
-            newValue = methodContext.expandString(this.defaultExdr);
+        if (this.scriptlet != null) {
+            try {
+                newValue = this.scriptlet.executeScript(methodContext.getEnvMap());
+            } catch (Exception exc) {
+                Debug.logWarning(exc, "Error evaluating scriptlet [" + this.scriptlet + "]: " + exc, module);
+            }
+        } else if (!this.fromFma.isEmpty()) {
+            newValue = this.fromFma.get(methodContext.getEnvMap());
+        } else if (!this.valueFse.isEmpty()) {
+            newValue = this.valueFse.expand(methodContext.getEnvMap());
+        }
+        if (ObjectType.isEmpty(newValue) && !this.defaultFse.isEmpty()) {
+            newValue = this.defaultFse.expand(methodContext.getEnvMap());
         }
         if (!setIfNull && newValue == null) {
-            if (Debug.verboseOn())
-                Debug.logVerbose("Field value not found (null) with name [" + fromField + "] and value [" + valueExdr + "], and there was not default value, not setting field", module);
             return true;
         }
         if (!setIfEmpty && ObjectType.isEmpty(newValue)) {
-            if (Debug.verboseOn())
-                Debug.logVerbose("Field value not found (empty) with name [" + fromField + "] and value [" + valueExdr + "], and there was not default value, not setting field", module);
             return true;
         }
-        // Convert attributes to the corresponding data types
         Locale locale = null;
         TimeZone timeZone = null;
         Timestamp fromStamp = null;
+        int years = 0;
+        int months = 0;
+        int days = 0;
+        int hours = 0;
+        int minutes = 0;
+        int seconds = 0;
+        int millis = 0;
         try {
-            if (!this.localeExdr.isEmpty()) {
-                locale = (Locale) ObjectType.simpleTypeConvert(methodContext.expandString(this.localeExdr), "Locale", null, null);
-            }
-            if (!this.timeZoneExdr.isEmpty()) {
-                timeZone = (TimeZone) ObjectType.simpleTypeConvert(methodContext.expandString(this.timeZoneExdr), "TimeZone", null, null);
+            if (!this.localeFse.isEmpty()) {
+                locale = (Locale) ObjectType.simpleTypeConvert(this.localeFse.expand(methodContext.getEnvMap()), "Locale", null, null);
             }
             if (locale == null) {
                 locale = methodContext.getLocale();
@@ -128,6 +186,9 @@ public class SetCalendar extends MethodO
             if (locale == null) {
                 locale = Locale.getDefault();
             }
+            if (!this.timeZoneFse.isEmpty()) {
+                timeZone = (TimeZone) ObjectType.simpleTypeConvert(this.timeZoneFse.expand(methodContext.getEnvMap()), "TimeZone", null, null);
+            }
             if (timeZone == null) {
                 timeZone = methodContext.getTimeZone();
             }
@@ -135,21 +196,30 @@ public class SetCalendar extends MethodO
                 timeZone = TimeZone.getDefault();
             }
             fromStamp = (Timestamp) MiniLangUtil.convertType(newValue, java.sql.Timestamp.class, locale, timeZone, UtilDateTime.DATE_TIME_FORMAT);
+            if (!this.yearsFse.isEmpty()) {
+                years= Integer.parseInt(this.yearsFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.monthsFse.isEmpty()) {
+                months = Integer.parseInt(this.monthsFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.daysFse.isEmpty()) {
+                days = Integer.parseInt(this.daysFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.hoursFse.isEmpty()) {
+                hours = Integer.parseInt(this.hoursFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.minutesFse.isEmpty()) {
+                minutes = Integer.parseInt(this.minutesFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.secondsFse.isEmpty()) {
+                seconds = Integer.parseInt(this.secondsFse.expandString(methodContext.getEnvMap()));
+            }
+            if (!this.millisFse.isEmpty()) {
+                millis = Integer.parseInt(this.millisFse.expandString(methodContext.getEnvMap()));
+            }
         } catch (Exception e) {
-            // Catching all exceptions - even potential ClassCastException
-            if (Debug.verboseOn())
-                Debug.logVerbose("Error converting attributes to objects: " + e.getMessage(), module);
-            return true;
+            throw new MiniLangRuntimeException("Exception thrown while parsing attributes: " + e.getMessage(), this);
         }
-        // Convert Strings to ints
-        int years = this.yearsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.yearsExdr));
-        int months = this.monthsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.monthsExdr));
-        int days = this.daysExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.daysExdr));
-        int hours = this.hoursExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.hoursExdr));
-        int minutes = this.minutesExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.minutesExdr));
-        int seconds = this.secondsExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.secondsExdr));
-        int millis = this.millisExdr.isEmpty() ? 0 : Integer.parseInt(methodContext.expandString(this.millisExdr));
-        // Adjust calendar
         Calendar cal = UtilDateTime.toCalendar(fromStamp, timeZone, locale);
         cal.add(Calendar.MILLISECOND, millis);
         cal.add(Calendar.SECOND, seconds);
@@ -159,9 +229,8 @@ public class SetCalendar extends MethodO
         cal.add(Calendar.MONTH, months);
         cal.add(Calendar.YEAR, years);
         Timestamp toStamp = new Timestamp(cal.getTimeInMillis());
-        // Align period start/end
         if (!periodAlignStart.isEmpty()) {
-            String period = methodContext.expandString(periodAlignStart);
+            String period = periodAlignStart.expandString(methodContext.getEnvMap());
             if ("day".equals(period)) {
                 toStamp = UtilDateTime.getDayStart(toStamp, 0, timeZone, locale);
             } else if ("week".equals(period)) {
@@ -170,9 +239,11 @@ public class SetCalendar extends MethodO
                 toStamp = UtilDateTime.getMonthStart(toStamp, 0, timeZone, locale);
             } else if ("year".equals(period)) {
                 toStamp = UtilDateTime.getYearStart(toStamp, 0, timeZone, locale);
+            } else {
+                throw new MiniLangRuntimeException("Invalid period-align-start attribute value: " + period, this);
             }
         } else if (!periodAlignEnd.isEmpty()) {
-            String period = methodContext.expandString(periodAlignEnd);
+            String period = periodAlignEnd.expandString(methodContext.getEnvMap());
             if ("day".equals(period)) {
                 toStamp = UtilDateTime.getDayEnd(toStamp, timeZone, locale);
             } else if ("week".equals(period)) {
@@ -181,31 +252,93 @@ public class SetCalendar extends MethodO
                 toStamp = UtilDateTime.getMonthEnd(toStamp, timeZone, locale);
             } else if ("year".equals(period)) {
                 toStamp = UtilDateTime.getYearEnd(toStamp, timeZone, locale);
+            } else {
+                throw new MiniLangRuntimeException("Invalid period-align-end attribute value: " + period, this);
             }
         }
-        if (Debug.verboseOn())
-            Debug.logVerbose("In screen setting calendar [" + this.field.toString(), module);
-        this.field.put(methodContext, toStamp);
+        this.fieldFma.put(methodContext.getEnvMap(), toStamp);
         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() {
-        return "<set-calendar field=\"" + this.field + (this.valueExdr.isEmpty() ? "" : "\" value=\"" + this.valueExdr.getOriginal()) + (this.fromField.isEmpty() ? "" : "\" from-field=\"" + this.fromField) + (this.defaultExdr.isEmpty() ? "" : "\" default-value=\"" + this.defaultExdr.getOriginal())
-                + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<set-calendar ");
+        sb.append("field=\"").append(this.fieldFma).append("\" ");
+        if (!this.fromFma.isEmpty()) {
+            sb.append("from=\"").append(this.fromFma).append("\" ");
+        }
+        if (this.scriptlet != null) {
+            sb.append("from=\"").append(this.scriptlet).append("\" ");
+        }
+        if (!this.valueFse.isEmpty()) {
+            sb.append("value=\"").append(this.valueFse).append("\" ");
+        }
+        if (!this.defaultFse.isEmpty()) {
+            sb.append("default=\"").append(this.defaultFse).append("\" ");
+        }
+        if (!this.yearsFse.isEmpty()) {
+            sb.append("years=\"").append(this.yearsFse).append("\" ");
+        }
+        if (!this.monthsFse.isEmpty()) {
+            sb.append("months=\"").append(this.monthsFse).append("\" ");
+        }
+        if (!this.daysFse.isEmpty()) {
+            sb.append("days=\"").append(this.daysFse).append("\" ");
+        }
+        if (!this.hoursFse.isEmpty()) {
+            sb.append("hours=\"").append(this.hoursFse).append("\" ");
+        }
+        if (!this.minutesFse.isEmpty()) {
+            sb.append("minutes=\"").append(this.minutesFse).append("\" ");
+        }
+        if (!this.secondsFse.isEmpty()) {
+            sb.append("seconds=\"").append(this.secondsFse).append("\" ");
+        }
+        if (!this.millisFse.isEmpty()) {
+            sb.append("millis=\"").append(this.millisFse).append("\" ");
+        }
+        if (!this.periodAlignStart.isEmpty()) {
+            sb.append("period-align-start=\"").append(this.localeFse).append("\" ");
+        }
+        if (!this.periodAlignEnd.isEmpty()) {
+            sb.append("period-align-end=\"").append(this.localeFse).append("\" ");
+        }
+        if (!this.localeFse.isEmpty()) {
+            sb.append("locale=\"").append(this.localeFse).append("\" ");
+        }
+        if (!this.timeZoneFse.isEmpty()) {
+            sb.append("time-zone=\"").append(this.timeZoneFse).append("\" ");
+        }
+        if (this.setIfNull) {
+            sb.append("set-if-null=\"true\" ");
+        }
+        if (!this.setIfEmpty) {
+            sb.append("set-if-empty=\"false\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;set-calendar&gt; element.
+     */
     public static final class SetCalendarFactory implements Factory<SetCalendar> {
+        @Override
         public SetCalendar createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new SetCalendar(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "set-calendar";
         }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java?rev=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/SetOperation.java Wed Jun 13 06:04:49 2012
@@ -36,7 +36,7 @@ import org.ofbiz.minilang.method.MethodO
 import org.w3c.dom.Element;
 
 /**
- * Assigns a field from an expression or script, or from a constant value. Also supports a default value and type conversion.
+ * Implements the &lt;set&gt; element.
  */
 public final class SetOperation extends MethodOperation {
 
@@ -73,6 +73,7 @@ public final class SetOperation extends 
     }
 
     private final FlexibleStringExpander defaultFse;
+    private final FlexibleStringExpander formatFse;
     private final FlexibleMapAccessor<Object> fieldFma;
     private final FlexibleMapAccessor<Object> fromFma;
     private final Scriptlet scriptlet;
@@ -85,11 +86,9 @@ public final class SetOperation extends 
     public SetOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
         if (MiniLangValidate.validationOn()) {
-            /*
             MiniLangValidate.deprecatedAttribute(simpleMethod, element, "from-field", "replace with \"from\"");
             MiniLangValidate.deprecatedAttribute(simpleMethod, element, "default-value", "replace with \"default\"");
-            */
-            MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "type", "set-if-null", "set-if-empty");
+            MiniLangValidate.attributeNames(simpleMethod, element, "field", "from-field", "from", "value", "default-value", "default", "format", "type", "set-if-null", "set-if-empty");
             MiniLangValidate.requiredAttributes(simpleMethod, element, "field");
             MiniLangValidate.requireAnyAttribute(simpleMethod, element, "from-field", "from", "value");
             MiniLangValidate.constantPlusExpressionAttributes(simpleMethod, element, "value");
@@ -112,6 +111,7 @@ public final class SetOperation extends 
         }
         this.valueFse = FlexibleStringExpander.getInstance(element.getAttribute("value"));
         this.defaultFse = FlexibleStringExpander.getInstance(element.getAttribute("default"));
+        this.formatFse = FlexibleStringExpander.getInstance(element.getAttribute("format"));
         this.type = element.getAttribute("type");
         Class<?> targetClass = null;
         if (!this.type.isEmpty()) {
@@ -124,7 +124,7 @@ public final class SetOperation extends 
         this.targetClass = targetClass;
         this.setIfNull = "true".equals(element.getAttribute("set-if-null")); // default to false, anything but true is false
         this.setIfEmpty = !"false".equals(element.getAttribute("set-if-empty")); // default to true, anything but false is true
-        if (!this.fromFma.isEmpty() && !this.valueFse.isEmpty()) {
+        if (!fromAttribute.isEmpty() && !this.valueFse.isEmpty()) {
             throw new IllegalArgumentException("Cannot include both a from attribute and a value attribute in a <set> element.");
         }
     }
@@ -166,13 +166,17 @@ public final class SetOperation extends 
                 newValue = FastList.newInstance();
             } else {
                 try {
+                    String format = null;
+                    if (!this.formatFse.isEmpty()) {
+                        format = this.formatFse.expandString(methodContext.getEnvMap());
+                    }
                     Class<?> targetClass = this.targetClass;
                     if (targetClass == null) {
                         targetClass = MiniLangUtil.getObjectClassForConversion(newValue);
                     }
-                    newValue = MiniLangUtil.convertType(newValue, targetClass, methodContext.getLocale(), methodContext.getTimeZone(), null);
+                    newValue = MiniLangUtil.convertType(newValue, targetClass, methodContext.getLocale(), methodContext.getTimeZone(), format);
                 } catch (Exception e) {
-                    String errMsg = "Could not convert field value for the field: [" + this.fieldFma.toString() + "] to the [" + this.type + "] type for the value [" + newValue + "]: " + e.toString();
+                    String errMsg = "Could not convert field value for the field: [" + this.fieldFma.toString() + "] to the [" + this.type + "] type for the value [" + newValue + "]: " + e.getMessage();
                     Debug.logWarning(e, errMsg, module);
                     this.simpleMethod.addErrorMessage(methodContext, errMsg);
                     return false;
@@ -180,7 +184,7 @@ public final class SetOperation extends 
             }
         }
         if (Debug.verboseOn())
-            Debug.logVerbose("In screen setting field [" + this.fieldFma.toString() + "] to value: " + newValue, module);
+            Debug.logVerbose("Setting field [" + this.fieldFma.toString() + "] to value: " + newValue, module);
         this.fieldFma.put(methodContext.getEnvMap(), newValue);
         return true;
     }
@@ -216,15 +220,26 @@ public final class SetOperation extends 
         if (this.type.length() > 0) {
             sb.append("type=\"").append(this.type).append("\" ");
         }
+        if (this.setIfNull) {
+            sb.append("set-if-null=\"true\" ");
+        }
+        if (!this.setIfEmpty) {
+            sb.append("set-if-empty=\"false\" ");
+        }
         sb.append("/>");
         return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;set&gt; element.
+     */
     public static final class SetOperationFactory implements Factory<SetOperation> {
+        @Override
         public SetOperation createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new SetOperation(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "set";
         }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java?rev=1349646&r1=1349645&r2=1349646&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/envops/StringAppend.java Wed Jun 13 06:04:49 2012
@@ -20,110 +20,106 @@ package org.ofbiz.minilang.method.envops
 
 import java.text.MessageFormat;
 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.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.w3c.dom.Element;
 
 /**
- * Appends the specified String to a field
+ * Implements the &lt;string-append&gt; element.
  */
-public class StringAppend extends MethodOperation {
-
-    public static final String module = StringAppend.class.getName();
+public final class StringAppend extends MethodOperation {
 
-    ContextAccessor<List<? extends Object>> argListAcsr;
-    ContextAccessor<String> fieldAcsr;
-    ContextAccessor<Map<String, Object>> mapAcsr;
-    String prefix;
-    String string;
-    String suffix;
+    private final FlexibleMapAccessor<List<? extends Object>> argListFma;
+    private final FlexibleMapAccessor<String> fieldFma;
+    private final FlexibleStringExpander prefixFse;
+    private final FlexibleStringExpander stringFse;
+    private final FlexibleStringExpander suffixFse;
 
     public StringAppend(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        string = element.getAttribute("string");
-        prefix = element.getAttribute("prefix");
-        suffix = element.getAttribute("suffix");
-        // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported
-        fieldAcsr = new ContextAccessor<String>(element.getAttribute("field"), element.getAttribute("field-name"));
-        mapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("map-name"));
-        argListAcsr = new ContextAccessor<List<? extends Object>>(element.getAttribute("arg-list"), element.getAttribute("arg-list-name"));
-    }
-
-    public String appendString(String oldValue, MethodContext methodContext) {
-        String value = methodContext.expandString(string);
-        String prefixValue = methodContext.expandString(prefix);
-        String suffixValue = methodContext.expandString(suffix);
-        if (!argListAcsr.isEmpty()) {
-            List<? extends Object> argList = argListAcsr.get(methodContext);
-            if (UtilValidate.isNotEmpty(argList)) {
-                value = MessageFormat.format(value, argList.toArray());
-            }
-        }
-        StringBuilder newValue = new StringBuilder();
-        if (UtilValidate.isNotEmpty(value)) {
-            if (UtilValidate.isEmpty(oldValue)) {
-                newValue.append(value);
-            } else {
-                newValue.append(oldValue);
-                if (prefixValue != null)
-                    newValue.append(prefixValue);
-                newValue.append(value);
-                if (suffixValue != null)
-                    newValue.append(suffixValue);
-            }
-        } else {
-            if (UtilValidate.isEmpty(oldValue)) {
-                newValue.append(oldValue);
-            }
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "field", "arg-list", "prefix", "string", "suffix");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "field", "string");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "field", "arg-list");
+            MiniLangValidate.noChildElements(simpleMethod, element);
         }
-        return newValue.toString();
+        argListFma = FlexibleMapAccessor.getInstance(element.getAttribute("arg-list"));
+        fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
+        prefixFse = FlexibleStringExpander.getInstance(element.getAttribute("prefix"));
+        stringFse = FlexibleStringExpander.getInstance(element.getAttribute("string"));
+        suffixFse = FlexibleStringExpander.getInstance(element.getAttribute("suffix"));
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        if (!mapAcsr.isEmpty()) {
-            Map<String, Object> toMap = mapAcsr.get(methodContext);
-            if (toMap == null) {
-                if (Debug.verboseOn())
-                    Debug.logVerbose("Map not found with name " + mapAcsr + ", creating new map", module);
-                toMap = FastMap.newInstance();
-                mapAcsr.put(methodContext, toMap);
+        String value = stringFse.expandString(methodContext.getEnvMap());
+        List<? extends Object> argList = argListFma.get(methodContext.getEnvMap());
+        if (argList != null) {
+            try {
+                value = MessageFormat.format(value, argList.toArray());
+            } catch (IllegalArgumentException e) {
+                throw new MiniLangRuntimeException("Exception thrown while formatting the string attribute: " + e.getMessage(), this);
             }
-            String oldValue = fieldAcsr.get(toMap, methodContext);
-            fieldAcsr.put(toMap, this.appendString(oldValue, methodContext), methodContext);
-        } else {
-            String oldValue = fieldAcsr.get(methodContext);
-            fieldAcsr.put(methodContext, this.appendString(oldValue, methodContext));
+        }
+        if (!value.isEmpty()) {
+            String prefixValue = prefixFse.expandString(methodContext.getEnvMap());
+            String suffixValue = suffixFse.expandString(methodContext.getEnvMap());
+            StringBuilder newValue = new StringBuilder();
+            String oldValue = fieldFma.get(methodContext.getEnvMap());
+            if (oldValue != null) {
+                newValue.append(oldValue);
+            }
+            newValue.append(prefixValue).append(value).append(suffixValue);
+            fieldFma.put(methodContext.getEnvMap(), newValue.toString());
         }
         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: something more than the empty tag
-        return "<string-append string=\"" + this.string + "\" prefix=\"" + this.prefix + "\" suffix=\"" + this.suffix + "\" field-name=\"" + this.fieldAcsr + "\" map-name=\"" + this.mapAcsr + "\"/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<string-append ");
+        sb.append("field=\"").append(this.fieldFma).append("\" ");
+        sb.append("string=\"").append(this.stringFse).append("\" ");
+        if (!this.argListFma.isEmpty()) {
+            sb.append("arg-list=\"").append(this.argListFma).append("\" ");
+        }
+        if (!this.prefixFse.isEmpty()) {
+            sb.append("prefix=\"").append(this.prefixFse).append("\" ");
+        }
+        if (!this.suffixFse.isEmpty()) {
+            sb.append("suffix=\"").append(this.suffixFse).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;string-append&gt; element.
+     */
     public static final class StringAppendFactory implements Factory<StringAppend> {
+        @Override
         public StringAppend createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new StringAppend(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "string-append";
         }