commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ra...@apache.org
Subject svn commit: r415512 [1/2] - in /jakarta/commons/proper/scxml/trunk: ./ src/main/java/org/apache/commons/scxml/ src/main/java/org/apache/commons/scxml/invoke/ src/main/java/org/apache/commons/scxml/io/ src/main/java/org/apache/commons/scxml/model/ src/m...
Date Tue, 20 Jun 2006 06:06:51 GMT
Author: rahul
Date: Mon Jun 19 23:06:49 2006
New Revision: 415512

URL: http://svn.apache.org/viewvc?rev=415512&view=rev
Log:
Implemented <invoke> (Section 4.4) and its children <param> (Section 4.5) and <finalize> (Section 4.6) -- all sections from the January 06 W3C WD [ http://www.w3.org/TR/scxml/ ]. With this addition, Commons SCXML aligns with the Jan '06 WD.

The primary addition is the Invoker interface, which is used to define the possible interactions between the parent state machine (executor) and the types of invocable activities. Invocable activities must first register an Invoker implementation class for the appropriate "targettype" (attribute of <invoke>) with the parent SCXMLExecutor.

The communication link between the parent state machine executor and the invoked activity is a bi-directional events pipe. All events triggered on the parent state machine get forwarded to the invoked activity. The processing semantics for these events depend upon the "targettype", and thereby vary per concrete implementation of the Invoker interface.

The Invoker "lifecycle" is outlined below: 

 * Instantiation via Class.newInstance() (Invoker implementation requires accessible constructor).
 * Configuration (setters for parent state ID and SCInstance).
 * Initiation of invoked activity via invoke() method, passing the source URI and the map of params.
 * Zero or more bi-directional event triggers.
 * Either completion or cancellation.

These additions introduce backwards incompatible changes to the SCXMLSemantics interface (two new methods).

I will bring up the couple of open issues (such as event names TBD in WD and handling invocation failure) at the related W3C face to face meeting later this week.

Added:
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/invoke/
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/invoke/InvokeTest.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/invoke/InvokeTestSuite.java   (with props)
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/invoke/invoked-01.xml   (with props)
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/invoke/invoker-01.xml   (with props)
Modified:
    jakarta/commons/proper/scxml/trunk/build.xml
    jakarta/commons/proper/scxml/trunk/pom.xml
    jakarta/commons/proper/scxml/trunk/project.xml
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCInstance.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLExecutor.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLSemantics.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLDigester.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/State.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/semantics/SCXMLSemanticsImpl.java
    jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCInstanceTest.java
    jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCXMLTestHelper.java

Modified: jakarta/commons/proper/scxml/trunk/build.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/build.xml?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/build.xml (original)
+++ jakarta/commons/proper/scxml/trunk/build.xml Mon Jun 19 23:06:49 2006
@@ -15,7 +15,7 @@
    limitations under the License.
 -->
 <!--build.xml generated by maven from project.xml version 1.0-SNAPSHOT
-  on date March 1 2006, time 0941-->
+  on date June 19 2006, time 1131-->
 
 <project default="jar" name="commons-scxml" basedir=".">
   <property name="defaulttargetdir" value="target">
@@ -131,6 +131,8 @@
           <include name="org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java">
           </include>
           <include name="org/apache/commons/scxml/env/servlet/EnvServletTestSuite.java">
+          </include>
+          <include name="org/apache/commons/scxml/invoke/InvokeTestSuite.java">
           </include>
           <include name="org/apache/commons/scxml/io/IOTestSuite.java">
           </include>

Modified: jakarta/commons/proper/scxml/trunk/pom.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/pom.xml?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/pom.xml (original)
+++ jakarta/commons/proper/scxml/trunk/pom.xml Mon Jun 19 23:06:49 2006
@@ -186,6 +186,7 @@
             <include>org/apache/commons/scxml/env/jexl/EnvJexlTestSuite.java</include>
             <include>org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java</include>
             <include>org/apache/commons/scxml/env/servlet/EnvServletTestSuite.java</include>
+            <include>org/apache/commons/scxml/invoke/InvokeTestSuite.java</include>
             <include>org/apache/commons/scxml/io/IOTestSuite.java</include>
             <include>org/apache/commons/scxml/model/ModelTestSuite.java</include>
             <include>org/apache/commons/scxml/semantics/SemanticsTestSuite.java</include>

Modified: jakarta/commons/proper/scxml/trunk/project.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/project.xml?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/project.xml (original)
+++ jakarta/commons/proper/scxml/trunk/project.xml Mon Jun 19 23:06:49 2006
@@ -214,6 +214,7 @@
         <include>org/apache/commons/scxml/env/jexl/EnvJexlTestSuite.java</include>
         <include>org/apache/commons/scxml/env/jsp/EnvJspTestSuite.java</include>
         <include>org/apache/commons/scxml/env/servlet/EnvServletTestSuite.java</include>
+        <include>org/apache/commons/scxml/invoke/InvokeTestSuite.java</include>
         <include>org/apache/commons/scxml/io/IOTestSuite.java</include>
         <include>org/apache/commons/scxml/model/ModelTestSuite.java</include>
         <include>org/apache/commons/scxml/semantics/SemanticsTestSuite.java</include>

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCInstance.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCInstance.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCInstance.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCInstance.java Mon Jun 19 23:06:49 2006
@@ -22,6 +22,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.commons.scxml.invoke.Invoker;
+import org.apache.commons.scxml.invoke.InvokerException;
 import org.apache.commons.scxml.model.Datamodel;
 import org.apache.commons.scxml.model.History;
 import org.apache.commons.scxml.model.TransitionTarget;
@@ -51,6 +53,18 @@
     private Map histories;
 
     /**
+     * The <code>Invoker</code> classes <code>Map</code>, keyed by
+     * &lt;invoke&gt; target types (specified using "targettype" attribute).
+     */
+    private Map invokerClasses;
+
+    /**
+     * The <code>Map</code> of active <code>Invoker</code>s, keyed by
+     * (leaf) <code>State</code>s.
+     */
+    private Map invokers;
+
+    /**
      * The evaluator for expressions.
      */
     private Evaluator evaluator;
@@ -61,14 +75,24 @@
     private Context rootContext;
 
     /**
+     * The owning state machine executor.
+     */
+    private SCXMLExecutor executor;
+
+    /**
      * Constructor.
+     *
+     * @param executor The executor that this instance is attached to.
      */
-    SCInstance() {
+    SCInstance(final SCXMLExecutor executor) {
         this.notificationRegistry = new NotificationRegistry();
         this.contexts = new HashMap();
         this.histories = new HashMap();
+        this.invokerClasses = new HashMap();
+        this.invokers = new HashMap();
         this.evaluator = null;
         this.rootContext = null;
+        this.executor = executor;
     }
 
     /**
@@ -227,6 +251,103 @@
         if (lastConfiguration != null) {
             lastConfiguration.clear();
         }
+    }
+
+    /**
+     * Get the {@link SCXMLExecutor} this instance is attached to.
+     *
+     * @return The SCXMLExecutor this instance is attached to.
+     * @see org.apache.commons.scxml.SCXMLExecutor
+     */
+    public SCXMLExecutor getExecutor() {
+        return executor;
+    }
+
+    /**
+     * Register an {@link Invoker} class for this target type.
+     *
+     * @param targettype The target type (specified by "targettype"
+     *                   attribute of &lt;invoke&gt; tag).
+     * @param invokerClass The <code>Invoker</code> <code>Class</code>.
+     */
+    void registerInvokerClass(final String targettype,
+            final Class invokerClass) {
+        invokerClasses.put(targettype, invokerClass);
+    }
+
+    /**
+     * Remove the {@link Invoker} class registered for this target
+     * type (if there is one registered).
+     *
+     * @param targettype The target type (specified by "targettype"
+     *                   attribute of &lt;invoke&gt; tag).
+     */
+    void unregisterInvokerClass(final String targettype) {
+        invokerClasses.remove(targettype);
+    }
+
+    /**
+     * Get the {@link Invoker} for this {@link TransitionTarget}.
+     * May return <code>null</code>. A non-null <code>Invoker</code> will be
+     * returned if and only if the <code>TransitionTarget</code> is
+     * currently active and contains an &lt;invoke&gt; child.
+     *
+     * @param targettype The type of the target being invoked.
+     * @return An {@link Invoker} for the specified type, if an
+     *         invoker class is registered against that type,
+     *         <code>null</code> otherwise.
+     * @throws InvokerException When a suitable {@link Invoker} cannot
+     *                          be instantiated.
+     */
+    public Invoker newInvoker(final String targettype)
+    throws InvokerException {
+        Class invokerClass = (Class) invokerClasses.get(targettype);
+        if (invokerClass == null) {
+            throw new InvokerException("No Invoker registered for "
+                + "targettype \"" + targettype + "\"");
+        }
+        Invoker invoker = null;
+        try {
+            invoker = (Invoker) invokerClass.newInstance();
+        } catch (InstantiationException ie) {
+            throw new InvokerException(ie.getMessage(), ie.getCause());
+        } catch (IllegalAccessException iae) {
+            throw new InvokerException(iae.getMessage(), iae.getCause());
+        }
+        return invoker;
+    }
+
+    /**
+    * Get the {@link Invoker} for this {@link TransitionTarget}.
+     * May return <code>null</code>. A non-null {@link Invoker} will be
+     * returned if and only if the {@link TransitionTarget} is
+     * currently active and contains an &lt;invoke&gt; child.
+     *
+     * @param transitionTarget The <code>TransitionTarget</code>.
+     * @return The Invoker.
+     */
+    public Invoker getInvoker(final TransitionTarget transitionTarget) {
+        return (Invoker) invokers.get(transitionTarget);
+    }
+
+    /**
+     * Set the {@link Invoker} for this {@link TransitionTarget}.
+     *
+     * @param transitionTarget The TransitionTarget.
+     * @param invoker The Invoker.
+     */
+    public void setInvoker(final TransitionTarget transitionTarget,
+            final Invoker invoker) {
+        invokers.put(transitionTarget, invoker);
+    }
+
+    /**
+     * Return the Map of {@link Invoker}s currently "active".
+     *
+     * @return The map of invokers.
+     */
+    public Map getInvokers() {
+        return invokers;
     }
 
 }

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLExecutor.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLExecutor.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLExecutor.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLExecutor.java Mon Jun 19 23:06:49 2006
@@ -21,6 +21,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.logging.Log;
@@ -100,29 +101,41 @@
             throws ModelException {
         // Set event data, saving old values
         Object[] oldData = setEventData(evts);
-        ArrayList evs = new ArrayList(Arrays.asList(evts));
+
+        // Forward events (external only) to any existing invokes,
+        // and finalize processing
+        semantics.processInvokes(evts, errorReporter, scInstance);
+
+        List evs = new ArrayList(Arrays.asList(evts));
+        Step step = null;
+
         do {
             // CreateStep
-            Step step = new Step(evs, currentStatus);
+            step = new Step(evs, currentStatus);
             // EnumerateReachableTransitions
             semantics.enumerateReachableTransitions(stateMachine, step,
-                    errorReporter);
+                errorReporter);
             // FilterTransitionSet
-            semantics.filterTransitionsSet(step, errorReporter, scInstance);
+            semantics.filterTransitionsSet(step, eventdispatcher,
+                errorReporter, scInstance);
             // FollowTransitions
             semantics.followTransitions(step, errorReporter, scInstance);
             // UpdateHistoryStates
             semantics.updateHistoryStates(step, errorReporter, scInstance);
             // ExecuteActions
             semantics.executeActions(step, stateMachine, eventdispatcher,
-                    errorReporter, scInstance);
+                errorReporter, scInstance);
             // AssignCurrentStatus
             updateStatus(step);
             // ***Cleanup external events if superStep
             if (superStep) {
                 evs.clear();
             }
-        } while(superStep && currentStatus.getEvents().size() > 0);
+        } while (superStep && currentStatus.getEvents().size() > 0);
+
+        // InitiateInvokes only after state machine has stabilized
+        semantics.initiateInvokes(step, errorReporter, scInstance);
+
         // Restore event data
         restoreEventData(oldData);
         logState();
@@ -184,7 +197,7 @@
         }
         this.currentStatus = null;
         this.stateMachine = null;
-        this.scInstance = new SCInstance();
+        this.scInstance = new SCInstance(this);
         this.scInstance.setEvaluator(expEvaluator);
     }
 
@@ -198,7 +211,6 @@
     public void reset() throws ModelException {
         // Reset all variable contexts
         Context rootCtx = scInstance.getRootContext();
-        rootCtx.reset();
         // Clone root datamodel
         if (stateMachine == null) {
             log.error(ERR_NO_STATE_MACHINE);
@@ -242,6 +254,8 @@
         if (superStep && currentStatus.getEvents().size() > 0) {
             this.triggerEvents(new TriggerEvent[0]);
         } else {
+            // InitiateInvokes only after state machine has stabilized
+            semantics.initiateInvokes(step, errorReporter, scInstance);
             logState();
         }
     }
@@ -459,6 +473,29 @@
         Object observable = transition;
         scInstance.getNotificationRegistry().removeListener(observable,
             listener);
+    }
+
+    /**
+     * Register an <code>Invoker</code> for this target type.
+     *
+     * @param targettype The target type (specified by "targettype"
+     *                   attribute of &lt;invoke&gt; tag).
+     * @param invokerClass The <code>Invoker</code> <code>Class</code>.
+     */
+    public void registerInvokerClass(final String targettype,
+            final Class invokerClass) {
+        scInstance.registerInvokerClass(targettype, invokerClass);
+    }
+
+    /**
+     * Remove the <code>Invoker</code> registered for this target
+     * type (if there is one registered).
+     *
+     * @param targettype The target type (specified by "targettype"
+     *                   attribute of &lt;invoke&gt; tag).
+     */
+    public void unregisterInvokerClass(final String targettype) {
+        scInstance.unregisterInvokerClass(targettype);
     }
 
     /**

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLSemantics.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLSemantics.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLSemantics.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/SCXMLSemantics.java Mon Jun 19 23:06:49 2006
@@ -121,13 +121,20 @@
      *
      * @param step
      *            with current status
+     * @param evtDispatcher
+     *            the event dispatcher - EventDispatcher instance
      * @param errRep
      *            ErrorReporter callback
      * @param scInstance
      *            The state chart instance
+     *
+     * @throws ModelException
+     *             in case there is a fatal SCXML object model problem.
      */
-    void filterTransitionsSet(final Step step, final ErrorReporter errRep,
-            final SCInstance scInstance);
+    void filterTransitionsSet(final Step step,
+            final EventDispatcher evtDispatcher, final ErrorReporter errRep,
+            final SCInstance scInstance)
+    throws ModelException;
 
     /**
      * Follow the candidate transitions for this execution Step, and update the
@@ -158,4 +165,36 @@
     void updateHistoryStates(final Step step, final ErrorReporter errRep,
             final SCInstance scInstance);
 
+    /**
+     * Forward events to invoked activities, execute finalize handlers.
+     *
+     * @param events
+     *            The events to be forwarded
+     * @param errRep
+     *            ErrorReporter callback
+     * @param scInstance
+     *            The state chart instance
+     *
+     * @throws ModelException
+     *             in case there is a fatal SCXML object model problem.
+     */
+    void processInvokes(final TriggerEvent[] events,
+            final ErrorReporter errRep, final SCInstance scInstance)
+    throws ModelException;
+
+    /**
+     * Initiate any new invoked activities.
+     *
+     * @param step
+     *            The current Step
+     * @param errRep
+     *            ErrorReporter callback
+     * @param scInstance
+     *            The state chart instance
+     *
+     */
+    void initiateInvokes(final Step step, final ErrorReporter errRep,
+            final SCInstance scInstance);
+
 }
+

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,66 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.invoke;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml.SCXMLExecutor;
+import org.apache.commons.scxml.TriggerEvent;
+import org.apache.commons.scxml.model.ModelException;
+
+/**
+ * Trigger the given {@link TriggerEvent} (or array of) on the given
+ * state machine executor asynchronously, once.
+ */
+class AsyncTrigger implements Runnable {
+
+    /** The state machine executor. */
+    private SCXMLExecutor executor;
+    /** The event(s) to be triggered. */
+    private TriggerEvent[] events;
+    /** The log. */
+    private Log log = LogFactory.getLog(AsyncTrigger.class);
+
+    /**
+     * Constructor.
+     *
+     * @param executor The {@link SCXMLExecutor} to trigger the event on.
+     * @param event The {@link TriggerEvent}.
+     */
+    AsyncTrigger(final SCXMLExecutor executor, final TriggerEvent event) {
+        this.executor = executor;
+        this.events = new TriggerEvent[1];
+        this.events[0] = event;
+        new Thread(this).run();
+    }
+
+    /**
+     * Fire the event(s).
+     */
+    public void run() {
+        try {
+            synchronized (executor) {
+                executor.triggerEvents(events);
+            }
+        } catch (ModelException me) {
+            log.error(me.getMessage(), me);
+        }
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/AsyncTrigger.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,119 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.invoke;
+
+import java.util.Map;
+
+import org.apache.commons.scxml.SCInstance;
+import org.apache.commons.scxml.TriggerEvent;
+
+/**
+ * <p>The Invoker interface is used to define the possible interactions
+ * between the parent state machine (executor) and the types of invocable
+ * activities.</p>
+ *
+ * <p>Invocable activities must first register an Invoker implementation class
+ * for the appropriate "targettype" (attribute of &lt;invoke&gt;) with the
+ * parent <code>SCXMLExecutor</code>.</p>
+ *
+ * <p>The communication link between the parent state machine executor and
+ * the invoked activity is a bi-directional events pipe.</p>
+ *
+ * <p>All events triggered on the parent state machine get forwarded to the
+ * invoked activity. The processing semantics for these events depend
+ * upon the "targettype", and thereby vary per concrete implementation of
+ * this interface.</p>
+ *
+ * <p>The invoked activity in turn must fire a special "done" event
+ * when it concludes. It may fire additional events before the "done"
+ * event. The semantics of any additional events depend upon the
+ * "targettype". The invoked activity must not fire any events after the
+ * "done" event. The name of the special "done" event must be
+ * the ID of the parent state wherein the corresponding &lt;invoke&gt;
+ * resides, with the String ".invoke.done" appended.</p>
+ *
+ * <p>The Invoker "lifecycle" is outlined below:
+ *  <ol>
+ *   <li>Instantiation via {@link Class#newInstance()}
+ *       (Invoker implementation requires accessible constructor).</li>
+ *   <li>Configuration (setters for parent state ID and
+ *       {@link SCInstance}).</li>
+ *   <li>Initiation of invoked activity via invoke() method, passing
+ *       the source URI and the map of params.</li>
+ *   <li>Zero or more bi-directional event triggering.</li>
+ *   <li>Either completion or cancellation.</li>
+ *  </ol>
+ * </p>
+ */
+public interface Invoker {
+
+    /**
+     * Set the state ID of the owning state for the &lt;invoke&gt;.
+     * Implementations must use this ID for constructing the event name for
+     * the special "done" event (and optionally, for other event names
+     * as well).
+     *
+     * @param parentStateId The ID of the parent state.
+     */
+    void setParentStateId(String parentStateId);
+
+    /**
+     * Set the "context" of the parent state machine, which provides the
+     * channel.
+     *
+     * @param scInstance The "context" of the parent state machine.
+     */
+    void setSCInstance(SCInstance scInstance);
+
+    /**
+     * Begin this invocation.
+     *
+     * @param source The source URI of the activity being invoked.
+     * @param params The &lt;param&gt; values
+     * @throws InvokerException In case there is a fatal problem with
+     *                          invoking the source.
+     */
+    void invoke(String source, Map params)
+    throws InvokerException;
+
+    /**
+     * Forwards the events triggered on the parent state machine
+     * on to the invoked activity.
+     *
+     * @param evts
+     *            an array of external events which triggered during the last
+     *            time quantum
+     *
+     * @throws InvokerException In case there is a fatal problem with
+     *                          processing the events forwarded by the
+     *                          parent state machine.
+     */
+    void parentEvents(TriggerEvent[] evts)
+    throws InvokerException;
+
+    /**
+     * Cancel this invocation.
+     *
+     * @throws InvokerException In case there is a fatal problem with
+     *                          canceling this invoke.
+     */
+    void cancel()
+    throws InvokerException;
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/Invoker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,61 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.invoke;
+
+/**
+ * Exception thrown when a process specified by an &lt;invoke&gt;
+ * cannot be initiated.
+ *
+ */
+public class InvokerException extends Exception {
+
+    /**
+     * @see java.lang.Exception#Exception()
+     */
+    public InvokerException() {
+        super();
+    }
+
+    /**
+     * @see java.lang.Exception#Exception(java.lang.String)
+     * @param message The error message
+     */
+    public InvokerException(final String message) {
+        super(message);
+    }
+
+    /**
+     * @see java.lang.Exception#Exception(java.lang.Throwable)
+     * @param cause The cause
+     */
+    public InvokerException(final Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * @see java.lang.Exception#Exception(String, Throwable)
+     * @param message The error message
+     * @param cause The cause
+     */
+    public InvokerException(final String message,
+            final Throwable cause) {
+        super(message, cause);
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/InvokerException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,145 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.invoke;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.Evaluator;
+import org.apache.commons.scxml.SCInstance;
+import org.apache.commons.scxml.SCXMLExecutor;
+import org.apache.commons.scxml.TriggerEvent;
+import org.apache.commons.scxml.env.SimpleDispatcher;
+import org.apache.commons.scxml.env.SimpleErrorHandler;
+import org.apache.commons.scxml.env.SimpleErrorReporter;
+import org.apache.commons.scxml.io.SCXMLDigester;
+import org.apache.commons.scxml.model.ModelException;
+import org.apache.commons.scxml.model.SCXML;
+import org.xml.sax.SAXException;
+
+/**
+ * A simple {@link Invoker} for SCXML documents. Invoked SCXML document
+ * may not contain external namespace elements, further invokes etc.
+ */
+public class SimpleSCXMLInvoker implements Invoker {
+
+    /** Parent state ID. */
+    private String parentStateId;
+    /** Event prefix, all events sent to the parent executor must begin
+     *  with this prefix. */
+    private String eventPrefix;
+    /** Invoking document's SCInstance. */
+    private SCInstance parentSCInstance;
+    /** The invoked state machine executor. */
+    private SCXMLExecutor executor;
+    /** Cancellation status. */
+    private boolean cancelled;
+
+    //// Constants
+    /** Prefix for all events sent to the parent state machine. */
+    private static String invokePrefix = ".invoke.";
+    /** Suffix for invoke done event. */
+    private static String invokeDone = "done";
+    /** Suffix for invoke cancel response event. */
+    private static String invokeCancelResponse = "cancel.response";
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void setParentStateId(final String parentStateId) {
+        this.parentStateId = parentStateId;
+        this.eventPrefix = parentStateId + invokePrefix;
+        this.cancelled = false;
+    }
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void setSCInstance(final SCInstance scInstance) {
+        this.parentSCInstance = scInstance;
+    }
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void invoke(final String source, final Map params)
+    throws InvokerException {
+        SCXML scxml = null;
+        try {
+            scxml = SCXMLDigester.digest(source,
+                new SimpleErrorHandler(), null);
+        } catch (ModelException me) {
+            throw new InvokerException(me.getMessage(), me.getCause());
+        } catch (IOException ioe) {
+            throw new InvokerException(ioe.getMessage(), ioe.getCause());
+        } catch (SAXException se) {
+            throw new InvokerException(se.getMessage(), se.getCause());
+        }
+        Evaluator eval = parentSCInstance.getEvaluator();
+        executor = new SCXMLExecutor(eval,
+            new SimpleDispatcher(), new SimpleErrorReporter());
+        Context rootCtx = eval.newContext(null);
+        for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            rootCtx.setLocal((String) entry.getKey(), entry.getValue());
+        }
+        executor.setRootContext(rootCtx);
+        executor.setStateMachine(scxml);
+        try {
+            executor.go();
+        } catch (ModelException me) {
+            throw new InvokerException(me.getMessage(), me.getCause());
+        }
+    }
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void parentEvents(final TriggerEvent[] evts)
+    throws InvokerException {
+        if (cancelled) {
+            return; // no further processing should take place
+        }
+        boolean doneBefore = executor.getCurrentStatus().isFinal();
+        try {
+            executor.triggerEvents(evts);
+        } catch (ModelException me) {
+            throw new InvokerException(me.getMessage(), me.getCause());
+        }
+        if (!doneBefore && executor.getCurrentStatus().isFinal()) {
+            TriggerEvent te = new TriggerEvent(eventPrefix + invokeDone,
+                TriggerEvent.SIGNAL_EVENT);
+            new AsyncTrigger(parentSCInstance.getExecutor(), te);
+        }
+    }
+
+    /**
+     * {@inheritDoc}.
+     */
+    public void cancel()
+    throws InvokerException {
+        cancelled = true;
+        TriggerEvent te = new TriggerEvent(eventPrefix
+            + invokeCancelResponse, TriggerEvent.SIGNAL_EVENT);
+        new AsyncTrigger(parentSCInstance.getExecutor(), te);
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/SimpleSCXMLInvoker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html Mon Jun 19 23:06:49 2006
@@ -0,0 +1,31 @@
+<html>
+<!-- 
+ *
+ *    
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *
+ *
+-->
+<head>
+</head>
+<body>
+
+  <p>A collection of classes related to the SCXML &lt;invoke&gt;
+     element and its children, dealing with the invocation of
+     activities associated with a particular state in the state machine.</p>
+
+</body>
+</html>

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/invoke/package.html
------------------------------------------------------------------------------
    svn:mime-type = text/html

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/ModelUpdater.java Mon Jun 19 23:06:49 2006
@@ -26,6 +26,7 @@
 import org.apache.commons.scxml.SCXMLHelper;
 import org.apache.commons.scxml.model.History;
 import org.apache.commons.scxml.model.Initial;
+import org.apache.commons.scxml.model.Invoke;
 import org.apache.commons.scxml.model.ModelException;
 import org.apache.commons.scxml.model.Parallel;
 import org.apache.commons.scxml.model.SCXML;
@@ -162,8 +163,34 @@
             }
         }
         Parallel p = s.getParallel();
+        Invoke inv = s.getInvoke();
+        if ((inv != null && p != null)
+                || (inv != null && !c.isEmpty())
+                || (p != null && !c.isEmpty())) {
+            logAndThrowModelError(ERR_STATE_BAD_CONTENTS,
+                new Object[] {getStateName(s)});
+        }
         if (p != null) {
             updateParallel(p, targets);
+        } else if (inv != null) {
+            String ttype = inv.getTargettype();
+            if (ttype == null || ttype.trim().length() == 0) {
+                logAndThrowModelError(ERR_INVOKE_NO_TARGETTYPE,
+                    new Object[] {getStateName(s)});
+            }
+            String src = inv.getSrc();
+            boolean noSrc = (src == null || src.trim().length() == 0);
+            String srcexpr = inv.getSrcexpr();
+            boolean noSrcexpr = (srcexpr == null
+                                 || srcexpr.trim().length() == 0);
+            if (noSrc && noSrcexpr) {
+                logAndThrowModelError(ERR_INVOKE_NO_SRC,
+                    new Object[] {getStateName(s)});
+            }
+            if (!noSrc && !noSrcexpr) {
+                logAndThrowModelError(ERR_INVOKE_AMBIGUOUS_SRC,
+                    new Object[] {getStateName(s)});
+            }
         } else {
             Iterator j = c.keySet().iterator();
             while (j.hasNext()) {
@@ -270,6 +297,15 @@
         + "null or not a descendant of {0}";
 
     /**
+     * Error message when a state element contains anything other than
+     * one &lt;parallel&gt;, one &lt;invoke&gt; or any number of
+     * &lt;state&gt; children.
+     */
+    private static final String ERR_STATE_BAD_CONTENTS = "{0} should "
+        + "contain either one <parallel>, one <invoke> or any number of "
+        + "<state> children.";
+
+    /**
      * Error message when a referenced history state cannot be found.
      */
     private static final String ERR_STATE_NO_HIST = "Referenced history state"
@@ -306,4 +342,27 @@
         "No default target specified for history with ID \"{0}\""
         + " belonging to {1}";
 
+    /**
+     * Error message when an &lt;invoke&gt; does not specify a "targettype"
+     * attribute.
+     */
+    private static final String ERR_INVOKE_NO_TARGETTYPE = "{0} contains "
+        + "<invoke> with no \"targettype\" attribute specified.";
+
+    /**
+     * Error message when an &lt;invoke&gt; does not specify a "src"
+     * or a "srcexpr" attribute.
+     */
+    private static final String ERR_INVOKE_NO_SRC = "{0} contains "
+        + "<invoke> without a \"src\" or \"srcexpr\" attribute specified.";
+
+    /**
+     * Error message when an &lt;invoke&gt; specifies both "src" and "srcexpr"
+     * attributes.
+     */
+    private static final String ERR_INVOKE_AMBIGUOUS_SRC = "{0} contains "
+        + "<invoke> with both \"src\" and \"srcexpr\" attributes specified,"
+        + " must specify either one, but not both.";
+
 }
+

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLDigester.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLDigester.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLDigester.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLDigester.java Mon Jun 19 23:06:49 2006
@@ -50,14 +50,17 @@
 import org.apache.commons.scxml.model.Executable;
 import org.apache.commons.scxml.model.Exit;
 import org.apache.commons.scxml.model.ExternalContent;
+import org.apache.commons.scxml.model.Finalize;
 import org.apache.commons.scxml.model.History;
 import org.apache.commons.scxml.model.If;
 import org.apache.commons.scxml.model.Initial;
+import org.apache.commons.scxml.model.Invoke;
 import org.apache.commons.scxml.model.Log;
 import org.apache.commons.scxml.model.ModelException;
 import org.apache.commons.scxml.model.OnEntry;
 import org.apache.commons.scxml.model.OnExit;
 import org.apache.commons.scxml.model.Parallel;
+import org.apache.commons.scxml.model.Param;
 import org.apache.commons.scxml.model.SCXML;
 import org.apache.commons.scxml.model.Send;
 import org.apache.commons.scxml.model.State;
@@ -513,6 +516,9 @@
     /** &lt;transition&gt; element. */
     private static final String XPU_TR = "!*/transition";
 
+    /** &lt;finalize&gt; element. */
+    private static final String XPU_FIN = "!*/finalize";
+
     //// Path Fragments, constants prefixed by XPF_
     // Onentries and Onexits
     /** &lt;onentry&gt; child element. */
@@ -532,6 +538,16 @@
     /** &lt;initial&gt; child element. */
     private static final String XPF_INI = "/initial";
 
+    // Invoke, param and finalize
+    /** &lt;invoke&gt; child element of &lt;state&gt;. */
+    private static final String XPF_INV = "/invoke";
+
+    /** &lt;param&gt; child element of &lt;invoke&gt;. */
+    private static final String XPF_PRM = "/param";
+
+    /** &lt;finalize&gt; child element of &lt;invoke&gt;. */
+    private static final String XPF_FIN = "/finalize";
+
     // History
     /** &lt;history&gt; child element. */
     private static final String XPF_HIST = "/history";
@@ -682,6 +698,7 @@
         addCustomActionRules(XPU_ONEX, scxmlRules, customActions);
         addCustomActionRules(XPU_TR, scxmlRules, customActions);
         addCustomActionRules(XPU_IF, scxmlRules, customActions);
+        addCustomActionRules(XPU_FIN, scxmlRules, customActions);
 
         return scxmlRules;
 
@@ -706,6 +723,7 @@
         scxmlRules.add(xp, new ObjectCreateRule(State.class));
         addStatePropertiesRules(xp, scxmlRules, customActions, pr);
         addDatamodelRules(xp + XPF_DM, scxmlRules, scxml, pr);
+        addInvokeRules(xp + XPF_INV, scxmlRules, customActions, pr, scxml);
         addInitialRules(xp + XPF_INI, scxmlRules, customActions, pr, scxml);
         addHistoryRules(xp + XPF_HIST, scxmlRules, customActions, pr, scxml);
         addParentRule(xp, scxmlRules, parent);
@@ -780,6 +798,33 @@
     }
 
     /**
+     * Add Digester rules for all &lt;invoke&gt; elements.
+     *
+     * @param xp The Digester style XPath expression of the parent
+     *           XML element
+     * @param scxmlRules The rule set to be used for digestion
+     * @param customActions The list of {@link CustomAction}s this digester
+     *              instance will process, can be null or empty
+     * @param pr The PathResolver
+     * @param scxml The parent SCXML document (or null)
+     */
+    private static void addInvokeRules(final String xp,
+            final ExtendedBaseRules scxmlRules, final List customActions,
+            final PathResolver pr, final SCXML scxml) {
+        scxmlRules.add(xp, new ObjectCreateRule(Invoke.class));
+        scxmlRules.add(xp, new SetPropertiesRule());
+        scxmlRules.add(xp, new UpdateInvokeRule(pr));
+        scxmlRules.add(xp + XPF_PRM, new ObjectCreateRule(Param.class));
+        scxmlRules.add(xp + XPF_PRM, new SetPropertiesRule());
+        scxmlRules.add(xp + XPF_PRM, new SetNextRule("addParam"));
+        scxmlRules.add(xp + XPF_FIN, new ObjectCreateRule(Finalize.class));
+        scxmlRules.add(xp + XPF_FIN, new UpdateFinalizeRule());
+        addActionRules(xp + XPF_FIN, scxmlRules, customActions);
+        scxmlRules.add(xp + XPF_FIN, new SetNextRule("setFinalize"));
+        scxmlRules.add(xp, new SetNextRule("setInvoke"));
+    }
+
+    /**
      * Add Digester rules for all &lt;initial&gt; elements.
      *
      * @param xp The Digester style XPath expression of the parent
@@ -1357,5 +1402,58 @@
             s.setDatamodel(externalSCXML.getDatamodel());
         }
     }
+
+    /**
+     * Custom digestion rule for setting PathResolver for runtime retrieval
+     * and parent state.
+     *
+     */
+    public static class UpdateInvokeRule extends Rule {
+
+        /**
+         * The PathResolver to set.
+         * @see PathResolver
+         */
+        private PathResolver pr;
+
+        /**
+         * Constructor.
+         * @param pr The PathResolver
+         *
+         * @see PathResolver
+         */
+        public UpdateInvokeRule(final PathResolver pr) {
+            super();
+            this.pr = pr;
+        }
+
+        /**
+         * @see Rule#begin(String, String, Attributes)
+         */
+        public final void begin(final String namespace, final String name,
+                final Attributes attributes) {
+            Invoke invoke = (Invoke) getDigester().peek();
+            invoke.setPathResolver(pr);
+        }
+    }
+
+    /**
+     * Custom digestion rule for setting state parent of finalize.
+     *
+     */
+    public static class UpdateFinalizeRule extends Rule {
+
+        /**
+         * @see Rule#begin(String, String, Attributes)
+         */
+        public final void begin(final String namespace, final String name,
+                final Attributes attributes) {
+            Finalize finalize = (Finalize) getDigester().peek();
+            // state/invoke/finalize --> peek(2)
+            TransitionTarget tt = (TransitionTarget) getDigester().peek(2);
+            finalize.setParent(tt);
+        }
+    }
+
 }
 

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/io/SCXMLSerializer.java Mon Jun 19 23:06:49 2006
@@ -44,9 +44,11 @@
 import org.apache.commons.scxml.model.ElseIf;
 import org.apache.commons.scxml.model.Exit;
 import org.apache.commons.scxml.model.ExternalContent;
+import org.apache.commons.scxml.model.Finalize;
 import org.apache.commons.scxml.model.History;
 import org.apache.commons.scxml.model.If;
 import org.apache.commons.scxml.model.Initial;
+import org.apache.commons.scxml.model.Invoke;
 import org.apache.commons.scxml.model.Log;
 import org.apache.commons.scxml.model.OnEntry;
 import org.apache.commons.scxml.model.OnExit;
@@ -146,8 +148,11 @@
             }
         }
         Parallel p = s.getParallel();
+        Invoke inv = s.getInvoke();
         if (p != null) {
             serializeParallel(b, p, indent + INDENT);
+        } else if (inv != null) {
+            serializeInvoke(b , inv, indent + INDENT);
         } else {
             Map c = s.getChildren();
             Iterator j = c.keySet().iterator();
@@ -183,6 +188,45 @@
     }
 
     /**
+     * Serialize this Invoke object.
+     *
+     * @param b The buffer to append the serialization to
+     * @param i The Invoke to serialize
+     * @param indent The indent for this XML element
+     */
+    public static void serializeInvoke(final StringBuffer b,
+            final Invoke i, final String indent) {
+        b.append(indent).append("<invoke");
+        String ttype = i.getTargettype();
+        String src = i.getSrc();
+        String srcexpr = i.getSrcexpr();
+        if (ttype != null) {
+            b.append(" targettype=\"").append(ttype).append("\"");
+        }
+        // Prefer src
+        if (src != null) {
+            b.append(" src=\"").append(src).append("\"");
+        } else if (srcexpr != null) {
+            b.append(" srcexpr=\"").append(srcexpr).append("\"");
+        }
+        b.append(">\n");
+        Map params = i.getParams();
+        for (Iterator iter = params.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry e = (Map.Entry) iter.next();
+            b.append(indent).append(INDENT).append("<param name=\"").
+                append(e.getKey()).append("\" expr=\"").
+                append(e.getValue()).append("\"/>\n");
+        }
+        Finalize f = i.getFinalize();
+        if (f != null) {
+            b.append(indent).append(INDENT).append("<finalize>\n");
+            serializeActions(b, f.getActions(), indent + INDENT + INDENT);
+            b.append(indent).append(INDENT).append("</finalize>\n");
+        }
+        b.append(indent).append("</invoke>\n");
+    }
+
+    /**
      * Serialize this Initial object.
      *
      * @param b The buffer to append the serialization to
@@ -496,7 +540,7 @@
             final StringBuffer b, final TransitionTarget t) {
         String id = t.getId();
         if (id != null) {
-            b.append(" id=\"" + id + "\"");
+            b.append(" id=\"").append(id).append("\"");
         }
         TransitionTarget pt = t.getParent();
         if (pt != null) {

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,35 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.model;
+
+/**
+ * The class in this SCXML object model that corresponds to the
+ * &lt;finalize&gt; SCXML element.
+ *
+ */
+public class Finalize extends Executable {
+
+    /**
+     * Default no-args constructor for Digester.
+     */
+    public Finalize() {
+        super();
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Finalize.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,181 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.scxml.PathResolver;
+
+/**
+ * The class in this SCXML object model that corresponds to the
+ * &lt;invoke&gt; SCXML element.
+ *
+ */
+public class Invoke {
+
+    /**
+     * The type of target to be invoked.
+     */
+    private String targettype;
+
+    /**
+     * The source URL for the external service.
+     */
+    private String src;
+
+    /**
+     * The expression that evaluates to the source URL for the
+     * external service.
+     */
+    private String srcexpr;
+
+    /**
+     * The Map of the params to be sent to the invoked process.
+     */
+    private Map params;
+
+    /**
+     * The &lt;finalize&gt; child, may be null.
+     */
+    private Finalize finalize;
+
+    /**
+     * {@link PathResolver} for resolving the "src" or "srcexpr" result.
+     */
+    private PathResolver pathResolver;
+
+    /**
+     * Default no-args constructor for Digester.
+     */
+    public Invoke() {
+        params = new HashMap();
+    }
+
+    /**
+     * Get the target type for this &lt;invoke&gt; element.
+     *
+     * @return String Returns the targettype.
+     */
+    public final String getTargettype() {
+        return targettype;
+    }
+
+    /**
+     * Set the target type for this &lt;invoke&gt; element.
+     *
+     * @param targettype The targettype to set.
+     */
+    public final void setTargettype(final String targettype) {
+        this.targettype = targettype;
+    }
+
+    /**
+     * Get the URL for the external service.
+     *
+     * @return String The URL.
+     */
+    public final String getSrc() {
+        return src;
+    }
+
+    /**
+     * Set the URL for the external service.
+     *
+     * @param src The source URL.
+     */
+    public final void setSrc(final String src) {
+        this.src = src;
+    }
+
+    /**
+     * Get the expression that evaluates to the source URL for the
+     * external service.
+     *
+     * @return String The source expression.
+     */
+    public final String getSrcexpr() {
+        return srcexpr;
+    }
+
+    /**
+     * Set the expression that evaluates to the source URL for the
+     * external service.
+     *
+     * @param srcexpr The source expression.
+     */
+    public final void setSrcexpr(final String srcexpr) {
+        this.srcexpr = srcexpr;
+    }
+
+    /**
+     * Get the params Map.
+     *
+     * @return Map The params map.
+     */
+    public final Map getParams() {
+        return params;
+    }
+
+    /**
+     * Add this param to this invoke.
+     *
+     * @param param The invoke parameter.
+     */
+    public final void addParam(final Param param) {
+        params.put(param.getName(), param.getExpr());
+    }
+
+    /**
+     * Get the Finalize for this Invoke.
+     *
+     * @return Finalize The Finalize for this Invoke.
+     */
+    public final Finalize getFinalize() {
+        return finalize;
+    }
+
+    /**
+     * Set the Finalize for this Invoke.
+     *
+     * @param finalize The Finalize for this Invoke.
+     */
+    public final void setFinalize(final Finalize finalize) {
+        this.finalize = finalize;
+    }
+
+    /**
+     * Get the {@link PathResolver}.
+     *
+     * @return Returns the pathResolver.
+     */
+    public PathResolver getPathResolver() {
+        return pathResolver;
+    }
+
+    /**
+     * Set the {@link PathResolver}.
+     *
+     * @param pathResolver The pathResolver to set.
+     */
+    public void setPathResolver(final PathResolver pathResolver) {
+        this.pathResolver = pathResolver;
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Invoke.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java?rev=415512&view=auto
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java Mon Jun 19 23:06:49 2006
@@ -0,0 +1,81 @@
+/*
+ *
+ *   Copyright 2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.commons.scxml.model;
+
+/**
+ * The class in this SCXML object model that corresponds to the
+ * &lt;param&gt; SCXML element.
+ *
+ */
+public class Param {
+
+    /**
+     * The param name.
+     */
+    private String name;
+
+    /**
+     * The param expression, may be null.
+     */
+    private String expr;
+
+    /**
+     * Default no-args constructor for Digester.
+     */
+    public Param() {
+        name = null;
+        expr = null;
+    }
+    /**
+     * Get the name for this param.
+     *
+     * @return String The param name.
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Set the name for this param.
+     *
+     * @param name The param name.
+     */
+    public final void setName(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Get the expression for this param value.
+     *
+     * @return String The expression for this param value.
+     */
+    public final String getExpr() {
+        return expr;
+    }
+
+    /**
+     * Set the expression for this param value.
+     *
+     * @param expr The expression for this param value.
+     */
+    public final void setExpr(final String expr) {
+        this.expr = expr;
+    }
+
+}
+

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Param.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/State.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/State.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/State.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/State.java Mon Jun 19 23:06:49 2006
@@ -32,17 +32,27 @@
 
     /**
      * The Map containing immediate children of this State, keyed by
-     * their IDs. Incompatible with the parallel property.
+     * their IDs. Incompatible with the parallel or invoke property.
      */
     private Map children;
 
     /**
      * The Parallel child, which defines a set of parallel substates.
-     * May occur 0 or 1 times. Incompatible with the state property.
+     * May occur 0 or 1 times. Incompatible with the state or invoke property.
      */
     private Parallel parallel;
 
     /**
+     * The Invoke child, which defines an external process that should
+     * be invoked, immediately after the onentry executable content,
+     * and the transitions become candidates after the invoked
+     * process has completed its execution.
+     * May occur 0 or 1 times. Incompatible with the state or parallel
+     * property.
+     */
+    private Invoke invoke;
+
+    /**
      * Boolean property indicating whether this is a final state or not.
      * Default value is false . Final states may not have substates or
      * outgoing transitions.
@@ -118,6 +128,25 @@
      */
     public final void setParallel(final Parallel parallel) {
         this.parallel = parallel;
+    }
+
+    /**
+     * Get the Invoke child (may be null).
+     *
+     * @return Invoke Returns the invoke.
+     */
+    public final Invoke getInvoke() {
+        return invoke;
+    }
+
+    /**
+     * Set the Invoke child.
+     *
+     * @param invoke
+     *            The invoke to set.
+     */
+    public final void setInvoke(final Invoke invoke) {
+        this.invoke = invoke;
     }
 
     /**

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/semantics/SCXMLSemanticsImpl.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/semantics/SCXMLSemanticsImpl.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/semantics/SCXMLSemanticsImpl.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/semantics/SCXMLSemanticsImpl.java Mon Jun 19 23:06:49 2006
@@ -21,26 +21,35 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml.Context;
 import org.apache.commons.scxml.ErrorReporter;
+import org.apache.commons.scxml.Evaluator;
 import org.apache.commons.scxml.EventDispatcher;
 import org.apache.commons.scxml.NotificationRegistry;
+import org.apache.commons.scxml.PathResolver;
 import org.apache.commons.scxml.SCInstance;
 import org.apache.commons.scxml.SCXMLExpressionException;
 import org.apache.commons.scxml.SCXMLHelper;
 import org.apache.commons.scxml.SCXMLSemantics;
 import org.apache.commons.scxml.Step;
 import org.apache.commons.scxml.TriggerEvent;
+import org.apache.commons.scxml.invoke.Invoker;
+import org.apache.commons.scxml.invoke.InvokerException;
 import org.apache.commons.scxml.model.Action;
+import org.apache.commons.scxml.model.Finalize;
 import org.apache.commons.scxml.model.History;
 import org.apache.commons.scxml.model.Initial;
+import org.apache.commons.scxml.model.Invoke;
 import org.apache.commons.scxml.model.ModelException;
 import org.apache.commons.scxml.model.OnEntry;
 import org.apache.commons.scxml.model.OnExit;
@@ -147,6 +156,7 @@
     throws ModelException {
         NotificationRegistry nr = scInstance.getNotificationRegistry();
         Collection internalEvents = step.getAfterStatus().getEvents();
+        Map invokers = scInstance.getInvokers();
         // ExecutePhaseActions / OnExit
         for (Iterator i = step.getExitList().iterator(); i.hasNext();) {
             TransitionTarget tt = (TransitionTarget) i.next();
@@ -161,6 +171,19 @@
                 errRep.onError(ErrorReporter.EXPRESSION_ERROR, e.getMessage(),
                         oe);
             }
+            // check if invoke is active in this state
+            if (invokers.containsKey(tt)) {
+                Invoker toCancel = (Invoker) invokers.get(tt);
+                try {
+                    toCancel.cancel();
+                } catch (InvokerException ie) {
+                    TriggerEvent te = new TriggerEvent(tt.getId()
+                        + ".invoke.cancel.failed", TriggerEvent.ERROR_EVENT);
+                    internalEvents.add(te);
+                }
+                // done here, don't wait for cancel response
+                invokers.remove(tt);
+            }
             nr.fireOnExit(tt, tt);
             nr.fireOnExit(stateMachine, tt);
             TriggerEvent te = new TriggerEvent(tt.getId() + ".exit",
@@ -288,13 +311,19 @@
     /**
      * @param step
      *            [inout]
+     * @param evtDispatcher
+     *            The {@link EventDispatcher} [in]
      * @param errRep
      *            ErrorReporter callback [inout]
      * @param scInstance
      *            The state chart instance [in]
+     * @throws ModelException
+     *             in case there is a fatal SCXML object model problem.
      */
     public void filterTransitionsSet(final Step step,
-            final ErrorReporter errRep, final SCInstance scInstance) {
+            final EventDispatcher evtDispatcher,
+            final ErrorReporter errRep, final SCInstance scInstance)
+    throws ModelException {
         /*
          * - filter transition set by applying events
          * (step/beforeStatus/events + step/externalEvents) (local check)
@@ -302,9 +331,8 @@
          * each transition (local check) - transition precedence (bottom-up)
          * as defined by SCXML specs
          */
-        Set allEvents = new HashSet(step.getBeforeStatus().getEvents()
-                .size()
-                + step.getExternalEvents().size());
+        Set allEvents = new HashSet(step.getBeforeStatus().getEvents().size()
+            + step.getExternalEvents().size());
         //for now, we only match against event names
         for (Iterator ei = step.getBeforeStatus().getEvents().iterator();
                 ei.hasNext();) {
@@ -316,6 +344,27 @@
             TriggerEvent te = (TriggerEvent) ei.next();
             allEvents.add(te.getName());
         }
+        // Finalize invokes, if applicable
+        for (Iterator iter = scInstance.getInvokers().keySet().iterator();
+                iter.hasNext();) {
+            State s = (State) iter.next();
+            if (finalizeMatch(s.getId(), allEvents)) {
+                Finalize fn = s.getInvoke().getFinalize();
+                if (fn != null) {
+                    try {
+                        for (Iterator fnIter = fn.getActions().iterator();
+                                fnIter.hasNext();) {
+                            ((Action) fnIter.next()).execute(evtDispatcher,
+                                errRep, scInstance, appLog,
+                                step.getAfterStatus().getEvents());
+                        }
+                    } catch (SCXMLExpressionException e) {
+                        errRep.onError(ErrorReporter.EXPRESSION_ERROR,
+                            e.getMessage(), fn);
+                    }
+                }
+            }
+        }
         //remove list (filtered-out list)
         List removeList = new LinkedList();
         //iterate over non-filtered transition set
@@ -582,39 +631,6 @@
     }
 
     /**
-     * Implements prefix match, that is, if, for example,
-     * &quot;mouse.click&quot; is a member of eventOccurrences and a
-     * transition is triggered by &quot;mouse&quot;, the method returns true.
-     *
-     * @param transEvent
-     *            a trigger event of a transition
-     * @param eventOccurrences
-     *            current events
-     * @return true/false
-     */
-    public boolean eventMatch(final String transEvent,
-            final Set eventOccurrences) {
-        if (SCXMLHelper.isStringEmpty(transEvent)) {
-            return true;
-        } else {
-            String transEventDot = transEvent + "."; // prefix event support
-            Iterator i = eventOccurrences.iterator();
-            while (i.hasNext()) {
-                String evt = (String) i.next();
-                if (evt == null) {
-                    continue; // Unnamed events
-                } else if (evt.equals("*")) {
-                    return true; // Wildcard
-                } else if (evt.equals(transEvent)
-                            || evt.startsWith(transEventDot)) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
      * Follow the candidate transitions for this execution Step, and update the
      * lists of entered and exited states accordingly.
      *
@@ -682,6 +698,180 @@
                 ((State) o).setDone(false);
             }
         }
+    }
+    /**
+     * Process any existing invokes, includes forwarding external events,
+     * and executing any finalize handlers.
+     *
+     * @param events
+     *            The events to be forwarded
+     * @param errRep
+     *            ErrorReporter callback
+     * @param scInstance
+     *            The state chart instance
+     * @throws ModelException
+     *             in case there is a fatal SCXML object model problem.
+     */
+    public void processInvokes(final TriggerEvent[] events,
+            final ErrorReporter errRep, final SCInstance scInstance)
+    throws ModelException {
+        Set eventNames = new HashSet();
+        //for now, we only match against event names
+        for (int i = 0; i < events.length; i++) {
+            eventNames.add(events[i].getName());
+        }
+        for (Iterator invokeIter = scInstance.getInvokers().entrySet().
+                iterator(); invokeIter.hasNext();) {
+            Map.Entry iEntry = (Map.Entry) invokeIter.next();
+            String parentId = ((TransitionTarget) iEntry.getKey()).getId();
+            if (!finalizeMatch(parentId, eventNames)) { // prevent cycles
+                Invoker inv = (Invoker) iEntry.getValue();
+                try {
+                    inv.parentEvents(events);
+                } catch (InvokerException ie) {
+                    appLog.error(ie.getMessage(), ie);
+                    throw new ModelException(ie.getMessage(), ie.getCause());
+                }
+            }
+        }
+    }
+
+    /**
+     * Initiate any new invokes.
+     *
+     * @param step
+     *            The current Step
+     * @param errRep
+     *            ErrorReporter callback
+     * @param scInstance
+     *            The state chart instance
+     */
+    public void initiateInvokes(final Step step, final ErrorReporter errRep,
+            final SCInstance scInstance) {
+        Evaluator eval = scInstance.getEvaluator();
+        Collection internalEvents = step.getAfterStatus().getEvents();
+        for (Iterator iter = step.getAfterStatus().getStates().iterator();
+                iter.hasNext();) {
+            State s = (State) iter.next();
+            Context ctx = scInstance.getContext(s);
+            Invoke i = s.getInvoke();
+            if (i != null && scInstance.getInvoker(s) == null) {
+                String src = i.getSrc();
+                if (src == null) {
+                    String srcexpr = i.getSrcexpr();
+                    Object srcObj = null;
+                    try {
+                        srcObj = eval.eval(ctx, srcexpr);
+                        src = String.valueOf(srcObj);
+                    } catch (SCXMLExpressionException see) {
+                        errRep.onError(ErrorReporter.EXPRESSION_ERROR,
+                            see.getMessage(), i);
+                    }
+                }
+                String source = src;
+                PathResolver pr = i.getPathResolver();
+                if (pr != null) {
+                    source = i.getPathResolver().resolvePath(src);
+                }
+                String ttype = i.getTargettype();
+                Invoker inv = null;
+                try {
+                    inv = scInstance.newInvoker(ttype);
+                } catch (InvokerException ie) {
+                    TriggerEvent te = new TriggerEvent(s.getId()
+                        + ".invoke.failed", TriggerEvent.ERROR_EVENT);
+                    internalEvents.add(te);
+                    continue;
+                }
+                inv.setParentStateId(s.getId());
+                inv.setSCInstance(scInstance);
+                Map params = i.getParams();
+                Map args = new HashMap();
+                for (Iterator pIter = params.entrySet().iterator();
+                        pIter.hasNext();) {
+                    Map.Entry entry = (Map.Entry) pIter.next();
+                    String argName = (String) entry.getKey();
+                    String argExpr = (String) entry.getValue();
+                    Object argValue = null;
+                    if (argExpr != null && argExpr.trim().length() > 0) {
+                        try {
+                            argValue = eval.eval(ctx, argExpr);
+                        } catch (SCXMLExpressionException see) {
+                            errRep.onError(ErrorReporter.EXPRESSION_ERROR,
+                                see.getMessage(), i);
+                        }
+                    }
+                    args.put(argName, argValue);
+                }
+                try {
+                    inv.invoke(source, args);
+                } catch (InvokerException ie) {
+                    TriggerEvent te = new TriggerEvent(s.getId()
+                        + ".invoke.failed", TriggerEvent.ERROR_EVENT);
+                    internalEvents.add(te);
+                    continue;
+                }
+                scInstance.setInvoker(s, inv);
+            }
+        }
+    }
+
+    /**
+     * Implements prefix match, that is, if, for example,
+     * &quot;mouse.click&quot; is a member of eventOccurrences and a
+     * transition is triggered by &quot;mouse&quot;, the method returns true.
+     *
+     * @param transEvent
+     *            a trigger event of a transition
+     * @param eventOccurrences
+     *            current events
+     * @return true/false
+     */
+    protected boolean eventMatch(final String transEvent,
+            final Set eventOccurrences) {
+        if (SCXMLHelper.isStringEmpty(transEvent)) {
+            return true;
+        } else {
+            String transEventDot = transEvent + "."; // prefix event support
+            Iterator i = eventOccurrences.iterator();
+            while (i.hasNext()) {
+                String evt = (String) i.next();
+                if (evt == null) {
+                    continue; // Unnamed events
+                } else if (evt.equals("*")) {
+                    return true; // Wildcard
+                } else if (evt.equals(transEvent)
+                            || evt.startsWith(transEventDot)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Implements event prefix match to ascertain &lt;finalize&gt; execution.
+     *
+     * @param parentStateId
+     *            the ID of the parent state of the &lt;invoke&gt; holding
+     *            the &lt;finalize&gt;
+     * @param eventOccurrences
+     *            current events
+     * @return true/false
+     */
+    protected boolean finalizeMatch(final String parentStateId,
+            final Set eventOccurrences) {
+        String prefix = parentStateId + ".invoke."; // invoke prefix
+        Iterator i = eventOccurrences.iterator();
+        while (i.hasNext()) {
+            String evt = (String) i.next();
+            if (evt == null) {
+                continue; // Unnamed events
+            } else if (evt.startsWith(prefix)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**

Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java Mon Jun 19 23:06:49 2006
@@ -32,6 +32,7 @@
 import org.apache.commons.scxml.TriggerEvent;
 import org.apache.commons.scxml.env.SimpleDispatcher;
 import org.apache.commons.scxml.env.Tracer;
+import org.apache.commons.scxml.invoke.SimpleSCXMLInvoker;
 import org.apache.commons.scxml.io.SCXMLDigester;
 import org.apache.commons.scxml.io.SCXMLSerializer;
 import org.apache.commons.scxml.model.ModelException;
@@ -86,7 +87,7 @@
             System.out.println(SCXMLSerializer.serialize(doc));
             SCXMLExecutor exec = new SCXMLExecutor(evaluator, ed, trc);
             exec.addListener(doc, trc);
-            exec.setSuperStep(true);
+            exec.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
             exec.setRootContext(rootCtx);
             exec.setStateMachine(doc);
             exec.go();

Modified: jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/AllSCXMLTestSuite.java Mon Jun 19 23:06:49 2006
@@ -25,6 +25,7 @@
 import org.apache.commons.scxml.env.jexl.EnvJexlTestSuite;
 import org.apache.commons.scxml.env.jsp.EnvJspTestSuite;
 import org.apache.commons.scxml.env.servlet.EnvServletTestSuite;
+import org.apache.commons.scxml.invoke.InvokeTestSuite;
 import org.apache.commons.scxml.io.IOTestSuite;
 import org.apache.commons.scxml.model.ModelTestSuite;
 import org.apache.commons.scxml.semantics.SemanticsTestSuite;
@@ -62,6 +63,7 @@
         suite.addTest(EnvJspTestSuite.suite());
         suite.addTest(EnvServletTestSuite.suite());
         suite.addTest(EnvTestSuite.suite());
+        suite.addTest(InvokeTestSuite.suite());
         suite.addTest(IOTestSuite.suite());
         suite.addTest(ModelTestSuite.suite());
         suite.addTest(SCXMLTestSuite.suite());

Modified: jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCInstanceTest.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCInstanceTest.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCInstanceTest.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCInstanceTest.java Mon Jun 19 23:06:49 2006
@@ -47,7 +47,7 @@
     private SCInstance instance;
     
     public void setUp() {
-        instance = new SCInstance();
+        instance = new SCInstance(null);
     }
     
     public void testGetRootContextNull() {

Modified: jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCXMLTestHelper.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCXMLTestHelper.java?rev=415512&r1=415511&r2=415512&view=diff
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCXMLTestHelper.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/test/java/org/apache/commons/scxml/SCXMLTestHelper.java Mon Jun 19 23:06:49 2006
@@ -58,6 +58,8 @@
         try {
             scxml = SCXMLDigester.digest(url, errHandler, customActions);
         } catch (Exception e) {
+            Log log = LogFactory.getLog(SCXMLTestHelper.class);
+            log.error(e.getMessage(), e);
             Assert.fail(e.getMessage());
         }
         Assert.assertNotNull(scxml);
@@ -177,6 +179,8 @@
         try {
             exec.triggerEvents(evts);
         } catch (Exception e) {
+            Log log = LogFactory.getLog(SCXMLTestHelper.class);
+            log.error(e.getMessage(), e);
             Assert.fail(e.getMessage());
         }
         return exec.getCurrentStatus().getStates();
@@ -187,6 +191,8 @@
         try {
             exec.triggerEvents(evts);
         } catch (Exception e) {
+            Log log = LogFactory.getLog(SCXMLTestHelper.class);
+            log.error(e.getMessage(), e);
             Assert.fail(e.getMessage());
         }
         return exec.getCurrentStatus().getStates();
@@ -196,6 +202,8 @@
         try {
             exec.triggerEvents(evts);
         } catch (Exception e) {
+            Log log = LogFactory.getLog(SCXMLTestHelper.class);
+            log.error(e.getMessage(), e);
             Assert.fail(e.getMessage());
         }
         return exec.getCurrentStatus().getStates();



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message