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/07/10 14:06:00 UTC

svn commit: r1359626 [4/12] - in /ofbiz/branches/release12.04: ./ framework/base/ framework/base/src/org/ofbiz/base/util/collections/ framework/base/src/org/ofbiz/base/util/collections/test/ framework/base/src/org/ofbiz/base/util/string/ framework/enti...

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/FieldObject.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/FieldObject.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/FieldObject.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/FieldObject.java Tue Jul 10 12:05:55 2012
@@ -18,72 +18,46 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method;
 
-import java.util.Map;
-
-import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.ObjectType;
 import org.ofbiz.base.util.UtilGenerics;
-import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
 import org.ofbiz.minilang.SimpleMethod;
 import org.w3c.dom.Element;
 
 /**
- * A type of MethodObject that represents an Object value in a certain location
+ * Implements the <field> element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Cfield%3E}}">Mini-language Reference</a>
  */
-public class FieldObject<T> extends MethodObject<T> {
-
-    public static final String module = FieldObject.class.getName();
+public final class FieldObject<T> extends MethodObject<T> {
 
-    ContextAccessor<T> fieldAcsr;
-    ContextAccessor<Map<String, ? extends Object>> mapAcsr;
-    String type;
+    private final FlexibleMapAccessor<Object> fieldFma;
+    private final String type;
 
     public FieldObject(Element element, SimpleMethod simpleMethod) {
         super(element, simpleMethod);
-        // the schema for this element now just has the "field" attribute, though the old "field-name" and "map-name" pair is still supported
-        fieldAcsr = new ContextAccessor<T>(element.getAttribute("field"), element.getAttribute("field-name"));
-        mapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("map-name"));
-        type = element.getAttribute("type");
-        if (UtilValidate.isEmpty(type)) {
-            type = "String";
+        this.fieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("field"));
+        String typeAttribute = element.getAttribute("type");
+        if (typeAttribute.isEmpty()) {
+            this.type = "java.lang.String";
+        } else {
+            this.type = typeAttribute;
         }
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public T getObject(MethodContext methodContext) {
-        T fieldVal = null;
-        if (!mapAcsr.isEmpty()) {
-            Map<String, ? extends Object> fromMap = mapAcsr.get(methodContext);
-            if (fromMap == null) {
-                Debug.logWarning("Map not found with name " + mapAcsr + ", not getting Object value, returning null.", module);
-                return null;
-            }
-            fieldVal = fieldAcsr.get(fromMap, methodContext);
-        } else {
-            // no map name, try the env
-            fieldVal = fieldAcsr.get(methodContext);
-        }
-        if (fieldVal == null) {
-            if (Debug.infoOn())
-                Debug.logInfo("Field value not found with name " + fieldAcsr + " in Map with name " + mapAcsr + ", not getting Object value, returning null.", module);
-            return null;
-        }
-        return fieldVal;
+        return (T) this.fieldFma.get(methodContext.getEnvMap());
     }
 
     @Override
-    public Class<T> getTypeClass(ClassLoader loader) {
-        try {
-            return UtilGenerics.cast(ObjectType.loadClass(type, loader));
-        } catch (ClassNotFoundException e) {
-            Debug.logError(e, "Could not find class for type: " + type, module);
-            return null;
-        }
+    public Class<T> getTypeClass(MethodContext methodContext) throws ClassNotFoundException {
+        return UtilGenerics.cast(ObjectType.loadClass(this.type, methodContext.getLoader()));
     }
 
-    /** Get the name for the type of the object */
     @Override
     public String getTypeName() {
-        return type;
+        return this.type;
     }
 }

Copied: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java (from r1339291, ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java)
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java?p2=ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java&p1=ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java&r1=1339291&r2=1359626&rev=1359626&view=diff
==============================================================================
--- ofbiz/trunk/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MessageElement.java Tue Jul 10 12:05:55 2012
@@ -29,6 +29,8 @@ import org.w3c.dom.Element;
 
 /**
  * Implements the &lt;fail-message&gt; and &lt;fail-property&gt; elements.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{<failmessage>}}">Mini-language Reference</a>
  */
 public final class MessageElement extends MiniLangElement {
 

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodContext.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodContext.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodContext.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodContext.java Tue Jul 10 12:05:55 2012
@@ -18,7 +18,6 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method;
 
-import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
 import java.util.TimeZone;
@@ -28,41 +27,42 @@ import javax.servlet.http.HttpServletRes
 
 import javolution.util.FastMap;
 
+import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilHttp;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.collections.FlexibleMapAccessor;
 import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.GenericValue;
-import org.ofbiz.minilang.SimpleMethod;
 import org.ofbiz.security.Security;
 import org.ofbiz.security.authz.Authorization;
 import org.ofbiz.service.DispatchContext;
 import org.ofbiz.service.LocalDispatcher;
 
 /**
- * A single operation, does the specified operation on the given field
+ * A container for the Mini-language script engine state.
  */
-public class MethodContext implements Iterable<Map.Entry<String, Object>> {
+public final class MethodContext {
 
     public static final int EVENT = 1;
     public static final int SERVICE = 2;
 
-    protected Authorization authz;
-    protected DispatchContext ctx;
-    protected Delegator delegator;
-    protected LocalDispatcher dispatcher;
-    protected Map<String, Object> env = FastMap.newInstance();
-    protected ClassLoader loader;
-    protected Locale locale;
-    protected int methodType;
-    protected Map<String, Object> parameters;
-    protected HttpServletRequest request = null;
-    protected HttpServletResponse response = null;
-    protected Map<String, Object> results = null;
-    protected Security security;
-    protected TimeZone timeZone;
-    protected GenericValue userLogin;
+    private Authorization authz;
+    private Delegator delegator;
+    private LocalDispatcher dispatcher;
+    private Map<String, Object> env = FastMap.newInstance();
+    private ClassLoader loader;
+    private Locale locale;
+    private int methodType;
+    private Map<String, Object> parameters;
+    private HttpServletRequest request = null;
+    private HttpServletResponse response = null;
+    private Map<String, Object> results = FastMap.newInstance();
+    private Security security;
+    private TimeZone timeZone;
+    private int traceCount = 0;
+    private int traceLogLevel = Debug.INFO;
+    private GenericValue userLogin;
 
     public MethodContext(DispatchContext ctx, Map<String, ? extends Object> context, ClassLoader loader) {
         this.methodType = MethodContext.SERVICE;
@@ -74,7 +74,6 @@ public class MethodContext implements It
         this.delegator = ctx.getDelegator();
         this.authz = ctx.getAuthorization();
         this.security = ctx.getSecurity();
-        this.results = FastMap.newInstance();
         this.userLogin = (GenericValue) context.get("userLogin");
         if (this.loader == null) {
             try {
@@ -144,8 +143,6 @@ public class MethodContext implements It
                 if (this.userLogin == null)
                     this.userLogin = (GenericValue) this.request.getSession().getAttribute("userLogin");
             }
-        } else if (methodType == MethodContext.SERVICE) {
-            this.results = FastMap.newInstance();
         }
         if (this.loader == null) {
             try {
@@ -156,15 +153,6 @@ public class MethodContext implements It
         }
     }
 
-    public String expandString(FlexibleStringExpander originalExdr) {
-        return originalExdr.expandString(this.env);
-    }
-
-    /** Expands environment variables delimited with ${} */
-    public String expandString(String original) {
-        return FlexibleStringExpander.expandString(original, this.env);
-    }
-
     public Authorization getAuthz() {
         return this.authz;
     }
@@ -190,15 +178,11 @@ public class MethodContext implements It
      * @return The environment value if found, otherwise null.
      */
     public <T> T getEnv(String key) {
-        String ekey = this.expandString(key);
+        String ekey = FlexibleStringExpander.expandString(key, this.env);
         FlexibleMapAccessor<T> fma = FlexibleMapAccessor.getInstance(ekey);
         return this.getEnv(fma);
     }
 
-    public Iterator<Map.Entry<String, Object>> getEnvEntryIterator() {
-        return this.env.entrySet().iterator();
-    }
-
     public Map<String, Object> getEnvMap() {
         return this.env;
     }
@@ -247,12 +231,16 @@ public class MethodContext implements It
         return this.timeZone;
     }
 
+    public int getTraceLogLevel() {
+        return this.traceLogLevel;
+    }
+
     public GenericValue getUserLogin() {
         return this.userLogin;
     }
 
-    public Iterator<Map.Entry<String, Object>> iterator() {
-        return this.env.entrySet().iterator();
+    public boolean isTraceOn() {
+        return this.traceCount > 0;
     }
 
     /**
@@ -279,7 +267,7 @@ public class MethodContext implements It
      *            The value to set in the named environment location.
      */
     public <T> void putEnv(String key, T value) {
-        String ekey = this.expandString(key);
+        String ekey = FlexibleStringExpander.expandString(key, this.env);
         FlexibleMapAccessor<T> fma = FlexibleMapAccessor.getInstance(ekey);
         this.putEnv(fma, value);
     }
@@ -304,19 +292,23 @@ public class MethodContext implements It
      *            The name of the environment value to get. Can contain "." syntax elements as described above.
      */
     public <T> T removeEnv(String key) {
-        String ekey = this.expandString(key);
+        String ekey = FlexibleStringExpander.expandString(key, this.env);
         FlexibleMapAccessor<T> fma = FlexibleMapAccessor.getInstance(ekey);
         return this.removeEnv(fma);
     }
 
-    public void setErrorReturn(String errMsg, SimpleMethod simpleMethod) {
-        if (getMethodType() == MethodContext.EVENT) {
-            putEnv(simpleMethod.getEventErrorMessageName(), errMsg);
-            putEnv(simpleMethod.getEventResponseCodeName(), simpleMethod.getDefaultErrorCode());
-        } else if (getMethodType() == MethodContext.SERVICE) {
-            putEnv(simpleMethod.getServiceErrorMessageName(), errMsg);
-            putEnv(simpleMethod.getServiceResponseMessageName(), simpleMethod.getDefaultErrorCode());
+    public void setTraceOff() {
+        if (this.traceCount > 0) {
+            this.traceCount--;
+        }
+    }
+
+    public void setTraceOn(int logLevel) {
+        if (this.traceCount == 0) {
+            // Outermost trace element sets the logging level
+            this.traceLogLevel = logLevel;
         }
+        this.traceCount++;
     }
 
     public void setUserLogin(GenericValue userLogin, String userLoginEnvName) {

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodObject.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodObject.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodObject.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodObject.java Tue Jul 10 12:05:55 2012
@@ -18,25 +18,24 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method;
 
+import org.ofbiz.minilang.MiniLangElement;
 import org.ofbiz.minilang.SimpleMethod;
 import org.w3c.dom.Element;
 
 /**
  * A single Object value to be used as a parameter or whatever
  */
-public abstract class MethodObject<T> {
-
-    protected SimpleMethod simpleMethod;
+public abstract class MethodObject<T> extends MiniLangElement {
 
     public MethodObject(Element element, SimpleMethod simpleMethod) {
-        this.simpleMethod = simpleMethod;
+        super(element, simpleMethod);
     }
 
     /** Get the Object value */
     public abstract T getObject(MethodContext methodContext);
 
     /** Get the Class for the type of the object */
-    public abstract Class<T> getTypeClass(ClassLoader loader);
+    public abstract Class<T> getTypeClass(MethodContext methodContext) throws ClassNotFoundException;
 
     /** Get the name for the type of the object */
     public abstract String getTypeName();

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodOperation.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodOperation.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodOperation.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/MethodOperation.java Tue Jul 10 12:05:55 2012
@@ -23,47 +23,44 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.minilang.MiniLangElement;
 import org.ofbiz.minilang.MiniLangException;
 import org.ofbiz.minilang.SimpleMethod;
 import org.w3c.dom.Element;
 
 /**
- * A single operation, does the specified operation on the given field
+ * An abstract class for Mini-language element models.
  */
-public abstract class MethodOperation {
+public abstract class MethodOperation extends MiniLangElement {
 
-    private final Object lineNumber;
-    protected final SimpleMethod simpleMethod;
-    private final String tagName;
 
     protected MethodOperation(Element element, SimpleMethod simpleMethod) {
-        this.lineNumber = element.getUserData("startLine");
-        this.simpleMethod = simpleMethod;
-        this.tagName = element.getTagName().intern();
+        super(element, simpleMethod);
     }
 
-    /** Execute the operation. Returns false if no further operations should be executed. 
+    /**
+     * Executes the operation.
+     * Returns <code>true</code> if script execution should continue, or
+     * <code>false</code> if script execution should stop.
+     * 
      * @throws MiniLangException */
     public abstract boolean exec(MethodContext methodContext) throws MiniLangException;
 
-    /** Create an expanded string representation of the operation, is for the current context */
-    public abstract String expandedString(MethodContext methodContext);
-
-    public String getLineNumber() {
-        return this.lineNumber == null ? "unknown" : this.lineNumber.toString();
-    }
-
-    public SimpleMethod getSimpleMethod() {
-        return this.simpleMethod;
+    /** Create a string representation of the operation, using the current context.
+     * @deprecated No replacement.
+     */
+    public String expandedString(MethodContext methodContext) {
+        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
     }
 
-    public String getTagName() {
-        return this.tagName;
+    /** Create a string representation of the operation - similar to the original XML.
+     * @deprecated Use {@link #toString()}.
+     */
+    public String rawString() {
+        return toString();
     }
 
-    /** Create a raw string representation of the operation, would be similar to original XML */
-    public abstract String rawString();
-
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.TYPE)
     public @interface DeprecatedOperation {

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/StringObject.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/StringObject.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/StringObject.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/StringObject.java Tue Jul 10 12:05:55 2012
@@ -18,44 +18,34 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method;
 
-import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.minilang.SimpleMethod;
 import org.w3c.dom.Element;
 
 /**
- * A type of MethodObject that represents a String constant value to be used as an Object
+ * Specifies a <code>java.lang.String</code> to be passed as an argument to a method call.
  */
-public class StringObject extends MethodObject<String> {
+public final class StringObject extends MethodObject<String> {
 
-    String cdataValue;
-    String value;
+    private final FlexibleStringExpander cdataValueFse;
+    private final FlexibleStringExpander valueFse;
 
     public StringObject(Element element, SimpleMethod simpleMethod) {
         super(element, simpleMethod);
-        value = element.getAttribute("value");
-        cdataValue = UtilXml.elementValue(element);
+        this.cdataValueFse = FlexibleStringExpander.getInstance(UtilXml.elementValue(element));
+        this.valueFse = FlexibleStringExpander.getInstance(element.getAttribute("value"));
     }
 
     @Override
     public String getObject(MethodContext methodContext) {
-        String value = methodContext.expandString(this.value);
-        String cdataValue = methodContext.expandString(this.cdataValue);
-        boolean valueExists = UtilValidate.isNotEmpty(value);
-        boolean cdataValueExists = UtilValidate.isNotEmpty(cdataValue);
-        if (valueExists && cdataValueExists) {
-            return value + cdataValue;
-        } else {
-            if (valueExists) {
-                return value;
-            } else {
-                return cdataValue;
-            }
-        }
+        String value = this.valueFse.expandString(methodContext.getEnvMap());
+        String cdataValue = this.cdataValueFse.expandString(methodContext.getEnvMap());
+        return value.concat(cdataValue);
     }
 
     @Override
-    public Class<String> getTypeClass(ClassLoader loader) {
+    public Class<String> getTypeClass(MethodContext methodContext) throws ClassNotFoundException {
         return java.lang.String.class;
     }
 

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallBsh.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallBsh.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallBsh.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallBsh.java Tue Jul 10 12:05:55 2012
@@ -22,18 +22,17 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.util.List;
 import java.util.Map;
 
-import javolution.util.FastList;
-
 import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.StringUtil;
 import org.ofbiz.base.util.UtilGenerics;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.minilang.MiniLangException;
+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;
@@ -42,48 +41,58 @@ import bsh.EvalError;
 import bsh.Interpreter;
 
 /**
- * Simple class to wrap messages that come either from a straight string or a properties file
+ * Implements the &lt;call-bsh&gt; element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Ccallbsh%3E}}">Mini-language Reference</a>
  */
-public class CallBsh extends MethodOperation {
+public final class CallBsh extends MethodOperation {
 
     public static final String module = CallBsh.class.getName();
-    public static final int bufferLength = 4096;
 
-    ContextAccessor<List<Object>> errorListAcsr;
-    String inline = null;
-    String resource = null;
+    // This method is needed only during the v1 to v2 transition
+    private static boolean autoCorrect(Element element) {
+        boolean elementModified = false;
+        String errorListAttr = element.getAttribute("error-list-name");
+        if (errorListAttr.length() > 0) {
+            element.removeAttribute("error-list-name");
+            elementModified = true;
+        }
+        return elementModified;
+    }
+
+    private final String inline;
+    private final String resource;
 
     public CallBsh(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        inline = UtilXml.elementValue(element);
-        resource = element.getAttribute("resource");
-        errorListAcsr = new ContextAccessor<List<Object>>(element.getAttribute("error-list-name"), "error_list");
-        if (UtilValidate.isNotEmpty(inline)) {
-            // pre-parse/compile inlined bsh, only accessed here
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.handleError("<call-bsh> element is deprecated (use <script>)", simpleMethod, element);
+            MiniLangValidate.attributeNames(simpleMethod, element, "resource");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "resource");
+            MiniLangValidate.noChildElements(simpleMethod, element);
+        }
+        boolean elementModified = autoCorrect(element);
+        if (elementModified && MiniLangUtil.autoCorrectOn()) {
+            MiniLangUtil.flagDocumentAsCorrected(element);
         }
+        this.inline = StringUtil.convertOperatorSubstitutions(UtilXml.elementValue(element));
+        this.resource = element.getAttribute("resource");
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        List<Object> messages = errorListAcsr.get(methodContext);
-        if (messages == null) {
-            messages = FastList.newInstance();
-            errorListAcsr.put(methodContext, messages);
-        }
         Interpreter bsh = new Interpreter();
         bsh.setClassLoader(methodContext.getLoader());
         try {
             // setup environment
-            for (Map.Entry<String, Object> entry : methodContext) {
+            for (Map.Entry<String, Object> entry : methodContext.getEnvMap().entrySet()) {
                 bsh.set(entry.getKey(), entry.getValue());
             }
             // run external, from resource, first if resource specified
-            if (UtilValidate.isNotEmpty(resource)) {
-                String resource = methodContext.expandString(this.resource);
-                InputStream is = methodContext.getLoader().getResourceAsStream(resource);
-
+            if (UtilValidate.isNotEmpty(this.resource)) {
+                InputStream is = methodContext.getLoader().getResourceAsStream(this.resource);
                 if (is == null) {
-                    messages.add("Could not find bsh resource: " + resource);
+                    this.simpleMethod.addErrorMessage(methodContext, "Could not find bsh resource: " + this.resource);
                 } else {
                     BufferedReader reader = null;
                     try {
@@ -100,13 +109,13 @@ public class CallBsh extends MethodOpera
                             methodContext.putAllEnv(UtilGenerics.<String, Object> checkMap(resourceResult));
                         }
                     } catch (IOException e) {
-                        messages.add("IO error loading bsh resource: " + e.getMessage());
+                        this.simpleMethod.addErrorMessage(methodContext, "IO error loading bsh resource: " + e.getMessage());
                     } finally {
                         if (reader != null) {
                             try {
                                 reader.close();
                             } catch (IOException e) {
-                                messages.add("IO error closing BufferedReader: " + e.getMessage());
+                                this.simpleMethod.addErrorMessage(methodContext, "IO error closing BufferedReader: " + e.getMessage());
                             }
                         }
                     }
@@ -123,30 +132,33 @@ public class CallBsh extends MethodOpera
                 methodContext.putAllEnv(UtilGenerics.<String, Object> checkMap(inlineResult));
             }
         } catch (EvalError e) {
-            Debug.logError(e, "BeanShell execution caused an error", module);
-            messages.add("BeanShell execution caused an error: " + e.getMessage());
+            Debug.logWarning(e, "BeanShell execution caused an error", module);
+            this.simpleMethod.addErrorMessage(methodContext, "BeanShell execution caused an error: " + e.getMessage());
         }
         // always return true, error messages just go on the error list
         return true;
     }
 
     @Override
-    public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
-    }
-
-    @Override
-    public String rawString() {
-        // TODO: something more than the empty tag
-        return "<call-bsh/>";
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<set ");
+        if (this.resource.length() > 0) {
+            sb.append("resource=\"").append(this.resource).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;call-bsh&gt; element.
+     */
     public static final class CallBshFactory implements Factory<CallBsh> {
+        @Override
         public CallBsh createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new CallBsh(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "call-bsh";
         }

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallClassMethod.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallClassMethod.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallClassMethod.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallClassMethod.java Tue Jul 10 12:05:55 2012
@@ -19,17 +19,17 @@
 
 package org.ofbiz.minilang.method.callops;
 
+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.ObjectType;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
 import org.ofbiz.minilang.MiniLangException;
+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.FieldObject;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodObject;
@@ -38,81 +38,88 @@ import org.ofbiz.minilang.method.StringO
 import org.w3c.dom.Element;
 
 /**
- * Calls a Java class method using the given fields as parameters
+ * Implements the &lt;call-class-method&gt; element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Ccallclassmethod%3E}}">Mini-language Reference</a>
  */
-public class CallClassMethod extends MethodOperation {
+public final class CallClassMethod extends MethodOperation {
 
     public static final String module = CallClassMethod.class.getName();
 
-    String className;
-    String methodName;
-    /** A list of MethodObject objects to use as the method call parameters */
-    List<MethodObject<?>> parameters;
-    ContextAccessor<Object> retFieldAcsr;
-    ContextAccessor<Map<String, Object>> retMapAcsr;
+    private final String className;
+    private final Class<?> methodClass;
+    private final String methodName;
+    private final List<MethodObject<?>> parameters;
+    private final FlexibleMapAccessor<Object> retFieldFma;
 
     public CallClassMethod(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        className = element.getAttribute("class-name");
-        methodName = element.getAttribute("method-name");
-        // the schema for this element now just has the "ret-field" attribute, though the
-        // old "ret-field-name" and "ret-map-name" pair is still supported
-        retFieldAcsr = new ContextAccessor<Object>(element.getAttribute("ret-field"), element.getAttribute("ret-field-name"));
-        retMapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("ret-map-name"));
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.handleError("<call-class-method> element is deprecated (use <script>)", simpleMethod, element);
+            MiniLangValidate.attributeNames(simpleMethod, element, "class-name", "method-name", "ret-field");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "class-name", "method-name");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "class-name", "method-name");
+            MiniLangValidate.childElements(simpleMethod, element, "string", "field");
+        }
+        this.className = element.getAttribute("class-name");
+        Class<?> methodClass = null;
+        try {
+            methodClass = ObjectType.loadClass(this.className);
+        } catch (ClassNotFoundException e) {
+            MiniLangValidate.handleError("Class not found with name " + this.className, simpleMethod, element);
+        }
+        this.methodClass = methodClass;
+        this.methodName = element.getAttribute("method-name");
+        this.retFieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("ret-field"));
         List<? extends Element> parameterElements = UtilXml.childElementList(element);
         if (parameterElements.size() > 0) {
-            parameters = FastList.newInstance();
+            ArrayList<MethodObject<?>> parameterList = new ArrayList<MethodObject<?>>(parameterElements.size());
             for (Element parameterElement : parameterElements) {
-                MethodObject<?> methodObject = null;
                 if ("string".equals(parameterElement.getNodeName())) {
-                    methodObject = new StringObject(parameterElement, simpleMethod);
+                    parameterList.add(new StringObject(parameterElement, simpleMethod));
                 } else if ("field".equals(parameterElement.getNodeName())) {
-                    methodObject = new FieldObject<Object>(parameterElement, simpleMethod);
-                } else {
-                    // whoops, invalid tag here, print warning
-                    Debug.logWarning("Found an unsupported tag under the call-object-method tag: " + parameterElement.getNodeName() + "; ignoring", module);
-                }
-                if (methodObject != null) {
-                    parameters.add(methodObject);
+                    parameterList.add(new FieldObject<Object>(parameterElement, simpleMethod));
                 }
             }
+            parameterList.trimToSize();
+            this.parameters = Collections.unmodifiableList(parameterList);
+        } else {
+            this.parameters = null;
         }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        String className = methodContext.expandString(this.className);
-        String methodName = methodContext.expandString(this.methodName);
-        Class<?> methodClass = null;
-        try {
-            methodClass = ObjectType.loadClass(className, methodContext.getLoader());
-        } catch (ClassNotFoundException e) {
-            Debug.logError(e, "Class to create not found with name " + className + " in create-object operation", module);
-
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Class to create not found with name " + className + ": " + e.toString() + "]";
-            methodContext.setErrorReturn(errMsg, simpleMethod);
-            return false;
-        }
-        return CallObjectMethod.callMethod(simpleMethod, methodContext, parameters, methodClass, null, methodName, retFieldAcsr, retMapAcsr);
+        MiniLangUtil.callMethod(this, methodContext, parameters, methodClass, null, methodName, retFieldFma);
+        return true;
     }
 
     @Override
-    public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
-    }
-
-    @Override
-    public String rawString() {
-        // TODO: something more than the empty tag
-        return "<call-class-method/>";
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<call-class-method ");
+        if (!this.className.isEmpty()) {
+            sb.append("class-name=\"").append(this.className).append("\" ");
+        }
+        if (!this.methodName.isEmpty()) {
+            sb.append("method-name=\"").append(this.methodName).append("\" ");
+        }
+        if (!this.retFieldFma.isEmpty()) {
+            sb.append("ret-field=\"").append(this.retFieldFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;call-class-method&gt; element.
+     */
     public static final class CallClassMethodFactory implements Factory<CallClassMethod> {
+        @Override
         public CallClassMethod createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new CallClassMethod(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "call-class-method";
         }

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallObjectMethod.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallObjectMethod.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallObjectMethod.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallObjectMethod.java Tue Jul 10 12:05:55 2012
@@ -18,19 +18,17 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.callops;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 
-import javolution.util.FastList;
-import javolution.util.FastMap;
-
-import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.collections.FlexibleMapAccessor;
 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.FieldObject;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodObject;
@@ -39,164 +37,84 @@ import org.ofbiz.minilang.method.StringO
 import org.w3c.dom.Element;
 
 /**
- * Calls a Java object method using the given fields as parameters
+ * Implements the &lt;call-object-method&gt; element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Ccallobjectmethod%3E}}">Mini-language Reference</a>
  */
-public class CallObjectMethod extends MethodOperation {
+public final class CallObjectMethod extends MethodOperation {
 
     public static final String module = CallClassMethod.class.getName();
 
-    public static boolean callMethod(SimpleMethod simpleMethod, MethodContext methodContext, List<MethodObject<?>> parameters, Class<?> methodClass, Object methodObject, String methodName, ContextAccessor<Object> retFieldAcsr, ContextAccessor<Map<String, Object>> retMapAcsr) {
-        Object[] args = null;
-        Class<?>[] parameterTypes = null;
-        if (parameters != null) {
-            args = new Object[parameters.size()];
-            parameterTypes = new Class<?>[parameters.size()];
-            int i = 0;
-            for (MethodObject<?> methodObjectDef : parameters) {
-                args[i] = methodObjectDef.getObject(methodContext);
-                Class<?> typeClass = methodObjectDef.getTypeClass(methodContext.getLoader());
-                if (typeClass == null) {
-                    String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Parameter type not found with name " + methodObjectDef.getTypeName() + "]";
-                    Debug.logError(errMsg, module);
-                    methodContext.setErrorReturn(errMsg, simpleMethod);
-                    return false;
-                }
-                parameterTypes[i] = typeClass;
-                i++;
-            }
-        }
-        try {
-            Method method = methodClass.getMethod(methodName, parameterTypes);
-            try {
-                Object retValue = method.invoke(methodObject, args);
-                // if retFieldAcsr is empty, ignore return value
-                if (!retFieldAcsr.isEmpty()) {
-                    if (!retMapAcsr.isEmpty()) {
-                        Map<String, Object> retMap = retMapAcsr.get(methodContext);
-                        if (retMap == null) {
-                            retMap = FastMap.newInstance();
-                            retMapAcsr.put(methodContext, retMap);
-                        }
-                        retFieldAcsr.put(retMap, retValue, methodContext);
-                    } else {
-                        // no map name, use the env
-                        retFieldAcsr.put(methodContext, retValue);
-                    }
-                }
-            } catch (IllegalAccessException e) {
-                Debug.logError(e, "Could not access method in call method operation", module);
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Could not access method to execute named " + methodName + ": " + e.toString() + "]";
-                methodContext.setErrorReturn(errMsg, simpleMethod);
-                return false;
-            } catch (IllegalArgumentException e) {
-                Debug.logError(e, "Illegal argument calling method in call method operation", module);
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Illegal argument calling method to execute named " + methodName + ": " + e.toString() + "]";
-                methodContext.setErrorReturn(errMsg, simpleMethod);
-                return false;
-            } catch (InvocationTargetException e) {
-                Debug.logError(e.getTargetException(), "Method in call method operation threw an exception", module);
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Method to execute named " + methodName + " threw an exception: " + e.getTargetException() + "]";
-                methodContext.setErrorReturn(errMsg, simpleMethod);
-                return false;
-            }
-        } catch (NoSuchMethodException e) {
-            Debug.logError(e, "Could not find method to execute in simple-method call method operation", module);
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Could not find method to execute named " + methodName + ": " + e.toString() + "]";
-            methodContext.setErrorReturn(errMsg, simpleMethod);
-            return false;
-        } catch (SecurityException e) {
-            Debug.logError(e, "Security exception finding method to execute in simple-method call method operation", module);
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Security exception finding method to execute named " + methodName + ": " + e.toString() + "]";
-            methodContext.setErrorReturn(errMsg, simpleMethod);
-            return false;
-        }
-        return true;
-    }
-
-    String methodName;
-    ContextAccessor<Object> objFieldAcsr;
-    ContextAccessor<Map<String, ? extends Object>> objMapAcsr;
-    /** A list of MethodObject objects to use as the method call parameters */
-    List<MethodObject<?>> parameters;
-    ContextAccessor<Object> retFieldAcsr;
-    ContextAccessor<Map<String, Object>> retMapAcsr;
+    private final String methodName;
+    private final FlexibleMapAccessor<Object> objFieldFma;
+    private final List<MethodObject<?>> parameters;
+    private final FlexibleMapAccessor<Object> retFieldFma;
 
     public CallObjectMethod(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        // the schema for this element now just has the "obj-field" attribute, though the
-        // old "obj-field-name" and "obj-map-name" pair is still supported
-        objFieldAcsr = new ContextAccessor<Object>(element.getAttribute("obj-field"), element.getAttribute("obj-field-name"));
-        objMapAcsr = new ContextAccessor<Map<String, ? extends Object>>(element.getAttribute("obj-map-name"));
-        methodName = element.getAttribute("method-name");
-        // the schema for this element now just has the "ret-field" attribute, though the
-        // old "ret-field-name" and "ret-map-name" pair is still supported
-        retFieldAcsr = new ContextAccessor<Object>(element.getAttribute("ret-field"), element.getAttribute("ret-field-name"));
-        retMapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("ret-map-name"));
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.handleError("<call-object-method> element is deprecated (use <script>)", simpleMethod, element);
+            MiniLangValidate.attributeNames(simpleMethod, element, "obj-field", "method-name", "ret-field");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "method-name");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "obj-field", "method-name");
+            MiniLangValidate.childElements(simpleMethod, element, "string", "field");
+        }
+        this.methodName = element.getAttribute("method-name");
+        this.objFieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("obj-field"));
+        this.retFieldFma = FlexibleMapAccessor.getInstance(element.getAttribute("ret-field"));
         List<? extends Element> parameterElements = UtilXml.childElementList(element);
         if (parameterElements.size() > 0) {
-            parameters = FastList.newInstance();
+            ArrayList<MethodObject<?>> parameterList = new ArrayList<MethodObject<?>>(parameterElements.size());
             for (Element parameterElement : parameterElements) {
-                MethodObject<?> methodObject = null;
                 if ("string".equals(parameterElement.getNodeName())) {
-                    methodObject = new StringObject(parameterElement, simpleMethod);
+                    parameterList.add(new StringObject(parameterElement, simpleMethod));
                 } else if ("field".equals(parameterElement.getNodeName())) {
-                    methodObject = new FieldObject<Object>(parameterElement, simpleMethod);
-                } else {
-                    // whoops, invalid tag here, print warning
-                    Debug.logWarning("Found an unsupported tag under the call-object-method tag: " + parameterElement.getNodeName() + "; ignoring", module);
-                }
-                if (methodObject != null) {
-                    parameters.add(methodObject);
+                    parameterList.add(new FieldObject<Object>(parameterElement, simpleMethod));
                 }
             }
+            parameterList.trimToSize();
+            this.parameters = Collections.unmodifiableList(parameterList);
+        } else {
+            this.parameters = null;
         }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        String methodName = methodContext.expandString(this.methodName);
-        Object methodObject = null;
-        if (!objMapAcsr.isEmpty()) {
-            Map<String, ? extends Object> fromMap = objMapAcsr.get(methodContext);
-            if (fromMap == null) {
-                Debug.logWarning("Map not found with name " + objMapAcsr + ", which should contain the object to execute a method on; not executing method, rerturning error.", module);
-                String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Map not found with name " + objMapAcsr + ", which should contain the object to execute a method on]";
-                methodContext.setErrorReturn(errMsg, simpleMethod);
-                return false;
-            }
-            methodObject = objFieldAcsr.get(fromMap, methodContext);
-        } else {
-            // no map name, try the env
-            methodObject = objFieldAcsr.get(methodContext);
-        }
+        Object methodObject = this.objFieldFma.get(methodContext.getEnvMap());
         if (methodObject == null) {
-            if (Debug.infoOn())
-                Debug.logInfo("Object not found to execute method on with name " + objFieldAcsr + " in Map with name " + objMapAcsr + ", not executing method, rerturning error.", module);
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [Object not found to execute method on with name " + objFieldAcsr + " in Map with name " + objMapAcsr + "]";
-            methodContext.setErrorReturn(errMsg, simpleMethod);
-            return false;
+            throw new MiniLangRuntimeException("Object not found: " + this.objFieldFma, this);
         }
-        Class<?> methodClass = methodObject.getClass();
-        return CallObjectMethod.callMethod(simpleMethod, methodContext, parameters, methodClass, methodObject, methodName, retFieldAcsr, retMapAcsr);
-    }
-
-    @Override
-    public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
+        MiniLangUtil.callMethod(this, methodContext, parameters, methodObject.getClass(), methodObject, methodName, retFieldFma);
+        return true;
     }
 
     @Override
-    public String rawString() {
-        // TODO: something more than the empty tag
-        return "<call-object-method/>";
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<call-class-method ");
+        if (!this.objFieldFma.isEmpty()) {
+            sb.append("obj-field=\"").append(this.objFieldFma).append("\" ");
+        }
+        if (!this.methodName.isEmpty()) {
+            sb.append("method-name=\"").append(this.methodName).append("\" ");
+        }
+        if (!this.retFieldFma.isEmpty()) {
+            sb.append("ret-field=\"").append(this.retFieldFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;call-object-method&gt; element.
+     */
     public static final class CallObjectMethodFactory implements Factory<CallObjectMethod> {
+        @Override
         public CallObjectMethod createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new CallObjectMethod(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "call-object-method";
         }

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallScript.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallScript.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallScript.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallScript.java Tue Jul 10 12:05:55 2012
@@ -21,7 +21,7 @@ package org.ofbiz.minilang.method.callop
 import org.ofbiz.base.util.ScriptUtil;
 import org.ofbiz.base.util.Scriptlet;
 import org.ofbiz.base.util.StringUtil;
-import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.minilang.MiniLangException;
 import org.ofbiz.minilang.MiniLangRuntimeException;
 import org.ofbiz.minilang.MiniLangUtil;
@@ -32,7 +32,9 @@ import org.ofbiz.minilang.method.MethodO
 import org.w3c.dom.Element;
 
 /**
- * Executes a script.
+ * Implements the &lt;script&gt; element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Cscript%3E}}">Mini-language Reference</a>
  */
 public final class CallScript extends MethodOperation {
 
@@ -69,14 +71,11 @@ public final class CallScript extends Me
         if (elementModified && MiniLangUtil.autoCorrectOn()) {
             MiniLangUtil.flagDocumentAsCorrected(element);
         }
-        String scriptAttribute = element.getAttribute("script");
-        if (MiniLangUtil.containsScript(scriptAttribute)) {
-            this.scriptlet = new Scriptlet(StringUtil.convertOperatorSubstitutions(scriptAttribute));
+        String scriptLocation = element.getAttribute("location");
+        if (scriptLocation.isEmpty()) {
             this.location = null;
             this.method = null;
         } else {
-            this.scriptlet = null;
-            String scriptLocation = element.getAttribute("location");
             int pos = scriptLocation.lastIndexOf("#");
             if (pos == -1) {
                 this.location = scriptLocation;
@@ -86,58 +85,63 @@ public final class CallScript extends Me
                 this.method = scriptLocation.substring(pos + 1);
             }
         }
+        String inlineScript = element.getAttribute("script");
+        if (inlineScript.isEmpty()) {
+            inlineScript = UtilXml.elementValue(element);
+        }
+        if (inlineScript != null && MiniLangUtil.containsScript(inlineScript)) {
+            this.scriptlet = new Scriptlet(StringUtil.convertOperatorSubstitutions(inlineScript));
+        } else {
+            this.scriptlet = null;
+        }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
+        if (this.location != null) {
+            if (location.endsWith(".xml")) {
+                SimpleMethod.runSimpleMethod(location, method, methodContext);
+            } else {
+                ScriptUtil.executeScript(this.location, this.method, methodContext.getEnvMap());
+            }
+        }
         if (this.scriptlet != null) {
             try {
                 this.scriptlet.executeScript(methodContext.getEnvMap());
             } catch (Exception e) {
                 throw new MiniLangRuntimeException(e.getMessage(), this);
             }
-            return true;
-        }
-        if (location.endsWith(".xml")) {
-            SimpleMethod.runSimpleMethod(location, method, methodContext);
-        } else {
-            ScriptUtil.executeScript(this.location, this.method, methodContext.getEnvMap());
         }
         return true;
     }
 
     @Override
-    public String expandedString(MethodContext methodContext) {
-        return FlexibleStringExpander.expandString(toString(), methodContext.getEnvMap());
-    }
-
-    @Override
-    public String rawString() {
-        return toString();
-    }
-
-    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder("<script ");
-        if (this.location != null && this.location.length() > 0) {
+        if (this.location != null) {
             sb.append("location=\"").append(this.location);
-            if (this.method != null && this.method.length() > 0) {
+            if (this.method != null) {
                 sb.append("#").append(this.method);
             }
             sb.append("\" ");
         }
         if (this.scriptlet != null) {
-            sb.append("scriptlet=\"").append(this.scriptlet).append("\" ");
+            sb.append("script=\"").append(this.scriptlet).append("\" ");
         }
         sb.append("/>");
         return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;script&gt; element.
+     */
     public static final class CallScriptFactory implements Factory<CallScript> {
+        @Override
         public CallScript createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new CallScript(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "script";
         }

Modified: ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallService.java
URL: http://svn.apache.org/viewvc/ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallService.java?rev=1359626&r1=1359625&r2=1359626&view=diff
==============================================================================
--- ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallService.java (original)
+++ ofbiz/branches/release12.04/framework/minilang/src/org/ofbiz/minilang/method/callops/CallService.java Tue Jul 10 12:05:55 2012
@@ -18,11 +18,12 @@
  *******************************************************************************/
 package org.ofbiz.minilang.method.callops;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-import javolution.util.FastList;
 import javolution.util.FastMap;
 
 import org.ofbiz.base.util.Debug;
@@ -31,11 +32,14 @@ import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilProperties;
 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.FlexibleServletAccessor;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
 import org.ofbiz.entity.GenericValue;
 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.artifact.ArtifactInfoContext;
 import org.ofbiz.minilang.method.MethodContext;
 import org.ofbiz.minilang.method.MethodOperation;
 import org.ofbiz.service.GenericServiceException;
@@ -44,65 +48,63 @@ import org.ofbiz.service.ServiceUtil;
 import org.w3c.dom.Element;
 
 /**
- * Calls a service using the given parameters
+ * Implements the &lt;call-service&gt; element.
+ * 
+ * @see <a href="https://cwiki.apache.org/OFBADMIN/mini-language-reference.html#Mini-languageReference-{{%3Ccallservice%3E}}">Mini-language Reference</a>
  */
-public class CallService extends MethodOperation {
+public final class CallService extends MethodOperation {
 
     public static final String module = CallService.class.getName();
     public static final String resource = "MiniLangErrorUiLabels";
 
-    protected String breakOnErrorStr;
-    protected FlexibleMessage defaultMessage;
-    protected String errorCode;
-    protected FlexibleMessage errorPrefix;
-    protected FlexibleMessage errorSuffix;
-    protected String includeUserLoginStr;
-    protected ContextAccessor<Map<String, Object>> inMapAcsr;
-    protected FlexibleMessage messagePrefix;
-    protected FlexibleMessage messageSuffix;
-    /** Require a new transaction for this service */
-    protected String requireNewTransactionStr;
-    /** A list of strings with names of new maps to create */
-    protected List<String> resultsToMap = FastList.newInstance();
-    /** A list of ResultToFieldDef objects */
-    protected List<ResultToFieldDef> resultToField = FastList.newInstance();
-    /** the key is the request attribute name, the value is the result name to get */
-    protected Map<FlexibleServletAccessor<Object>, ContextAccessor<Object>> resultToRequest = FastMap.newInstance();
-    /** the key is the result entry name, the value is the result name to get */
-    protected Map<ContextAccessor<Object>, ContextAccessor<Object>> resultToResult = FastMap.newInstance();
-    /** the key is the session attribute name, the value is the result name to get */
-    protected Map<FlexibleServletAccessor<Object>, ContextAccessor<Object>> resultToSession = FastMap.newInstance();
-    protected String serviceName;
-    protected String successCode;
-    protected FlexibleMessage successPrefix;
-    protected FlexibleMessage successSuffix;
-    /** Override the default transaction timeout, only works if we start the transaction */
-    protected int transactionTimeout;
+    private final boolean breakOnError;
+    private final FlexibleMessage defaultMessage;
+    private final String errorCode;
+    private final FlexibleMessage errorPrefix;
+    private final FlexibleMessage errorSuffix;
+    private final boolean includeUserLogin;
+    private final FlexibleMapAccessor<Map<String, Object>> inMapFma;
+    private final FlexibleMessage messagePrefix;
+    private final FlexibleMessage messageSuffix;
+    private final boolean requireNewTransaction;
+    private final List<String> resultsToMapList;
+    private final List<ResultToField> resultToFieldList;
+    private final List<ResultToRequest> resultToRequestList;
+    private final List<ResultToResult> resultToResultList;
+    private final List<ResultToSession> resultToSessionList;
+    private final FlexibleStringExpander serviceNameFse;
+    private final String successCode;
+    private final FlexibleMessage successPrefix;
+    private final FlexibleMessage successSuffix;
+    private final int transactionTimeout;
 
     public CallService(Element element, SimpleMethod simpleMethod) throws MiniLangException {
         super(element, simpleMethod);
-        serviceName = element.getAttribute("service-name");
-        inMapAcsr = new ContextAccessor<Map<String, Object>>(element.getAttribute("in-map-name"));
-        includeUserLoginStr = element.getAttribute("include-user-login");
-        breakOnErrorStr = element.getAttribute("break-on-error");
+        if (MiniLangValidate.validationOn()) {
+            MiniLangValidate.attributeNames(simpleMethod, element, "service-name", "in-map-name", "include-user-login", "break-on-error", "error-code", "require-new-transaction", "transaction-timeout", "success-code");
+            MiniLangValidate.constantAttributes(simpleMethod, element, "include-user-login", "break-on-error", "error-code", "require-new-transaction", "transaction-timeout", "success-code");
+            MiniLangValidate.expressionAttributes(simpleMethod, element, "service-name", "in-map-name");
+            MiniLangValidate.requiredAttributes(simpleMethod, element, "service-name");
+            MiniLangValidate.childElements(simpleMethod, element, "error-prefix", "error-suffix", "success-prefix", "success-suffix", "message-prefix", "message-suffix", "default-message", "results-to-map", "result-to-field", "result-to-request", "result-to-session", "result-to-result");
+        }
+        serviceNameFse = FlexibleStringExpander.getInstance(element.getAttribute("service-name"));
+        inMapFma = FlexibleMapAccessor.getInstance(element.getAttribute("in-map-name"));
+        includeUserLogin = !"false".equals(element.getAttribute("include-user-login"));
+        breakOnError = !"false".equals(element.getAttribute("break-on-error"));
         errorCode = element.getAttribute("error-code");
-        if (UtilValidate.isEmpty(errorCode))
-            errorCode = "error";
-        this.requireNewTransactionStr = element.getAttribute("require-new-transaction");
-        String timeoutStr = UtilXml.checkEmpty(element.getAttribute("transaction-timeout"), element.getAttribute("transaction-timout"));
+        requireNewTransaction = "true".equals(element.getAttribute("require-new-transaction"));
+        String timeoutStr = UtilXml.checkEmpty(element.getAttribute("transaction-timeout"));
         int timeout = -1;
-        if (!UtilValidate.isEmpty(timeoutStr)) {
+        if (!timeoutStr.isEmpty()) {
             try {
                 timeout = Integer.parseInt(timeoutStr);
             } catch (NumberFormatException e) {
-                Debug.logWarning(e, "Setting timeout to 0 (default)", module);
+                MiniLangValidate.handleError("Exception thrown while parsing transaction-timeout attribute: " + e.getMessage(), simpleMethod, element);
                 timeout = 0;
             }
         }
-        this.transactionTimeout = timeout;
+        transactionTimeout = timeout;
         successCode = element.getAttribute("success-code");
-        if (UtilValidate.isEmpty(successCode))
-            successCode = "success";
         errorPrefix = new FlexibleMessage(UtilXml.firstChildElement(element, "error-prefix"), "service.error.prefix");
         errorSuffix = new FlexibleMessage(UtilXml.firstChildElement(element, "error-suffix"), "service.error.suffix");
         successPrefix = new FlexibleMessage(UtilXml.firstChildElement(element, "success-prefix"), "service.success.prefix");
@@ -112,81 +114,84 @@ public class CallService extends MethodO
         defaultMessage = new FlexibleMessage(UtilXml.firstChildElement(element, "default-message"), null);// "service.default.message"
         List<? extends Element> resultsToMapElements = UtilXml.childElementList(element, "results-to-map");
         if (UtilValidate.isNotEmpty(resultsToMapElements)) {
+            List<String> resultsToMapList = new ArrayList<String>(resultsToMapElements.size());
             for (Element resultsToMapElement : resultsToMapElements) {
-                resultsToMap.add(resultsToMapElement.getAttribute("map-name"));
+                resultsToMapList.add(resultsToMapElement.getAttribute("map-name"));
             }
+            this.resultsToMapList = Collections.unmodifiableList(resultsToMapList);
+        } else {
+            this.resultsToMapList = null;
         }
         List<? extends Element> resultToFieldElements = UtilXml.childElementList(element, "result-to-field");
         if (UtilValidate.isNotEmpty(resultToFieldElements)) {
+            List<ResultToField> resultToFieldList = new ArrayList<ResultToField>(resultToFieldElements.size());
             for (Element resultToFieldElement : resultToFieldElements) {
-                ResultToFieldDef rtfDef = new ResultToFieldDef();
-
-                rtfDef.resultName = resultToFieldElement.getAttribute("result-name");
-                rtfDef.mapAcsr = new ContextAccessor<Map<String, Object>>(resultToFieldElement.getAttribute("map-name"));
-                String field = resultToFieldElement.getAttribute("field");
-                if (UtilValidate.isEmpty(field))
-                    field = resultToFieldElement.getAttribute("field-name");
-                rtfDef.fieldAcsr = new ContextAccessor<Object>(field, rtfDef.resultName);
-
-                resultToField.add(rtfDef);
+                resultToFieldList.add(new ResultToField(resultToFieldElement));
             }
+            this.resultToFieldList = Collections.unmodifiableList(resultToFieldList);
+        } else {
+            this.resultToFieldList = null;
         }
-        // get result-to-request and result-to-session sub-ops
         List<? extends Element> resultToRequestElements = UtilXml.childElementList(element, "result-to-request");
         if (UtilValidate.isNotEmpty(resultToRequestElements)) {
+            List<ResultToRequest> resultToRequestList = new ArrayList<ResultToRequest>(resultToRequestElements.size());
             for (Element resultToRequestElement : resultToRequestElements) {
-                FlexibleServletAccessor<Object> reqAcsr = new FlexibleServletAccessor<Object>(resultToRequestElement.getAttribute("request-name"), resultToRequestElement.getAttribute("result-name"));
-                ContextAccessor<Object> resultAcsr = new ContextAccessor<Object>(resultToRequestElement.getAttribute("result-name"));
-                resultToRequest.put(reqAcsr, resultAcsr);
+                resultToRequestList.add(new ResultToRequest(resultToRequestElement));
             }
+            this.resultToRequestList = Collections.unmodifiableList(resultToRequestList);
+        } else {
+            this.resultToRequestList = null;
         }
         List<? extends Element> resultToSessionElements = UtilXml.childElementList(element, "result-to-session");
         if (UtilValidate.isNotEmpty(resultToSessionElements)) {
+            List<ResultToSession> resultToSessionList = new ArrayList<ResultToSession>(resultToSessionElements.size());
             for (Element resultToSessionElement : resultToSessionElements) {
-                FlexibleServletAccessor<Object> sesAcsr = new FlexibleServletAccessor<Object>(resultToSessionElement.getAttribute("session-name"), resultToSessionElement.getAttribute("result-name"));
-                ContextAccessor<Object> resultAcsr = new ContextAccessor<Object>(resultToSessionElement.getAttribute("result-name"));
-                resultToSession.put(sesAcsr, resultAcsr);
+                resultToSessionList.add(new ResultToSession(resultToSessionElement));
             }
+            this.resultToSessionList = Collections.unmodifiableList(resultToSessionList);
+        } else {
+            this.resultToSessionList = null;
         }
         List<? extends Element> resultToResultElements = UtilXml.childElementList(element, "result-to-result");
         if (UtilValidate.isNotEmpty(resultToResultElements)) {
+            List<ResultToResult> resultToResultList = new ArrayList<ResultToResult>(resultToResultElements.size());
             for (Element resultToResultElement : resultToResultElements) {
-                ContextAccessor<Object> serResAcsr = new ContextAccessor<Object>(resultToResultElement.getAttribute("service-result-name"), resultToResultElement.getAttribute("result-name"));
-                ContextAccessor<Object> resultAcsr = new ContextAccessor<Object>(resultToResultElement.getAttribute("result-name"));
-                resultToResult.put(serResAcsr, resultAcsr);
+                resultToResultList.add(new ResultToResult(resultToResultElement));
             }
+            this.resultToResultList = Collections.unmodifiableList(resultToResultList);
+        } else {
+            this.resultToResultList = null;
         }
     }
 
     @Override
     public boolean exec(MethodContext methodContext) throws MiniLangException {
-        boolean includeUserLogin = !"false".equals(methodContext.expandString(includeUserLoginStr));
-        boolean breakOnError = !"false".equals(methodContext.expandString(breakOnErrorStr));
-        String serviceName = methodContext.expandString(this.serviceName);
-        String errorCode = methodContext.expandString(this.errorCode);
-        String successCode = methodContext.expandString(this.successCode);
-        Map<String, Object> inMap = null;
-        if (inMapAcsr.isEmpty()) {
+        if (methodContext.isTraceOn()) {
+            outputTraceMessage(methodContext, "Begin call-service.");
+        }
+        String serviceName = serviceNameFse.expandString(methodContext.getEnvMap());
+        String errorCode = this.errorCode;
+        if (errorCode.isEmpty()) {
+            errorCode = simpleMethod.getDefaultErrorCode();
+        }
+        String successCode = this.successCode;
+        if (successCode.isEmpty()) {
+            successCode = simpleMethod.getDefaultSuccessCode();
+        }
+        Map<String, Object> inMap = inMapFma.get(methodContext.getEnvMap());
+        if (inMap == null) {
             inMap = FastMap.newInstance();
-        } else {
-            inMap = inMapAcsr.get(methodContext);
-            if (inMap == null) {
-                inMap = FastMap.newInstance();
-                inMapAcsr.put(methodContext, inMap);
-            }
         }
         // before invoking the service, clear messages
         if (methodContext.getMethodType() == MethodContext.EVENT) {
             methodContext.removeEnv(simpleMethod.getEventErrorMessageName());
             methodContext.removeEnv(simpleMethod.getEventEventMessageName());
             methodContext.removeEnv(simpleMethod.getEventResponseCodeName());
-        } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+        } else {
             methodContext.removeEnv(simpleMethod.getServiceErrorMessageName());
             methodContext.removeEnv(simpleMethod.getServiceSuccessMessageName());
             methodContext.removeEnv(simpleMethod.getServiceResponseMessageName());
         }
-        // invoke the service
-        Map<String, Object> result = null;
         // add UserLogin to context if expected
         if (includeUserLogin) {
             GenericValue userLogin = methodContext.getUserLogin();
@@ -199,80 +204,82 @@ public class CallService extends MethodO
         if (locale != null) {
             inMap.put("locale", locale);
         }
+        // invoke the service
+        Map<String, Object> result = null;
         try {
-            if (UtilValidate.isEmpty(this.requireNewTransactionStr) && this.transactionTimeout < 0) {
-                result = methodContext.getDispatcher().runSync(serviceName, inMap);
-            } else {
-                ModelService modelService = methodContext.getDispatcher().getDispatchContext().getModelService(serviceName);
-                boolean requireNewTransaction = modelService.requireNewTransaction;
-                int timeout = modelService.transactionTimeout;
-                if (UtilValidate.isNotEmpty(this.requireNewTransactionStr)) {
-                    requireNewTransaction = "true".equalsIgnoreCase(this.requireNewTransactionStr) ? true : false;
-                }
-                if (this.transactionTimeout >= 0) {
-                    timeout = this.transactionTimeout;
-                }
-                result = methodContext.getDispatcher().runSync(serviceName, inMap, timeout, requireNewTransaction);
+            ModelService modelService = methodContext.getDispatcher().getDispatchContext().getModelService(serviceName);
+            int timeout = modelService.transactionTimeout;
+            if (this.transactionTimeout >= 0) {
+                timeout = this.transactionTimeout;
+            }
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Invoking service \"" + serviceName + "\", require-new-transaction = " + requireNewTransaction + ", transaction-timeout = " + timeout + ", IN attributes:", inMap.toString());
             }
+            result = methodContext.getDispatcher().runSync(serviceName, inMap, timeout, requireNewTransaction);
         } catch (GenericServiceException e) {
-            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [problem invoking the [" + serviceName + "] service with the map named [" + inMapAcsr + "] containing [" + inMap + "]: " + e.getMessage() + "]";
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Service engine threw an exception: " + e.getMessage());
+            }
+            String errMsg = "ERROR: Could not complete the " + simpleMethod.getShortDescription() + " process [problem invoking the [" + serviceName + "] service with the map named [" + inMapFma + "] containing [" + inMap + "]: " + e.getMessage() + "]";
             Debug.logError(e, errMsg, module);
             if (breakOnError) {
                 if (methodContext.getMethodType() == MethodContext.EVENT) {
                     methodContext.putEnv(simpleMethod.getEventErrorMessageName(), errMsg);
                     methodContext.putEnv(simpleMethod.getEventResponseCodeName(), errorCode);
-                } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+                } else {
                     methodContext.putEnv(simpleMethod.getServiceErrorMessageName(), errMsg);
                     methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), errorCode);
                 }
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "break-on-error set to \"true\", halting script execution. End call-service.");
+                }
                 return false;
             } else {
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "End call-service.");
+                }
                 return true;
             }
         }
-        if (resultsToMap.size() > 0) {
-            for (String mapName : resultsToMap) {
+        if (resultsToMapList != null) {
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Processing " + resultsToMapList.size() + " <results-to-map> elements.");
+            }
+            for (String mapName : resultsToMapList) {
                 methodContext.putEnv(mapName, UtilMisc.makeMapWritable(result));
             }
         }
-        if (resultToField.size() > 0) {
-            for (ResultToFieldDef rtfDef : resultToField) {
-                if (!rtfDef.mapAcsr.isEmpty()) {
-                    Map<String, Object> tempMap = rtfDef.mapAcsr.get(methodContext);
-                    if (tempMap == null) {
-                        tempMap = FastMap.newInstance();
-                        rtfDef.mapAcsr.put(methodContext, tempMap);
-                    }
-                    rtfDef.fieldAcsr.put(tempMap, result.get(rtfDef.resultName), methodContext);
-                } else {
-                    rtfDef.fieldAcsr.put(methodContext, result.get(rtfDef.resultName));
-                }
+        if (resultToFieldList != null) {
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Processing " + resultToFieldList.size() + " <result-to-field> elements.");
+            }
+            for (ResultToField rtfDef : resultToFieldList) {
+                rtfDef.exec(methodContext, result);
+            }
+        }
+        if (resultToResultList != null) {
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Processing " + resultToResultList.size() + " <result-to-result> elements.");
+            }
+            for (ResultToResult rtrDef : resultToResultList) {
+                rtrDef.exec(methodContext, result);
             }
         }
-        // only run this if it is in an EVENT context
         if (methodContext.getMethodType() == MethodContext.EVENT) {
-            if (resultToRequest.size() > 0) {
-                for (Map.Entry<FlexibleServletAccessor<Object>, ContextAccessor<Object>> entry : resultToRequest.entrySet()) {
-                    FlexibleServletAccessor<Object> requestAcsr = entry.getKey();
-                    ContextAccessor<Object> resultAcsr = entry.getValue();
-                    requestAcsr.put(methodContext.getRequest(), resultAcsr.get(result, methodContext), methodContext.getEnvMap());
-                }
-            }
-            if (resultToSession.size() > 0) {
-                for (Map.Entry<FlexibleServletAccessor<Object>, ContextAccessor<Object>> entry : resultToSession.entrySet()) {
-                    FlexibleServletAccessor<Object> sessionAcsr = entry.getKey();
-                    ContextAccessor<Object> resultAcsr = entry.getValue();
-                    sessionAcsr.put(methodContext.getRequest().getSession(), resultAcsr.get(result, methodContext), methodContext.getEnvMap());
+            if (resultToRequestList != null) {
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "Processing " + resultToRequestList.size() + " <result-to-request> elements.");
+                }
+                for (ResultToRequest rtrDef : resultToRequestList) {
+                    rtrDef.exec(methodContext, result);
                 }
             }
-        }
-        // only run this if it is in an SERVICE context
-        if (methodContext.getMethodType() == MethodContext.SERVICE) {
-            if (resultToResult.size() > 0) {
-                for (Map.Entry<ContextAccessor<Object>, ContextAccessor<Object>> entry : resultToResult.entrySet()) {
-                    ContextAccessor<Object> targetResultAcsr = entry.getKey();
-                    ContextAccessor<Object> resultAcsr = entry.getValue();
-                    targetResultAcsr.put(methodContext.getResults(), resultAcsr.get(result, methodContext), methodContext);
+            if (resultToSessionList != null) {
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "Processing " + resultToSessionList.size() + " <result-to-session> elements.");
+                }
+                for (ResultToSession rtsDef : resultToSessionList) {
+                    rtsDef.exec(methodContext, result);
                 }
             }
         }
@@ -303,11 +310,8 @@ public class CallService extends MethodO
                     }
                     methodContext.putEnv(simpleMethod.getEventErrorMessageListName(), errorMessageList);
                 }
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+            } else {
                 ServiceUtil.addErrors(UtilMisc.<String, String> getListFromMap(methodContext.getEnvMap(), this.simpleMethod.getServiceErrorMessageListName()), UtilMisc.<String, String, Object> getMapFromMap(methodContext.getEnvMap(), this.simpleMethod.getServiceErrorMessageMapName()), result);
-                // the old way, makes a mess of messages passed up the stack:
-                // methodContext.putEnv(simpleMethod.getServiceErrorMessageName(),
-                // errorMessage);
                 Debug.logError(new Exception(errorMessage), module);
             }
         }
@@ -315,7 +319,7 @@ public class CallService extends MethodO
         if (UtilValidate.isNotEmpty(successMessage)) {
             if (methodContext.getMethodType() == MethodContext.EVENT) {
                 methodContext.putEnv(simpleMethod.getEventEventMessageName(), successMessage);
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+            } else {
                 methodContext.putEnv(simpleMethod.getServiceSuccessMessageName(), successMessage);
             }
         }
@@ -323,28 +327,38 @@ public class CallService extends MethodO
         if (UtilValidate.isEmpty(errorMessage) && UtilValidate.isEmpty(errorMessageList) && UtilValidate.isEmpty(successMessage) && UtilValidate.isNotEmpty(defaultMessageStr)) {
             if (methodContext.getMethodType() == MethodContext.EVENT) {
                 methodContext.putEnv(simpleMethod.getEventEventMessageName(), defaultMessageStr);
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+            } else {
                 methodContext.putEnv(simpleMethod.getServiceSuccessMessageName(), defaultMessageStr);
             }
         }
-        // handle the result
         String responseCode = result.containsKey(ModelService.RESPONSE_MESSAGE) ? (String) result.get(ModelService.RESPONSE_MESSAGE) : successCode;
         if (errorCode.equals(responseCode)) {
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Service returned an error.");
+            }
             if (breakOnError) {
                 if (methodContext.getMethodType() == MethodContext.EVENT) {
                     methodContext.putEnv(simpleMethod.getEventResponseCodeName(), responseCode);
-                } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+                } else {
                     methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), responseCode);
                 }
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "break-on-error set to \"true\", halting script execution. End call-service.");
+                }
                 return false;
             } else {
-                // avoid responseCode here since we are ignoring the error
+                if (methodContext.isTraceOn()) {
+                    outputTraceMessage(methodContext, "End call-service.");
+                }
                 return true;
             }
         } else {
+            if (methodContext.isTraceOn()) {
+                outputTraceMessage(methodContext, "Service ran successfully. End call-service.");
+            }
             if (methodContext.getMethodType() == MethodContext.EVENT) {
                 methodContext.putEnv(simpleMethod.getEventResponseCodeName(), responseCode);
-            } else if (methodContext.getMethodType() == MethodContext.SERVICE) {
+            } else {
                 methodContext.putEnv(simpleMethod.getServiceResponseMessageName(), responseCode);
             }
             return true;
@@ -352,34 +366,99 @@ public class CallService extends MethodO
     }
 
     @Override
-    public String expandedString(MethodContext methodContext) {
-        // TODO: something more than a stub/dummy
-        return this.rawString();
-    }
-
-    public String getServiceName() {
-        return this.serviceName;
+    public void gatherArtifactInfo(ArtifactInfoContext aic) {
+        aic.addServiceName(this.serviceNameFse.toString());
     }
 
     @Override
-    public String rawString() {
-        // TODO: something more than the empty tag
-        return "<call-service/>";
+    public String toString() {
+        StringBuilder sb = new StringBuilder("<call-service ");
+        sb.append("service-name=\"").append(this.serviceNameFse).append("\" ");
+        if (!this.inMapFma.isEmpty()) {
+            sb.append("in-map-name=\"").append(this.inMapFma).append("\" ");
+        }
+        sb.append("/>");
+        return sb.toString();
     }
 
+    /**
+     * A factory for the &lt;call-service&gt; element.
+     */
     public static final class CallServiceFactory implements Factory<CallService> {
+        @Override
         public CallService createMethodOperation(Element element, SimpleMethod simpleMethod) throws MiniLangException {
             return new CallService(element, simpleMethod);
         }
 
+        @Override
         public String getName() {
             return "call-service";
         }
     }
 
-    public static class ResultToFieldDef {
-        public ContextAccessor<Object> fieldAcsr;
-        public ContextAccessor<Map<String, Object>> mapAcsr;
-        public String resultName;
+    private final class ResultToField {
+        private final FlexibleMapAccessor<Object> fieldFma;
+        private final FlexibleMapAccessor<Object> resultFma;
+
+        private ResultToField(Element element) {
+            resultFma = FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
+            String fieldAttribute = element.getAttribute("field");
+            if (fieldAttribute.isEmpty()) {
+                fieldFma = resultFma;
+            } else {
+                fieldFma = FlexibleMapAccessor.getInstance(fieldAttribute);
+            }
+        }
+
+        private void exec(MethodContext methodContext, Map<String, Object> resultMap) {
+            fieldFma.put(methodContext.getEnvMap(), resultFma.get(resultMap));
+        }
+    }
+
+    private final class ResultToRequest {
+        private final FlexibleMapAccessor<Object> resultFma;
+        private final FlexibleServletAccessor<Object> requestFsa;
+
+        private ResultToRequest(Element element) {
+            requestFsa = new FlexibleServletAccessor<Object>(element.getAttribute("request-name"), element.getAttribute("result-name"));
+            resultFma =FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
+        }
+
+        private void exec(MethodContext methodContext, Map<String, Object> resultMap) {
+            requestFsa.put(methodContext.getRequest(), resultFma.get(resultMap), methodContext.getEnvMap());
+        }
+    }
+
+    private final class ResultToResult {
+        private final FlexibleMapAccessor<Object> resultFma;
+        private final FlexibleMapAccessor<Object> serviceResultFma;
+
+        private ResultToResult(Element element) {
+            resultFma = FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
+            String serviceResultAttribute = element.getAttribute("service-result-name");
+            if (serviceResultAttribute.isEmpty()) {
+                serviceResultFma = resultFma;
+            } else {
+                serviceResultFma = FlexibleMapAccessor.getInstance(serviceResultAttribute);
+            }
+        }
+
+        private void exec(MethodContext methodContext, Map<String, Object> resultMap) {
+            serviceResultFma.put(methodContext.getResults(), resultFma.get(resultMap));
+        }
+    }
+
+    private final class ResultToSession {
+        private final FlexibleMapAccessor<Object> resultFma;
+        private final FlexibleServletAccessor<Object> requestFsa;
+
+        private ResultToSession(Element element) {
+            requestFsa = new FlexibleServletAccessor<Object>(element.getAttribute("session-name"), element.getAttribute("result-name"));
+            resultFma =FlexibleMapAccessor.getInstance(element.getAttribute("result-name"));
+        }
+
+        private void exec(MethodContext methodContext, Map<String, Object> resultMap) {
+            requestFsa.put(methodContext.getRequest().getSession(), resultFma.get(resultMap), methodContext.getEnvMap());
+        }
     }
 }