[jbpm-commits] JBoss JBPM SVN: r6740 - in jbpm4/trunk/modules: pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor and 2 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Tue Oct 5 04:42:01 EDT 2010


Author: rebody
Date: 2010-10-05 04:42:00 -0400 (Tue, 05 Oct 2010)
New Revision: 6740

Added:
   jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java
Modified:
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmElFactory.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java
   jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ObjectDescriptor.java
   jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ResourceBundleELResovlerTest.java
   jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch08-Scripting.xml
Log:
JBPM-2887 support custom function in EL.

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/Expression.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -131,6 +131,11 @@
     return elContext;
   }
 
+  public static void reset() {
+    expressionFactory = null;
+    elContext = null;
+  }
+
   public abstract String getExpressionString();
 
   public abstract boolean isLiteralText();

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmElFactory.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmElFactory.java	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmElFactory.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -34,7 +34,7 @@
 
   public static JbpmElFactory getJbpmElFactory() {
     JbpmElFactory contextFactory = EnvironmentImpl.getFromCurrent(JbpmElFactory.class, false);
-    if (contextFactory==null) {
+    if (contextFactory == null) {
       contextFactory = new JbpmElFactoryImpl();
     }
     return contextFactory;

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/el/JbpmFunctionMapper.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -40,6 +40,9 @@
 
   public JbpmFunctionMapper(Map<String, Class<?>> functionClassMap) {
     this.functionClassMap = functionClassMap;
+    if (functionClassMap.isEmpty()) {
+      functionClassMap.put("", JstlFunction.class);
+    }
   }
 
   public Method resolveFunction(String prefix, String localName) {
@@ -52,7 +55,7 @@
     Class<?> functionClass = functionClassMap.get(prefix);
     if (functionClass == null) {
       if (log.isInfoEnabled()) {
-        log.info("cannot find functionClass for prefix : " + prefix);
+        log.info("cannot find functionClass for prefix : [" + prefix + "]");
       }
       return null;
     }

Modified: jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ObjectDescriptor.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ObjectDescriptor.java	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/pvm/src/main/java/org/jbpm/pvm/internal/wire/descriptor/ObjectDescriptor.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -94,7 +94,7 @@
    * TODO check if this member can be replaced by a RefDescriptor in the factoryDescriptor member.
    *
    * */
-  String factoryObjectName;
+  protected String factoryObjectName;
 
   protected Expression expression;
 
@@ -136,75 +136,81 @@
     Object object = null;
     Class<?> clazz = null;
 
-    if (className!=null) {
+    if (className != null) {
       try {
         clazz = ReflectUtil.classForName(className);
       } catch (Exception e) {
-        throw new JbpmClassNotFoundException("couldn't load class "+className, e);
+        throw new JbpmClassNotFoundException("couldn't load class " + className, e);
       }
 
-      if (methodName==null) {
+      if (methodName == null) {
         // plain instantiation
         try {
           Object[] args = getArgs(wireContext, argDescriptors);
           Constructor<?> constructor = ReflectUtil.findConstructor(clazz, argDescriptors, args);
-          if (constructor==null) {
-            throw new WireException("couldn't find constructor "+clazz.getName()+" with args "+Arrays.toString(args));
+          if (constructor == null) {
+            throw new WireException("couldn't find constructor " + clazz.getName() + " with args " + Arrays.toString(args));
           }
           object = constructor.newInstance(args);
         } catch (WireException e) {
           throw e;
         } catch (Exception e) {
-          throw new WireException("couldn't create object '"+(name!=null ? name : className)+"': "+e.getMessage(), e);
+          throw new WireException("couldn't create object '" + (name != null ? name : className) + "': " + e.getMessage(), e);
         }
       }
 
-    } else if (factoryObjectName!=null) {
+    } else if (factoryObjectName != null) {
       // referenced factory object
       object = wireContext.get(factoryObjectName);
-      if (object==null) {
-        throw new WireException("can't invoke method '"+methodName+"' on null, resulted from fetching object '"+factoryObjectName+"' from this wiring environment");
+      if (object == null) {
+        throw new WireException("can't invoke method '" + methodName
+          + "' on null, resulted from fetching object '" + factoryObjectName + "' from this wiring environment");
       }
 
     } else if (factoryDescriptor!=null) {
       // factory object descriptor
       object = wireContext.create(factoryDescriptor, false);
-      if (object==null) {
-        throw new WireException("created factory object is null, can't invoke method '"+methodName+"' on it");
+      if (object == null) {
+        throw new WireException("created factory object is null, can't invoke method '" + methodName + "' on it");
       }
-    } else if (expression!=null) {
+    } else if (expression != null) {
       object = expression.evaluateInScope(wireContext.getScopeInstance());
     }
 
-    if (methodName!=null) {
+    if (methodName != null) {
       try {
         object = invokeMethod(methodName, argDescriptors, wireContext, object, clazz);
 
       } catch (WireException e) {
         throw e;
       } catch (Exception e) {
-        throw new WireException("couldn't invoke factory method "+methodName+": "+e.getMessage(), e);
+        throw new WireException("couldn't invoke factory method " + methodName + ": " + e.getMessage(), e);
       }
     }
 
     return object;
   }
 
-  public static Object invokeMethod(String methodName, List<ArgDescriptor> argDescriptors, WireContext wireContext, Object object, Class< ? > clazz) throws Exception {
+  public static Object invokeMethod(String methodName,
+                                    List<ArgDescriptor> argDescriptors,
+                                    WireContext wireContext,
+                                    Object object,
+                                    Class<?> clazz) throws Exception {
     // method invocation on object or static method invocation in case object is null
-    if (object!=null) {
+    if (object != null) {
       clazz = object.getClass();
     }
     Object[] args = ObjectDescriptor.getArgs(wireContext, argDescriptors);
     Method method = ReflectUtil.findMethod(clazz, methodName, argDescriptors, args);
-    if (method==null) {
+    if (method == null) {
       // throw exception but first, generate decent message
-      throw new WireException("method "+ReflectUtil.getSignature(methodName, argDescriptors, args)+" is not available on "+
-          (object!=null ? "object "+object+" ("+clazz.getName()+")" : "class "+clazz.getName()));
+      throw new WireException("method " + ReflectUtil.getSignature(methodName, argDescriptors, args) + " is not available on "
+        + (object != null ? "object " + object + " (" + clazz.getName() + ")" : "class " + clazz.getName()));
     }
     if (object == null && (!Modifier.isStatic(method.getModifiers()))) {
       // A non static method is invoked on a null object
-      throw new WireException("method "+ clazz.getName() + "." + ReflectUtil.getSignature(methodName, argDescriptors, args)+" is not static. It cannot be called on a null object.");
+      throw new WireException("method " + clazz.getName() + "." + ReflectUtil.getSignature(methodName, argDescriptors, args)
+        + " is not static. It cannot be called on a null object.");
     }
     object = ReflectUtil.invoke(method, object, args);
     return object;
@@ -225,37 +231,37 @@
       if (isAutoWireEnabled) {
         autoWire(object, wireContext);
       }
-      if (operations!=null) {
-        for(Operation operation: operations) {
+      if (operations != null) {
+        for(Operation operation : operations) {
           operation.apply(object, wireContext);
         }
       }
-    } catch (Exception e) {
-      throw new WireException("couldn't initialize object '"+(name!=null ? name : className)+"': "+e.getMessage(), e);
+    } catch (Throwable e) {
+      throw new WireException("couldn't initialize object '" + (name != null ? name : className) + "': " + e.getMessage(), e);
     }
   }
 
   public Class<?> getType(WireDefinition wireDefinition) {
-    if (className!=null) {
+    if (className != null) {
       try {
         return ReflectUtil.classForName(className);
       } catch (Exception e) {
-        throw new WireException("couldn't load class '"+className+"'", e);
+        throw new WireException("couldn't load class '" + className + "'", e);
       }
     }
 
     Descriptor descriptor = null;
-    if (factoryDescriptor!=null) {
+    if (factoryDescriptor != null) {
       descriptor = factoryDescriptor;
-    } else if (factoryObjectName!=null) {
+    } else if (factoryObjectName != null) {
       descriptor = wireDefinition.getDescriptor(factoryObjectName);
     }
 
-    if (descriptor!=null) {
+    if (descriptor != null) {
       Class<?> factoryClass = descriptor.getType(wireDefinition);
-      if (factoryClass!=null) {
+      if (factoryClass != null) {
         Method method = ReflectUtil.findMethod(factoryClass, methodName, argDescriptors, null);
-        if (method!=null) {
+        if (method != null) {
           return method.getReturnType();
         }
       }
@@ -271,11 +277,11 @@
    */
   protected void autoWire(Object object, WireContext wireContext) {
     Class<?> clazz = object.getClass();
-    while (clazz!=null) {
+    while (clazz != null) {
       Field[] declaredFields = clazz.getDeclaredFields();
-      if (declaredFields!=null) {
-        for (Field field: declaredFields) {
-          if (! Modifier.isStatic(field.getModifiers())) {
+      if (declaredFields != null) {
+        for (Field field : declaredFields) {
+          if (!Modifier.isStatic(field.getModifiers())) {
             String fieldName = field.getName();
             Class<?> fieldType = field.getType();
 
@@ -306,16 +312,16 @@
               }
             }
 
-            if (autoWireValue!=null) {
+            if (autoWireValue != null) {
               try {
-                if (log.isTraceEnabled()) log.trace("auto wiring field "+fieldName+" in "+name);
+                if (log.isTraceEnabled()) log.trace("auto wiring field " + fieldName + " in " + name);
                 ReflectUtil.set(field, object, autoWireValue);
               } catch (JbpmException e) {
                 if(e.getCause() instanceof IllegalArgumentException) {
-                  log.info("WARNING: couldn't auto wire "+fieldName+" (of type "+fieldType.getName()+") " +
-                      "with value "+autoWireValue + " (of type "+autoWireValue.getClass().getName()+")");
+                  log.info("WARNING: couldn't auto wire " + fieldName + " (of type " + fieldType.getName() + ") "
+                    + "with value " + autoWireValue + " (of type " + autoWireValue.getClass().getName() + ")");
                 } else {
-                  log.info("WARNING: couldn't auto wire "+fieldName+" with value "+autoWireValue);
+                  log.info("WARNING: couldn't auto wire " + fieldName + " with value " + autoWireValue);
                 }
               }
             }
@@ -335,9 +341,9 @@
    */
   public static Object[] getArgs(WireContext wireContext, List<ArgDescriptor> argDescriptors) throws Exception {
     Object[] args = null;
-    if (argDescriptors!=null) {
+    if (argDescriptors != null) {
       args = new Object[argDescriptors.size()];
-      for(int i=0; i<argDescriptors.size(); i++) {
+      for (int i = 0; i < argDescriptors.size(); i++) {
         ArgDescriptor argDescriptor = argDescriptors.get(i);
         Object arg;
         try {
@@ -346,7 +352,7 @@
         } catch (RuntimeException e) {
           // i have made sure that the runtime exception is caught everywhere the getArgs method
           // is used so that a better descriptive exception can be rethrown
-          throw new Exception("couldn't create argument "+i+": "+e.getMessage(), e);
+          throw new Exception("couldn't create argument " + i + ": " + e.getMessage(), e);
         }
       }
     }
@@ -369,7 +375,7 @@
    * @param operation operation to add.
    */
   public void addOperation(Operation operation) {
-    if (operations==null) {
+    if (operations == null) {
       operations = new ArrayList<Operation>();
     }
     operations.add(operation);

Added: jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java	                        (rev 0)
+++ jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ExpressionTest.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -0,0 +1,144 @@
+
+package org.jbpm.pvm.internal.el;
+
+import java.util.*;
+import junit.framework.*;
+import org.jbpm.pvm.internal.model.*;
+import org.jbpm.pvm.internal.env.*;
+import org.jbpm.pvm.internal.processengine.*;
+
+public class ExpressionTest extends TestCase {
+    public void testPrimivite() {
+        Expression expr = Expression.create("#{1}");
+        assertEquals(Long.valueOf(1L), expr.evaluate());
+    }
+
+    public void testSimpleVariable() {
+        Expression expr = Expression.create("#{variableName}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("variableName", "variableValue");
+        assertEquals("variableValue", expr.evaluate(executionImpl));
+    }
+
+    public void testMap() {
+        Map map = new HashMap();
+        map.put("key", "value");
+
+        Expression expr = Expression.create("#{map.key}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("map", map);
+        assertEquals("value", expr.evaluate(executionImpl));
+    }
+
+    public void testList() {
+        List list = new ArrayList();
+        list.add("value");
+
+        Expression expr = Expression.create("#{list[0]}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("list", list);
+        assertEquals("value", expr.evaluate(executionImpl));
+    }
+
+    public void testArray() {
+        String[] array = new String[]{"value"};
+
+        Expression expr = Expression.create("#{array[0]}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("array", array);
+        assertEquals("value", expr.evaluate(executionImpl));
+    }
+
+    public void testBean() {
+        Bean bean = new Bean();
+        bean.setName("Lingo");
+
+        Expression expr = Expression.create("#{bean.name}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("bean", bean);
+        assertEquals("Lingo", expr.evaluate(executionImpl));
+    }
+
+    public void testMethod() {
+        Bean bean = new Bean();
+
+        Expression expr = Expression.create("#{bean.hello('Lingo')}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("bean", bean);
+        assertEquals("Hello Lingo", expr.evaluate(executionImpl));
+    }
+
+    public void testFunction() {
+        List list = new ArrayList();
+        list.add("1");
+        list.add("2");
+
+        Expression expr = Expression.create("#{length(list)}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        executionImpl.setVariable("list", list);
+        assertEquals(2, expr.evaluate(executionImpl));
+    }
+
+    public void testCustomFunction() {
+      EnvironmentFactory environmentFactory = ProcessEngineImpl.parseXmlString(
+        "<jbpm-configuration>" +
+        "  <process-engine-context>" +
+        "    <object class='org.jbpm.pvm.internal.el.JbpmElFactoryImpl'>" +
+        "      <field name='functionClassMap'>" +
+        "        <map>" +
+        "          <entry>" +
+        "            <key>" +
+        "              <string value=''/>" +
+        "            </key>" +
+        "            <value>" +
+        "              <class class-name='org.jbpm.pvm.internal.el.JstlFunction'/>" +
+        "            </value>" +
+        "          </entry>" +
+        "          <entry>" +
+        "            <key>" +
+        "              <string value='myPrefix'/>" +
+        "            </key>" +
+        "            <value>" +
+        "              <class class-name='" + CustomFunction.class.getName() + "'/>" +
+        "            </value>" +
+        "          </entry>" +
+        "        </map>" +
+        "      </field>" +
+        "    </object>" +
+        "  </process-engine-context>" +
+        "</jbpm-configuration>"
+      );
+
+      EnvironmentImpl environment = environmentFactory.openEnvironment();
+      try {
+        Expression.reset();
+        Expression expr = Expression.create("#{myPrefix:doSomething()}");
+        ExecutionImpl executionImpl = new ExecutionImpl();
+        assertEquals("do something", expr.evaluate(executionImpl));
+      } finally {
+        environment.close();
+      }
+    }
+
+    public static class Bean {
+        private String name;
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String hello(String username) {
+            return "Hello " + username;
+        }
+    }
+
+    public static class CustomFunction {
+        public static String doSomething() {
+            return "do something";
+        }
+    }
+}

Modified: jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ResourceBundleELResovlerTest.java
===================================================================
--- jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ResourceBundleELResovlerTest.java	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/pvm/src/test/java/org/jbpm/pvm/internal/el/ResourceBundleELResovlerTest.java	2010-10-05 08:42:00 UTC (rev 6740)
@@ -18,11 +18,11 @@
   }
 
   public static class MyResources extends ListResourceBundle {
-     public Object[][] getContents() {
-       return contents;
-     }
-     static final Object[][] contents = {
-       {"text.title", "Title"}
-     };
-   }
+    public Object[][] getContents() {
+      return contents;
+    }
+    static final Object[][] contents = {
+      {"text.title", "Title"}
+    };
+  }
 }

Modified: jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch08-Scripting.xml
===================================================================
--- jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch08-Scripting.xml	2010-10-05 01:43:06 UTC (rev 6739)
+++ jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch08-Scripting.xml	2010-10-05 08:42:00 UTC (rev 6740)
@@ -1,15 +1,189 @@
 <chapter id="scripting">
   <title>Scripting</title>
-  
-  <para>Only jUEL is configured as the scripting language.  jUEL is 
-  an implementation of the Unified Expression Language.  For detailed description 
-  of how to use UEL, please refer to  
-  <ulink url="http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html">
-  the JEE 5 Tutorial, section Unified Expression Language</ulink>  
-  </para>
-  
-  <para>To configure other scripting languages then jUEL, please 
-  refer to the developer's guide (non supported).
-  </para>
 
+  <section>
+    <title>Script Manager</title>
+
+    <para>
+      Only jUEL is configured as the scripting language.  jUEL is
+      an implementation of the Unified Expression Language.  For detailed description
+      of how to use UEL, please refer to
+      <ulink url="http://java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html">
+      the JEE 5 Tutorial, section Unified Expression Language</ulink>
+    </para>
+
+    <para>
+      To configure other scripting languages then jUEL, please
+      refer to the developer's guide (non supported).
+    </para>
+  </section>
+
+  <section>
+    <title>Expression</title>
+
+    <para>
+      From jBPM-4.4, we used <ulink url="http://juel.sourceforge.net/">jUEL</ulink> to evaluate the expressions.
+      Here is the types of expressions that we supported:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>Constants</para>
+            <programlisting><![CDATA[
+Expression expr = Expression.create("#{1}");
+assertEquals(Long.valueOf(1L), expr.evaluate());]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Simple Variable</para>
+            <programlisting><![CDATA[
+Expression expr = Expression.create("#{variableName}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("variableName", "variableValue");
+assertEquals("variableValue", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Map</para>
+            <programlisting><![CDATA[
+Map map = new HashMap();
+map.put("key", "value");
+
+Expression expr = Expression.create("#{map.key}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("map", map);
+assertEquals("value", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>List</para>
+            <programlisting><![CDATA[
+List list = new ArrayList();
+list.add("value");
+
+Expression expr = Expression.create("#{list[0]}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("list", list);
+assertEquals("value", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Array</para>
+            <programlisting><![CDATA[
+String[] array = new String[]{"value"};
+
+Expression expr = Expression.create("#{array[0]}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("array", array);
+assertEquals("value", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Java Bean</para>
+            <programlisting><![CDATA[
+Bean bean = new Bean();
+bean.setName("Lingo");
+
+Expression expr = Expression.create("#{bean.name}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("bean", bean);
+assertEquals("Lingo", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Invoke Method</para>
+            <programlisting><![CDATA[
+Bean bean = new Bean();
+
+Expression expr = Expression.create("#{bean.hello('Lingo')}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("bean", bean);
+assertEquals("Hello Lingo", expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>BundleResource</para>
+            <programlisting><![CDATA[
+MyResources myResources = new MyResources();
+ExecutionImpl execution = new ExecutionImpl();
+execution.setVariable("resourceBundle", myResources);
+
+Expression expr = Expression.create("#{resourceBundle['text.title']}");
+Object result = expr.evaluate(execution);
+
+assertEquals("Title", result);]]>
+            </programlisting>
+        </listitem>
+        <listitem>
+            <para>Function</para>
+            <programlisting><![CDATA[
+List list = new ArrayList();
+list.add("1");
+list.add("2");
+
+Expression expr = Expression.create("#{length(list)}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+executionImpl.setVariable("list", list);
+assertEquals(2, expr.evaluate(executionImpl));]]>
+            </programlisting>
+        </listitem>
+    </itemizedlist>
+
+     <para>
+       Besides the default function - org.jbpm.pvm.internal.el.JstlFunction, we could provide our own function to EL.
+     </para>
+
+     <para>
+       First, we should modify jbpm.default.cfg.xml, add our custom function class and related prefix, like this:
+     </para>
+
+     <programlisting><![CDATA[
+
+<object class='org.jbpm.pvm.internal.el.JbpmElFactoryImpl'>
+  <field name='functionClassMap'>
+    <map>
+      <entry>
+        <key>
+          <string value=''/>
+        </key>
+        <value>
+          <class class-name='org.jbpm.pvm.internal.el.JstlFunction'/>
+        </value>
+      </entry>
+      <entry>
+        <key>
+          <string value='myPrefix'/>
+        </key>
+        <value>
+          <class class-name='custom.CustomFunction'/>
+        </value>
+      </entry>
+    </map>
+  </field>
+</object>]]>
+     </programlisting>
+
+     <para>
+       Then all of static methods of CustomFunction could be invoked in EL.
+     </para>
+
+     <programlisting><![CDATA[
+public class CustomFunction {
+    public static String doSomething() {
+        return "do something";
+    }
+}]]>
+     </programlisting>
+
+     <para>
+       The expression will use the prefix to get the related method of function class.
+     </para>
+
+     <programlisting><![CDATA[
+Expression expr = Expression.create("#{myPrefix:doSomething()}");
+ExecutionImpl executionImpl = new ExecutionImpl();
+assertEquals("do something", expr.evaluate(executionImpl));]]>
+     </programlisting>
+  </section>
+
 </chapter>



More information about the jbpm-commits mailing list