You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ra...@apache.org on 2005/10/15 04:41:25 UTC

svn commit: r321280 - in /jakarta/commons/sandbox/scxml/trunk: ./ xdocs/ xdocs/usecases/ xdocs/usecases/shale-dialogs/

Author: rahul
Date: Fri Oct 14 19:41:20 2005
New Revision: 321280

URL: http://svn.apache.org/viewcvs?rev=321280&view=rev
Log:
The second illustrated usecase for Commons SCXML is Shale dialogs.

The content in this commit is just a port of:

http://people.apache.org/~rahul/scxml-in-shale/ 
*time sensitive URL*

with some changes based on comments from Craig on dev@struts.

Added:
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml   (with props)
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml   (with props)
Modified:
    jakarta/commons/sandbox/scxml/trunk/project.properties
    jakarta/commons/sandbox/scxml/trunk/xdocs/navigation.xml
    jakarta/commons/sandbox/scxml/trunk/xdocs/usecases.xml

Modified: jakarta/commons/sandbox/scxml/trunk/project.properties
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/project.properties?rev=321280&r1=321279&r2=321280&view=diff
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/project.properties (original)
+++ jakarta/commons/sandbox/scxml/trunk/project.properties Fri Oct 14 19:41:20 2005
@@ -18,7 +18,7 @@
 maven.xdoc.version=${pom.currentVersion}
 maven.xdoc.developmentProcessUrl=http://jakarta.apache.org/commons/charter.html
 maven.xdoc.includeProjectDocumentation=yes
-maven.xdoc.xml.copy=usecases/rdc-group/*.xml
+maven.xdoc.xml.copy=usecases/rdc-group/*.xml,usecases/shale-dialogs/*.xml
 
 maven.javadoc.links=http://java.sun.com/j2se/1.4.2/docs/api/
 

Modified: jakarta/commons/sandbox/scxml/trunk/xdocs/navigation.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/navigation.xml?rev=321280&r1=321279&r2=321280&view=diff
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/navigation.xml (original)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/navigation.xml Fri Oct 14 19:41:20 2005
@@ -27,6 +27,9 @@
         <item     name="SCXML in RDC group container"  
                   href="/usecases/scxml-in-rdc-group.html" />
 
+        <item     name="SCXML in Shale dialogs"        
+                  href="/usecases/scxml-in-shale-dialogs.html" />
+
       </item>
 
     </menu>

Modified: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases.xml?rev=321280&r1=321279&r2=321280&view=diff
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases.xml (original)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases.xml Fri Oct 14 19:41:20 2005
@@ -49,6 +49,8 @@
      <a href="http://jakarta.apache.org/taglibs/doc/rdc-doc/intro.html">
      Reusable Dialog Components (RDC) Framework</a> &lt;group&gt;
      container.</li>
+     <li><a href="usecases/scxml-in-shale-dialogs.html">Usecase 2</a> -
+     Use in <a href="http://struts.apache.org/shale">Shale</a> dialogs</li>
     </ul>
    </p>
    <br/>

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml Fri Oct 14 19:41:20 2005
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Copyright 2003-2004 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.
+-->
+
+<document>
+
+ <properties>
+  <title>Commons SCXML Usecases - Shale dialogs</title>
+  <author email="commons-dev@jakarta.apache.org">Commons Documentation Team</author>
+ </properties>
+
+ <body>
+
+  <section name="SCXML documents to describe Shale dialogs">
+
+   <p><a href="http://struts.apache.org/shale">Shale</a> is
+   &quot;<i>a proposal for a modern web application framework, fundamentaly
+   based on JavaServer Faces</i>&quot;. The Shale Framework includes a Dialog
+   Manager, to describe &quot;conversations&quot; or &quot;dialogs&quot;
+   (involving multiple views) with the user. Such a dialog is described
+   using a state-machine like declarative notation defined by the Shale
+   Framework. An alternative is using SCXML to describe the Shale dialogs
+   by introducing a <code>DialogNavigationHandler</code> that uses the
+   Commons SCXML engine.
+   </p>
+
+   <subsection name="Motivation">
+    <ul>
+     <li>SCXML semantics support parallelism, allowing multiple dialogs
+     to execute at the same time (a.k.a regions), and interact with each
+     other. This will be useful as Shale Dialog Managers evolve.</li>
+     <li>The Commons SCXML implementation allows for registering listeners
+     that get notified as the state machine executes (onentry, onexit,
+     ontransition).</li>
+     <li>Those developing multi-channel applications, or using frameworks
+     that use SCXML for the controller bits in other contexts (e.g. 
+     RDC framework), may be inclined towards SCXML-based authoring for Shale
+     dialogs.</li>
+    </ul>
+   </subsection>
+
+   <subsection name="Proof of concept">
+    <p>There are two war files below, the first one uses SCXML
+    documents to describe the Shale dialogs, and the second
+    one is the Shale source distro as-is, built locally
+    (use cases of interest are the log on / create profile dialogs).
+    <ul>
+     <!-- 
+          The next two links point to my personal web space since I
+          was not too keen on polluting the Commons SCXML space in SVN
+          with usecases war files.
+     -->
+     <li><a href="http://people.apache.org/~rahul/scxml-in-shale/struts-shale-usecases-scxml.war">
+     struts-shale-usecases-scxml.war</a>
+     - Shale usecases war file with SCXML dialogs (note absence of
+     <code>dialog-config.xml</code> in <code>WEB-INF/</code>, since
+     SCXML documents are used to describe the Shale dialogs instead)</li>
+     <li><a href="http://people.apache.org/~rahul/scxml-in-shale/struts-shale-usecases.war">
+     struts-shale-usecases.war</a>
+     - Shale usecases war file (09/28/05 snapshot, not an official
+     nightly build)</li>
+    </ul>
+    </p>
+  </subsection>
+
+  <subsection name="Building">
+   <p>For the proof of concept, we delegate the SCXML documents based
+   Shale Dialog Management to a 
+   &quot;<code>SCXMLDialogNavigationHandler</code>&quot;, instead of
+   the <code>DialogNavigationHandler</code> in <code>shale-core</code>.
+   </p>
+
+   <p>Some of the Javadoc is reproduced here:</p>
+
+   <p>Recipe for using SCXML documents to drive Shale dialogs:
+    <ol>
+     <li>Build the <code>SCXMLDialogNavigationHandler</code> (available
+     below, use a Commons SCXML nightly build 10/09/05 or later) and make it
+     available to your web application classpath (<code>WEB-INF/classes</code>).
+     </li>
+     <li>Update the &quot;<code>WEB-INF/faces-config.xml</code>&quot;
+     for your web application such that the
+     &quot;<code>faces-config/application/navigation-handler</code>&quot;
+     entry points to
+     &quot;<code>org.apache.commons.scxml.usecases.SCXMLDialogNavigationHandler</code>&quot;
+     (with the appropriate package name, if you changed it).
+     </li>
+     <li>As an alternative to (1) and (2), you can place a <i>jar</i> in the 
+     <code>WEB-INF/lib</code> directory which contains the
+     <code>SCXMLDialogNavigationHandler</code> and a
+     <code>META-INF/faces-config.xml</code> with just the entry in (2).</li>
+     <li>Use SCXML documents to describe Shale dialog flows (details below)
+     in your application. You may have multiple mappings from transition
+     targets to JSF views to support multi-channel applications.</li>
+     <li>The SCXML-based dialog is entered when
+     <code>handleNavigation()</code> is called with a logical outcome
+     of the form &quot;<code>dialog:xxx</code>&quot; and there is no current
+     dialog in progress, where &quot;<code>xxx</code>&quot; is the URL pointing
+     to the SCXML document.</li>
+    </ol>
+   </p>
+
+   <p>Using SCXML documents to define the Shale dialog &quot;flows&quot;:
+    <ul>
+     <li>ActionState instances may be mapped to executable content
+     in UML <code>&lt;onentry&gt;</code> (and may be chained similarly).</li>
+     <li>ViewState instances may be mapped to UML transition
+     targets.</li>
+     <li>SubdialogState instances may be mapped to external SCXML
+     documents.</li>
+     <li>EndState instances may be mapped to SCXML final states.</li>
+     <li>The SCXMLDialogNavigationHandler defines a
+     <code>&quot;faces.outcome&quot;</code> event which the relevant SCXML
+     transitions from a &quot;view state&quot; can wait for.</li>
+    </ul>
+   </p>
+   </subsection>
+
+   <subsection name="Artifacts">
+   <p>Relevant artifacts:
+   <ol>
+    <li><a href="shale-dialogs/SCXMLDialogNavigationHandler.java">
+    SCXMLDialogNavigationHandler.java</a></li>
+    <li><a href="shale-dialogs/SCXMLDialogNavigationHandler.java.txt">
+    SCXMLDialogNavigationHandler.java.txt</a>
+    (for browsers that insist of enforcing mime-type by filename 
+    extension)</li>
+    <li><a href="shale-dialogs/dialog-config.xml">dialog-config.xml</a>
+    (from Shale distro, 09/28/05 snapshot)</li>
+    <li><a href="shale-dialogs/log-on-config.xml">log-on-config.xml</a>
+    (SCXML document describing the &quot;Log On&quot; dialog)</li>
+    <li><a href="shale-dialogs/edit-profile-config.xml">
+    edit-profile-config.xml</a> (SCXML document describing
+    the &quot;Edit Profile&quot; dialog)</li>
+    <li><a href="shale-dialogs/dialogstate2view.xml">dialogstate2view.xml</a>
+    (Map UML states and activities)</li>
+   </ol>
+   </p>
+   </subsection>
+
+  </section> 
+
+ </body>
+
+</document>

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/scxml-in-shale-dialogs.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java Fri Oct 14 19:41:20 2005
@@ -0,0 +1,509 @@
+/*
+ * Copyright 2004-2005 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.
+ */
+/*
+ * You may build in a package on your choice. Dependency information:
+ *
+ * Commons SCXML dependencies -
+ * http://jakarta.apache.org/commons/sandbox/scxml/dependencies.html
+ *
+ * Struts Shale dependencies -
+ * http://struts.apache.org/shale/ 
+ * (Currently under "Foundations" section)
+ */
+package org.apache.commons.scxml.usecases;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.scxml.SCXMLDigester;
+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.env.SimpleSCXMLListener;
+import org.apache.commons.scxml.env.faces.SessionContext;
+import org.apache.commons.scxml.env.faces.ShaleDialogELEvaluator;
+import org.apache.commons.scxml.model.ModelException;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.commons.scxml.model.TransitionTarget;
+
+import org.apache.shale.dialog.Globals;
+import org.apache.shale.dialog.Status;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+
+/**
+ * <p>SCXML configuration file(s) driven Shale dialog navigation handler.</p>
+ *
+ * <p>Recipe for using SCXML documents to drive Shale dialogs:
+ *   <ol>
+ *    <li>Build the <code>SCXMLDialogNavigationHandler</code> (available
+ *     below, use a Commons SCXML nightly build 10/09/05 or later) and make it
+ *     available to your web application classpath (<code>WEB-INF/classes</code>).
+ *    </li>
+ *    <li>Update the &quot;<code>WEB-INF/faces-config.xml</code>&quot;
+ *     for your web application such that the
+ *     &quot;<code>faces-config/application/navigation-handler</code>&quot;
+ *     entry points to
+ *     &quot;<code>org.apache.commons.scxml.usecases.SCXMLDialogNavigationHandler</code>&quot;
+ *     (with the appropriate package name, if you changed it).
+ *    </li>
+ *    <li>As an alternative to (1) and (2), you can place a <i>jar</i> in the 
+ *     <code>WEB-INF/lib</code> directory which contains the
+ *     <code>SCXMLDialogNavigationHandler</code> and a
+ *     <code>META-INF/faces-config.xml</code> with just the entry in (2).</li>
+ *    <li>Use SCXML documents to describe Shale dialog flows (details below)
+ *     in your application. You may have multiple mappings from transition
+ *     targets to JSF views to support multi-channel applications.</li>
+ *    <li>The SCXML-based dialog is entered when
+ *     <code>handleNavigation()</code> is called with a logical outcome
+ *     of the form &quot;<code>dialog:xxx</code>&quot; and there is no current
+ *     dialog in progress, where &quot;<code>xxx</code>&quot; is the URL pointing
+ *     to the SCXML document.</li>
+ *   </ol>
+ * </p>
+ *
+ * <p>Using SCXML documents to define the Shale dialog "flows":
+ *   <ul>
+ *     <li>ActionState instances may be mapped to executable content
+ *         in UML &lt;onentry&gt (and may be chained similarly).</li>
+ *     <li>ViewState instances may be mapped to UML transition
+ *         targets.</li>
+ *     <li>SubdialogState instances may be mapped to external SCXML
+ *         documents.</li>
+ *     <li>EndState instances may be mapped to SCXML final states.</li>
+ *     <li>The {@link SCXMLDialogNavigationHandler} defines a
+ *         &quot;faces.outcome&quot; event which the relevant SCXML
+ *         transitions from a &quot;view state&quot; can wait for.</li>
+ *   </ul>
+ * </p>
+ *
+ * <p>Towards pluggable dialog management in Shale - A &quot;black box&quot;
+ *    dialog may consist of the following tuple:
+ *   <ul>
+ *     <li>Unique dialog identifier</li>
+ *     <li>A generic NavigationHandler (i.e. dialog strategy)</li>
+ *     <li>An dialog/flow configuration resource (Ex: SCXML document)</li>
+ *     <li>Optionally, multiple other configuration resources,
+ *      (Ex: one for each channel - web, voice, small device, etc.)</li>
+ *   </ul>
+ *    The Shale DialogNavigationHandler may then delegate appropriately.
+ * </p>
+ */
+public final class SCXMLDialogNavigationHandler extends NavigationHandler {
+
+    // ------------------------------------------------------------ Constructors
+    /**
+     * <p>Create a new {@link SCXMLDialogNavigationHandler}, wrapping the
+     * specified standard navigation handler implementation.</p>
+     *
+     * @param handler Standard <code>NavigationHandler</code> we are wrapping
+     */
+    public SCXMLDialogNavigationHandler(NavigationHandler handler) {
+
+        this.handler = handler;
+
+    }
+
+    // -------------------------------------------------------- Static Variables
+    /**
+     * <p>The prefix on a logical outcome String that indicates the remainder
+     * of the string is the URL of a SCXML-based Shale dialog to be entered.</p>
+     */
+    public static final String PREFIX = "dialog:";
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The standard <code>NavigationHandler</code> implementation that
+     * we are wrapping.</p>
+     */
+    private NavigationHandler handler = null;
+
+    /**
+     * <p>The <code>Log</code> instance for this class.</p>
+     */
+    private final Log log = LogFactory.getLog(getClass());
+
+    /**
+     * <p>Key under which we will store the SCXMLExecutor (more generally,
+     * some session scoped state pertaining to the current dialog).</p>
+     */
+    private String dialogKey = null; // Cached on first use
+
+    /**
+     * <p>Map storing SCXML state IDs as keys and JSF view IDs as values.</p>
+     */
+    private Map target2viewMap = null;
+
+    // ----------------------------------------------- NavigationHandler Methods
+
+    /**
+     * <p>Handle the navigation request implied by the specified parameters.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param fromAction The action binding expression that was evaluated
+     *  to retrieve the specified outcome (if any)
+     * @param outcome The logical outcome returned by the specified action
+     *
+     * @exception IllegalArgumentException if the configuration information
+     *  for a previously saved position cannot be found
+     * @exception IllegalArgumentException if an unknown State type is found
+     */
+    public void handleNavigation(FacesContext context, String fromAction,
+                                 String outcome) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("handleNavigation(viewId=" +
+                      context.getViewRoot().getViewId() +
+                      ",fromAction=" + fromAction +
+                      ",outcome=" + outcome + ")");
+        }
+
+        SCXMLExecutor exec = getDialogExecutor(context);
+        String viewId = null;
+        
+        if (exec == null && outcome != null && outcome.startsWith(PREFIX)) {
+        	
+        	/**** DIALOG ENTRY ****/
+        	// dialog is a state machine, parse & obtain an executor
+        	exec = initDialogExecutor(context, outcome.substring(PREFIX.
+        			length()));
+
+        	if (exec != null) {
+        		// cache executor in session scope
+        		// TODO: Shale caches Dialog instances. SCXMLExecutor
+        		// knows what state(s) the dialog is in, so Dialog#findState()
+        		// is not needed.
+        		setDialogExecutor(context, exec);
+        		// obtain our initial view
+        		viewId = getCurrentViewId(exec);
+        	}
+        	// else delegate
+        	
+        } else if (exec != null) {
+        	
+        	/**** SUBSEQUENT TURNS OF DIALOG ****/
+        	// pass a handle to the current ctx (for evaluating binding exprs)
+        	updateEvaluator(context, outcome);
+        	// fire a "faces.outcome" event on the dialog's state machine
+        	TriggerEvent[] te = { new TriggerEvent("faces.outcome",
+        			TriggerEvent.SIGNAL_EVENT) };
+        	try {
+        		exec.triggerEvents(te);
+        	} catch (ModelException me) {
+        		log.error(me.getMessage(), me);
+        	}
+        	// obtain next view
+        	viewId = getCurrentViewId(exec);
+        }
+
+        if (viewId != null) {
+        
+        	// we understood this "outcome" and we have a new view to render
+        	log.info("Rendering view: " + viewId);
+        	updateDialogStatus(context, exec);
+        	render(context, viewId);
+
+        } else {
+        
+        	/**** DELEGATE BY DEFAULT ****/
+        	handler.handleNavigation(context, fromAction, outcome);
+
+        }
+
+
+    }
+
+    /**
+     * <p>Return the SCXMLExecutor for the specified SCXML document, if it
+     * exists; otherwise, return <code>null</code>.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param dialogIdentifier URL of the SCXML document for the requested
+     *                         dialog
+     */
+    private SCXMLExecutor initDialogExecutor(FacesContext context,
+    		String dialogIdentifier) {
+
+        assert context != null;
+        assert dialogIdentifier != null;
+        
+        // We're parsing the SCXML dialog just in time here
+        URL scxmlDocument = null;
+        try {
+        	scxmlDocument = context.getExternalContext().
+				getResource(dialogIdentifier);
+        } catch (MalformedURLException mue) {
+        	log.error(mue.getMessage(), mue);
+        }
+
+        if (scxmlDocument == null) {
+        	log.warn("No SCXML document at: " + dialogIdentifier);
+        	return null;
+        }
+        
+        SCXML scxml = null;
+        ShaleDialogELEvaluator evaluator = new ShaleDialogELEvaluator();
+        evaluator.setFacesContext(context);
+        try {
+            scxml = SCXMLDigester.digest(scxmlDocument,
+            		new SimpleErrorHandler(), new SessionContext(context),
+                	evaluator);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        if (scxml == null) {
+        	log.warn("Could not parse SCXML document at: " + dialogIdentifier);
+        	return null;
+        }
+        
+        SCXMLExecutor exec = null;
+        try {
+            exec = new SCXMLExecutor(evaluator, new SimpleDispatcher(),
+            		new SimpleErrorReporter());
+            scxml.addListener(new SimpleSCXMLListener());
+            exec.setSuperStep(true);
+            exec.setStateMachine(scxml);
+        } catch (ModelException me) {
+        	log.warn(me.getMessage(), me);
+        	return null;
+        }
+        
+        // read SCXML state IDs to JSF view IDs map, channel dependent
+        readState2ViewMap(context, dialogIdentifier, null);
+        
+        // FIXME: Remove dependence on the org.apache.shale.dialog.impl package
+        // below (introduced so we can reuse the existing StatusImpl and the
+        // AbstractFacesBean subtypes in the usecases war for the proof of
+        // concept).
+        // Ignoring STATUS_PARAM since usecases war doesn't use it for the
+        // log on / edit profile dialogs.
+        // TODO: The next line should be Dialog Manager implementation agnostic
+        Status status =	new org.apache.shale.dialog.impl.StatusImpl();
+
+        context.getExternalContext().getSessionMap().put(Globals.STATUS, status);
+        status.push(new Status.Position(dialogIdentifier, getCurrentViewId(exec)));
+        
+        return exec;
+        
+    }
+
+    /**
+     * <p>Set the {@link SCXMLExecutor} instance for the current user.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param exec <code>SCXMLExecutor</code> that will run the dialog
+     */
+    private void setDialogExecutor(FacesContext context, SCXMLExecutor exec) {
+
+    	assert context != null;
+    	assert exec != null;
+    	
+        Map map = context.getExternalContext().getSessionMap();
+        String key = getDialogKey(context);
+        assert key != null;
+        map.put(key, exec);
+        
+    }
+
+    /**
+     * <p>Return the {@link SCXMLExecutor} instance for the current user.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     */
+    private SCXMLExecutor getDialogExecutor(FacesContext context) {
+
+        assert context != null;
+
+        Map map = context.getExternalContext().getSessionMap();
+        String key = getDialogKey(context);
+        return (SCXMLExecutor) map.get(key);
+
+    }
+
+    /**
+     * Update evaluator with current FacesContext for evaluation of
+     * binding expressions used in Shale dialog.
+     */
+    private void updateEvaluator(FacesContext context, String outcome) {
+    	
+    	assert context != null;
+    	
+    	((ShaleDialogELEvaluator) getDialogExecutor(context).getEvaluator()).
+			setFacesContext(context);
+    	context.getExternalContext().getSessionMap().put("outcome", outcome);
+    }
+
+    /**
+     * Update dialog Status
+     * 
+     * @param context The FacesContext
+     * @param exec The SCXMLExecutor
+     */
+    private void updateDialogStatus(FacesContext context, SCXMLExecutor exec) {
+    	
+    	assert context != null;
+    	assert exec != null;
+    	
+    	// TODO: Test this
+    	Status status = (Status) context.getExternalContext().getSessionMap().
+			get(Globals.STATUS);
+    	if (exec.getCurrentStatus().isFinal()) {
+            setDialogExecutor(context, null);
+            status.pop();
+    	} else {
+            status.peek().setStateName(getCurrentViewId(exec));
+    	}
+    }
+
+    /**
+     * Get next view to render, assuming one view at a time. 
+     *
+     * @param currentStates The set of current states
+     * @return String The JSF viewId of the next view
+     */
+    private String getCurrentViewId(SCXMLExecutor exec) {
+    	
+    	assert exec != null;
+    	
+    	Set currentStates = exec.getCurrentStatus().getStates();
+    	for (Iterator i = currentStates.iterator(); i.hasNext(); ) {
+    		String targetId = ((TransitionTarget) i.next()).getId();
+    		if (target2viewMap.containsKey(targetId)) {
+    			return (String) target2viewMap.get(targetId);
+    		}
+    	}
+    	return null;
+    }
+
+    /**
+     * <p>Return the session scope attribute key under which we will
+     * store dialog state for the current user.  The value
+     * is specified by a context init parameter named by constant
+     * <code>Globals.DIALOG_STATE_PARAM</code>, or defaults to the value
+     * specified by constant <code>Globals.DIALOG_STATE</code>.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     */
+    private String getDialogKey(FacesContext context) {
+    	
+    	assert context != null;
+    	
+        if (dialogKey == null) {
+            dialogKey =
+              context.getExternalContext().
+			  	getInitParameter(Globals.DIALOG_STATE_PARAM);
+            if (dialogKey == null) {
+                dialogKey = Globals.DIALOG_STATE;
+            }
+        }
+        return dialogKey;
+
+    }
+
+    /**
+     * <p>Render the view corresponding to the specified view identifier.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param viewId View identifier to be rendered, or <code>null</code>
+     *  to rerender the current view
+     */
+    private void render(FacesContext context, String viewId) {
+
+        assert context != null;
+
+        if (log.isDebugEnabled()) {
+            log.debug("render(viewId=" + viewId + ")");
+        }
+
+        // Stay on the same view if requested
+        if (viewId == null) {
+            return;
+        }
+
+        // Create the specified view so that it can be rendered
+        ViewHandler vh = context.getApplication().getViewHandler();
+        UIViewRoot view = vh.createView(context, viewId);
+        view.setViewId(viewId);
+        context.setViewRoot(view);
+
+    }
+
+    /**
+     * FIXME: - Placeholder for SCXML state ID to JSF view ID mapper.
+     * Provides multi-channel aspect to Shale dialog management.
+     * 
+     */
+    private void readState2ViewMap(FacesContext context,
+    		String dialogIdentifier, String channel) {
+    	
+    	assert context != null;
+
+    	String STATE_TO_VIEW_MAP = "/WEB-INF/dialogstate2view.xml";
+    	target2viewMap = new HashMap();
+
+		Digester digester = new Digester();
+		digester.clear();
+		digester.setNamespaceAware(false);
+        digester.setUseContextClassLoader(false);
+        digester.setValidating(false);
+        digester.addRule("map/entry", new Rule() {
+        	/** SCXML target ID. */
+        	private String targetId;
+        	/** JSF view ID. */
+        	private String viewId;
+            /** {@inheritDoc} */
+            public final void begin(final String namespace, final String name,
+                    final Attributes attributes) {
+            	targetId = attributes.getValue("targetId");
+            	viewId = attributes.getValue("viewId");
+            }
+            /** {@inheritDoc} */
+            public void end(final String namespace, final String name) {
+            	target2viewMap.put(targetId, viewId);
+            }
+        });
+        
+        try {
+            URL mapURL = context.getExternalContext().getResource(STATE_TO_VIEW_MAP);
+        	InputSource source = new InputSource(mapURL.toExternalForm());
+        	source.setByteStream(mapURL.openStream());
+        	digester.parse(source);
+        } catch (Exception e) {
+        	log.error(e.getMessage(), e);
+        }
+    }
+
+}

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt Fri Oct 14 19:41:20 2005
@@ -0,0 +1,509 @@
+/*
+ * Copyright 2004-2005 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.
+ */
+/*
+ * You may build in a package on your choice. Dependency information:
+ *
+ * Commons SCXML dependencies -
+ * http://jakarta.apache.org/commons/sandbox/scxml/dependencies.html
+ *
+ * Struts Shale dependencies -
+ * http://struts.apache.org/shale/ 
+ * (Currently under "Foundations" section)
+ */
+package org.apache.commons.scxml.usecases;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.application.NavigationHandler;
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.commons.scxml.SCXMLDigester;
+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.env.SimpleSCXMLListener;
+import org.apache.commons.scxml.env.faces.SessionContext;
+import org.apache.commons.scxml.env.faces.ShaleDialogELEvaluator;
+import org.apache.commons.scxml.model.ModelException;
+import org.apache.commons.scxml.model.SCXML;
+import org.apache.commons.scxml.model.TransitionTarget;
+
+import org.apache.shale.dialog.Globals;
+import org.apache.shale.dialog.Status;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+
+/**
+ * <p>SCXML configuration file(s) driven Shale dialog navigation handler.</p>
+ *
+ * <p>Recipe for using SCXML documents to drive Shale dialogs:
+ *   <ol>
+ *    <li>Build the <code>SCXMLDialogNavigationHandler</code> (available
+ *     below, use a Commons SCXML nightly build 10/09/05 or later) and make it
+ *     available to your web application classpath (<code>WEB-INF/classes</code>).
+ *    </li>
+ *    <li>Update the &quot;<code>WEB-INF/faces-config.xml</code>&quot;
+ *     for your web application such that the
+ *     &quot;<code>faces-config/application/navigation-handler</code>&quot;
+ *     entry points to
+ *     &quot;<code>org.apache.commons.scxml.usecases.SCXMLDialogNavigationHandler</code>&quot;
+ *     (with the appropriate package name, if you changed it).
+ *    </li>
+ *    <li>As an alternative to (1) and (2), you can place a <i>jar</i> in the 
+ *     <code>WEB-INF/lib</code> directory which contains the
+ *     <code>SCXMLDialogNavigationHandler</code> and a
+ *     <code>META-INF/faces-config.xml</code> with just the entry in (2).</li>
+ *    <li>Use SCXML documents to describe Shale dialog flows (details below)
+ *     in your application. You may have multiple mappings from transition
+ *     targets to JSF views to support multi-channel applications.</li>
+ *    <li>The SCXML-based dialog is entered when
+ *     <code>handleNavigation()</code> is called with a logical outcome
+ *     of the form &quot;<code>dialog:xxx</code>&quot; and there is no current
+ *     dialog in progress, where &quot;<code>xxx</code>&quot; is the URL pointing
+ *     to the SCXML document.</li>
+ *   </ol>
+ * </p>
+ *
+ * <p>Using SCXML documents to define the Shale dialog "flows":
+ *   <ul>
+ *     <li>ActionState instances may be mapped to executable content
+ *         in UML &lt;onentry&gt (and may be chained similarly).</li>
+ *     <li>ViewState instances may be mapped to UML transition
+ *         targets.</li>
+ *     <li>SubdialogState instances may be mapped to external SCXML
+ *         documents.</li>
+ *     <li>EndState instances may be mapped to SCXML final states.</li>
+ *     <li>The {@link SCXMLDialogNavigationHandler} defines a
+ *         &quot;faces.outcome&quot; event which the relevant SCXML
+ *         transitions from a &quot;view state&quot; can wait for.</li>
+ *   </ul>
+ * </p>
+ *
+ * <p>Towards pluggable dialog management in Shale - A &quot;black box&quot;
+ *    dialog may consist of the following tuple:
+ *   <ul>
+ *     <li>Unique dialog identifier</li>
+ *     <li>A generic NavigationHandler (i.e. dialog strategy)</li>
+ *     <li>An dialog/flow configuration resource (Ex: SCXML document)</li>
+ *     <li>Optionally, multiple other configuration resources,
+ *      (Ex: one for each channel - web, voice, small device, etc.)</li>
+ *   </ul>
+ *    The Shale DialogNavigationHandler may then delegate appropriately.
+ * </p>
+ */
+public final class SCXMLDialogNavigationHandler extends NavigationHandler {
+
+    // ------------------------------------------------------------ Constructors
+    /**
+     * <p>Create a new {@link SCXMLDialogNavigationHandler}, wrapping the
+     * specified standard navigation handler implementation.</p>
+     *
+     * @param handler Standard <code>NavigationHandler</code> we are wrapping
+     */
+    public SCXMLDialogNavigationHandler(NavigationHandler handler) {
+
+        this.handler = handler;
+
+    }
+
+    // -------------------------------------------------------- Static Variables
+    /**
+     * <p>The prefix on a logical outcome String that indicates the remainder
+     * of the string is the URL of a SCXML-based Shale dialog to be entered.</p>
+     */
+    public static final String PREFIX = "dialog:";
+
+    // ------------------------------------------------------ Instance Variables
+
+    /**
+     * <p>The standard <code>NavigationHandler</code> implementation that
+     * we are wrapping.</p>
+     */
+    private NavigationHandler handler = null;
+
+    /**
+     * <p>The <code>Log</code> instance for this class.</p>
+     */
+    private final Log log = LogFactory.getLog(getClass());
+
+    /**
+     * <p>Key under which we will store the SCXMLExecutor (more generally,
+     * some session scoped state pertaining to the current dialog).</p>
+     */
+    private String dialogKey = null; // Cached on first use
+
+    /**
+     * <p>Map storing SCXML state IDs as keys and JSF view IDs as values.</p>
+     */
+    private Map target2viewMap = null;
+
+    // ----------------------------------------------- NavigationHandler Methods
+
+    /**
+     * <p>Handle the navigation request implied by the specified parameters.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param fromAction The action binding expression that was evaluated
+     *  to retrieve the specified outcome (if any)
+     * @param outcome The logical outcome returned by the specified action
+     *
+     * @exception IllegalArgumentException if the configuration information
+     *  for a previously saved position cannot be found
+     * @exception IllegalArgumentException if an unknown State type is found
+     */
+    public void handleNavigation(FacesContext context, String fromAction,
+                                 String outcome) {
+
+        if (log.isDebugEnabled()) {
+            log.debug("handleNavigation(viewId=" +
+                      context.getViewRoot().getViewId() +
+                      ",fromAction=" + fromAction +
+                      ",outcome=" + outcome + ")");
+        }
+
+        SCXMLExecutor exec = getDialogExecutor(context);
+        String viewId = null;
+        
+        if (exec == null && outcome != null && outcome.startsWith(PREFIX)) {
+        	
+        	/**** DIALOG ENTRY ****/
+        	// dialog is a state machine, parse & obtain an executor
+        	exec = initDialogExecutor(context, outcome.substring(PREFIX.
+        			length()));
+
+        	if (exec != null) {
+        		// cache executor in session scope
+        		// TODO: Shale caches Dialog instances. SCXMLExecutor
+        		// knows what state(s) the dialog is in, so Dialog#findState()
+        		// is not needed.
+        		setDialogExecutor(context, exec);
+        		// obtain our initial view
+        		viewId = getCurrentViewId(exec);
+        	}
+        	// else delegate
+        	
+        } else if (exec != null) {
+        	
+        	/**** SUBSEQUENT TURNS OF DIALOG ****/
+        	// pass a handle to the current ctx (for evaluating binding exprs)
+        	updateEvaluator(context, outcome);
+        	// fire a "faces.outcome" event on the dialog's state machine
+        	TriggerEvent[] te = { new TriggerEvent("faces.outcome",
+        			TriggerEvent.SIGNAL_EVENT) };
+        	try {
+        		exec.triggerEvents(te);
+        	} catch (ModelException me) {
+        		log.error(me.getMessage(), me);
+        	}
+        	// obtain next view
+        	viewId = getCurrentViewId(exec);
+        }
+
+        if (viewId != null) {
+        
+        	// we understood this "outcome" and we have a new view to render
+        	log.info("Rendering view: " + viewId);
+        	updateDialogStatus(context, exec);
+        	render(context, viewId);
+
+        } else {
+        
+        	/**** DELEGATE BY DEFAULT ****/
+        	handler.handleNavigation(context, fromAction, outcome);
+
+        }
+
+
+    }
+
+    /**
+     * <p>Return the SCXMLExecutor for the specified SCXML document, if it
+     * exists; otherwise, return <code>null</code>.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param dialogIdentifier URL of the SCXML document for the requested
+     *                         dialog
+     */
+    private SCXMLExecutor initDialogExecutor(FacesContext context,
+    		String dialogIdentifier) {
+
+        assert context != null;
+        assert dialogIdentifier != null;
+        
+        // We're parsing the SCXML dialog just in time here
+        URL scxmlDocument = null;
+        try {
+        	scxmlDocument = context.getExternalContext().
+				getResource(dialogIdentifier);
+        } catch (MalformedURLException mue) {
+        	log.error(mue.getMessage(), mue);
+        }
+
+        if (scxmlDocument == null) {
+        	log.warn("No SCXML document at: " + dialogIdentifier);
+        	return null;
+        }
+        
+        SCXML scxml = null;
+        ShaleDialogELEvaluator evaluator = new ShaleDialogELEvaluator();
+        evaluator.setFacesContext(context);
+        try {
+            scxml = SCXMLDigester.digest(scxmlDocument,
+            		new SimpleErrorHandler(), new SessionContext(context),
+                	evaluator);
+        } catch (Exception e) {
+            log.error(e.getMessage(), e);
+        }
+
+        if (scxml == null) {
+        	log.warn("Could not parse SCXML document at: " + dialogIdentifier);
+        	return null;
+        }
+        
+        SCXMLExecutor exec = null;
+        try {
+            exec = new SCXMLExecutor(evaluator, new SimpleDispatcher(),
+            		new SimpleErrorReporter());
+            scxml.addListener(new SimpleSCXMLListener());
+            exec.setSuperStep(true);
+            exec.setStateMachine(scxml);
+        } catch (ModelException me) {
+        	log.warn(me.getMessage(), me);
+        	return null;
+        }
+        
+        // read SCXML state IDs to JSF view IDs map, channel dependent
+        readState2ViewMap(context, dialogIdentifier, null);
+        
+        // FIXME: Remove dependence on the org.apache.shale.dialog.impl package
+        // below (introduced so we can reuse the existing StatusImpl and the
+        // AbstractFacesBean subtypes in the usecases war for the proof of
+        // concept).
+        // Ignoring STATUS_PARAM since usecases war doesn't use it for the
+        // log on / edit profile dialogs.
+        // TODO: The next line should be Dialog Manager implementation agnostic
+        Status status =	new org.apache.shale.dialog.impl.StatusImpl();
+
+        context.getExternalContext().getSessionMap().put(Globals.STATUS, status);
+        status.push(new Status.Position(dialogIdentifier, getCurrentViewId(exec)));
+        
+        return exec;
+        
+    }
+
+    /**
+     * <p>Set the {@link SCXMLExecutor} instance for the current user.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param exec <code>SCXMLExecutor</code> that will run the dialog
+     */
+    private void setDialogExecutor(FacesContext context, SCXMLExecutor exec) {
+
+    	assert context != null;
+    	assert exec != null;
+    	
+        Map map = context.getExternalContext().getSessionMap();
+        String key = getDialogKey(context);
+        assert key != null;
+        map.put(key, exec);
+        
+    }
+
+    /**
+     * <p>Return the {@link SCXMLExecutor} instance for the current user.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     */
+    private SCXMLExecutor getDialogExecutor(FacesContext context) {
+
+        assert context != null;
+
+        Map map = context.getExternalContext().getSessionMap();
+        String key = getDialogKey(context);
+        return (SCXMLExecutor) map.get(key);
+
+    }
+
+    /**
+     * Update evaluator with current FacesContext for evaluation of
+     * binding expressions used in Shale dialog.
+     */
+    private void updateEvaluator(FacesContext context, String outcome) {
+    	
+    	assert context != null;
+    	
+    	((ShaleDialogELEvaluator) getDialogExecutor(context).getEvaluator()).
+			setFacesContext(context);
+    	context.getExternalContext().getSessionMap().put("outcome", outcome);
+    }
+
+    /**
+     * Update dialog Status
+     * 
+     * @param context The FacesContext
+     * @param exec The SCXMLExecutor
+     */
+    private void updateDialogStatus(FacesContext context, SCXMLExecutor exec) {
+    	
+    	assert context != null;
+    	assert exec != null;
+    	
+    	// TODO: Test this
+    	Status status = (Status) context.getExternalContext().getSessionMap().
+			get(Globals.STATUS);
+    	if (exec.getCurrentStatus().isFinal()) {
+            setDialogExecutor(context, null);
+            status.pop();
+    	} else {
+            status.peek().setStateName(getCurrentViewId(exec));
+    	}
+    }
+
+    /**
+     * Get next view to render, assuming one view at a time. 
+     *
+     * @param currentStates The set of current states
+     * @return String The JSF viewId of the next view
+     */
+    private String getCurrentViewId(SCXMLExecutor exec) {
+    	
+    	assert exec != null;
+    	
+    	Set currentStates = exec.getCurrentStatus().getStates();
+    	for (Iterator i = currentStates.iterator(); i.hasNext(); ) {
+    		String targetId = ((TransitionTarget) i.next()).getId();
+    		if (target2viewMap.containsKey(targetId)) {
+    			return (String) target2viewMap.get(targetId);
+    		}
+    	}
+    	return null;
+    }
+
+    /**
+     * <p>Return the session scope attribute key under which we will
+     * store dialog state for the current user.  The value
+     * is specified by a context init parameter named by constant
+     * <code>Globals.DIALOG_STATE_PARAM</code>, or defaults to the value
+     * specified by constant <code>Globals.DIALOG_STATE</code>.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     */
+    private String getDialogKey(FacesContext context) {
+    	
+    	assert context != null;
+    	
+        if (dialogKey == null) {
+            dialogKey =
+              context.getExternalContext().
+			  	getInitParameter(Globals.DIALOG_STATE_PARAM);
+            if (dialogKey == null) {
+                dialogKey = Globals.DIALOG_STATE;
+            }
+        }
+        return dialogKey;
+
+    }
+
+    /**
+     * <p>Render the view corresponding to the specified view identifier.</p>
+     *
+     * @param context <code>FacesContext</code> for the current request
+     * @param viewId View identifier to be rendered, or <code>null</code>
+     *  to rerender the current view
+     */
+    private void render(FacesContext context, String viewId) {
+
+        assert context != null;
+
+        if (log.isDebugEnabled()) {
+            log.debug("render(viewId=" + viewId + ")");
+        }
+
+        // Stay on the same view if requested
+        if (viewId == null) {
+            return;
+        }
+
+        // Create the specified view so that it can be rendered
+        ViewHandler vh = context.getApplication().getViewHandler();
+        UIViewRoot view = vh.createView(context, viewId);
+        view.setViewId(viewId);
+        context.setViewRoot(view);
+
+    }
+
+    /**
+     * FIXME: - Placeholder for SCXML state ID to JSF view ID mapper.
+     * Provides multi-channel aspect to Shale dialog management.
+     * 
+     */
+    private void readState2ViewMap(FacesContext context,
+    		String dialogIdentifier, String channel) {
+    	
+    	assert context != null;
+
+    	String STATE_TO_VIEW_MAP = "/WEB-INF/dialogstate2view.xml";
+    	target2viewMap = new HashMap();
+
+		Digester digester = new Digester();
+		digester.clear();
+		digester.setNamespaceAware(false);
+        digester.setUseContextClassLoader(false);
+        digester.setValidating(false);
+        digester.addRule("map/entry", new Rule() {
+        	/** SCXML target ID. */
+        	private String targetId;
+        	/** JSF view ID. */
+        	private String viewId;
+            /** {@inheritDoc} */
+            public final void begin(final String namespace, final String name,
+                    final Attributes attributes) {
+            	targetId = attributes.getValue("targetId");
+            	viewId = attributes.getValue("viewId");
+            }
+            /** {@inheritDoc} */
+            public void end(final String namespace, final String name) {
+            	target2viewMap.put(targetId, viewId);
+            }
+        });
+        
+        try {
+            URL mapURL = context.getExternalContext().getResource(STATE_TO_VIEW_MAP);
+        	InputSource source = new InputSource(mapURL.toExternalForm());
+        	source.setByteStream(mapURL.openStream());
+        	digester.parse(source);
+        } catch (Exception e) {
+        	log.error(e.getMessage(), e);
+        }
+    }
+
+}

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/SCXMLDialogNavigationHandler.java.txt
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml Fri Oct 14 19:41:20 2005
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+
+  Copyright 2004-2005 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.
+
+  $Id$
+
+-->
+
+<!--
+
+  Dialog definitions for Shale Use Cases Example Web Application
+
+-->
+
+<!DOCTYPE dialogs PUBLIC
+  "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN"
+  "http://struts.apache.org/dtds/shale-dialog-config_1_0.dtd">
+
+<dialogs>
+
+
+  <!-- Log On / Create Profile Dialog -->
+  <dialog                name="Log On"
+                        start="Check Cookie">
+
+    <action              name="Check Cookie"
+                       method="#{profile$logon.check}">
+      <transition     outcome="authenticated"
+                       target="Exit"/>
+      <transition     outcome="unauthenticated"
+                       target="Logon Form"/>
+    </action>
+
+    <view                name="Logon Form"
+                       viewId="/profile/logon.jsp">
+      <transition     outcome="authenticated"
+                       target="Exit"/>
+      <transition     outcome="create"
+                       target="Create Profile"/>
+    </view>
+
+    <subdialog           name="Create Profile"
+                   dialogName="Edit Profile">
+      <transition     outcome="success"
+                       target="Exit"/>
+    </subdialog>
+
+    <end                 name="Exit"
+                       viewId="/usecases.jsp"/>
+
+  </dialog>
+
+
+  <!-- Edit Profile Dialog -->
+  <dialog                name="Edit Profile"
+                        start="Setup">
+
+    <!-- Global transitioh definitions -->
+    <transition       outcome="cancel"
+                       target="Cancel"/>
+    <transition       outcome="finish"
+                       target="Finish"/>
+
+    <action              name="Setup"
+                       method="#{profile$edit.setup}">
+      <transition     outcome="success"
+                       target="Page 1"/>
+    </action>
+
+    <view                name="Page 1"
+                       viewId="/profile/profile1.jsp">
+      <transition     outcome="next"
+                       target="Page 2"/>
+    </view>
+
+    <view                name="Page 2"
+                       viewId="/profile/profile2.jsp">
+      <transition     outcome="next"
+                       target="Page 3"/>
+      <transition     outcome="previous"
+                       target="Page 1"/>
+    </view>
+
+    <view                name="Page 3"
+                       viewId="/profile/profile3.jsp">
+      <transition     outcome="next"
+                       target="Exit"/>
+      <transition     outcome="previous"
+                       target="Page 2"/>
+    </view>
+
+    <action              name="Cancel"
+                       method="#{profile$edit.cancel}">
+      <transition     outcome="success"
+                       target="Exit"/>
+    </action>
+
+    <action              name="Finish"
+                       method="#{profile$edit.finish}">
+      <transition     outcome="password"
+                       target="Page 1"/>
+      <transition     outcome="success"
+                       target="Exit"/>
+      <transition     outcome="username"
+                       target="Page 1"/>
+    </action>
+
+    <end                 name="Exit"
+                       viewId="/usecases.jsp"/>
+
+  </dialog>
+
+
+</dialogs>

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialog-config.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml Fri Oct 14 19:41:20 2005
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2004-2005 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.
+-->
+<map>
+  <entry   targetId="logon"   viewId="/profile/logon.jsp"     />
+  <entry   targetId="page1"   viewId="/profile/profile1.jsp"  />
+  <entry   targetId="page2"   viewId="/profile/profile2.jsp"  />
+  <entry   targetId="page3"   viewId="/profile/profile3.jsp"  />
+  <entry   targetId="exit"    viewId="/usecases.jsp"          />
+</map>

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/dialogstate2view.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml Fri Oct 14 19:41:20 2005
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  Copyright 2004-2005 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.
+
+  $Id$
+
+-->
+
+<!--
+
+  Dialog definitions for Shale Use Cases Example Web Application
+  written out as SCXML to demonstrate use of Commons SCXML as one
+  of Shale's Dialog Manager implementations.
+
+  Related artifacts from <dialog name="Edit Profile">...</dialog>
+  in original dialogs definition file from Shale nightlies.
+
+-->
+
+<scxml xmlns="http://www.w3.org/2005/01/SCXML" version="1.0"  
+       initialstate="edit">
+
+  <state                id="edit">
+
+    <initial>
+      <transition>
+        <target       next="setup"/>
+      </transition>
+    </initial>
+
+    <!-- global transitions (within state "edit") -->
+
+    <transition      event="faces.outcome"
+                      cond="${outcome eq 'cancel'}">
+      <target         next="cancel"/>
+    </transition>
+
+    <transition      event="faces.outcome"
+                      cond="${outcome eq 'finish'}">
+      <target         next="finish"/>
+    </transition>
+
+    <state              id="setup">
+
+      <onentry>
+        <var          name="setupOutcome"
+                      expr="#{profile$edit.setup}" />
+      </onentry>
+
+      <transition     cond="${setupOutcome eq 'success'}">
+        <target       next="page1"/>
+      </transition>
+
+    </state>
+
+    <state              id="page1">
+
+      <transition    event="faces.outcome"
+                      cond="${outcome eq 'next'}">
+        <target       next="page2"/>
+      </transition>
+
+    </state>
+
+    <state              id="page2">
+
+      <transition    event="faces.outcome"
+                      cond="${outcome eq 'previous'}">
+        <target       next="page1"/>
+      </transition>
+
+      <transition    event="faces.outcome"
+                      cond="${outcome eq 'next'}">
+        <target       next="page3"/>
+      </transition>
+
+    </state>
+
+    <state              id="page3">
+
+      <transition    event="faces.outcome"
+                      cond="${outcome eq 'previous'}">
+        <target       next="page2"/>
+      </transition>
+
+      <transition    event="faces.outcome"
+                      cond="${outcome eq 'next'}">
+        <target       next="editExit"/>
+      </transition>
+
+    </state>
+
+  </state>
+
+  <state                id="cancel">
+
+    <onentry>
+      <var            name="cancelOutcome"
+                      expr="#{profile$edit.cancel}" />
+    </onentry>
+
+    <transition       cond="${cancelOutcome eq 'success'}">
+      <var            name="outcome"
+                      expr="cancel"/>
+      <target         next="editExit"/>
+    </transition>
+
+  </state> 
+
+  <state                id="finish">
+
+    <onentry>
+      <var            name="finishOutcome"
+                      expr="#{profile$edit.finish}" />
+    </onentry>
+
+    <transition       cond="${finishOutcome eq 'username'}">
+      <target         next="page1"/>
+    </transition>
+
+    <transition       cond="${finishOutcome eq 'password'}">
+      <target         next="page1"/>
+    </transition>
+
+    <transition       cond="${finishOutcome eq 'success'}">
+      <var            name="outcome"
+                      expr="success"/>
+      <target         next="editExit"/>
+    </transition>
+
+  </state>
+
+  <state                id="editExit"
+                     final="true" />
+
+</scxml>

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/edit-profile-config.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml?rev=321280&view=auto
==============================================================================
--- jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml (added)
+++ jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml Fri Oct 14 19:41:20 2005
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  Copyright 2004-2005 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.
+
+  $Id$
+
+-->
+
+<!--
+
+  Dialog definitions for Shale Use Cases Example Web Application
+  written out as SCXML to demonstrate use of Commons SCXML as one
+  of Shale's Dialog Manager implementations.
+
+  Related artifacts from <dialog name="Log On">...</dialog>
+  in original dialogs definition file from Shale nightlies.
+
+-->
+
+<scxml xmlns="http://www.w3.org/2005/01/SCXML" version="1.0"  
+       initialstate="checkCookie">
+
+
+  <state                 id="checkCookie">
+
+    <onentry>
+      <var             name="cookieOutcome"
+                       expr="#{profile$logon.check}" />
+    </onentry>
+
+    <transition        cond="${cookieOutcome eq 'authenticated'}">
+      <target          next="exit"/>
+    </transition>
+
+    <transition        cond="${cookieOutcome eq 'unauthenticated'}">
+      <target          next="logon"/>
+    </transition>
+
+  </state>
+
+  <state                 id="logon">
+
+    <transition       event="faces.outcome"
+                       cond="${outcome eq 'authenticated'}">
+      <target          next="exit"/>
+    </transition>
+
+    <transition       event="faces.outcome"
+                       cond="${outcome eq 'create'}">
+      <target          next="createProfile"/>
+    </transition>
+
+  </state>
+
+  <state                 id="createProfile"
+                        src="edit-profile-config.xml" >
+
+      <transition     event="createProfile.done"
+                       cond="${outcome eq 'success' or outcome eq 'cancel'}">
+        <target        next="exit"/>
+      </transition>
+
+  </state>
+
+  <state                 id="exit"
+                      final="true" />
+
+</scxml>

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/scxml/trunk/xdocs/usecases/shale-dialogs/log-on-config.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL



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