[jboss-svn-commits] JBL Code SVN: r10259 - in labs/jbossesb/trunk: product/core/listeners/src/org/jboss/soa/esb/listeners/message and 3 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Mar 16 08:24:29 EDT 2007


Author: kevin.conner at jboss.com
Date: 2007-03-16 08:24:28 -0400 (Fri, 16 Mar 2007)
New Revision: 10259

Added:
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycle.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycleException.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionPipelineProcessor.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessorMethodInfo.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionLifecycleProcessor.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionPipelineProcessor.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionProcessor.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionInfo.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessor.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessorFailure.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessor.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorConstructorFailure.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorFailure.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessor.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessorFailure.java
   labs/jbossesb/trunk/product/core/rosetta/src/org/jboss/soa/esb/util/ClassUtil.java
Modified:
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionProcessor.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipeline.java
   labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/MessageAwareListener.java
   labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipelineUnitTest.java
   labs/jbossesb/trunk/qa/junit/src/org/jboss/soa/esb/actions/SmooksTransformerTest.java
Log:
Added new action processing pipeline code: JBESB-463

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycle.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycle.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycle.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.actions;
+
+/**
+ * Interface representing lifecycle methods of an action. 
+ * <p/>
+ * Actions implementing this interface will participate in the application
+ * lifecycle and should not contain any state specific to a particular message
+ * instance.  Each {@link ActionProcessingPipeline} will instantiate a single
+ * instance of the action to process all messages passing through the pipeline.  
+ *  
+ * @author kevin
+ */
+public interface ActionLifecycle
+{
+    /**
+     * Initialise the action instance.
+     * <p/>
+     * This method is called after the action instance has been instantiated so that
+     * configuration options can be validated.
+     * 
+     * @throws ActionLifecycleException for errors during initialisation.
+     */
+    public void initialise()
+        throws ActionLifecycleException ;
+
+    /**
+     * Destroy the action instance.
+     * <p/>
+     * This method is called prior to the release of the action instance.  All
+     * resources associated with this action instance should be released as the
+     * instance will no longer be used.
+     */
+    public void destroy()
+        throws ActionLifecycleException ;
+}
\ No newline at end of file


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycle.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycleException.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycleException.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycleException.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,69 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.actions;
+
+/**
+ * Exception representing errors in an action lifecycle.
+ * @author kevin
+ */
+public class ActionLifecycleException extends Exception
+{
+    /**
+     * serial version UID of this exception.
+     */
+    private static final long serialVersionUID = 3275504884247607474L;
+
+    /**
+     * Construct a default action lifecycle exception.
+     */
+    public ActionLifecycleException()
+    {
+    }
+
+    /**
+     * Construct an action lifecycle exception with the specified message.
+     * @param message The exception message.
+     */
+    public ActionLifecycleException(final String message) 
+    {
+	super(message);
+    }
+
+    /**
+     * Construct an action lifecycle exception with the associated cause.
+     * @param cause The associated cause.
+     */
+    public ActionLifecycleException(final Throwable cause)
+    {
+	super(cause);
+    }
+
+    /**
+     * Construct an action lifecycle exception with the specified message and associated cause.
+     * @param message The exception message.
+     * @param cause The associated cause.
+     */
+    public ActionLifecycleException(String message, Throwable cause)
+    {
+	super(message, cause);
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionLifecycleException.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionPipelineProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionPipelineProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionPipelineProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,78 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.actions;
+
+import org.jboss.soa.esb.message.Message;
+
+/**
+ * Interface representing processor actions used in a pipeline.
+ * <p/>
+ * A pipeline will instantiate a single instance of the implementing class
+ * for processing every message passing through the pipeline.
+ * 
+ * @author kevin
+ */
+public interface ActionPipelineProcessor extends ActionLifecycle
+{
+    /**
+     * The name of the process method.
+     */
+    public String PROCESS_METHOD = "process" ;
+    /**
+     * The name of the processException method.
+     */
+    public String PROCESS_EXCEPTION_METHOD = "processException" ;
+    /**
+     * The name of the processSuccess method.
+     */
+    public String PROCESS_SUCCESS_METHOD = "processSuccess" ;
+    
+    /**
+     * Perform the action processing on the specified message.
+     * This method is invoked for each message passing throught the pipeline.
+     * 
+     * @param message The current message being processed.
+     * @return The message to be passed to the next stage of the pipeline.
+     * @throws ActionProcessingException for errors during processing.
+     */
+    public Message process(final Message message)
+        throws ActionProcessingException ;
+    
+    /**
+     * Process an exception generated by the pipeline processing.
+     * Invoked when the processing of a subsequent stage of the
+     * pipeline generates an exception.
+     * 
+     * @param message The original message.
+     * @param ex The exception raised by the pipeline processing
+     */
+    public void processException(final Message message, final Exception ex) ;
+    
+    /**
+     * Process a successful pipeline process. 
+     * Invoked when the pipeline processing completes successfully.
+     * 
+     * @param message The original message.
+     */
+    public void processSuccess(final Message message) ;
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionPipelineProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionProcessor.java	2007-03-16 12:01:01 UTC (rev 10258)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/actions/ActionProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -39,6 +39,8 @@
  * </ol>
  * @author <a href="mailto:tom.fennelly at jboss.com">tom.fennelly at jboss.com</a>
  * @since Version 4.0
+ * 
+ * @deprecated This interface has been replaced by {@link ActionPipelineProcessor}
  */
 public interface ActionProcessor {
     

Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipeline.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipeline.java	2007-03-16 12:01:01 UTC (rev 10258)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipeline.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -22,295 +22,267 @@
 
 package org.jboss.soa.esb.listeners.message;
 
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import org.apache.log4j.Logger;
 import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionLifecycle;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
 import org.jboss.soa.esb.helpers.ConfigTree;
 import org.jboss.soa.esb.listeners.ListenerTagNames;
 import org.jboss.soa.esb.message.Message;
+import org.jboss.soa.esb.util.ClassUtil;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.Observable;
 
-
 /**
  * Action Processing Pipeline.
  * <p/>
  * Runs a list of action classes on a message
- *
+ * 
  * @author <a href="mailto:schifest at heuristica.com.ar">schifest at heuristica.com.ar</a>
+ * @author kevin
  * @since Version 4.0
  */
-public class ActionProcessingPipeline extends Observable implements Runnable
+public class ActionProcessingPipeline
 {
-   private boolean processingComplete = false;
-   private ClassLoader classloader;
+    /**
+     * The logger instance.
+     */
+    private final static Logger LOGGER = Logger.getLogger(ActionProcessingPipeline.class) ;
+    
+    /**
+     * The processors.
+     */
+    private final ActionPipelineProcessor[] processors ;
+    /**
+     * The active flag.
+     */
+    private final AtomicBoolean active = new AtomicBoolean(false) ;
 
-   /**
-    * public constructor
-    *
-    * @param message Message - The initial message to be run through the whole action
-    *                class chain
-    */
-   public ActionProcessingPipeline(Message message, ConfigTree config)
-           throws ConfigurationException
-   {
-      if (null == message)
-         throw new IllegalArgumentException("Message must be not null");
-      _message = message;
-      _config = config;
-      if (null == _config)
-         throw new IllegalArgumentException("Configuration needed for action classes");
-      _actionList = _config.getChildren(ListenerTagNames.ACTION_ELEMENT_TAG);
-      if (null == _actionList || _actionList.length < 1)
-         throw new ConfigurationException("No actions in list");
-   }
-
-
-   public ClassLoader getClassloader()
-   {
-      return classloader;
-   }
-
-   /**
-    * context classloader the thread should run in
-    *
-    * @param classloader
-    */
-   public void setClassloader(ClassLoader classloader)
-   {
-      this.classloader = classloader;
-   }
-
-   /**
-    * @return Message - current Message of this action chain processor
-    */
-   public Message getMessage()
-   {
-      return _message;
-   }
-
-   /**
-    * Implement Runnable Interface
-    * <p/>Uses reflection to instantiate action classes that must have a public constructor
-    * that takes a single ConfigTree as argument
-    * <p/>Requires each action class to have a public method that takes a Message and returns a Message
-    * <br/>Default name for it is 'process'  but can optionally be defined in the 'process' attribute
-    * of the corresponding &lt;action&gt; element of the ConfigTree
-    * <p/>Each &lt;action&gt; element can optionally define a method (taking a Message argument) to be
-    * called upon successful completion of the action class (that step of the chain)
-    * <br/>Default name for it is 'process'  but can optionally be defined in the 'process' attribute
-    * <p/>See actionClassException and actionClassFinishedOk
-    */
-   public void run()
-   {
-      ClassLoader old = Thread.currentThread().getContextClassLoader();
-      try
-      {
-         if (classloader != null)
-         {
-            Thread.currentThread().setContextClassLoader(classloader);
-         }
-         // Run the message through each ActionProcessor...
-         _currentIndex = -1;
-         for (ConfigTree oCurr : _actionList)
-         {
-            _currentIndex++;
-            String attrName = ListenerTagNames.ACTION_CLASS_TAG;
-            _currentAction = oCurr.getAttribute(attrName);
-            _currentClass = Thread.currentThread().getContextClassLoader().loadClass(_currentAction);
-            Constructor oConst = _currentClass.getConstructor(new Class[]{ConfigTree.class});
-            _currentProcessor = oConst.newInstance(oCurr);
-
-            attrName = ListenerTagNames.PROCESS_METHOD_TAG;
-            String[] saMethodList = obtainAttribute(oCurr, attrName, attrName).split(",");
-
-            for (String currMethod : saMethodList)
+    /**
+     * public constructor
+     * @param message Message - The initial message to be run through the whole action 
+     * class chain
+     */
+    public ActionProcessingPipeline(final ConfigTree config)
+    	throws ConfigurationException
+    {
+    	if (config == null)
+        {
+    	    throw new IllegalArgumentException("Configuration needed for action classes") ;
+        }
+        
+    	final ConfigTree[] actionList = config.getChildren(ListenerTagNames.ACTION_ELEMENT_TAG) ;
+        
+    	if ((actionList == null) || (actionList.length == 0))
+        {
+            throw new ConfigurationException("No actions in list") ;
+        }
+        
+        final ArrayList<ActionPipelineProcessor> processorList = new ArrayList<ActionPipelineProcessor>() ;
+        
+        for(final ConfigTree actionConfig: actionList)
+        {
+            final String actionClassTag = actionConfig.getAttribute(ListenerTagNames.ACTION_CLASS_TAG) ;
+            if (LOGGER.isDebugEnabled())
             {
-//                	_logger.debug("Attempting to invoke "+_currentClass.getName()+" method "+currMethod);
-               Method method = _currentClass.getMethod(currMethod, new Class[]{Message.class});
-
-               // The processing result of each action feeds into the processing of the next action...
-               try
-               {
-                  Message next = (Message) method.invoke(_currentProcessor, new Object[]{_message});
-                  if (next == null)
-                  {
-                     _logger.debug(prematureTermination("returned <null> - Cannot continue"));
-                     return;
-                  }
-                  _message = next;
-               }
-               catch (ClassCastException eCast)
-               {
-                  // If action class returns non Message, log and abort chain
-                  _logger.error(prematureTermination("returned a non Message Object)"));
-                  return;
-               }
-               catch (InvocationTargetException e)
-               {
-                  // If action class threw exception, log and abort chain
-                  _logger.error("Process method threw Exception", e);
-                  actionClassException(oCurr, _message, e.getCause());
-                  return;
-               }
+                LOGGER.debug("Registering action class " + actionClassTag) ;
             }
-            actionClassFinishedOk(oCurr, _message);
-         }
-         // notification of action chain end can be done with a no-operation action class
-         // with a proper ListenerPropertyNames.ACTION_NORMAL_COMPLETION_CALLBACK method
-         // Same idea when some interaction needed with the 'esb unaware' world
-      }
-      catch (ClassNotFoundException e)
-      {
-         _logger.error(prematureTermination("action class is not in path"), e);
-      }
-      catch (NoSuchMethodException e)
-      {
-         _logger.error(prematureTermination("method not found"), e);
-      }
-      catch (InstantiationException e)
-      {
-         _logger.error(prematureTermination("cannot instantiate action class"), e);
-      }
-      catch (InvocationTargetException e)
-      {
-         _logger.error(prematureTermination("method not found"), e);
-      }
-      catch (IllegalAccessException e)
-      {
-         _logger.error(prematureTermination("unable to access method"), e);
-      }
-      catch (IllegalArgumentException e)
-      {
-         _logger.error(prematureTermination(e.getMessage()), e);
-      }
-      finally
-      {
-         Thread.currentThread().setContextClassLoader(old);
-         processingComplete = true;
-         setChanged();
-         notifyObservers(new Integer(-1));
-      }
-   }
-
-   protected String prematureTermination(String s)
-   {
-      return new StringBuilder("Premature termination of action processing pipeline ")
-              .append(getActionNames())
-              .append("].  ActionProcessor [").append(_currentAction)
-              .append("] ").append(s)
-              .toString()
-              ;
-   }
-
-   /**
-    * If 'current' action step was configured with a 'exceptionMethod' attribute
-    * that method will be called with a single argument of type Exception
-    *
-    * @param tree   ConfigTree - where to look for the exceptionMetod attribute
-    * @param thrown Exception - to be used in invocation to method (if found)
-    */
-   protected void actionClassException(ConfigTree tree, Message msg, Throwable thrown)
-   {
-      String sMethod = obtainAttribute(tree, ListenerTagNames.EXCEPTION_METHOD_TAG, null);
-      if (null != sMethod)
-         try
-         {
-            Method method = _currentClass.getMethod(sMethod, new Class[]{Message.class, Throwable.class});
-            method.invoke(_currentProcessor, new Object[]{msg, thrown});
-         }
-         catch (NoSuchMethodException e)
-         {
-            _logger.error(e);
-         }
-         catch (InvocationTargetException e)
-         {
-            _logger.error(e);
-         }
-         catch (IllegalAccessException e)
-         {
-            _logger.error(e);
-         }
-   }
-
-   /**
-    * If 'current' action step was configured with an 'okMethod' attribute
-    * that method will be called with no arguments
-    *
-    * @param tree ConfigTree - where to look for the okMetod attribute
-    */
-   protected void actionClassFinishedOk(ConfigTree tree, Message msg)
-   {
-      String sMethod = obtainAttribute(tree, ListenerTagNames.NORMAL_COMPLETION_METHOD_TAG, null);
-      if (null != sMethod)
-         try
-         {
-            Method method = _currentClass.getMethod(sMethod, new Class[]{Message.class});
-            method.invoke(_currentProcessor, new Object[]{msg});
-         }
-         catch (NoSuchMethodException e)
-         {
-            _logger.error(e);
-         }
-         catch (InvocationTargetException e)
-         {
-            _logger.error(e);
-         }
-         catch (IllegalAccessException e)
-         {
-            _logger.error(e);
-         }
-   }
-
-   protected String[] getActionNames()
-   {
-      String[] sa = new String[_actionList.length];
-      int i1 = 0;
-      for (ConfigTree oCurr : _actionList)
-         sa[i1++] = obtainAttribute(oCurr, ListenerTagNames.ACTION_CLASS_TAG, "NO_CLASSNAME");
-      return sa;
-   }
-
-   private static String obtainAttribute(ConfigTree tree, String p_sAtt, String p_sDefault)
-   {
-      String sVal = tree.getAttribute(p_sAtt);
-      return (null != sVal) ? sVal : p_sDefault;
-   } // ________________________________
-
-   protected ConfigTree[] _actionList;
-   protected int _currentIndex;
-   protected String _currentAction;
-   protected Class _currentClass;
-   protected Object _currentProcessor;
-   protected Message _message;
-   protected ConfigTree _config;
-   protected Logger _logger = Logger.getLogger(this.getClass());
-
-   /**
-    * @return Returns the processingComplete.
-    */
-   public boolean isProcessingComplete()
-   {
-      return processingComplete;
-   }
-
-   /**
-    * Wait until processing is complete.
-    */
-   public void waitUntilComplete()
-   {
-      while (!processingComplete)
-      {
-         try
-         {
-            Thread.sleep(50);  // TODO magic number
-         }
-         catch (InterruptedException e)
-         {
-            _logger.error("Thread Interrupted.", e);
-         }
-      }
-   }
+            final Class actionClass ;
+            try
+            {
+                actionClass = ClassUtil.forName(actionClassTag, getClass()) ;
+            }
+            catch (final ClassNotFoundException cnfe)
+            {
+                throw new ConfigurationException("Could not load action class " + actionClassTag) ;
+            }
+            
+            final ActionPipelineProcessor processor ;
+            if (ActionPipelineProcessor.class.isAssignableFrom(actionClass))
+            {
+                final ActionPipelineProcessor currentProcessor = (ActionPipelineProcessor)ActionProcessorMethodInfo.getActionClassInstance(actionConfig, actionClass) ;
+                if (ActionProcessorMethodInfo.checkOverridden(actionConfig))
+                {
+                    if (LOGGER.isDebugEnabled())
+                    {
+                        LOGGER.debug("Using overridden action pipeline processor for " + actionClassTag) ;
+                    }
+                    processor = new OverriddenActionPipelineProcessor(actionConfig, currentProcessor) ;
+                }
+                else
+                {
+                    if (LOGGER.isDebugEnabled())
+                    {
+                        LOGGER.debug("Using normal action pipeline processor for " + actionClassTag) ;
+                    }
+                    processor = currentProcessor ;
+                }
+            }
+            else if (ActionLifecycle.class.isAssignableFrom(actionClass))
+            {
+                if (LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("Using overridden action lifecycle processor for " + actionClassTag) ;
+                }
+                final ActionLifecycle currentLifecycle = (ActionLifecycle)ActionProcessorMethodInfo.getActionClassInstance(actionConfig, actionClass) ;
+                processor = new OverriddenActionLifecycleProcessor(actionConfig, currentLifecycle) ;
+            }
+            else
+            {
+                LOGGER.warn("Action class " + actionClassTag + " does not implement the ActionLifecycle interface") ;
+                if (LOGGER.isDebugEnabled())
+                {
+                    LOGGER.debug("Using overridden actions processor for " + actionClassTag) ;
+                }
+                processor = new OverriddenActionProcessor(actionConfig, actionClass) ;
+            }
+            processorList.add(processor) ;
+        }
+        processors = processorList.toArray(new ActionPipelineProcessor[processorList.size()]) ;
+    }
+    
+    /**
+     * Handle the initialisation of the pipeline
+     * @throws ConfigurationException For errors during initialisation.
+     */
+    public void initialise()
+        throws ConfigurationException
+    {
+        final int numLifecycles = processors.length ;
+        for(int count = 0 ; count < numLifecycles ; count++)
+        {
+            final ActionLifecycle lifecycle = processors[count] ;
+            try
+            {
+                lifecycle.initialise() ;
+            }
+            catch (final Exception ex)
+            {
+                handleDestroy(count-1) ;
+                throw new ConfigurationException("Unexpected exception during lifecycle initialisation", ex) ;
+            }
+        }
+        active.set(true) ;
+    }
+    
+    /**
+     * Handle the destruction of the pipeline
+     */
+    public void destroy()
+    {
+        active.set(false) ;
+        handleDestroy(processors.length-1) ;
+    }
+    
+    /**
+     * Process the specified message.
+     * @param message The current message.
+     * @return true if the processing was successful, false otherwise.
+     */
+    public boolean process(final Message message)
+    {
+        if (active.get())
+        {
+            LOGGER.debug("pipeline process for message") ;
+            
+            final int numProcessors = processors.length ;
+            final Message[] messages = new Message[numProcessors] ;
+            
+            Message currentMessage = message ;
+            
+            for(int count = 0 ; count < numProcessors ; count++)
+            {
+                final ActionPipelineProcessor processor = processors[count] ;
+                messages[count] = currentMessage ;
+                try
+                {
+                    LOGGER.debug("executing processor " + count) ;
+                    currentMessage = processor.process(currentMessage) ;
+                    if (currentMessage == null)
+                    {
+                        throw new ActionProcessingException("Null message returned from action processor") ;
+                    }
+                }
+                catch (final Exception ex)
+                {
+                    LOGGER.warn("Unexpected exception caught while processing the action pipeline", ex) ;
+                    notifyException(count, ex, messages) ;
+                    return false ;
+                }
+            }
+            
+            notifySuccess(messages) ;
+            return true ;
+        }
+        else
+        {
+            LOGGER.debug("pipeline process disabled for message") ;
+            return false ;
+        }
+    }
+    
+    /**
+     * Handle the destruction of the pipeline from the specified position.
+     * @param initialPosition The initial position to begin destruction. 
+     */
+    private void handleDestroy(final int initialPosition)
+    {
+        for(int count = initialPosition ; count >=0 ; count--)
+        {
+            final ActionLifecycle lifecycle = processors[count] ;
+            try
+            {
+                lifecycle.destroy() ;
+            }
+            catch (final Exception ex)
+            {
+                LOGGER.warn("Unexpected exception during lifecycle destruction", ex) ;
+            }
+        }
+    }
+    
+    /**
+     * Notify the processors of an error during processing.
+     * @param initialPosition The position of the first processor to notify.
+     * @param ex The exception which caused the failure.
+     * @param messages The messages associated with successful processors.
+     */
+    private void notifyException(final int initialPosition, final Exception ex, final Message[] messages)
+    {
+        for (int count = initialPosition ; count >=0 ; count--)
+        {
+            final ActionPipelineProcessor processor = processors[count] ;
+            try
+            {
+                processor.processException(messages[count], ex) ;
+            }
+            catch (final Exception ex2)
+            {
+                LOGGER.warn("Unexpected exception notifying processor of pipeline failure", ex2) ;
+            }
+        }
+    }
+    
+    /**
+     * Notify the processors of a successful pipeline process.
+     * @param messages The messages associated with the processors.
+     */
+    private void notifySuccess(final Message[] messages)
+    {
+        for (int count = messages.length - 1 ; count >=0 ; count--)
+        {
+            final ActionPipelineProcessor processor = processors[count] ;
+            try
+            {
+                processor.processSuccess(messages[count]) ;
+            }
+            catch (final Exception ex)
+            {
+                LOGGER.warn("Unexpected exception notifying processor of pipeline success", ex) ;
+            }
+        }
+    }
 }

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessorMethodInfo.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessorMethodInfo.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessorMethodInfo.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,345 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.listeners.message;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.log4j.Logger;
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.listeners.ListenerTagNames;
+import org.jboss.soa.esb.message.Message;
+
+/**
+ * Class providing information for dynamic manipulation of the action processors. 
+ * @author kevin
+ */
+class ActionProcessorMethodInfo
+{
+    /**
+     * The logger for this class.
+     */
+    private static final Logger LOGGER = Logger.getLogger(ActionProcessorMethodInfo.class) ;
+    
+    /**
+     * The process methods.
+     */
+    private final Method[] processMethods;
+    /**
+     * The process success method.
+     */
+    private final Method processSuccess;
+    /**
+     * The process exception method.
+     */
+    private final Method processException ;
+    
+    /**
+     * Construct the action processor method info.
+     * @param processMethods The process methods or null if not configured.
+     * @param processSuccess The process success method or null if not configured.
+     * @param processException The process exception method or null if not configured.
+     */
+    private ActionProcessorMethodInfo(final Method[] processMethods, final Method processSuccess,
+        final Method processException)
+    {
+        this.processMethods = processMethods ;
+        this.processSuccess = processSuccess ;
+        this.processException = processException ;
+    }
+
+    /**
+     * Do we have process method overrides?
+     * @return true if there are overrides, false otherwise.
+     */
+    boolean hasProcessMethods()
+    {
+        return (processMethods != null) ;
+    }
+    
+    /**
+     * Process the methods.
+     * @param instance The action processor instance.
+     * @param message The initial message.
+     * @return The last message.
+     * @throws ActionProcessingException for errors during processing.
+     */
+    Message processMethods(final Object instance, final Message message)
+        throws ActionProcessingException
+    {
+        Message currentMessage = message ;
+        if (hasProcessMethods())
+        {
+            final int numProcessMethods = processMethods.length ;
+            for(int count = 0 ; count < numProcessMethods ; count++)
+            {
+                final Method processMethod = processMethods[count] ;
+                try
+                {
+                    final Object response = processMethod.invoke(instance, currentMessage) ;
+                    if (response instanceof Message)
+                    {
+                        currentMessage = (Message)response ;
+                    }
+                    else
+                    {
+                        throw new ActionProcessingException("Unexpected response type from processor: " + response) ;
+                    }
+                }
+                catch (final IllegalAccessException iae)
+                {
+                    throw new ActionProcessingException("Illegal access from processor", iae) ;
+                }
+                catch (final InvocationTargetException ite)
+                {
+                    final Throwable th = ite.getTargetException() ;
+                    if (th instanceof ActionProcessingException)
+                    {
+                        throw (ActionProcessingException)th ;
+                    }
+                    throw new ActionProcessingException("Unexpected invocation target exception from processor", th) ;
+                }
+            }
+        }
+        return currentMessage ;
+    }
+
+    /**
+     * Do we have a process success override?
+     * @return true if there is an override, false otherwise.
+     */
+    boolean hasProcessSuccess()
+    {
+        return (processSuccess != null) ;
+    }
+    
+    /**
+     * Process the success method.
+     * @param instance The action processor instance.
+     * @param message The initial message.
+     */
+    void processSuccess(final Object instance, final Message message)
+    {
+        if (hasProcessSuccess())
+        {
+            try
+            {
+                processSuccess.invoke(instance, message) ;
+            }
+            catch (final IllegalAccessException iae)
+            {
+                LOGGER.warn("Illegal access from processor", iae) ;
+            }
+            catch (final InvocationTargetException ite)
+            {
+                final Throwable th = ite.getTargetException() ;
+                LOGGER.warn("Unexpected invocation target exception from processor", th) ;
+            }
+        }
+    }
+
+
+    /**
+     * Do we have a process exception override?
+     * @return true if there is an override, false otherwise.
+     */
+    boolean hasProcessException()
+    {
+        return (processException != null) ;
+    }
+    
+    /**
+     * Process the exception method.
+     * @param instance The action processor instance.
+     * @param message The initial message.
+     * @param ex The exception.
+     */
+    void processException(final Object instance, final Message message, final Exception ex)
+    {
+        if (hasProcessException())
+        {
+            try
+            {
+                processException.invoke(instance, message, ex) ;
+            }
+            catch (final IllegalAccessException iae)
+            {
+                LOGGER.warn("Illegal access from processor", iae) ;
+            }
+            catch (final InvocationTargetException ite)
+            {
+                final Throwable th = ite.getTargetException() ;
+                LOGGER.warn("Unexpected invocation target exception from processor", th) ;
+            }
+        }
+    }
+
+    /**
+     * Check to see if any of the default configurations have been overridden.
+     * @param actionConfig The action config.
+     * @return true if there is an override, false otherwise.
+     */
+    static boolean checkOverridden(final ConfigTree actionConfig)
+    {
+        final String processMethod = actionConfig.getAttribute(ListenerTagNames.PROCESS_METHOD_TAG) ;
+        if (processMethod == null || ActionPipelineProcessor.PROCESS_METHOD.equals(processMethod))
+        {
+            final String successMethod = actionConfig.getAttribute(ListenerTagNames.NORMAL_COMPLETION_METHOD_TAG) ;
+            if (successMethod == null || ActionPipelineProcessor.PROCESS_SUCCESS_METHOD.equals(successMethod))
+            {
+                final String exceptionMethod = actionConfig.getAttribute(ListenerTagNames.EXCEPTION_METHOD_TAG) ;
+                return ((exceptionMethod != null) && !ActionPipelineProcessor.PROCESS_EXCEPTION_METHOD.equals(exceptionMethod)) ;
+            }
+        }
+        return true ;
+    }
+
+    /**
+     * Get the method info for method overrides.
+     * @param actionConfig The action config.
+     * @param actionClass The action class.
+     * @return The action processor method info.
+     * @throws ConfigurationException for configuration errors
+     */
+    static ActionProcessorMethodInfo getMethodInfo(final ConfigTree actionConfig, final Class actionClass)
+        throws ConfigurationException
+    {
+        try
+        {
+            final String processMethodName = actionConfig.getAttribute(ListenerTagNames.PROCESS_METHOD_TAG, ActionPipelineProcessor.PROCESS_METHOD) ;
+            final Method[] processMethods = getMethods(actionClass, processMethodName, Message.class);
+            
+            final String processSuccessName = actionConfig.getAttribute(ListenerTagNames.NORMAL_COMPLETION_METHOD_TAG) ;
+            final Method processSuccess = getMethod(actionClass, processSuccessName, Message.class);
+            
+            final String processExceptionName = actionConfig.getAttribute(ListenerTagNames.EXCEPTION_METHOD_TAG) ;
+            final Method processException = getMethod(actionClass, processExceptionName, Message.class, Exception.class) ;
+            
+            return new ActionProcessorMethodInfo(processMethods, processSuccess, processException) ;
+        }
+        catch (final NoSuchMethodException nsme)
+        {
+            throw new ConfigurationException("Invalid processor method in configuration", nsme) ;
+        }
+    }
+    
+    /**
+     * Get the methods specified by the list.
+     * @param actionClass The action class
+     * @param methodNameList The list of method names
+     * @param classes The method signature classes.
+     * @return The methods.
+     * @throws NoSuchMethodException If a method cannot be located.
+     */
+    private static Method[] getMethods(final Class actionClass, final String methodNameList, Class ...classes)
+        throws NoSuchMethodException
+    {
+        final String[] methodNames = methodNameList.split(",") ;
+        final int numMethodNames = (methodNames == null ? 0 : methodNames.length) ;
+        
+        final Method[] methods = new Method[numMethodNames] ;
+        
+        for(int count = 0 ; count < numMethodNames ; count++)
+        {
+            final String methodName = methodNames[count].trim() ;
+            methods[count] = getMethod(actionClass, methodName, classes) ;
+        }
+        return methods ;
+    }
+    
+    /**
+     * Get the specified method.
+     * @param actionClass The action class
+     * @param methodName The method name
+     * @param classes The method signature classes.
+     * @return The method.
+     * @throws NoSuchMethodException If the method cannot be located.
+     */
+    private static Method getMethod(final Class actionClass, final String methodName, Class ...classes)
+        throws NoSuchMethodException
+    {
+        if (methodName != null)
+        {
+            return actionClass.getMethod(methodName, classes) ;
+        }
+        else
+        {
+            return null ;
+        }
+    }
+
+    /**
+     * Get an constructor for the action class.
+     * @param actionClass The action class.
+     * @return The constructor of the action class.
+     * @throws ConfigurationException For errors during instantiation.
+     */
+    static Constructor getActionClassConstructor(final Class actionClass)
+        throws ConfigurationException
+    {
+        try
+        {
+            return actionClass.getConstructor(new Class[] {ConfigTree.class}) ;
+        }
+        catch (final NoSuchMethodException nsme)
+        {
+            throw new ConfigurationException("Action " + actionClass.getName() + " does not have correct constructor") ;
+        }
+    }
+
+    /**
+     * Get an instance of the action class.
+     * @param actionConfig The action class configuration.
+     * @param actionClass The action class.
+     * @return The instance of the action class.
+     * @throws ConfigurationException For errors during instantiation.
+     */
+    static Object getActionClassInstance(final ConfigTree actionConfig, final Class actionClass)
+        throws ConfigurationException
+    {
+        return getActionClassInstance(actionConfig, getActionClassConstructor(actionClass)) ;
+    }
+
+    /**
+     * Get an instance of the action class.
+     * @param actionConfig The action class configuration.
+     * @param actionConstructor The action class constructor.
+     * @return The instance of the action class.
+     * @throws ConfigurationException For errors during instantiation.
+     */
+    static Object getActionClassInstance(final ConfigTree actionConfig, final Constructor actionConstructor)
+        throws ConfigurationException
+    {
+        try
+        {
+            return actionConstructor.newInstance(actionConfig) ;
+        }
+        catch (final Exception ex)
+        {
+            throw new ConfigurationException("Unexpected exception while instantiating action instance", ex) ;
+        }
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/ActionProcessorMethodInfo.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Modified: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/MessageAwareListener.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/MessageAwareListener.java	2007-03-16 12:01:01 UTC (rev 10258)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/MessageAwareListener.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -22,6 +22,11 @@
 
 package org.jboss.soa.esb.listeners.message;
 
+import java.lang.reflect.Method;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.log4j.Logger;
 import org.jboss.internal.soa.esb.couriers.PickUpOnlyCourier;
 import org.jboss.soa.esb.ConfigurationException;
@@ -43,333 +48,338 @@
 import org.jboss.soa.esb.services.registry.RegistryException;
 import org.jboss.soa.esb.util.Util;
 
-import java.lang.reflect.Method;
-import java.util.Observable;
-import java.util.Observer;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
 /**
  * Esb Message aware transport independent listener. <p/> Relies on the
  * CourierFactory to obtain an appropriate Courier for the EPR this listener
  * will be listening on <br/>Keeps a thread pool to instantiate
  * ActionProcessingPipelines whenever a Message is received
- *
+ * 
  * @author <a
  *         href="mailto:schifest at heuristica.com.ar">schifest at heuristica.com.ar</a>
  * @since Version 4.0
  */
 
-public class MessageAwareListener extends AbstractThreadedManagedLifecycle implements Observer
+public class MessageAwareListener  extends AbstractThreadedManagedLifecycle
 {
-   /**
-    * serial version uid for this class
-    */
-   private static final long serialVersionUID = -9198018611828254359L;
+        /**
+         * serial version uid for this class
+         */
+        private static final long serialVersionUID = -9198018611828254359L;
+        /**
+         * The action pipeline.
+         */
+        private ActionProcessingPipeline pipeline ;
+    
+        /**
+	 * public constructor
+	 * 
+	 * @param config
+	 *            ConfigTree - Containing 'static' configuration for this
+	 *            instance
+	 * @throws ConfigurationException
+	 */
+	public MessageAwareListener(final ConfigTree config)
+			throws ConfigurationException
+	{
+            super(config);
+            _config = config ;
+            checkMyParms() ;
+	}
 
-   /**
-    * public constructor
-    *
-    * @param config ConfigTree - Containing 'static' configuration for this
-    *               instance
-    * @throws ConfigurationException
-    */
-   public MessageAwareListener(final ConfigTree config)
-           throws ConfigurationException
-   {
-      super(config);
-      _config = config;
-      checkMyParms();
-   }
+	/**
+	 * Check for mandatory and optional attributes in parameter tree
+	 * 
+	 * @throws ConfigurationException -
+	 *             if mandatory atts are not right or actionClass not in
+	 *             classpath
+	 */
+	protected void checkMyParms () throws ConfigurationException
+	{
+                _eprCategoryName = _config.getAttribute(ListenerTagNames.SERVICE_CATEGORY_NAME_TAG);
+                _eprName = _config.getAttribute(ListenerTagNames.SERVICE_NAME_TAG);
 
-   /**
-    * Check for mandatory and optional attributes in parameter tree
-    *
-    * @throws ConfigurationException -
-    *                                if mandatory atts are not right or actionClass not in
-    *                                classpath
-    */
-   protected void checkMyParms() throws ConfigurationException
-   {
-      _eprCategoryName = _config.getAttribute(ListenerTagNames.SERVICE_CATEGORY_NAME_TAG);
-      _eprName = _config.getAttribute(ListenerTagNames.SERVICE_NAME_TAG);
+                final String maxThreadVal = _config.getAttribute(ListenerTagNames.MAX_THREADS_TAG) ;
+                
+                if (!Util.isNullString(maxThreadVal))
+                {
+                    try
+                    {
+                        _maxThreads = Integer.parseInt(maxThreadVal) ;
+                    }
+                    catch (NumberFormatException nfe)
+                    {
+                        _maxThreads = _defaultMaxThreads ;
+                        _logger.warn("Invalid " + ListenerTagNames.MAX_THREADS_TAG + " attribute, defaulting to <" + _maxThreads + ">") ;
+                    }
+                }
 
-      final String maxThreadVal = _config.getAttribute(ListenerTagNames.MAX_THREADS_TAG);
+		if (Util.isNullString(_eprCategoryName))
+			throw new ConfigurationException(
+					"Missing or invalid " + ListenerTagNames.SERVICE_CATEGORY_NAME_TAG);
+		if (Util.isNullString(_eprName))
+			throw new ConfigurationException(
+					"Missing or invalid " + ListenerTagNames.SERVICE_NAME_TAG);
 
-      if (!Util.isNullString(maxThreadVal))
-      {
-         try
-         {
-            _maxThreads = Integer.parseInt(maxThreadVal);
-         }
-         catch (NumberFormatException nfe)
-         {
-            _maxThreads = _defaultMaxThreads;
-            _logger.warn("Invalid " + ListenerTagNames.MAX_THREADS_TAG + " attribute, defaulting to <" + _maxThreads + ">");
-         }
-      }
-
-      if (Util.isNullString(_eprCategoryName))
-         throw new ConfigurationException(
-                 "Missing or invalid " + ListenerTagNames.SERVICE_CATEGORY_NAME_TAG);
-      if (Util.isNullString(_eprName))
-         throw new ConfigurationException(
-                 "Missing or invalid " + ListenerTagNames.SERVICE_NAME_TAG);
-
-      ConfigTree eprElement = _config.getFirstChild(ListenerTagNames.EPR_TAG);
-      if (null == eprElement)
-         throw new ConfigurationException(
-                 "Missing or invalid " + ListenerTagNames.EPR_TAG + " element");
-      _epr = ListenerUtil.assembleEpr(eprElement);
-
-      String latency = _config.getAttribute(ListenerTagNames.POLL_LATENCY_SECS_TAG);
-      long lSeconds = 10;
-      if (null != latency)
-      {
-         try
-         {
-            lSeconds = Integer.parseInt(latency);
-         }
-         catch (NumberFormatException e)
-         {
-            _logger.warn("Invalid number format <" + latency + "> using default value (" + lSeconds + ")");
-         }
-      }
-      _latencySecs = lSeconds;
-   }
-
-   /**
-    * Handle the initialisation of the managed instance.
-    *
-    * @throws ManagedLifecycleException for errors while initialisation.
-    */
-   protected void doInitialise()
-           throws ManagedLifecycleException
-   {
-      final TwoWayCourier pickUpCourier;
-      try
-      {
-         pickUpCourier = CourierFactory.getPickupCourier(_epr);
-         try
-         {
-            final Method setPollLatency = pickUpCourier.getClass().getMethod(
-                    "setPollLatency", new Class[]{Long.class});
-            setPollLatency.invoke(pickUpCourier, new Long(1000 * _latencySecs));
-         }
-         catch (final NoSuchMethodException nsme)
-         {
-            // OK, just leave it null
-         }
-         catch (final Exception ex)
-         {
-            CourierUtil.cleanCourier(pickUpCourier);
-            throw new ManagedLifecycleException("Problems invoking setPollLatency(long)", ex);
-         }
-      }
-      catch (final MalformedEPRException mepre)
-      {
-         throw new ManagedLifecycleException("Malformed EPR: " + _epr);
-      }
-      catch (final CourierException ce)
-      {
-         throw new ManagedLifecycleException("No appropriate courier can be obtained for " + _epr, ce);
-      }
-
-      _pickUpCourier = pickUpCourier;
-
-      try
-      {
-         RegistryUtil.register(_config, _epr);
-      }
-      catch (final RegistryException re)
-      {
-         CourierUtil.cleanCourier(_pickUpCourier);
-         throw new ManagedLifecycleException("Unexpected error during registration for epr " + _epr, re);
-      }
-   }
-
-   /**
-    * Handle the start of the managed instance.
-    *
-    * @throws ManagedLifecycleException for errors while starting.
-    */
-   protected void doStart()
-           throws ManagedLifecycleException
-   {
-      checkExecutorTermination();
-
-      _execService = Executors.newFixedThreadPool(_maxThreads);
-
-      super.doStart();
-   }
-
-   /**
-    * Execute on the thread.
-    */
-   protected void doRun()
-   {
-      if (_logger.isDebugEnabled())
-      {
-         _logger.debug("doRun() method of " + this.getClass().getSimpleName()
-                 + " started on thread " + Thread.currentThread().getName());
-      }
-
-      while (isRunning())
-      {
-         // Only pickup a message when a thread is available
-         if (getActiveThreadCount() >= _maxThreads)
-         {
-            waitForRunningStateChange(ManagedLifecycleThreadState.STOPPING, _pauseLapseInMillis);
-         }
-         else
-         {
-            waitForEventAndProcess(100);
-         }
-      }
-      if (null != _execService)
-         _execService.shutdown();
-
-      if (_logger.isDebugEnabled())
-      {
-         _logger.debug("run() method of " + this.getClass().getSimpleName()
-                 + " finished on thread " + Thread.currentThread().getName());
-      }
-   }
-
-   public void waitForEventAndProcess(long maxWaitMillis)
-   {
-      Message message = null;
-      try
-      {
-         message = (maxWaitMillis > 0) ? _pickUpCourier
-                 .pickup(maxWaitMillis) : null;
-      }
-      catch (CourierTimeoutException e)
-      {
-         return;
-      }
-      catch (CourierException e)
-      {
-         _logger.error("Courier Exception", e);
-         return;
-      }
-
-      if (null != message)
-      {
-         ActionProcessingPipeline chain = null;
-
-         try
-         {
-            chain = new ActionProcessingPipeline(message, _config);
-            chain.setClassloader(getClassloader());
-            chain.addObserver(this);
-            updateThreadCount(+1);
-            _execService.execute(chain);
-         }
-         catch (Exception e)
-         {
-            _logger.error("ActionProcessingPipeline exception", e);
-            return;
-         }
-      }
-
-   } // ________________________________
-
-   /**
-    * Handle the destroy of the managed instance.
-    *
-    * @throws ManagedLifecycleException for errors while destroying.
-    */
-   protected void doDestroy()
-           throws ManagedLifecycleException
-   {
-      checkExecutorTermination();
-
-      CourierUtil.cleanCourier(_pickUpCourier);
-
-      RegistryUtil.unregister(_eprCategoryName, _eprName, _epr);
-   }
-
-   /**
-    * Check that the existing executor has been closed down.
-    *
-    * @throws ManagedLifecycleException If executor tasks are still active.
-    */
-   private void checkExecutorTermination()
-           throws ManagedLifecycleException
-   {
-      if (_execService != null)
-      {
-         try
-         {
+		ConfigTree eprElement = _config.getFirstChild(ListenerTagNames.EPR_TAG);
+		if (null == eprElement)
+			throw new ConfigurationException(
+					"Missing or invalid " + ListenerTagNames.EPR_TAG + " element");
+		_epr = ListenerUtil.assembleEpr(eprElement);
+                
+                String latency = _config.getAttribute(ListenerTagNames.POLL_LATENCY_SECS_TAG);
+                long lSeconds = 10;
+                if (null != latency)
+                {
+                    try
+                    {
+                        lSeconds = Integer.parseInt(latency);
+                    }
+                    catch (NumberFormatException e)
+                    {
+                        _logger.warn("Invalid number format <" + latency + "> using default value (" + lSeconds + ")");
+                    }
+                }
+                _latencySecs = lSeconds ;                
+	}
+        
+        /**
+         * Handle the initialisation of the managed instance.
+         * 
+         * @throws ManagedLifecycleException for errors while initialisation.
+         */
+        protected void doInitialise()
+            throws ManagedLifecycleException
+        {
+            final ActionProcessingPipeline pipeline ;
             try
             {
-               if (!_execService.awaitTermination(getTerminationPeriod(), TimeUnit.MILLISECONDS))
-               {
-                  throw new ManagedLifecycleException("Tasks remain active in executor");
-               }
+                pipeline = new ActionProcessingPipeline(_config) ;
+                pipeline.initialise() ;
             }
-            catch (final InterruptedException ie)
+            catch (final ConfigurationException ce)
             {
-               throw new ManagedLifecycleException("Interrupted waiting for active tasks to terminate");
+                throw new ManagedLifecycleException("Error configuring action processing pipeline", ce) ;
             }
-         }
-         finally
-         {
-            _execService = null;
-         }
-      }
-   }
+            this.pipeline = pipeline ;
+            final TwoWayCourier pickUpCourier ;
+            try
+            {
+                pickUpCourier = CourierFactory.getPickupCourier(_epr) ;
+                try
+                {
+                    final Method setPollLatency = pickUpCourier.getClass().getMethod(
+                        "setPollLatency", new Class[] { Long.class });
+                    setPollLatency.invoke(pickUpCourier, new Long(1000 * _latencySecs));
+                }
+                catch (final NoSuchMethodException nsme)
+                {
+                        // OK, just leave it null
+                }
+                catch (final Exception ex)
+                {
+                    CourierUtil.cleanCourier(pickUpCourier);
+                    throw new ManagedLifecycleException("Problems invoking setPollLatency(long)", ex) ;
+                }
+            }
+            catch (final MalformedEPRException mepre)
+            {
+                throw new ManagedLifecycleException("Malformed EPR: " + _epr) ;
+            }
+            catch (final CourierException ce)
+            {
+                throw new ManagedLifecycleException("No appropriate courier can be obtained for " + _epr, ce);
+            }
+            
+            _pickUpCourier = pickUpCourier ;
+         
+            try
+            {
+                RegistryUtil.register(_config, _epr);
+            }
+            catch (final RegistryException re)
+            {
+                CourierUtil.cleanCourier(_pickUpCourier);
+                throw new ManagedLifecycleException("Unexpected error during registration for epr " + _epr, re);
+            }
+        }
+        
+        /**
+         * Handle the start of the managed instance.
+         * 
+         * @throws ManagedLifecycleException for errors while starting.
+         */
+        protected void doStart()
+            throws ManagedLifecycleException
+        {
+            checkExecutorTermination() ;
+            
+            _execService = Executors.newFixedThreadPool(_maxThreads) ;
+            
+            super.doStart() ;
+        }
+        
+        /**
+         * Execute on the thread.
+         */
+        protected void doRun()
+        {
+            if (_logger.isDebugEnabled())
+            {
+                _logger.debug("doRun() method of " + this.getClass().getSimpleName()
+                            + " started on thread " + Thread.currentThread().getName());
+            }
+            
+            while (isRunning())
+            {
+                // Only pickup a message when a thread is available
+                if (getActiveThreadCount() >= _maxThreads)
+                {
+                    waitForRunningStateChange(ManagedLifecycleThreadState.STOPPING, _pauseLapseInMillis) ;
+                }
+                else
+                {
+                    waitForEventAndProcess(100) ;
+                }
+            }
+            if (null != _execService)
+                _execService.shutdown();
 
-   // Child threads will send a -1 when their run() method ends
-   // we need to prevent picking up Messages when there are no available
-   // threads in pool
-   public void update(Observable o, Object arg)
-   {
-      if (arg instanceof Integer)
-         updateThreadCount((Integer) arg);
-   }
+            if (_logger.isDebugEnabled())
+            {
+                _logger.debug("run() method of " + this.getClass().getSimpleName()
+                            + " finished on thread " + Thread.currentThread().getName());
+            }
+        }
+        
+	public void waitForEventAndProcess (long maxWaitMillis)
+	{
+		final Message message ;
+		try
+		{
+			message = (maxWaitMillis > 0) ? _pickUpCourier
+					.pickup(maxWaitMillis) : null;
+		}
+		catch (CourierTimeoutException e)
+		{
+			return;
+		}
+		catch (CourierException e)
+		{
+			_logger.error("Courier Exception", e);
+			return;
+		}
 
-   private int getActiveThreadCount()
-   {
-      synchronized (_synchThreads)
-      {
-         return _qRunningThreads;
-      }
-   }
+		if (null != message)
+		{
+			try
+			{
+                            final Runnable pipelineRunner = new Runnable() {
+                                public void run() {
+                                    try {
+                                        pipeline.process(message) ;
+                                    } finally {
+                                        updateThreadCount(-1) ;
+                                    }
+                                }
+                            } ;
+                            updateThreadCount(+1);
+                            _execService.execute(pipelineRunner);
+			}
+			catch (Exception e)
+			{
+				_logger.error("ActionProcessingPipeline exception", e);
+				return;
+			}
+		}
 
-   private void updateThreadCount(Integer i)
-   {
-      synchronized (_synchThreads)
-      {
-         _qRunningThreads += i.intValue();
-      }
-   }
+	} // ________________________________
+        
+        /**
+         * Handle the destroy of the managed instance.
+         * 
+         * @throws ManagedLifecycleException for errors while destroying.
+         */
+        protected void doDestroy()
+            throws ManagedLifecycleException
+        {
+            checkExecutorTermination() ;
+            
+            pipeline.destroy() ;
+            
+            CourierUtil.cleanCourier(_pickUpCourier);
+            
+            RegistryUtil.unregister(_eprCategoryName, _eprName, _epr) ;
+        }
+        
+        /**
+         * Check that the existing executor has been closed down.
+         * @throws ManagedLifecycleException If executor tasks are still active.
+         */
+        private void checkExecutorTermination()
+            throws ManagedLifecycleException
+        {
+            if (_execService != null)
+            {
+                try
+                {
+                    try
+                    {
+                        if (!_execService.awaitTermination(getTerminationPeriod(), TimeUnit.MILLISECONDS))
+                        {
+                            throw new ManagedLifecycleException("Tasks remain active in executor") ;
+                        }
+                    }
+                    catch (final InterruptedException ie)
+                    {
+                        throw new ManagedLifecycleException("Interrupted waiting for active tasks to terminate") ;
+                    }
+                }
+                finally
+                {
+                    _execService = null ;
+                }
+            }
+        }
 
-   private ConfigTree _config;
+        private int getActiveThreadCount()
+        {
+            synchronized (_synchThreads)
+            {
+                return _qRunningThreads ;
+            }
+        }
 
-   private String _eprCategoryName;
+        private void updateThreadCount(Integer i)
+        {
+            synchronized (_synchThreads)
+            {
+                _qRunningThreads += i.intValue();
+            }
+        }
 
-   private String _eprName;
+        private ConfigTree _config;
 
-   private EPR _epr;
+        private String _eprCategoryName;
 
-   private int _maxThreads;
+        private String _eprName;
 
-   private int _defaultMaxThreads;
+        private EPR _epr;
 
-   private long _latencySecs;
+        private int _maxThreads;
 
-   private long _pauseLapseInMillis = 50;
+        private int _defaultMaxThreads;
+        
+        private long _latencySecs;
+        
+        private long _pauseLapseInMillis = 50 ;
 
-   private ExecutorService _execService;
+        private ExecutorService _execService;
 
-   private Object _synchThreads = new Short((short) -1);
+        private Object _synchThreads = new Short((short) -1);
+        
+        private int _qRunningThreads;
 
-   private int _qRunningThreads;
-
-   private Logger _logger = Logger.getLogger(MessageAwareListener.class);
-
-   private PickUpOnlyCourier _pickUpCourier;
+        private Logger _logger = Logger.getLogger(MessageAwareListener.class);
+        
+        private PickUpOnlyCourier _pickUpCourier;
 }

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionLifecycleProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionLifecycleProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionLifecycleProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,138 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionLifecycle;
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+/**
+ * Instance of ActionPipelineProcessor to allow dynamic specification of the methods
+ * on a single instance of the action processor.
+ * @author kevin
+ */
+final class OverriddenActionLifecycleProcessor implements ActionPipelineProcessor
+{
+    /**
+     * The method info.
+     */
+    private final ActionProcessorMethodInfo methodInfo ;
+    /**
+     * The lifecycle.
+     */
+    private final ActionLifecycle lifecycle ;
+    
+    /**
+     * Construct the overridden action lifecycle processor.
+     * @param config The action config.
+     * @param lifecycle The lifecycle.
+     * @throws ConfigurationException for errors during configuration.
+     */
+    OverriddenActionLifecycleProcessor(final ConfigTree config, final ActionLifecycle lifecycle)
+        throws ConfigurationException
+    {
+        this.lifecycle = lifecycle ;
+        methodInfo = ActionProcessorMethodInfo.getMethodInfo(config, lifecycle.getClass()) ;
+    }
+    
+    /**
+     * Perform the action processing on the specified message.
+     * This method is invoked for each message passing throught the pipeline.
+     * 
+     * @param message The current message being processed.
+     * @return The message to be passed to the next stage of the pipeline.
+     * @throws ActionProcessingException for errors during processing.
+     */
+    public Message process(final Message message)
+        throws ActionProcessingException
+    {
+        if (methodInfo.hasProcessMethods())
+        {
+            return methodInfo.processMethods(lifecycle, message) ;
+        }
+        else
+        {
+            return message ;
+        }
+    }
+    
+    /**
+     * Process an exception generated by the pipeline processing.
+     * Invoked when the processing of a subsequent stage of the
+     * pipeline generates an exception.
+     * 
+     * @param message The original message.
+     * @param ex The exception raised by the pipeline processing
+     */
+    public void processException(final Message message, final Exception ex)
+    {
+        if (methodInfo.hasProcessException())
+        {
+            methodInfo.processException(lifecycle, message, ex) ;
+        }
+    }
+    
+    /**
+     * Process a successful pipeline process. 
+     * Invoked when the pipeline processing completes successfully.
+     * 
+     * @param message The original message.
+     */
+    public void processSuccess(final Message message)
+    {
+        if (methodInfo.hasProcessSuccess())
+        {
+            methodInfo.processSuccess(lifecycle, message) ;
+        }
+    }
+    
+    /**
+     * Initialise the action instance.
+     * <p/>
+     * This method is called after the action instance has been instantiated so that
+     * configuration options can be validated.
+     * 
+     * @throws ActionLifecycleException for errors during initialisation.
+     */
+    public void initialise()
+        throws ActionLifecycleException
+    {
+        lifecycle.initialise() ;
+    }
+
+    /**
+     * Destroy the action instance.
+     * <p/>
+     * This method is called prior to the release of the action instance.  All
+     * resources associated with this action instance should be released as the
+     * instance will no longer be used.
+     */
+    public void destroy()
+        throws ActionLifecycleException
+    {
+        lifecycle.destroy() ;
+    }
+}
\ No newline at end of file


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionLifecycleProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionPipelineProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionPipelineProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionPipelineProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,145 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+/**
+ * Instance of ActionPipelineProcessor to allow selective overriding of the methods
+ * on a single instance of the action processor.
+ * @author kevin
+ */
+final class OverriddenActionPipelineProcessor implements ActionPipelineProcessor
+{
+    /**
+     * The method info.
+     */
+    private final ActionProcessorMethodInfo methodInfo ;
+    /**
+     * The processor.
+     */
+    private final ActionPipelineProcessor processor ;
+    
+    /**
+     * Construct the overridden action pipeline processor.
+     * @param config The action config.
+     * @param processor The processor.
+     * @throws ConfigurationException for errors during configuration.
+     */
+    OverriddenActionPipelineProcessor(final ConfigTree config, final ActionPipelineProcessor processor)
+        throws ConfigurationException
+    {
+        this.processor = processor ;
+        methodInfo = ActionProcessorMethodInfo.getMethodInfo(config, processor.getClass()) ;
+    }
+    
+    /**
+     * Perform the action processing on the specified message.
+     * This method is invoked for each message passing throught the pipeline.
+     * 
+     * @param message The current message being processed.
+     * @return The message to be passed to the next stage of the pipeline.
+     * @throws ActionProcessingException for errors during processing.
+     */
+    public Message process(final Message message)
+        throws ActionProcessingException
+    {
+        if (methodInfo.hasProcessMethods())
+        {
+            return methodInfo.processMethods(processor, message) ;
+        }
+        else
+        {
+            return processor.process(message) ;
+        }
+    }
+    
+    /**
+     * Process an exception generated by the pipeline processing.
+     * Invoked when the processing of a subsequent stage of the
+     * pipeline generates an exception.
+     * 
+     * @param message The original message.
+     * @param ex The exception raised by the pipeline processing
+     */
+    public void processException(final Message message, final Exception ex)
+    {
+        if (methodInfo.hasProcessException())
+        {
+            methodInfo.processException(processor, message, ex) ;
+        }
+        else
+        {
+            processor.processException(message, ex) ;
+        }
+    }
+    
+    /**
+     * Process a successful pipeline process. 
+     * Invoked when the pipeline processing completes successfully.
+     * 
+     * @param message The original message.
+     */
+    public void processSuccess(final Message message)
+    {
+        if (methodInfo.hasProcessSuccess())
+        {
+            methodInfo.processSuccess(processor, message) ;
+        }
+        else
+        {
+            processor.processSuccess(message) ;
+        }
+    }
+    
+    /**
+     * Initialise the action instance.
+     * <p/>
+     * This method is called after the action instance has been instantiated so that
+     * configuration options can be validated.
+     * 
+     * @throws ActionLifecycleException for errors during initialisation.
+     */
+    public void initialise()
+        throws ActionLifecycleException
+    {
+        processor.initialise() ;
+    }
+
+    /**
+     * Destroy the action instance.
+     * <p/>
+     * This method is called prior to the release of the action instance.  All
+     * resources associated with this action instance should be released as the
+     * instance will no longer be used.
+     */
+    public void destroy()
+        throws ActionLifecycleException
+    {
+        processor.destroy() ;
+    }
+}
\ No newline at end of file


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionPipelineProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,165 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.listeners.message;
+
+import java.lang.reflect.Constructor;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.soa.esb.ConfigurationException;
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+/**
+ * Instance of ActionPipelineProcessor to allow dynamic specification of the methods
+ * on the action processor.
+ * @author kevin
+ */
+final class OverriddenActionProcessor implements ActionPipelineProcessor
+{
+    /**
+     * The method info.
+     */
+    private final ActionProcessorMethodInfo methodInfo ;
+    /**
+     * The action constructor.
+     */
+    private final Constructor constructor ;
+    /**
+     * The action config.
+     */
+    private final ConfigTree config ;
+    
+    /**
+     * The map of messages to associated instances.
+     */
+    private Map<Message, Object> messageInstanceMap = Collections.synchronizedMap(new HashMap<Message, Object>()) ;
+
+    /**
+     * Construct the overridden action processor.
+     * @param config The action config.
+     * @param actionClass The action class.
+     * @throws ConfigurationException for errors during configuration.
+     */
+    OverriddenActionProcessor(final ConfigTree config, final Class actionClass)
+        throws ConfigurationException
+    {
+        this.config = config ;
+        constructor = ActionProcessorMethodInfo.getActionClassConstructor(actionClass) ;
+        methodInfo = ActionProcessorMethodInfo.getMethodInfo(config, actionClass) ;
+    }
+    
+    /**
+     * Perform the action processing on the specified message.
+     * This method is invoked for each message passing throught the pipeline.
+     * 
+     * @param message The current message being processed.
+     * @return The message to be passed to the next stage of the pipeline.
+     * @throws ActionProcessingException for errors during processing.
+     */
+    public Message process(final Message message)
+        throws ActionProcessingException
+    {
+        if (methodInfo.hasProcessMethods())
+        {
+            final Object instance ;
+            try
+            {
+                instance = ActionProcessorMethodInfo.getActionClassInstance(config, constructor) ;
+            }
+            catch (final ConfigurationException ce)
+            {
+                throw new ActionProcessingException("Unexpected exception creating action class instance") ;
+            }
+            
+            messageInstanceMap.put(message, instance) ;
+            return methodInfo.processMethods(instance, message) ;
+        }
+        else
+        {
+            return message ;
+        }
+    }
+    
+    /**
+     * Process an exception generated by the pipeline processing.
+     * Invoked when the processing of a subsequent stage of the
+     * pipeline generates an exception.
+     * 
+     * @param message The original message.
+     * @param ex The exception raised by the pipeline processing
+     */
+    public void processException(final Message message, final Exception ex)
+    {
+        final Object instance = messageInstanceMap.remove(message) ;
+        if (instance != null)
+        {
+            methodInfo.processException(instance, message, ex) ;
+        }
+    }
+    
+    /**
+     * Process a successful pipeline process. 
+     * Invoked when the pipeline processing completes successfully.
+     * 
+     * @param message The original message.
+     */
+    public void processSuccess(final Message message)
+    {
+        final Object instance = messageInstanceMap.remove(message) ;
+        if (instance != null)
+        {
+            methodInfo.processSuccess(instance, message) ;
+        }
+    }
+    
+    /**
+     * Initialise the action instance.
+     * <p/>
+     * This method is called after the action instance has been instantiated so that
+     * configuration options can be validated.
+     * 
+     * @throws ActionLifecycleException for errors during initialisation.
+     */
+    public void initialise()
+        throws ActionLifecycleException
+    {
+        messageInstanceMap.clear() ;
+    }
+
+    /**
+     * Destroy the action instance.
+     * <p/>
+     * This method is called prior to the release of the action instance.  All
+     * resources associated with this action instance should be released as the
+     * instance will no longer be used.
+     */
+    public void destroy()
+        throws ActionLifecycleException
+    {
+        messageInstanceMap.clear() ;
+    }
+}
\ No newline at end of file


Property changes on: labs/jbossesb/trunk/product/core/listeners/src/org/jboss/soa/esb/listeners/message/OverriddenActionProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Modified: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipelineUnitTest.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipelineUnitTest.java	2007-03-16 12:01:01 UTC (rev 10258)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/ActionProcessingPipelineUnitTest.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -25,87 +25,307 @@
 import org.jboss.soa.esb.ConfigurationException;
 import org.jboss.soa.esb.helpers.ConfigTree;
 import org.jboss.soa.esb.listeners.ListenerTagNames;
-import org.jboss.soa.esb.message.Message;
 import org.jboss.soa.esb.message.format.MessageFactory;
 
 import junit.framework.TestCase;
 
 public class ActionProcessingPipelineUnitTest extends TestCase
 {
-	public void testConstructor () throws Exception
-	{
-		ConfigTree tree = new ConfigTree("tree");
-		Message msg = MessageFactory.getInstance().getMessage();
-		
-		msg.getBody().add("Hello", "World");
-		
-		@SuppressWarnings("unused")
-        ActionProcessingPipeline pipeline = null;
-		
-		try
-		{
-			pipeline = new ActionProcessingPipeline(null, tree);
-			
-			fail();
-		}
-		catch (IllegalArgumentException ex)
-		{
-		}
-		
-		try
-		{
-			pipeline = new ActionProcessingPipeline(msg, null);
-			
-			fail();
-		}
-		catch (IllegalArgumentException ex)
-		{
-		}
-		
-		try
-		{
-			pipeline = new ActionProcessingPipeline(msg, tree);
-			
-			fail();
-		}
-		catch (ConfigurationException ex)
-		{
-		}
-	}
-	
-	public void testMethods () throws Exception
-	{
-		ConfigTree parent = new ConfigTree("parent");
-		ConfigTree child = new ConfigTree(ListenerTagNames.ACTION_ELEMENT_TAG, parent);
-		
-		Message msg = MessageFactory.getInstance().getMessage();
-		
-		msg.getBody().add("Hello", "World");
-		
-		child.setAttribute(ListenerTagNames.ACTION_ELEMENT_TAG, "foo");
-		child.setAttribute(ListenerTagNames.ACTION_CLASS_TAG, "bar");
-		child.setAttribute(ListenerTagNames.PROCESS_METHOD_TAG, "process");
-		child.setAttribute(ListenerTagNames.EXCEPTION_METHOD_TAG, "error");
-		
-		ActionProcessingPipeline pipeline = new ActionProcessingPipeline(msg, parent);
-		
-		Message msg2 = pipeline.getMessage();
-		
-		if (!msg.equals(msg2))
-			fail();
-		
-		pipeline.prematureTermination("foobar");
-		
-		try
-		{
-			pipeline.actionClassException(child, msg, new Exception());
-			fail();
-		}
-		catch (Exception ex)
-		{
-		}
-		
-		if (pipeline.isProcessingComplete())
-			fail();
-	}
+    @Override
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+        MockActionInfo.reset() ;
+    }
+    
+    /*
+     * Tests to run
+     *  - create a pipeline with a failure, make sure failure is called in correct order and subsequent actions are not called.
+     *    Check initialise and destroy called.
+     *  
+     *  Do the above for each type of action.
+     */
+    
+    public void testActionPipelineProcessor()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, null, null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, null, null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, null, null) ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertTrue("Pipeline process failure", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4) ;
+        checkOrder(MockActionInfo.getSuccessList(), 4, 2, 0) ;
+        checkOrder(MockActionInfo.getExceptionList()) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 4, 2, 0) ;
+    }
+    
+    public void testActionPipelineProcessorFailure()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, null, null) ;
+        addAction(configTree, MockActionPipelineProcessorFailure.class.getName(),
+            null, null, null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, null, null) ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertFalse("Pipeline process succeeded", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2) ;
+        checkOrder(MockActionInfo.getSuccessList()) ;
+        checkOrder(MockActionInfo.getExceptionList(), 2, 0) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 4, 2, 0) ;
+    }
+    
+    public void testOverriddenActionPipelineProcessor()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, "anotherProcessSuccess", null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+                null, null, "anotherProcessException") ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4, 6) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertTrue("Pipeline process failure", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4, 6, 7) ;
+        checkOrder(MockActionInfo.getSuccessList(), 7, 4, 3, 0) ;
+        checkOrder(MockActionInfo.getExceptionList()) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 6, 4, 2, 0) ;
+    }
+    
+    public void testOverriddenActionPipelineProcessorFailure()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            null, "anotherProcessSuccess", null) ;
+        addAction(configTree, MockActionPipelineProcessorFailure.class.getName(),
+                null, null, "anotherProcessException") ;
+        addAction(configTree, MockActionPipelineProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4, 6) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertFalse("Pipeline process succeeded", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4) ;
+        checkOrder(MockActionInfo.getSuccessList()) ;
+        checkOrder(MockActionInfo.getExceptionList(), 5, 2, 0) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 6, 4, 2, 0) ;
+    }
+    
+    public void testOverriddenActionLifecycleProcessor()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            null, "processSuccess", null) ;
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+                null, null, "processException") ;
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4, 6) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertTrue("Pipeline process failure", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4, 6, 7) ;
+        checkOrder(MockActionInfo.getSuccessList(), 7, 2) ;
+        checkOrder(MockActionInfo.getExceptionList()) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 6, 4, 2, 0) ;
+    }
+    
+    public void testOverriddenActionLifecycleProcessorFailure()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            null, "anotherProcessSuccess", null) ;
+        addAction(configTree, MockActionLifecycleProcessorFailure.class.getName(),
+                null, null, "anotherProcessException") ;
+        addAction(configTree, MockActionLifecycleProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList(), 0, 2, 4, 6) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertFalse("Pipeline process succeeded", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4) ;
+        checkOrder(MockActionInfo.getSuccessList()) ;
+        checkOrder(MockActionInfo.getExceptionList(), 5) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList(), 6, 4, 2, 0) ;
+    }
+    
+    public void testOverriddenActionProcessor()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionProcessor.class.getName(),
+            null, "processSuccess", null) ;
+        addAction(configTree, MockActionProcessor.class.getName(),
+                null, null, "processException") ;
+        addAction(configTree, MockActionProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList()) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertTrue("Pipeline process failure", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4, 6, 7) ;
+        checkOrder(MockActionInfo.getSuccessList(), 7, 2) ;
+        checkOrder(MockActionInfo.getExceptionList()) ;
+        
+        final boolean secondResult = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertTrue("Pipeline process failure", secondResult) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4, 6, 7, 8, 10, 12, 14, 15) ;
+        checkOrder(MockActionInfo.getSuccessList(), 7, 2, 15, 10) ;
+        checkOrder(MockActionInfo.getExceptionList()) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList()) ;
+    }
+    
+    public void testOverriddenActionProcessorFailure()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionProcessor.class.getName(),
+            "process", null, null) ;
+        addAction(configTree, MockActionProcessor.class.getName(),
+            null, "anotherProcessSuccess", null) ;
+        addAction(configTree, MockActionProcessorFailure.class.getName(),
+                null, null, "anotherProcessException") ;
+        addAction(configTree, MockActionProcessor.class.getName(),
+            "process, anotherProcess", "anotherProcessSuccess", "anotherProcessException") ;
+
+        final ActionProcessingPipeline pipeline = new ActionProcessingPipeline(configTree) ;
+        pipeline.initialise() ;
+        checkOrder(MockActionInfo.getInitialiseList()) ;
+        
+        final boolean result = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertFalse("Pipeline process succeeded", result) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4) ;
+        checkOrder(MockActionInfo.getSuccessList()) ;
+        checkOrder(MockActionInfo.getExceptionList(), 5) ;
+        
+        final boolean secondResult = pipeline.process(MessageFactory.getInstance().getMessage()) ;
+        assertFalse("Pipeline process succeeded", secondResult) ;
+        checkOrder(MockActionInfo.getProcessList(), 0, 2, 4, 6, 8, 10) ;
+        checkOrder(MockActionInfo.getSuccessList()) ;
+        checkOrder(MockActionInfo.getExceptionList(), 5, 11) ;
+        
+        pipeline.destroy() ;
+        checkOrder(MockActionInfo.getDestroyList()) ;
+    }
+    
+    public void testInvalidConstructor()
+        throws Exception
+    {
+        final ConfigTree configTree = new ConfigTree("parent") ;
+        
+        addAction(configTree, MockActionPipelineProcessorConstructorFailure.class.getName(),
+            null, null, null) ;
+        try
+        {
+            new ActionProcessingPipeline(configTree) ;
+            fail("Expected ConfigurationException") ;
+        }
+        catch (final ConfigurationException ce)
+        {
+            
+        }
+    }
+    
+    private void addAction(final ConfigTree configTree, final String actionName,
+        final String processOverride, final String successOverride,
+        final String exceptionOverride)
+    {
+        final ConfigTree actionChild = new ConfigTree(ListenerTagNames.ACTION_ELEMENT_TAG, configTree) ;
+        actionChild.setAttribute(ListenerTagNames.ACTION_CLASS_TAG, actionName) ;
+        if (processOverride != null)
+        {
+            actionChild.setAttribute(ListenerTagNames.PROCESS_METHOD_TAG, processOverride) ;
+        }
+        if (successOverride != null)
+        {
+            actionChild.setAttribute(ListenerTagNames.NORMAL_COMPLETION_METHOD_TAG, successOverride) ;
+        }
+        if (exceptionOverride != null)
+        {
+            actionChild.setAttribute(ListenerTagNames.EXCEPTION_METHOD_TAG, exceptionOverride) ;
+        }
+    }
+    
+    private void checkOrder(final Integer[] list, int ... values)
+    {
+        final int numValues = (values == null ? 0 : values.length) ;
+        final int listLength = (list == null ? 0 : list.length) ;
+        
+        assertEquals("Unexpected list/values count", numValues, listLength) ;
+        
+        for(int count = 0 ; count < numValues ; count++)
+        {
+            assertEquals("Unexpected call order at count " + count, values[count], list[count].intValue()) ;
+        }
+    }
 }

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionInfo.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionInfo.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionInfo.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class MockActionInfo
+{
+    private static int actionId ;
+    private static List<Integer> initialiseList ;
+    private static List<Integer> processList ;
+    private static List<Integer> successList ;
+    private static List<Integer> exceptionList ;
+    private static List<Integer> destroyList ;
+    
+    static synchronized void reset()
+    {
+        actionId = 0 ;
+        initialiseList = new ArrayList<Integer>() ;
+        processList = new ArrayList<Integer>() ;
+        successList = new ArrayList<Integer>() ;
+        exceptionList = new ArrayList<Integer>() ;
+        destroyList = new ArrayList<Integer>() ;
+    }
+    
+    static synchronized Integer getNextId()
+    {
+        return Integer.valueOf(actionId++) ;
+    }
+    
+    static synchronized void addInitialiseId(final Integer id)
+    {
+        initialiseList.add(id) ;
+    }
+    
+    static synchronized Integer[] getInitialiseList()
+    {
+        return (Integer[])initialiseList.toArray(new Integer[initialiseList.size()]) ;
+    }
+    
+    static synchronized void addProcessId(final Integer id)
+    {
+        processList.add(id) ;
+    }
+    
+    static synchronized Integer[] getProcessList()
+    {
+        return (Integer[])processList.toArray(new Integer[processList.size()]) ;
+    }
+    
+    static synchronized void addSuccessId(final Integer id)
+    {
+        successList.add(id) ;
+    }
+    
+    static synchronized Integer[] getSuccessList()
+    {
+        return (Integer[])successList.toArray(new Integer[successList.size()]) ;
+    }
+    
+    static synchronized void addExceptionId(final Integer id)
+    {
+        exceptionList.add(id) ;
+    }
+    
+    static synchronized Integer[] getExceptionList()
+    {
+        return (Integer[])exceptionList.toArray(new Integer[exceptionList.size()]) ;
+    }
+    
+    static synchronized void addDestroyId(final Integer id)
+    {
+        destroyList.add(id) ;
+    }
+    
+    static synchronized Integer[] getDestroyList()
+    {
+        return (Integer[])destroyList.toArray(new Integer[destroyList.size()]) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionInfo.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,83 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionLifecycle;
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionLifecycleProcessor implements ActionLifecycle
+{
+    private final Integer id ;
+    private final Integer anotherId ;
+    
+    public MockActionLifecycleProcessor(final ConfigTree tree)
+    {
+        id = MockActionInfo.getNextId() ;
+        anotherId = MockActionInfo.getNextId() ;
+    }
+    
+    public Message process(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(id) ;
+        return message ;
+    }
+    
+    public Message anotherProcess(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(anotherId) ;
+        return message ;
+    }
+    
+    public void processException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(id) ;
+    }
+
+    public void anotherProcessException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(anotherId) ;
+    }
+
+    public void processSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(id) ;
+    }
+
+    public void anotherProcessSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(anotherId) ;
+    }
+
+    public void destroy() throws ActionLifecycleException
+    {
+        MockActionInfo.addDestroyId(id) ;
+    }
+
+    public void initialise() throws ActionLifecycleException
+    {
+        MockActionInfo.addInitialiseId(id) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessorFailure.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessorFailure.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessorFailure.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionLifecycleProcessorFailure extends MockActionLifecycleProcessor
+{
+    public MockActionLifecycleProcessorFailure(final ConfigTree tree)
+    {
+        super(tree) ;
+    }
+    
+    @Override
+    public Message process(Message message) throws ActionProcessingException
+    {
+        super.process(message) ;
+        throw new ActionProcessingException("This is a deliberate failure") ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionLifecycleProcessorFailure.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,83 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionPipelineProcessor implements ActionPipelineProcessor
+{
+    private final Integer id ;
+    private final Integer anotherId ;
+    
+    public MockActionPipelineProcessor(final ConfigTree tree)
+    {
+        id = MockActionInfo.getNextId() ;
+        anotherId = MockActionInfo.getNextId() ;
+    }
+    
+    public Message process(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(id) ;
+        return message ;
+    }
+    
+    public Message anotherProcess(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(anotherId) ;
+        return message ;
+    }
+
+    public void processException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(id) ;
+    }
+
+    public void anotherProcessException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(anotherId) ;
+    }
+
+    public void processSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(id) ;
+    }
+
+    public void anotherProcessSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(anotherId) ;
+    }
+
+    public void destroy() throws ActionLifecycleException
+    {
+        MockActionInfo.addDestroyId(id) ;
+    }
+
+    public void initialise() throws ActionLifecycleException
+    {
+        MockActionInfo.addInitialiseId(id) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorConstructorFailure.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorConstructorFailure.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorConstructorFailure.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionLifecycleException;
+import org.jboss.soa.esb.actions.ActionPipelineProcessor;
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionPipelineProcessorConstructorFailure implements ActionPipelineProcessor
+{
+    private final Integer id ;
+    
+    MockActionPipelineProcessorConstructorFailure(final ConfigTree tree)
+    {
+        id = MockActionInfo.getNextId() ;
+    }
+    
+    public Message process(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(id) ;
+        return message ;
+    }
+
+    public void processException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(id) ;
+    }
+
+    public void processSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(id) ;
+    }
+
+    public void destroy() throws ActionLifecycleException
+    {
+        MockActionInfo.addDestroyId(id) ;
+    }
+
+    public void initialise() throws ActionLifecycleException
+    {
+        MockActionInfo.addInitialiseId(id) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorConstructorFailure.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorFailure.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorFailure.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorFailure.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionPipelineProcessorFailure extends MockActionPipelineProcessor
+{
+    public MockActionPipelineProcessorFailure(final ConfigTree tree)
+    {
+        super(tree) ;
+    }
+    
+    @Override
+    public Message process(Message message) throws ActionProcessingException
+    {
+        super.process(message) ;
+        throw new ActionProcessingException("This is a deliberate failure") ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionPipelineProcessorFailure.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessor.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessor.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessor.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionProcessor
+{
+    private final Integer id ;
+    private final Integer anotherId ;
+    
+    public MockActionProcessor(final ConfigTree tree)
+    {
+        id = MockActionInfo.getNextId() ;
+        anotherId = MockActionInfo.getNextId() ;
+    }
+    
+    public Message process(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(id) ;
+        return message ;
+    }
+    
+    public Message anotherProcess(Message message) throws ActionProcessingException
+    {
+        MockActionInfo.addProcessId(anotherId) ;
+        return message ;
+    }
+
+    public void processException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(id) ;
+    }
+
+    public void anotherProcessException(Message message, Exception ex)
+    {
+        MockActionInfo.addExceptionId(anotherId) ;
+    }
+
+    public void processSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(id) ;
+    }
+
+    public void anotherProcessSuccess(Message message)
+    {
+        MockActionInfo.addSuccessId(anotherId) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessor.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessorFailure.java
===================================================================
--- labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessorFailure.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessorFailure.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.soa.esb.listeners.message;
+
+import org.jboss.soa.esb.actions.ActionProcessingException;
+import org.jboss.soa.esb.helpers.ConfigTree;
+import org.jboss.soa.esb.message.Message;
+
+public class MockActionProcessorFailure extends MockActionProcessor
+{
+    public MockActionProcessorFailure(final ConfigTree tree)
+    {
+        super(tree) ;
+    }
+    
+    @Override
+    public Message process(Message message) throws ActionProcessingException
+    {
+        super.process(message) ;
+        throw new ActionProcessingException("This is a deliberate failure") ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/listeners/tests/src/org/jboss/soa/esb/listeners/message/MockActionProcessorFailure.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Added: labs/jbossesb/trunk/product/core/rosetta/src/org/jboss/soa/esb/util/ClassUtil.java
===================================================================
--- labs/jbossesb/trunk/product/core/rosetta/src/org/jboss/soa/esb/util/ClassUtil.java	                        (rev 0)
+++ labs/jbossesb/trunk/product/core/rosetta/src/org/jboss/soa/esb/util/ClassUtil.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -0,0 +1,114 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2006, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.soa.esb.util;
+
+import java.io.InputStream;
+
+/**
+ * Utility methods to aid in class/resource loading.
+ * 
+ * @author kevin
+ */
+public class ClassUtil
+{
+    /**
+     * Load the specified class.
+     * @param className The name of the class to load.
+     * @param caller The class of the caller.
+     * @return The specified class.
+     * @throws ClassNotFoundException If the class cannot be found.
+     */
+    public static Class forName(final String className, final Class caller)
+        throws ClassNotFoundException
+    {
+        final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ;
+        if (threadClassLoader != null)
+        {
+            try
+            {
+                return threadClassLoader.loadClass(className) ;
+            }
+            catch (final ClassNotFoundException cnfe) {} // ignore
+        }
+        
+        
+        final ClassLoader classLoader = caller.getClassLoader() ;
+        if (classLoader != null)
+        {
+            try
+            {
+                return classLoader.loadClass(className) ;
+            }
+            catch (final ClassNotFoundException cnfe) {} // ignore
+        }
+        
+        return Class.forName(className, true, ClassLoader.getSystemClassLoader()) ;
+    }
+    
+    /**
+     * Get the specified resource as a stream.
+     * @param resourceName The name of the class to load.
+     * @param caller The class of the caller.
+     * @return The input stream for the resource or null if not found.
+     */
+    public static InputStream getResourceAsStream(final String resourceName, final Class caller)
+    {
+        final String resource ;
+        if (resourceName.startsWith("/"))
+        {
+                resource = resourceName.substring(1) ;
+        }
+        else
+        {
+                final Package callerPackage = caller.getPackage() ;
+                if (callerPackage != null)
+                {
+                        resource = callerPackage.getName().replace('.', '/') + '/' + resourceName ;
+                }
+                else
+                {
+                        resource = resourceName ;
+                }
+        }
+        final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ;
+        if (threadClassLoader != null)
+        {
+                final InputStream is = threadClassLoader.getResourceAsStream(resource) ;
+                if (is != null)
+                {
+                        return is ;
+                }
+        }
+        
+        final ClassLoader classLoader = caller.getClassLoader() ;
+        if (classLoader != null)
+        {
+                final InputStream is = classLoader.getResourceAsStream(resource) ;
+                if (is != null)
+                {
+                        return is ;
+                }
+        }
+        
+        return ClassLoader.getSystemResourceAsStream(resource) ;
+    }
+}


Property changes on: labs/jbossesb/trunk/product/core/rosetta/src/org/jboss/soa/esb/util/ClassUtil.java
___________________________________________________________________
Name: svn:keywords
   + Rev Date
Name: svn:eol-style
   + native

Modified: labs/jbossesb/trunk/qa/junit/src/org/jboss/soa/esb/actions/SmooksTransformerTest.java
===================================================================
--- labs/jbossesb/trunk/qa/junit/src/org/jboss/soa/esb/actions/SmooksTransformerTest.java	2007-03-16 12:01:01 UTC (rev 10258)
+++ labs/jbossesb/trunk/qa/junit/src/org/jboss/soa/esb/actions/SmooksTransformerTest.java	2007-03-16 12:24:28 UTC (rev 10259)
@@ -73,17 +73,9 @@
     private void process(Message message) throws SAXException, IOException, ConfigurationException {
 		ConfigTree config = ConfigTree.fromInputStream(getClass().getResourceAsStream("SmooksTransformerConfig.xml"));
 
-        ActionProcessingPipeline chain = new ActionProcessingPipeline(message, config); 
-		new Thread(chain).start();
-		
-		// Wait for the pipeline to finish processing the message...
-		while(!chain.isProcessingComplete()) {
-			try {
-				Thread.sleep(100);
-			} catch (InterruptedException e) {
-				e.printStackTrace();
-			}
-		}
+                ActionProcessingPipeline chain = new ActionProcessingPipeline(config);
+        
+                chain.process(message) ;
     }
 
 	private Message createEmptyMessage() {




More information about the jboss-svn-commits mailing list