You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shale.apache.org by cr...@apache.org on 2006/09/01 08:21:10 UTC

svn commit: r439203 - in /shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml: Globals.java ScxmlContext.java ScxmlContexts.java ShaleDialogELEvaluator.java config/ config/ConfigurationParser.java

Author: craigmcc
Date: Thu Aug 31 23:21:09 2006
New Revision: 439203

URL: http://svn.apache.org/viewvc?rev=439203&view=rev
Log:
Commit the proposed Commons SCXML based implementation of the sandbox
dialog2 APIs (see SHALE-263) as is, before doing any refactoring or
renaming.

Added:
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/Globals.java
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ShaleDialogELEvaluator.java
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/ConfigurationParser.java
Modified:
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContext.java
    shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContexts.java

Added: shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/Globals.java
URL: http://svn.apache.org/viewvc/shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/Globals.java?rev=439203&view=auto
==============================================================================
--- shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/Globals.java (added)
+++ shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/Globals.java Thu Aug 31 23:21:09 2006
@@ -0,0 +1,62 @@
+/*
+ * 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.shale.dialog2.scxml;
+
+/**
+ * <p>Manifest constants and well known event names for the
+ * Jakarta Commons SCXML driven Shale dialog implementation.</p>
+ *
+ * @since 1.0.4
+ */
+public class Globals {
+
+
+    /**
+     * <p>Context initialization paramater name under which a comma separated
+     * list of configuration resources to be parsed exists.</p>
+     */
+    public static final String CONFIGURATION =
+            "org.apache.shale.dialog2.scxml.CONFIGURATION";
+
+
+    /**
+     * <p>Application scope attribute under which a <code>Map</code> of
+     * {@link Dialog} definitions (keyed by dialog name) is stored.</p>
+     */
+    public static final String DIALOGS =
+            "org.apache.shale.dialog2.scxml.DIALOGS";
+
+
+    /**
+     * <p>The name of the postback event that the state machines should
+     * use to author transitions for, out of a "view" state.</p>
+     */
+    public static final String POSTBACK_EVENT =
+            "faces.outcome";
+
+
+    /**
+     * <p>The variable that holds the postback outcome in the root context
+     * of the state machine instance. Expressions within the SCXML document
+     * can then make references to this variable.</p>
+     */
+    public static final String POSTBACK_OUTCOME =
+            "outcome";
+
+}
+
+

Modified: shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContext.java
URL: http://svn.apache.org/viewvc/shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContext.java?rev=439203&r1=439202&r2=439203&view=diff
==============================================================================
--- shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContext.java (original)
+++ shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContext.java Thu Aug 31 23:21:09 2006
@@ -17,7 +17,18 @@
 package org.apache.shale.dialog2.scxml;
 
 import java.io.Serializable;
+import java.util.Iterator;
+
 import javax.faces.context.FacesContext;
+
+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.SimpleErrorReporter;
+import org.apache.commons.scxml.env.SimpleSCXMLListener;
+import org.apache.commons.scxml.model.ModelException;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.commons.scxml.model.State;
 import org.apache.shale.dialog2.Context;
 import org.apache.shale.dialog2.Contexts;
 
@@ -37,13 +48,31 @@
      * <p>Construct a new instance.</p>
      * 
      * @param instances {@link IContexts instance that owns us
+     * @param dialog The dialog's state machine (whose executable instance needs
+     *               to be created)
+     * @param name The dialog's logical name
      * @param id Dialog identifier assigned to this instance
-     * @param name Logical name of the dialog to be executed
      */
-    ScxmlContext(Contexts instances, String id, String name) {
+    ScxmlContext(Contexts instances, SCXML dialog, String name, String id) {
         this.instances = instances;
-        this.id = id;
         this.name = name;
+        this.id = id;
+
+        this.executor = new SCXMLExecutor(new ShaleDialogELEvaluator(),
+                        new SimpleDispatcher(), new SimpleErrorReporter());
+        this.executor.setStateMachine(dialog);
+        this.executor.addListener(dialog, new SimpleSCXMLListener());
+
+        // TODO - Consider adding an explicit root context backed by either the
+        // request or session map for greater EL capacities in the SCXML
+        // document describing this dialog
+
+        try {
+            this.executor.go();
+        } catch (ModelException me) {
+            // FIXME - Better exception
+            throw new IllegalArgumentException("SCXML dialog cannot start:" + name);
+        }
     }
     
 
@@ -80,6 +109,13 @@
     private String name = null;
 
 
+    /**
+     * <p>The {@link SCXMLExecutor}, an instance of the state machine
+     * defined for the SCXML document for this dialog.</p>
+     */
+    private SCXMLExecutor executor = null;
+ 
+
     // ----------------------------------------------------- Context Properties
 
 
@@ -119,7 +155,25 @@
 
     /** {@inheritDoc} */
     public String advance(FacesContext context, String outcome) {
-        return null; // FIXME - advance()
+
+        ((ShaleDialogELEvaluator) this.executor.getEvaluator()).
+                    setFacesContext(context);
+        this.executor.getRootContext().setLocal(Globals.POSTBACK_OUTCOME, outcome);
+
+        try {
+                this.executor.triggerEvent(new TriggerEvent(Globals.POSTBACK_EVENT,
+                                TriggerEvent.SIGNAL_EVENT));
+        } catch (ModelException me) {
+            // FIXME - Not an IAE
+                throw new IllegalArgumentException(me.getMessage());
+        }
+
+        // TODO - Re-evaluate before leaving sandbox
+        // Using C/C, "View" state ID is JSF viewId, which is an acceptable
+        // approach with Commons SCXML v0.5
+        Iterator iterator = this.executor.getCurrentStatus().getStates().iterator();
+        return ((State) iterator.next()).getId();
+
     }
 
 

Modified: shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContexts.java
URL: http://svn.apache.org/viewvc/shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContexts.java?rev=439203&r1=439202&r2=439203&view=diff
==============================================================================
--- shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContexts.java (original)
+++ shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ScxmlContexts.java Thu Aug 31 23:21:09 2006
@@ -18,10 +18,16 @@
 
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.Map;
+
+import javax.faces.FacesException;
 import javax.faces.context.FacesContext;
+
+import org.apache.commons.scxml.model.SCXML;
 import org.apache.shale.dialog2.Constants;
 import org.apache.shale.dialog2.Context;
 import org.apache.shale.dialog2.Contexts;
+import org.apache.shale.dialog2.scxml.config.ConfigurationParser;
 
 /**
  * <p>Implementation of {@link Contexts} for integrating
@@ -36,10 +42,17 @@
 
 
     /**
+     * <p><code>Map</code> of {@link SCXML} configurations, keyed
+     * by dialog name.  This value is lazily instantiated.</p>
+     */
+    private Map dialogs = null;
+
+
+    /**
      * <p>Map containing all currently active {@link Context} instances for
      * the current user.</p>
      */
-    private final HashMap map = new HashMap();
+    private final Map map = new HashMap();
 
 
     /**
@@ -53,7 +66,17 @@
 
     /** {@inheritDoc} */
     public Context create(FacesContext context, String name) {
-        ScxmlContext instance = new ScxmlContext(this, generateId(), name);
+
+        // Look up the specified dialog configuration
+        Map dialogs = dialogs(context);
+        SCXML dialog = (SCXML) dialogs.get(name);
+        if (dialog == null) {
+            throw new IllegalArgumentException("No definition for dialog name '"
+                                               + name + "' can be found");
+        }
+
+        // Configure a new ScxmlContext instance
+        ScxmlContext instance = new ScxmlContext(this, dialog, name, generateId());
         instance.setData(new HashMap());
         map.put(instance.getId(), instance);
         context.getExternalContext().getRequestMap().put(Constants.CONTEXT_BEAN, instance);
@@ -76,6 +99,67 @@
 
 
     // --------------------------------------------------------- Private Methods
+
+
+    /**
+     * <p>Return a <code>Map</code> of the configured {@link SCXML} instances,
+     * keyed by logical dialog name.  Upon the first request, the
+     * configuration resources will be processed.</p>
+     *
+     * @param context FacesContext for the current request
+     */
+    private Map dialogs(FacesContext context) {
+ 
+        // Return the cached instance (if any)
+        if (this.dialogs != null) {
+            return this.dialogs;
+        }
+
+        // Return the previously configured application scope instance (if any)
+        this.dialogs = (Map)
+          context.getExternalContext().getApplicationMap().get(Globals.DIALOGS);
+        if (this.dialogs != null) {
+            return this.dialogs;
+        }
+
+        // Parse our configuration resources and cache the results
+        ConfigurationParser parser = new ConfigurationParser();
+        parser.setDialogs(new HashMap());
+        String resources =
+          context.getExternalContext().getInitParameter(Globals.CONFIGURATION);
+        if (resources == null) {
+            resources = "";
+        }
+        int comma = 0;
+        String path = null;
+        try {
+            while (true) {
+                comma = resources.indexOf(",");
+                if (comma < 0) {
+                    path = resources.trim();
+                    resources = "";
+                } else {
+                    path = resources.substring(0, comma).trim();
+                    resources = resources.substring(comma + 1);
+                }
+                if (path.length() < 1) {
+                    break;
+                }
+                parser.setResource(context.getExternalContext().getResource(path));
+                parser.parse();
+            }
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new FacesException(e);
+        }
+
+        // Cache the results both locally and in application scope
+        this.dialogs = parser.getDialogs();
+        context.getExternalContext().getApplicationMap().put(Globals.DIALOGS, this.dialogs);
+        return this.dialogs;
+
+    }
 
 
     /**

Added: shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ShaleDialogELEvaluator.java
URL: http://svn.apache.org/viewvc/shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ShaleDialogELEvaluator.java?rev=439203&view=auto
==============================================================================
--- shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ShaleDialogELEvaluator.java (added)
+++ shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/ShaleDialogELEvaluator.java Thu Aug 31 23:21:09 2006
@@ -0,0 +1,160 @@
+/*
+ *
+ *   Copyright 2005-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.shale.dialog2.scxml;
+
+import java.util.regex.Pattern;
+
+import javax.faces.context.FacesContext;
+import javax.faces.el.EvaluationException;
+import javax.faces.el.MethodBinding;
+import javax.faces.el.MethodNotFoundException;
+import javax.faces.el.ReferenceSyntaxException;
+
+import org.apache.commons.scxml.Context;
+import org.apache.commons.scxml.SCXMLExpressionException;
+import org.apache.commons.scxml.env.jsp.ELEvaluator;
+
+
+/**
+ * <p>EL evaluator, for evaluating the expressions in SCXML documents used
+ * to specify Shale dialogs.</p>
+ *
+ * <p>This evaluator uses the following premises for evaluation:
+ *   <ol>
+ *     <li>JSF method binding expressions will take the form:
+ *         #{...}
+ *         These will return a <code>java.lang.String</code> object as
+ *         required by the methods associated with
+ *         <code>org.apache.shale.dialog.ActionState</code></li>
+ *     <li>JSP 2.0 EL expressions will take the form:
+ *         ${...}</li>
+ *   </ol>
+ * </p>
+ *
+ * <p>This evaluator delegates to the following expression evaluators:
+ *   <ol>
+ *     <li>JSF method binding expressions get delegated to the JSF
+ *         implementation (Ex: Apache MyFaces).</li>
+ *     <li>JSP expressions get delegated to the Apache Jakarta Commons
+ *         EL ExpressionEvaluator implementation. This evaluator adds
+ *         ability to evaluate special predicates defined by SCXML.</li>
+ *   </ol>
+ * </p>
+ */
+
+public class ShaleDialogELEvaluator extends ELEvaluator {
+
+
+    /**
+     * Shale ActionState method parameters.
+     */
+    private static final Object[] PARAMETERS = new Object[0];
+
+
+    /**
+     * Shale ActionState method signature.
+     */
+    private static final Class[] SIGNATURE = new Class[0];
+
+
+    // We do not have the privilege of having specific element attributes
+    // associated with specific types of expressions
+    /** Pattern for recognizing the method / value binding expression. */
+    private static Pattern jsfBindingExpr =
+        Pattern.compile("^//s*#//{.*//}//s*$");
+
+
+    /** FacesContext for this request. */
+    private FacesContext context;
+
+
+    /**
+     * Constructor.
+     */
+    public ShaleDialogELEvaluator() {
+        super();
+        this.context = null;
+    }
+
+
+    /**
+     * Set per request context.
+     *
+     * @param context The FacesContext for this request.
+     */
+    public void setFacesContext(final FacesContext context) {
+        this.context = context;
+    }
+
+
+    /**
+     * Evaluate an expression.
+     *
+     * @param ctx variable context
+     * @param expr expression
+     * @return Object The result of the evaluation
+     * @throws SCXMLExpressionException For a malformed expression
+     * @see ELEvaluator#eval(Context, String)
+     */
+    public Object eval(final Context ctx, final String expr)
+    throws SCXMLExpressionException {
+
+        if (jsfBindingExpr.matcher(expr).matches()) {
+            return invokeShaleActionStateMethod(expr);
+        }
+
+        return super.eval(ctx, expr);
+    }
+
+
+    /**
+     * Invoke method binding expression for Shale <code>ActionState</code>.
+     * Shale requires return type to be a <code>java.lang.String</code>.
+     *
+     * @param expr Method binding expression
+     * @return String Method return value
+     * @throws SCXMLExpressionException Re-throw potential Faces
+     *                  exceptions as a SCXMLExpressionException.
+     */
+    private String invokeShaleActionStateMethod(final String expr)
+    throws SCXMLExpressionException {
+
+        try {
+
+            MethodBinding mb = context.getApplication().
+                createMethodBinding(expr, SIGNATURE);
+            return (String) mb.invoke(context, PARAMETERS);
+
+        //Rethrow any exception as SCXMLExpressionException instance
+        } catch (ReferenceSyntaxException rse) {
+
+            throw new SCXMLExpressionException(rse.getMessage(), rse);
+
+        } catch (MethodNotFoundException mnfe) {
+
+            throw new SCXMLExpressionException(mnfe.getMessage(), mnfe);
+
+        } catch (EvaluationException ee) {
+
+            throw new SCXMLExpressionException(ee.getMessage(), ee);
+
+        }
+    }
+
+}

Added: shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/ConfigurationParser.java
URL: http://svn.apache.org/viewvc/shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/ConfigurationParser.java?rev=439203&view=auto
==============================================================================
--- shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/ConfigurationParser.java (added)
+++ shale/sandbox/shale-dialog2-scxml/src/main/java/org/apache/shale/dialog2/scxml/config/ConfigurationParser.java Thu Aug 31 23:21:09 2006
@@ -0,0 +1,266 @@
+/*
+ * 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.shale.dialog2.scxml.config;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+import org.apache.commons.scxml.env.SimpleErrorHandler;
+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.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * <p>Configuration utility for parsing SCXML documents as resources for
+ * defining dialogs.  This class has no dependencies on web tier APIs,
+ * only on the Commons SCXML state machine engine library, and
+ * on the parsing technology (Commons Digester) being used.</p>
+ *
+ * <p>TODO: Review Javadocs below if moved out of sandbox.
+ * The configuration for each Shale dialog exists as a standalone
+ * SCXML document, with additional dialog "metadata" file(s)
+ * that serve as the entry point for the Shale Dialog Manager.</p>
+ *
+ * <p>The analogy to the legacy dialog-config.xml file(s) are
+ * scxml-config.xml(s) that look like this:
+ * &lt;scxmldialogs&gt;
+ *     &lt;dialog name="Foo" scxmlconfig="foo.scxml" /&gt;
+ *     &lt;dialog name="Bar" scxmlconfig="bar.scxml" /&gt;
+ *     &lt;dialog name="Baz" scxmlconfig="baz.scxml" /&gt;
+ *     &lt;!-- etc. --&gt;
+ * &lt;/scxmldialogs&gt;
+ * </p>
+ *
+ * <p>To use this utility, instantiate a new instance and set the
+ * <code>dialogs</code>, <code>resource</code>, and <code>validating</code>
+ * properties.  Then, call the <code>parse()</code> method.  You can parse
+ * more than one resource by resetting the <code>resource</code>
+ * property and calling <code>parse()</code> again.</p>
+ *
+ * @since 1.0.4
+ */
+
+public final class ConfigurationParser {
+
+
+    // -------------------------------------------------------------- Properties
+
+    /**
+     * <p><code>Map</code> of <code>Dialog</code> instances resulting
+     * from parsing, keyed by dialog name.</p>
+     */
+    private Map dialogs = null;
+
+
+    /**
+     * <p>Return the <code>Map</code> of <code>Dialog</code> instances
+     * into which parsed information will be stored, keyed by dialog
+     * name.</p>
+     */
+    public Map getDialogs() {
+        return this.dialogs;
+    }
+
+
+    /**
+     * <p>Set the <code>Map</code> of <code>Dialog</code> instances
+     * into which parsed information will be stored, keyed by dialog
+     * name.</p>
+     *
+     * @param dialogs The new map
+     */
+    public void setDialogs(Map dialogs) {
+        this.dialogs = dialogs;
+    }
+
+
+    /**
+     * <p>The URL of the configuration resource to be parsed.</p>
+     */
+    private URL resource = null;
+
+
+    /**
+     * <p>Return the URL of the configuration resource to be parsed.</p>
+     */
+    public URL getResource() {
+        return this.resource;
+    }
+
+
+    /**
+     * <p>Set the URL of the configuration resource to be parsed.</p>
+     *
+     * @param resource The new resource URL
+     */
+    public void setResource(URL resource) {
+        this.resource = resource;
+    }
+
+
+    /**
+     * <p>Flag indicating whether we should do a validating parse or not.</p>
+     * FIXME - Change to true (also in Javadoc below), see to do listed below.
+     */
+    private boolean validating = false;
+
+
+    /**
+     * <p>Return a flag indicating whether we will be doing a validating parse
+     * or not.  Default value is <code>false</code>.</p>
+     */
+    public boolean isValidating() {
+        return this.validating;
+    }
+
+
+    /**
+     * <p>Set a flag indicating whether we will be doing a validating parse
+     * or not.</p>
+     *
+     * @param validating New flag value
+     */
+    public void setValidating(boolean validating) {
+        // TODO:
+        // Need a scxml-config DTD for Shale, ignore validity check requests
+        // Will need to be fixed if this class comes out of sandbox
+        //this.validating = validating;
+    }
+
+
+    // ---------------------------------------------------------- Public Methods
+
+
+    /**
+     * <p>Parse the configuration resource identified by the <code>resource</code>
+     * property, storing resulting information in the <code>Map</code> specified
+     * by the <code>dialogs</code> property.</p>
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception SAXException if an XML parsing error occurs
+     */
+    public void parse() throws IOException, SAXException {
+
+        Map metadata = new HashMap();
+        Digester digester = digester();
+        digester.clear();
+        digester.push(metadata);
+        InputSource source = new InputSource(getResource().toExternalForm());
+        source.setByteStream(getResource().openStream());
+        digester.parse(source);
+
+        parseDialogs(metadata);
+    }
+
+
+    // --------------------------------------------------------- Private Methods
+
+
+    /**
+     * <p>Return a fully configured <code>Digester</code> instance.</p>
+     */
+    private Digester digester() {
+
+        Digester digester = new Digester();
+
+        // Configure global characteristics
+        digester.setNamespaceAware(false);
+        digester.setUseContextClassLoader(true);
+        digester.setValidating(isValidating());
+
+        // Configure processing rules
+
+        // scxmldialogs/dialog
+        digester.addRule("scxmldialogs/dialog", new AddDialogMetadataRule());
+
+       return digester;
+
+    }
+
+
+    /**
+     * <p>Parse an individual SCXML document, storing resulting information
+     * as an entry in the <code>Map</code> specified by the <code>dialogs</code>
+     * property.</p>
+     */
+    private void parseDialogs(Map metadata) throws IOException, SAXException {
+
+        Iterator iterator = metadata.entrySet().iterator();
+
+        while (iterator.hasNext()) {
+
+                Map.Entry entry = (Map.Entry) iterator.next();
+                String name = (String) entry.getKey();
+                String scxmlconfig = (String) entry.getValue();
+
+                // TODO - Relative URL testing
+                URL resource = new URL(getResource(), scxmlconfig);
+                InputSource source = new InputSource(resource.toExternalForm());
+                source.setByteStream(resource.openStream());
+
+                SCXML dialog = null;
+                try {
+                    dialog = SCXMLDigester.digest(source, new SimpleErrorHandler());
+                } catch (ModelException me) {
+                    throw new SAXException(me.getMessage(), me);
+                }
+
+                dialogs.put(name, dialog);
+
+        }
+
+    }
+
+
+    // -------------------------------------------- Private Rule Implementations
+
+
+    /**
+     * <p>Custom <code>Digester</code> rule to add a dialog.</p>
+     */
+    static class AddDialogMetadataRule extends Rule {
+
+        /**
+         * Constructor.
+         */
+        public AddDialogMetadataRule() {
+            super();
+        }
+
+        /**
+         * @see Rule#begin(String, String, Attributes)
+         */
+        public final void begin(final String namespace, final String qname,
+                final Attributes attributes) {
+
+            Map metadata = (Map) getDigester().peek();
+            metadata.put(attributes.getValue("name"),
+                        attributes.getValue("scxmlconfig"));
+
+        }
+
+    }
+
+}