Attached is a patch which adds Spring-style dependency injection to the configuration of Nodes/Tasks in the Agila XML using a <property> element.

e.g.

<node id="3" type="activity" class="org.apache.agila.example.LeaveApplicationTask" display_name="Leave Application">
<property name="foo" value="hello"/>
<property name="bar">123</property>


<actors>
<actor name="Self"/>
</actors>
<bindings>
<binding name="numdays" type="el" datatype="String" value="numdays" input="true" output="true"/>
<binding name="reason" type="el" datatype="String" value="reason" input="true" output="true"/>
</bindings>
</node>


Currently only primitive type properties are supported.

Later on we could add a 'ref' attribute as an alternative to 'value', like Spring, to allow a full dependency injection container like Spring, Pico, HiveMind or even GBeans to be used to lookup some named object to be set as a property on a task. e.g. if a Task has to do some JDBC / email / JMS operations - we should use a real DI container for configuring those services and just refer to them from inside the Agila XML.

e.g.

<!--- look up some DataSource in the current ResolverService instance which could be Spring / JNDI / JMX etc -->
<property name="dataSource" ref="myCustomerDatabase"/>



But for now, the use of primitive types should be enough.


Index: project.xml
===================================================================
--- project.xml (revision 106904)
+++ project.xml (working copy)
@@ -80,7 +80,26 @@
             </properties>
        </dependency>
 
+      <!-- used to set properties on nodes in the XML -->
       <dependency>
+          <groupId>commons-beanutils</groupId>
+          <artifactId>commons-beanutils</artifactId>
+          <version>1.6.1</version>
+          <properties>
+               <war.bundle>true</war.bundle>
+             </properties>
+      </dependency>
+      <!-- dependency for beanutils -->
+      <dependency>
+          <groupId>commons-collections</groupId>
+          <artifactId>commons-collections</artifactId>
+          <version>2.1</version>
+          <properties>
+               <war.bundle>true</war.bundle>
+             </properties>
+      </dependency>
+
+      <dependency>
            <groupId>velocity</groupId>
            <artifactId>velocity</artifactId>
            <version>dep-1.4-rc1</version>
Index: src/test/org/apache/agila/LeaveApplication.xml
===================================================================
--- src/test/org/apache/agila/LeaveApplication.xml      (revision 106904)
+++ src/test/org/apache/agila/LeaveApplication.xml      (working copy)
@@ -33,6 +33,10 @@
             </node>
 
             <node id="3" type="activity" 
class="org.apache.agila.example.LeaveApplicationTask" display_name="Leave 
Application">
+                <!-- some example task properties to test out the XML 
marshalling -->
+                <property name="foo" value="hello"/>
+                <property name="bar">123</property>
+
                 <actors>
                     <actor name="Self"/>
                 </actors>
Index: src/test/org/apache/agila/util/XMLUtilTestCase.java
===================================================================
--- src/test/org/apache/agila/util/XMLUtilTestCase.java (revision 106904)
+++ src/test/org/apache/agila/util/XMLUtilTestCase.java (working copy)
@@ -20,6 +20,9 @@
 
 import org.apache.agila.model.BusinessProcess;
 import org.apache.agila.model.Variable;
+import org.apache.agila.model.NodeID;
+import org.apache.agila.model.Node;
+import org.apache.agila.example.LeaveApplicationTask;
 
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
@@ -72,6 +75,15 @@
         assertTrue( getRequiredVariables() == 1 );
     }
 
+    public void testPropertiesSet() {
+        Node node = businessProcess.getNode(new NodeID(3));
+        assertTrue("Not found node!", node instanceof LeaveApplicationTask);
+
+        LeaveApplicationTask task = (LeaveApplicationTask) node;
+        assertEquals("foo property", "hello", task.getFoo());
+        assertEquals("bar property", 123, task.getBar());
+    }
+
     private int getRequiredVariables() {
         int retVal = 0;
 
Index: src/java/org/apache/agila/example/LeaveApplicationTask.java
===================================================================
--- src/java/org/apache/agila/example/LeaveApplicationTask.java (revision 
106904)
+++ src/java/org/apache/agila/example/LeaveApplicationTask.java (working copy)
@@ -36,6 +36,26 @@
     protected final static String NUMDAYS = "numdays";
     protected final static String REASON = "reason";
 
+    // mock properties to test XML serialization
+    private String foo;
+    private int bar;
+
+    public int getBar() {
+        return bar;
+    }
+
+    public void setBar(int bar) {
+        this.bar = bar;
+    }
+
+    public String getFoo() {
+        return foo;
+    }
+
+    public void setFoo(String foo) {
+        this.foo = foo;
+    }
+
     /**
      * Start method for the activity.  Sets up a tast for the user
      *
Index: src/java/org/apache/agila/util/XMLUtil.java
===================================================================
--- src/java/org/apache/agila/util/XMLUtil.java (revision 106904)
+++ src/java/org/apache/agila/util/XMLUtil.java (working copy)
@@ -26,6 +26,7 @@
 import org.apache.agila.model.NodeID;
 
 import org.apache.agila.impl.BusinessProcessImpl;
+import org.apache.commons.beanutils.BeanUtils;
 import org.dom4j.io.SAXReader;
 import org.dom4j.Document;
 import org.dom4j.DocumentException;
@@ -37,6 +38,7 @@
 import java.io.Reader;
 import java.util.List;
 import java.util.Iterator;
+import java.lang.reflect.InvocationTargetException;
 
 /**
  *  Utility class for converting workflow XML to objects
@@ -164,6 +166,8 @@
          */
         String classname = node.attribute("class").getValue();
 
+
+        // TODO may wish to also use the Thread context class loader
         Node n = (Node) Class.forName(classname).newInstance();
 
         n.setNodeId(new 
NodeID(Integer.parseInt(node.attribute("id").getValue())));
@@ -175,12 +179,33 @@
         n.setDisplayName(node.attribute("display_name").getValue());
 
         /*
-         *  get and actors
+         *  set node properties
          */
 
+        List properties = node.selectNodes("property");
+
+        Iterator it = properties.iterator();
+
+        while(it.hasNext()) {
+
+            Element property = (Element) it.next();
+
+            String name = property.attributeValue("name");
+            String value = property.attributeValue("value");
+            if (value == null || value.equals("")) {
+                value = property.getText();
+            }
+
+            setProperty(n, name, value);
+        }
+
+        /*
+         *  get actors
+         */
+
         List actors = node.selectNodes("actors/actor");
 
-        Iterator it = actors.iterator();
+        it = actors.iterator();
 
         while(it.hasNext()) {
 
@@ -221,6 +246,18 @@
 
     }
 
+    /**
+     * Sets the JavaBean property on the given node from the given name and 
value
+     */
+    protected static void setProperty(Node node, String name, String value) {
+        try {
+            BeanUtils.setProperty(node, name, value);
+        }
+        catch (Exception e) {
+            throw new RuntimeException("Could not set property: " + name + " 
on node: " + node + " due to: " + e, e);
+        }
+    }
+
     private static String getValueOfAttribute(String name, Element node) {
 
         Attribute a = node.attribute(name);


James
-------
http://radio.weblogs.com/0112098/
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to