svn commit: r1340651 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/entityops/EntityCount.java src/org/ofbiz/minilang/method/entityops/EntityData.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1340651 - in /ofbiz/trunk/framework/minilang: dtd/simple-methods-v2.xsd src/org/ofbiz/minilang/method/entityops/EntityCount.java src/org/ofbiz/minilang/method/entityops/EntityData.java

adrianc
Author: adrianc
Date: Sun May 20 09:48:06 2012
New Revision: 1340651

URL: http://svn.apache.org/viewvc?rev=1340651&view=rev
Log:
Overhauled Mini-language <entity-count> and <entity-data> elements.

Modified:
    ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityCount.java
    ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityData.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=1340651&r1=1340650&r2=1340651&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd (original)
+++ ofbiz/trunk/framework/minilang/dtd/simple-methods-v2.xsd Sun May 20 09:48:06 2012
@@ -2001,80 +2001,58 @@ under the License.
     <xs:element name="entity-data" substitutionGroup="EntityMiscOperations">
         <xs:annotation>
             <xs:documentation>
-                Specify the location of an XML file that should be in the same format as any
-                of the entity engine XML files, or the entity engine transformed
-                XML files. And what this will do is either load or
-                assert that file depending on the mode.
-
-                If it finds the record but any of the fields are different,
-                this is in the assert mode still, it will report any field
-                that's different in a message on the error list. So that's
-                basically what you can in essence assert, that a certain
-                set of data exists in the database.
+                Load or assert an entity data XML file. The operation can be used in two modes:
+                "load" or "assert". The "load" mode will load the XML entity data into the database.
+                The "assert" mode will compare the XML entity data with the database -
+                any mismatched or missing data will be logged in the error message list.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
-            <xs:attributeGroup ref="attlist.entity-data"/>
+            <xs:attribute type="xs:string" name="location" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Specify the location of an XML file to load in database or verify in assert mode.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: constant, ${expression}.
+                </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="mode" default="load">
+                <xs:annotation>
+                    <xs:documentation>
+                        Operation mode: "load" or "assert". Defaults to "load".
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:simpleType>
+                    <xs:restriction base="xs:token">
+                        <xs:enumeration value="load" />
+                        <xs:enumeration value="assert" />
+                    </xs:restriction>
+                </xs:simpleType>
+            </xs:attribute>
+            <xs:attribute type="xs:integer" name="timeout">
+                <xs:annotation>
+                    <xs:documentation>
+                        Override the timeout to start a new transaction and load the data with a longer timeout.
+                        Used only when mode="load".
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute ref="error-list-name" />
+            <xs:attribute type="xs:string" name="delegator-name">
+                <xs:annotation>
+                    <xs:documentation>
+                        Overrides the delegator or default context by specifying a delegator-name.
+                        Optional. Attribute type: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.entity-data">
-        <xs:attribute type="xs:string" name="location" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Specify the location of an XML file to load in database or verify in assert mode.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="delegator-name" use="optional">
-            <xs:annotation>
-                <xs:documentation>
-                    Overrides the delegator or default context by specifying a delegator-name.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:integer" name="timeout" default="-1">
-            <xs:annotation>
-                <xs:documentation>
-                    Override the timeout to start a new transaction and load the data with a longer timeout.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute type="xs:string" name="error-list-name" default="error_list">
-            <xs:annotation>
-                <xs:documentation>
-                    The name of the list in the method environment to check for error messages.
-                    Defaults to "error_list".
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="mode" default="load">
-            <xs:annotation>
-                <xs:documentation>
-                    "load" or "assert". Default to "load".
-                </xs:documentation>
-            </xs:annotation>
-            <xs:simpleType>
-                <xs:restriction base="xs:token">
-                    <xs:enumeration value="load">
-                        <xs:annotation>
-                            <xs:documentation>
-                                Load the file into the database.
-                            </xs:documentation>
-                        </xs:annotation>
-                    </xs:enumeration>
-                    <xs:enumeration value="assert">
-                        <xs:annotation>
-                            <xs:documentation>
-                                Go through each row in the file, each record, and it
-                                will look that up by primary key. If it does not find it, it'll
-                                add a message to the error list about not having found it.
-                            </xs:documentation>
-                        </xs:annotation>
-                    </xs:enumeration>
-                </xs:restriction>
-            </xs:simpleType>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="find-by-primary-key" substitutionGroup="EntityFindOperations">
         <xs:annotation>
             <xs:documentation>
@@ -2673,55 +2651,56 @@ under the License.
     <xs:element name="entity-count" substitutionGroup="EntityFindOperations">
         <xs:annotation>
             <xs:documentation>
-                Returns a long presenting the number of results found matching the specified condition.
-                The entity-count is very  similar to the entity-condition.
+                Returns a numeric value representing the number of entity values matching the specified condition.
+                The entity-count element is very similar to the entity-condition element.
 
                 Specify the entity-name, optionally the delgator-name if you want to override that,
-                and then the name of the variable to put the count in.
+                and then the name of the variable to put the count value in.
 
                 You can do the same condition-expr (condition expression) or condition-list which can have condition-expr
                 and other condition-lists underneath it for a tree of conditions that can be arbitrarily complex.
-                You can also use the have-in-condition-list, this is the same as on the entity-condition.
-                What this will do basically is, rather than doing a query and getting the results back,
-                it will just count the results and put that number in the context in the variable named by the count-name.
+                You can also use the have-in-condition-list element, this is the same as the entity-condition.
             </xs:documentation>
         </xs:annotation>
         <xs:complexType>
             <xs:sequence>
                 <xs:choice>
-                    <xs:element ref="condition-expr"/>
-                    <xs:element ref="condition-list"/>
-                    <xs:element ref="condition-object"/>
+                    <xs:element ref="condition-expr" />
+                    <xs:element ref="condition-list" />
+                    <xs:element ref="condition-object" />
                 </xs:choice>
-                <xs:element minOccurs="0" ref="having-condition-list"/>
+                <xs:element minOccurs="0" ref="having-condition-list" />
             </xs:sequence>
-            <xs:attributeGroup ref="attlist.entity-count"/>
+            <xs:attribute name="entity-name" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Name of entity to count in.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="count-field" type="xs:string" use="required">
+                <xs:annotation>
+                    <xs:documentation>
+                        Name of the field (variable) to put result of the count in.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Required. Attribute type: expression.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="delegator-name" type="xs:string">
+                <xs:annotation>
+                    <xs:documentation>
+                        Name of a delegator to use.
+                        By default uses the delegator associated with that instance of the service engine.
+                        &lt;br/&gt;&lt;br/&gt;
+                        Optional. Attribute type: constant, ${expression}.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:attribute>
         </xs:complexType>
     </xs:element>
-    <xs:attributeGroup name="attlist.entity-count">
-        <xs:attribute name="entity-name" type="xs:string" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of entity to search in.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="delegator-name" type="xs:string">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of a delegator to use.
-                    By default uses the delegator associated with that instance of the service engine.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="count-field" type="xs:string" use="required">
-            <xs:annotation>
-                <xs:documentation>
-                    Name of the field (variable) to put result of the count in.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:attributeGroup>
     <xs:element name="get-related-one" substitutionGroup="EntityFindOperations">
         <xs:annotation>
             <xs:documentation>

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityCount.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityCount.java?rev=1340651&r1=1340650&r2=1340651&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityCount.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityCount.java Sun May 20 09:48:06 2012
@@ -18,9 +18,6 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.entityops;
 
-import java.util.Map;
-
-import org.ofbiz.minilang.artifact.ArtifactInfoContext;
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.GeneralException;
 import org.ofbiz.base.util.UtilValidate;
@@ -36,39 +33,47 @@ import org.ofbiz.entity.finder.EntityFin
 import org.ofbiz.entity.finder.EntityFinderUtil.ConditionObject;
 import org.ofbiz.entity.model.ModelEntity;
 import org.ofbiz.minilang.MiniLangException;
+import org.ofbiz.minilang.MiniLangValidate;
 import org.ofbiz.minilang.SimpleMethod;
+import org.ofbiz.minilang.artifact.ArtifactInfoContext;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.w3c.dom.Element;
 
 /**
- * Uses the delegator to find entity values by a condition
+ * Implements the &lt;entity-count&gt; element.
  */
-public class EntityCount extends MethodOperation {
+public final class EntityCount extends MethodOperation {
 
     public static final String module = EntityCount.class.getName();
 
-    protected FlexibleMapAccessor<Long> countAcsr;
-    protected FlexibleStringExpander delegatorNameExdr;
-    protected FlexibleStringExpander entityNameExdr;
-    protected Condition havingCondition;
-    protected Condition whereCondition;
+    private final FlexibleMapAccessor<Long> countFma;
+    private final FlexibleStringExpander delegatorNameFse;
+    private final FlexibleStringExpander entityNameFse;
+    private final Condition havingCondition;
+    private final Condition whereCondition;
 
     public EntityCount(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        this.entityNameExdr = FlexibleStringExpander.getInstance(element.getAttribute("entity-name"));
-        this.delegatorNameExdr = FlexibleStringExpander.getInstance(element.getAttribute("delegator-name"));
-        if (UtilValidate.isNotEmpty(element.getAttribute("count-field"))) {
-            this.countAcsr = FlexibleMapAccessor.getInstance(element.getAttribute("count-field"));
-        } else {
-            this.countAcsr = FlexibleMapAccessor.getInstance(element.getAttribute("count-name"));
-        }
-        // process condition-expr | condition-list
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "entity-name", "count-field", "delegator-name");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "entity-name", "count-field");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "count-field");
+            MiniLangValidate.childElements(simpleMethod, element, "condition-expr", "condition-list", "condition-object", "having-condition-list");
+            MiniLangValidate.requireAnyChildElement(simpleMethod, element, "condition-expr", "condition-list", "condition-object");
+        }
+        this.entityNameFse = FlexibleStringExpander.getInstance(element.getAttribute("entity-name"));
+        this.delegatorNameFse = FlexibleStringExpander.getInstance(element.getAttribute("delegator-name"));
+        this.countFma = FlexibleMapAccessor.getInstance(element.getAttribute("count-field"));
+        int conditionElementCount = 0;
         Element conditionExprElement = UtilXml.firstChildElement(element, "condition-expr");
+        conditionElementCount = conditionExprElement == null ? conditionElementCount : conditionElementCount++;
         Element conditionListElement = UtilXml.firstChildElement(element, "condition-list");
+        conditionElementCount = conditionListElement == null ? conditionElementCount : conditionElementCount++;
         Element conditionObjectElement = UtilXml.firstChildElement(element, "condition-object");
-        if (conditionExprElement != null && conditionListElement != null) {
-            throw new IllegalArgumentException("In entity find by condition element, cannot have condition-expr and condition-list sub-elements");
+        conditionElementCount = conditionObjectElement == null ? conditionElementCount : conditionElementCount++;
+        if (conditionElementCount > 1) {
+            MiniLangValidate.handleError("Element must include only one condition child element", simpleMethod, conditionObjectElement);
         }
         if (conditionExprElement != null) {
             this.whereCondition = new ConditionExpr(conditionExprElement);
@@ -76,47 +81,41 @@ public class EntityCount extends MethodO
             this.whereCondition = new ConditionList(conditionListElement);
         } else if (conditionObjectElement != null) {
             this.whereCondition = new ConditionObject(conditionObjectElement);
+        } else {
+            this.whereCondition = null;
         }
-        // process having-condition-list
         Element havingConditionListElement = UtilXml.firstChildElement(element, "having-condition-list");
         if (havingConditionListElement != null) {
             this.havingCondition = new ConditionList(havingConditionListElement);
+        } else {
+            this.havingCondition = null;
         }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
         try {
-            Map<String, Object> context = methodContext.getEnvMap();
+            String delegatorName = this.delegatorNameFse.expandString(methodContext.getEnvMap());
             Delegator delegator = methodContext.getDelegator();
-            String entityName = this.entityNameExdr.expandString(context);
-            String delegatorName = this.delegatorNameExdr.expandString(context);
             if (UtilValidate.isNotEmpty(delegatorName)) {
                 delegator = DelegatorFactory.getDelegator(delegatorName);
             }
+            String entityName = this.entityNameFse.expandString(methodContext.getEnvMap());
             ModelEntity modelEntity = delegator.getModelEntity(entityName);
-            // create whereEntityCondition from whereCondition
             EntityCondition whereEntityCondition = null;
             if (this.whereCondition != null) {
-                whereEntityCondition = this.whereCondition.createCondition(context, modelEntity, delegator.getModelFieldTypeReader(modelEntity));
+                whereEntityCondition = this.whereCondition.createCondition(methodContext.getEnvMap(), modelEntity, delegator.getModelFieldTypeReader(modelEntity));
             }
-            // create havingEntityCondition from havingCondition
             EntityCondition havingEntityCondition = null;
             if (this.havingCondition != null) {
-                havingEntityCondition = this.havingCondition.createCondition(context, modelEntity, delegator.getModelFieldTypeReader(modelEntity));
+                havingEntityCondition = this.havingCondition.createCondition(methodContext.getEnvMap(), modelEntity, delegator.getModelFieldTypeReader(modelEntity));
             }
             long count = delegator.findCountByCondition(entityName, whereEntityCondition, havingEntityCondition, null);
-            this.countAcsr.put(context, count);
+            this.countFma.put(methodContext.getEnvMap(), count);
         } catch (GeneralException e) {
-            Debug.logError(e, module);
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process: " + e.getMessage();
-            if (methodContext.getMethodType() == MethodContext.EVENT) {
-                methodContext.putEnv(simpleMethod.getEventErrorMessageName(), errMsg);
-                methodContext.putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
-                methodContext.putEnv(simpleMethod.getServiceErrorMessageName(), errMsg);
-                methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
-            }
+            String errMsg = "Exception thrown while performing entity count: " + e.getMessage();
+            Debug.logWarning(e, errMsg, module);
+            simpleMethod.addErrorMessage(methodContext, errMsg);
             return false;
         }
         return true;
@@ -124,26 +123,41 @@ public class EntityCount extends MethodO
 
     @Override
     public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
     @Override
     public void gatherArtifactInfo(ArtifactInfoContext aic) {
-        aic.addEntityName(entityNameExdr.toString());
+        aic.addEntityName(entityNameFse.toString());
     }
 
     @Override
     public String rawString() {
-        // TODO: something more than the empty tag
-        return "<entity-count/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<entity-count ");
+        sb.append("entity-name=\"").append(this.entityNameFse).append("\" ");
+        sb.append("count-field=\"").append(this.countFma).append("\" ");
+        if (!this.delegatorNameFse.isEmpty()) {
+            sb.append("delegator-name=\"").append(this.delegatorNameFse).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;entity-count&gt; element.
+     */
     public static final class EntityCountFactory implements Factory<EntityCount> {
+        @Override
         public EntityCount createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new EntityCount(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "entity-count";
         }

Modified: ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityData.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityData.java?rev=1340651&r1=1340650&r2=1340651&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityData.java (original)
+++ ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/entityops/EntityData.java Sun May 20 09:48:06 2012
@@ -27,52 +27,65 @@ import javolution.util.FastList;
 import org.ofbiz.base.location.FlexibleLocation;
 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.entity.Delegator;
 import org.ofbiz.entity.DelegatorFactory;
 import org.ofbiz.entity.util.EntityDataAssert;
 import org.ofbiz.entity.util.EntitySaxReader;
 import org.ofbiz.minilang.MiniLangException;
+import org.ofbiz.minilang.MiniLangValidate;
 import org.ofbiz.minilang.SimpleMethod;
-import org.ofbiz.minilang.method.ContextAccessor;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.w3c.dom.Element;
 
 /**
- * Uses the delegator to find entity values by a primary key
+ * Implements the &lt;entity-data&gt; element.
  */
-public class EntityData extends MethodOperation {
+public final class EntityData extends MethodOperation {
 
     public static final String module = EntityData.class.getName();
 
-    protected FlexibleStringExpander delegatorNameExdr;
-    protected ContextAccessor<List<Object>> errorListAcsr;
-    protected FlexibleStringExpander locationExdr;
-    protected String mode;
-    protected FlexibleStringExpander timeoutExdr;
+    private final FlexibleStringExpander delegatorNameFse;
+    private final FlexibleMapAccessor<List<Object>> errorListFma;
+    private final FlexibleStringExpander locationFse;
+    private final String mode;
+    private final int timeout;
 
     public EntityData(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        locationExdr = FlexibleStringExpander.getInstance(element.getAttribute("location"));
-        delegatorNameExdr = FlexibleStringExpander.getInstance(element.getAttribute("delegator-name"));
-        timeoutExdr = FlexibleStringExpander.getInstance(element.getAttribute("timeout"));
-        errorListAcsr = new ContextAccessor<List<Object>>(element.getAttribute("error-list-name"), "error_list");
-        mode = element.getAttribute("mode");
-        if (UtilValidate.isEmpty(mode)) {
-            mode = "load";
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "location", "timeout", "delegator-name", "error-list-name", "mode");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "location");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "timeout", "mode");
+            MiniLangValidate.noChildElements(simpleMethod, element);
+        }
+        locationFse = FlexibleStringExpander.getInstance(element.getAttribute("location"));
+        delegatorNameFse = FlexibleStringExpander.getInstance(element.getAttribute("delegator-name"));
+        String timeoutAttribute = element.getAttribute("timeout");
+        int timeout = -1;
+        if (!timeoutAttribute.isEmpty()) {
+            try {
+                timeout = Integer.parseInt(timeoutAttribute);
+            } catch (NumberFormatException e) {
+                MiniLangValidate.handleError("Exception thrown while parsing timeout attribute: " + e.getMessage(), simpleMethod, element);
+            }
         }
+        this.timeout = timeout;
+        errorListFma = FlexibleMapAccessor.getInstance(MiniLangValidate.checkAttribute(element.getAttribute("error-list-name"), "error_list"));
+        mode = MiniLangValidate.checkAttribute(element.getAttribute("mode"), "load");
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        List<Object> messages = errorListAcsr.get(methodContext);
+        List<Object> messages = errorListFma.get(methodContext.getEnvMap());
         if (messages == null) {
             messages = FastList.newInstance();
-            errorListAcsr.put(methodContext, messages);
+            errorListFma.put(methodContext.getEnvMap(), messages);
         }
-        String location = this.locationExdr.expandString(methodContext.getEnvMap());
-        String delegatorName = this.delegatorNameExdr.expandString(methodContext.getEnvMap());
+        String location = this.locationFse.expandString(methodContext.getEnvMap());
+        String delegatorName = this.delegatorNameFse.expandString(methodContext.getEnvMap());
         Delegator delegator = methodContext.getDelegator();
         if (UtilValidate.isNotEmpty(delegatorName)) {
             delegator = DelegatorFactory.getDelegator(delegatorName);
@@ -86,31 +99,19 @@ public class EntityData extends MethodOp
         if (dataUrl == null) {
             messages.add("Could not find Entity Data document in resource: " + location);
         }
-        String timeout = this.timeoutExdr.expandString(methodContext.getEnvMap());
-        int txTimeout = -1;
-        if (UtilValidate.isNotEmpty(timeout)) {
-            try {
-                txTimeout = Integer.parseInt(timeout);
-            } catch (NumberFormatException e) {
-                Debug.logWarning("Timeout not formatted properly in entity-data operation, defaulting to container default", module);
-            }
-        }
         if ("assert".equals(mode)) {
-            // load the XML file, read in one element at a time and check it against the
-            // database
             try {
                 EntityDataAssert.assertData(dataUrl, delegator, messages);
             } catch (Exception e) {
                 String xmlError = "Error checking/asserting XML Resource \"" + dataUrl.toExternalForm() + "\"; Error was: " + e.getMessage();
-                // Debug.logError(e, xmlError, module);
                 messages.add(xmlError);
+                Debug.logWarning(e, xmlError, module);
             }
         } else {
-            // again, default to load
             try {
                 EntitySaxReader reader = null;
-                if (txTimeout > 0) {
-                    reader = new EntitySaxReader(delegator, txTimeout);
+                if (timeout > 0) {
+                    reader = new EntitySaxReader(delegator, timeout);
                 } else {
                     reader = new EntitySaxReader(delegator);
                 }
@@ -118,7 +119,7 @@ public class EntityData extends MethodOp
             } catch (Exception e) {
                 String xmlError = "Error loading XML Resource \"" + dataUrl.toExternalForm() + "\"; Error was: " + e.getMessage();
                 messages.add(xmlError);
-                Debug.logError(e, xmlError, module);
+                Debug.logWarning(e, xmlError, module);
             }
         }
         return true;
@@ -126,23 +127,39 @@ public class EntityData extends MethodOp
 
     @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 "<entity-data/>";
+        return toString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<entity-data ");
+        sb.append("location=\"").append(this.locationFse).append("\" ");
+        sb.append("mode=\"").append(this.mode).append("\" ");
+        sb.append("timeout=\"").append(this.timeout).append("\" ");
+        if (!this.delegatorNameFse.isEmpty()) {
+            sb.append("delegator-name=\"").append(this.delegatorNameFse).append("\" ");
+        }
+        sb.append("error-list-name=\"").append(this.errorListFma).append("\" ");
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;entity-data&gt; element.
+     */
     public static final class EntityDataFactory implements Factory<EntityData> {
+        @Override
         public EntityData createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new EntityData(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
-            // FIXME: not in SimpleMethod
             return "entity-data";
         }
     }