You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@struts.apache.org by mr...@apache.org on 2005/02/15 22:10:32 UTC

svn commit: r153960 [1/3] - in struts/flow: ./ branches/ tags/ trunk/ trunk/src/ trunk/src/guess-example/ trunk/src/guess-example/WEB-INF/ trunk/src/java/ trunk/src/java/org/ trunk/src/java/org/apache/ trunk/src/java/org/apache/struts/ trunk/src/java/org/apache/struts/flow/ trunk/src/java/org/apache/struts/flow/core/ trunk/src/wizard-example/ trunk/src/wizard-example/WEB-INF/

Author: mrdon
Date: Tue Feb 15 13:09:29 2005
New Revision: 153960

URL: http://svn.apache.org/viewcvs?view=rev&rev=153960
Log:
Initial import of struts-flow

Added:
    struts/flow/
    struts/flow/branches/
    struts/flow/tags/
    struts/flow/trunk/
    struts/flow/trunk/build.xml   (with props)
    struts/flow/trunk/project.xml
    struts/flow/trunk/src/
    struts/flow/trunk/src/guess-example/
    struts/flow/trunk/src/guess-example/WEB-INF/
    struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js   (with props)
    struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml   (with props)
    struts/flow/trunk/src/guess-example/WEB-INF/web.xml   (with props)
    struts/flow/trunk/src/guess-example/guess.jsp   (with props)
    struts/flow/trunk/src/guess-example/index.html
    struts/flow/trunk/src/guess-example/success.jsp   (with props)
    struts/flow/trunk/src/java/
    struts/flow/trunk/src/java/org/
    struts/flow/trunk/src/java/org/apache/
    struts/flow/trunk/src/java/org/apache/struts/
    struts/flow/trunk/src/java/org/apache/struts/flow/
    struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/
    struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/FlowException.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/InvalidContinuationException.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JSContext.java
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JSErrorReporter.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JSGlobal.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JSLog.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JSWebContinuation.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/JavaScriptInterpreter.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/Logger.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/ScriptableMap.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/WebContinuation.java   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/core/package.html   (with props)
    struts/flow/trunk/src/java/org/apache/struts/flow/package.html   (with props)
    struts/flow/trunk/src/java/struts.js   (with props)
    struts/flow/trunk/src/java/system.js   (with props)
    struts/flow/trunk/src/wizard-example/
    struts/flow/trunk/src/wizard-example/WEB-INF/
    struts/flow/trunk/src/wizard-example/WEB-INF/struts-config.xml   (with props)
    struts/flow/trunk/src/wizard-example/WEB-INF/web.xml   (with props)
    struts/flow/trunk/src/wizard-example/WEB-INF/wizard-flow.js   (with props)
    struts/flow/trunk/src/wizard-example/WEB-INF/wizard.js   (with props)
    struts/flow/trunk/src/wizard-example/hobbies-form.jsp   (with props)
    struts/flow/trunk/src/wizard-example/index.html
    struts/flow/trunk/src/wizard-example/name-form.jsp   (with props)
    struts/flow/trunk/src/wizard-example/summary-form.jsp   (with props)

Added: struts/flow/trunk/build.xml
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/build.xml?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/build.xml (added)
+++ struts/flow/trunk/build.xml Tue Feb 15 13:09:29 2005
@@ -0,0 +1,269 @@
+<project name="struts-flow" default="jar" basedir=".">
+
+    <!-- ========== Initialization Properties ================================= -->
+    <!--
+            These property values may optionally be overridden with property
+            settings from an "ant" command line, the "antrc" properties file
+            in your home directory, or from settings in a superior build.xml
+            script.
+    -->
+
+    <!-- Java compilation options -->
+    <property name="compile.debug"         value="true" />
+    <property name="compile.deprecation"   value="true" />
+    <property name="compile.optimize"      value="false" />
+
+    <!-- Doc directory and packages that go in there -->
+    <property name="doc.dir"              value="./doc"/>
+
+    <!-- where all the library files are kept, plus what to include/exclude when building -->
+    <property name="lib.dir"              value="./lib" />
+    <property name="lib.core"              value="${lib.dir}/core" />
+    <property name="lib.build"              value="${lib.dir}/build" />
+
+    <!-- application information -->
+    <property name="app.name"           value="struts-flow" />
+    <property name="app.version"        value="0.3-dev" />
+
+    <!-- The base directory for distribution targets -->
+    <property name="dist.dir"           value="./dist" />
+   
+    <property name="src.dir" value="src" />
+    <property name="src.java" value="${src.dir}/java" />
+    <property name="src.guess.example" value="${src.dir}/guess-example" />
+    <property name="src.wizard.example" value="${src.dir}/wizard-example" />
+    
+    <property name="build.dir" value="build" />
+    <property name="build.guess.example" value="${build.dir}/guess-example" />
+    <property name="build.wizard.example" value="${build.dir}/wizard-example" />
+    <property name="build.target" value="${build.dir}/target" />
+
+    <property name="javadoc.packages" value="org.apache.struts.flow.*" />
+
+
+    <!-- ========== Derived Properties ======================================== -->
+    <!--
+            These property values are derived from values defined above, and
+            generally should NOT be overridden by command line settings
+    -->
+
+    <!-- The name of the web application archive file to be produced -->
+    <property name="app.jar"           value="${app.name}-${app.version}.jar" />
+    <property name="release.zip"           value="${app.name}-${app.version}.zip" />
+
+    <path id="base.classpath">
+        <fileset dir="lib">
+                <include name="**/*.jar"/>
+        </fileset>
+        <pathelement location="${build.target}"/>
+        <pathelement location="${build.test}" />
+    </path> 
+
+    <!-- ========== Executable Targets ======================================== -->
+    <!--
+            The "init" target evaluates "available" expressions as necessary
+            to modify the behavior of this script.
+    -->
+
+    <target name="init">
+        <echo    message="Processing build.target init ${app.name}"/>
+        <available file="${src.java}"   property="src.java.present"/>
+        <available file="${lib.dir}"     property="lib.dir.present"/>
+    </target>
+
+    <target name="download-dependencies" unless="lib.dir.present">
+        <mkdir dir="${lib.build}" />
+
+        <get dest="${lib.build}/servletapi-2.3.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/servletapi/jars/servletapi-2.3.jar"/> 
+
+        <mkdir dir="${lib.core}" />
+        <get dest="${lib.core}/struts-1.1.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/struts/jars/struts-1.1.jar"/> 
+
+        <get dest="${lib.core}/js-1.6R1.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/rhino/jars/js-1.6R1.jar"/> 
+
+        <get dest="${lib.core}/commons-chain-1.0.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/commons-chain/jars/commons-chain-1.0.jar"/> 
+
+        <get dest="${lib.core}/jakarta-oro-2.0.7.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/oro/jars/oro-2.0.7.jar"/> 
+
+        <get dest="${lib.core}/commons-logging.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/commons-logging/jars/commons-logging-1.0.3.jar"/> 
+ 
+        <get dest="${lib.core}/commons-beanutils.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/commons-beanutils/jars/commons-beanutils-1.7.0.jar"/> 
+ 
+        <get dest="${lib.core}/commons-validator.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/commons-validator/jars/commons-validator-1.1.3.jar"/> 
+        <get dest="${lib.core}/commons-digester.jar" usetimestamp="true" 
+              ignoreerrors="true" 
+              src="http://www.ibiblio.org/maven/commons-digester/jars/commons-digester-1.6.jar"/> 
+    </target>
+
+
+    <!--
+            The "clean" task deletes any created directories that have resulted
+            from running any of the other targets in this script.
+    -->
+
+    <target name="clean"
+        description="Clean build and distribution directories">
+        <echo    message="Processing build.target clean ${app.name}"/>
+        <delete   dir="${build.dir}" />
+        <delete   dir="${dist.dir}" />
+        <delete   dir="${doc.dir}" />
+    </target>
+
+    <!--
+            The "prepare" target creates a directory structure in the build target
+            area for the unpacked files associated with this web application
+    -->
+    <target name="prepare" depends="init, download-dependencies"
+        description="Prepare target directory">
+        <echo    message="Processing app ${app.name}"/>
+        <mkdir   dir="${build.dir}" />
+        <mkdir   dir="${build.target}" />
+        <mkdir   dir="${dist.dir}" />
+    </target>
+
+     <target name="release" depends="clean, jar, guess-example, wizard-example,javadoc"
+             description="Creates a release">
+        <echo message="Creating ${app.version} release" />
+        
+        <zip destfile="${release.zip}"
+            compress="true">
+            <zipfileset dir="${src.dir}" prefix="src" />
+            <zipfileset dir="${doc.dir}" prefix="doc" />
+            <zipfileset dir="${lib.dir}" prefix="lib" />
+            <zipfileset dir="${dist.dir}" prefix="dist" />
+            <fileset dir="." includes="build.xml" />
+        </zip>
+    </target>
+        
+        
+    <!--
+            The "compile" target compiles the Java source code of your web
+            application, if and only if the specified source directory
+            actually exists.
+    -->
+    <target name="compile" depends="prepare" description="Compile Java sources">
+        <echo    message="Processing app ${app.name}"/>
+
+        <echo    message="Source ${src.java}"/>
+        <echo    message="Target ${build.target}"/>
+        <javac  srcdir="${src.java}"
+            destdir="${build.target}"
+            debug="${compile.debug}"
+            deprecation="${compile.deprecation}"
+            optimize="${compile.optimize}">
+            <classpath refid="base.classpath" />
+        </javac>
+        <copy    todir="${build.target}">
+            <fileset dir="${src.java}">
+                <exclude name="**/*.java"/>
+                <exclude name="**/!dirinfo.txt"/>
+            </fileset>
+        </copy>
+    </target>
+
+<!--
+	<target name="run-tests" depends="compile">
+		<javac srcdir="${test.src}" destdir="${test.build}"
+			debug="on" optimize="off" deprecation="off" >
+            <classpath refid="base.classpath" />
+        </javac>
+		<junit printsummary="on" fork="on">
+			<formatter type="xml" />
+			<classpath refid="base.classpath" />
+
+			<batchtest todir="${test.results}">
+				<fileset dir="${test.src}">
+					<include name="**/*Test.java" />
+				</fileset>
+			</batchtest>
+		</junit>
+    </target>
+    -->
+    <!--
+            The 'javadoc' target creates the API documentation.
+            All javadoc is created in the ${doc.dir}/javadoc directory.
+    -->
+    <target name="javadoc" depends="init">
+        <mkdir dir="${doc.dir}/api"/>
+        <delete includeEmptyDirs="true" >
+            <fileset dir="${doc.dir}/api"/>
+        </delete>
+        <mkdir dir="${doc.dir}/api"/>
+        <javadoc packagenames="${javadoc.packages}"
+            sourcepath="${src.java}"
+            destdir="${doc.dir}/api"
+            author="true"
+            version="true"
+            private="false"
+            doctitle="${app.name} Version ${app.version}">
+            <classpath refid="base.classpath" />
+        </javadoc>
+    </target>
+    <!--
+            The "dist" target creates a web application archive containing
+            your completed web application, suitable for deployment on any
+            compatible servlet container.
+    -->
+   <target name="jar" depends="compile"
+        description="Create jar">
+        <echo    message="Processing jarfile ${app.name}"/>
+        <jar  jarfile="${dist.dir}/${app.jar}"
+            basedir="${build.target}"
+            excludes="**/example/*.*"/>
+    </target> 
+    
+    <target name="guess-example" depends="jar"
+        description="Create guess example">
+        <echo    message="Creating guess example"/>
+        <mkdir dir="${build.guess.example}" />
+        <mkdir dir="${build.guess.example}/WEB-INF/lib" />
+        <copy todir="${build.guess.example}">
+            <fileset dir="${src.guess.example}" excludes="WEB-INF/web.xml" />
+        </copy>
+        <copy todir="${build.guess.example}/WEB-INF/lib">
+            <fileset dir="${lib.core}" />
+        </copy>
+        <copy todir="${build.guess.example}/WEB-INF/lib" file="${dist.dir}/${app.jar}" />
+            
+        <war  destfile="${dist.dir}/guess-example.war"
+            basedir="${build.guess.example}"
+            webxml="${src.guess.example}/WEB-INF/web.xml"/>
+    </target> 
+ 
+    <target name="wizard-example" depends="jar"
+        description="Create wizard example">
+        <echo    message="Creating wizard example"/>
+        <mkdir dir="${build.wizard.example}" />
+        <mkdir dir="${build.wizard.example}/WEB-INF/lib" />
+        <copy todir="${build.wizard.example}">
+            <fileset dir="${src.wizard.example}" excludes="WEB-INF/web.xml" />
+        </copy>
+        <copy todir="${build.wizard.example}/WEB-INF/lib">
+            <fileset dir="${lib.core}" />
+        </copy>
+        <copy todir="${build.wizard.example}/WEB-INF/lib" file="${dist.dir}/${app.jar}" />
+            
+        <war  destfile="${dist.dir}/wizard-example.war"
+            basedir="${build.wizard.example}"
+            webxml="${src.wizard.example}/WEB-INF/web.xml"/>
+    </target> 
+
+
+    
+</project>

Propchange: struts/flow/trunk/build.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/project.xml
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/project.xml?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/project.xml (added)
+++ struts/flow/trunk/project.xml Tue Feb 15 13:09:29 2005
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project>
+  <pomVersion>3</pomVersion>
+  <id>struts-flow</id>
+  <name>Struts Flow</name>
+  <currentVersion>0.3-SNAPSHOT</currentVersion>
+  
+  <organization>
+    <name />
+    <url>http://struts.apache.org/flow/</url>
+    <logo />
+  </organization>
+  <logo>http://struts.apache.org/struts/images/struts.gif</logo>
+  <inceptionYear>2003</inceptionYear>
+  <package>org.apache.struts.flow</package>
+  <packageGroups>
+    <packageGroup>
+      <title>Struts Flow</title>
+      <packages>org.apache.struts.flow</packages>
+    </packageGroup>
+  </packageGroups>
+
+  <shortDescription>Struts Flow</shortDescription>
+
+  <!--  
+  <gumpRepositoryId></gumpRepositoryId>
+  -->
+
+  <description>
+    Struts Flow is a port of Cocoon's Control Flow to Struts to allow complex workflow, like multi-form wizards, to be easily implemented using continuations-capable JavaScript. It provides the ability to describe the order of Web pages that have to be sent to the client, at any given point in time in an application.
+  </description>
+    
+  <url>http://struts.apache.org/flow</url>
+  <repository>
+    <connection>scm|svn|http|//svn.apache.org/repos/asf/struts/flow/trunk</connection>
+    <developerConnection>scm|svn|https|//svn.apache.org/repos/asf/struts/flow/trunk</developerConnection>
+    <url>http://svn.apache.org/repos/asf/struts/flow/trunk</url>
+  </repository>
+  <versions>
+    <version>
+      <id>rel_0_3</id>
+      <name>rel_0_3</name>
+      <tag>rel_0_3</tag>
+    </version>
+  </versions>
+<!--
+  <branches>
+  	<branch>
+  	  <tag></tag>
+  	</branch>
+  </branches>
+-->  
+  <mailingLists>
+    <mailingList>
+      <name>Struts User List</name>
+      <subscribe>user-subscribe@struts.apache.org</subscribe>
+      <unsubscribe>user-unsubscribe@struts.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listId=42</archive>
+    </mailingList>
+    <mailingList>
+      <name>Struts Developer List</name>
+      <subscribe>dev-subscribe@struts.apache.org</subscribe>
+      <unsubscribe>dev-unsubscribe@struts.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/eyebrowse/SummarizeList?listId=41</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+	<developer>
+		<name>Don Brown</name>
+		<id>mrdon</id>
+        <email>mrdon at apache.org</email>
+		<organization/>
+	</developer>
+</developers>
+
+<!--   <contributors /> -->
+  <dependencies>
+    <dependency>
+      <id>servletapi</id>
+      <version>2.3</version>
+    </dependency>
+    <dependency>
+      <id>struts</id>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <id>rhino</id>
+      <artifactId>js</artifactId>
+      <version>1.6R1</version>
+    </dependency>
+    <dependency>
+      <id>commons-chain</id>
+      <version>1.0</version>
+    </dependency>
+    <dependency>
+      <id>commons-logging</id>
+      <version>1.0.3</version>
+    </dependency>
+    <dependency>
+      <id>commons-beanutils</id>
+      <version>1.7.0</version>
+    </dependency>
+    <dependency>
+      <id>commons-digester</id>
+      <version>1.6</version>
+    </dependency>
+    <dependency>
+      <id>commons-validator</id>
+      <version>1.1.3</version>
+    </dependency>
+    <dependency>
+      <id>oro</id>
+      <version>2.0.7</version>
+    </dependency>
+  </dependencies>
+  
+  <build>
+    <nagEmailAddress/>
+    <sourceDirectory>src/java</sourceDirectory>
+<!--
+    <unitTestSourceDirectory/>
+    <integrationUnitTestSourceDirectory/>
+    <aspectSourceDirectory/>
+
+    <resources>      
+      <resource>      
+        <directory></directory>
+        <includes>
+          <include></include>
+        </includes>
+      </resource>
+    </resources>
+
+    <unitTest>
+      <includes>
+        <include>**/Test*.java</include>
+      </includes>
+      <resources>
+        <resource>
+          <directory>src/test</directory>
+          <includes>
+            <include>**/*.jelly</include>
+            <include>**/*.xml</include>
+            <include>**/*.xsl</include>
+            <include>**/*.rng</include>
+            <include>**/*.dtd</include>
+            <include>**/*.properties</include>
+            <include>**/*.html</include>
+          </includes>
+        </resource>
+      </resources>
+    </unitTest>
+    
+    <integrationUnitTestPatterns></integrationUnitTestPatterns>
+-->
+
+  </build>
+
+  <reports>
+		<report>maven-javadoc-plugin</report>
+		<report>maven-junit-report-plugin</report>
+		<report>maven-jdepend-plugin</report>
+		<report>maven-checkstyle-plugin</report>
+		<report>maven-jxr-plugin</report>
+		<report>maven-linkcheck-plugin</report>
+		<report>maven-tasklist-plugin </report>
+		<report>maven-changes-plugin</report>
+		<report>maven-file-activity-plugin</report>
+<!--
+		<report>maven-changelog-plugin</report>
+		<report>maven-developer-activity-plugin</report>
+		<report>maven-license-plugin</report>
+-->
+  </reports>
+</project>

Added: struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js (added)
+++ struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js Tue Feb 15 13:09:29 2005
@@ -0,0 +1,37 @@
+function main() {
+
+  var random =  Math.round( Math.random() * 9 ) + 1;
+  var hint = "No hint for you!"
+  var guesses = 0;
+
+  while (true) {
+
+    // send guess page to user and wait for response
+    forwardAndWait("failure", 
+       { "random"  : random, 
+         "hint"    : hint,
+         "guesses" : guesses} );
+
+    // process user's guess
+    var guess = parseInt( getRequestParams().guess );
+    guesses++;
+    if (guess) {
+      if (guess > random) {
+        hint = "Nope, lower!"
+      } 
+      else if (guess < random) {
+        hint = "Nope, higher!"
+      } 
+      else {
+        // correct guess
+        break;
+      }
+    }
+  }
+
+  // send success page to user
+  forwardAndWait("success", 
+     {"random"  : random, 
+      "guess"   : guess, 
+      "guesses" : guesses} );
+}

Propchange: struts/flow/trunk/src/guess-example/WEB-INF/numberguess.js
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml (added)
+++ struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml Tue Feb 15 13:09:29 2005
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+
+<!DOCTYPE struts-config PUBLIC
+          "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
+          "http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
+
+<struts-config>
+
+
+  <!-- ========== Action Mapping Definitions ============================== -->
+  <action-mappings>
+
+    <action    path="/guess"
+               type="net.sf.struts.flow.FlowAction"
+          className="net.sf.struts.flow.FlowMapping">
+          
+      <set-property property="function" value="main" />
+
+      <forward name="failure"              path="/guess.jsp"/>
+      <forward name="success"              path="/success.jsp"/>
+    </action>
+ </action-mappings>   
+
+
+  <plug-in className="net.sf.struts.flow.FlowPlugIn">
+    <set-property property="scripts" value="/WEB-INF/numberguess.js" />
+    <set-property property="debugger" value="false" />
+    <set-property property="timeToLive" value="600000" />
+  </plug-in>
+
+
+</struts-config>

Propchange: struts/flow/trunk/src/guess-example/WEB-INF/struts-config.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/guess-example/WEB-INF/web.xml
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/WEB-INF/web.xml?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/WEB-INF/web.xml (added)
+++ struts/flow/trunk/src/guess-example/WEB-INF/web.xml Tue Feb 15 13:09:29 2005
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
+<web-app>
+  <!-- Action Servlet Configuration -->
+  <servlet>
+    <servlet-name>action</servlet-name>
+    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
+    <init-param>
+      <param-name>config</param-name>
+      <param-value>/WEB-INF/struts-config.xml</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+
+  <!-- Action Servlet Mapping -->
+  <servlet-mapping>
+    <servlet-name>action</servlet-name>
+    <url-pattern>*.do</url-pattern>
+  </servlet-mapping>
+</web-app>

Propchange: struts/flow/trunk/src/guess-example/WEB-INF/web.xml
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/guess-example/guess.jsp
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/guess.jsp?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/guess.jsp (added)
+++ struts/flow/trunk/src/guess-example/guess.jsp Tue Feb 15 13:09:29 2005
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<html>
+<head>
+  <title>Struts Flow number guessing game</title>
+</head>
+<body>
+
+  <h1>Guess the Number Between 1 and 10</h1>
+  
+  <h2><%= request.getAttribute("hint") %></h2>
+  
+  <h3>You've guessed <%= request.getAttribute("guesses") %> times.</h3>
+  
+  <form method="post" action="guess.do">
+    <input type="hidden" name="contid" value='<%= request.getAttribute("contid") %>' />
+    <input type="text" name="guess"/>
+    <input type="submit"/>
+  </form>
+  
+</body>
+</html>
\ No newline at end of file

Propchange: struts/flow/trunk/src/guess-example/guess.jsp
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/guess-example/index.html
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/index.html?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/index.html (added)
+++ struts/flow/trunk/src/guess-example/index.html Tue Feb 15 13:09:29 2005
@@ -0,0 +1,9 @@
+<html>
+<head>
+  <META HTTP-EQUIV="Refresh" CONTENT="0;URL=./guess.do">
+</head>
+<body>
+  <p>Should be redirected to <a href="guess.do">guess.do</a>
+  </p>
+</body>
+</html>

Added: struts/flow/trunk/src/guess-example/success.jsp
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/guess-example/success.jsp?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/guess-example/success.jsp (added)
+++ struts/flow/trunk/src/guess-example/success.jsp Tue Feb 15 13:09:29 2005
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<html>
+<head>
+  <title>cocoon flow number guessing game</title>
+</head>
+<body>
+
+  <h1>Success!</h1>
+   
+  <h2>The number was: <%= request.getAttribute("random") %></h2>
+  
+  <h3>It took you <%= request.getAttribute("guesses") %> tries.</h3>
+  
+  <p><a href="guess.do">Play again</a></p>
+  
+</body>
+</html>
\ No newline at end of file

Propchange: struts/flow/trunk/src/guess-example/success.jsp
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,84 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow;
+
+import org.apache.commons.logging.*;
+
+/**  Logger extension that hooks into commons-logging */
+public class CommonsLogger extends org.apache.struts.flow.core.Logger {
+
+    private final static Log log = LogFactory.getLog(CommonsLogger.class);
+
+
+    /**
+     *  Logs an error message
+     *
+     *@param  msg  The message
+     */
+    public void error(String msg) {
+        log.error(msg);
+    }
+
+
+    /**
+     *  Logs a warning message
+     *
+     *@param  msg  The message
+     */
+    public void warn(String msg) {
+        log.warn(msg);
+    }
+
+
+    /**
+     *  Logs an info message
+     *
+     *@param  msg  The message
+     */
+    public void info(String msg) {
+        log.info(msg);
+    }
+
+
+    /**
+     *  Logs a debug message
+     *
+     *@param  msg  The message
+     */
+    public void debug(String msg) {
+        log.debug(msg);
+    }
+
+
+    /**
+     *  Gets whether debugging is enabled
+     *
+     *@return    True if enabled
+     */
+    public boolean isDebugEnabled() {
+        return log.isDebugEnabled();
+    }
+
+
+    /**
+     *  Prints an exception
+     *
+     *@param  e  The exception
+     */
+    public void error(Exception e) {
+        log.error(e);
+    }
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/CommonsLogger.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow;
+
+/**
+ *  <p>
+ *
+ *  Global constants for the Chain of Responsibility Library.</p>
+ */
+public final class Constants {
+
+    // -------------------------------------------------- Context Attribute Keys
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the forward name for
+     *  the current request will be stored.</p>
+     */
+    public final static String FORWARD_NAME_KEY = "forward";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the continuation id for
+     *  the current request will be stored.</p>
+     */
+    public final static String CONTINUATION_ID_KEY = "contId";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the business data for
+     *  the current request will be stored.</p>
+     */
+    public final static String BIZ_DATA_KEY = "bizData";
+
+    
+    // ----------------------- Context Attribute Keys borrowed from Struts-Chain
+    
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the <code>Action</code> for
+     *  the current request will be stored.</p>
+     */
+    public final static String ACTION_KEY = "action";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the <code>ActionConfig</code>
+     *  for the current request will be stored.</p>
+     */
+    public final static String ACTION_CONFIG_KEY = "actionConfig";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the <code>ActionForm</code>
+     *  for the current request will be stored.</p>
+     */
+    public final static String ACTION_FORM_KEY = "actionForm";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the <code>ActionServet</code>
+     *  for the current application will be stored.</p>
+     */
+    public final static String ACTION_SERVLET_KEY = "actionServlet";
+
+    /**
+     *  <p>
+     *
+     *  The default context attribute under which the <code>MessageResources</code>
+     *  for the current request will be stored.</p>
+     */
+    public final static String MESSAGE_RESOURCES_KEY = "messageResources";
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/Constants.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,271 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow;
+
+import org.apache.struts.flow.core.Argument;
+import org.apache.struts.flow.core.JSContext;
+import org.apache.struts.flow.core.JavaScriptInterpreter;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.struts.action.*;
+
+import org.mozilla.javascript.Scriptable;
+import org.apache.commons.chain.web.servlet.ServletWebContext;
+
+/**  Executes scripts and continuations */
+public class FlowAction extends Action {
+
+    /**
+     *  Gets the interpreter when no script is specified
+     *
+     *@return    The interpreter value
+     */
+    protected JavaScriptInterpreter getInterpreter() {
+        return (JavaScriptInterpreter) servlet.getServletContext().getAttribute(FlowPlugIn.INTERPRETER_KEY);
+    }
+    
+    /**
+     *  Gets the interpreter for the requested script
+     *
+     *@param script The script to load the interpeter for
+     *@return    The interpreter value
+     */
+    protected JavaScriptInterpreter getInterpreter(String script) {
+        Map map = (Map)servlet.getServletContext().getAttribute(FlowPlugIn.INTERPRETERS_KEY);
+        return (JavaScriptInterpreter) map.get(script);
+    }
+
+
+    /**
+     *  Handle by either starting a new Control Flow or continuing an existing
+     *  one. The logic is:<br />
+     *  - If request contains contid, then continue existing flow.<br />
+     *  - Else if the action mapping parameter attribute has the contid, then
+     *  continue the existing flow.<br />
+     *  - Else start a new flow.<br />
+     *  The name of the function to execute for a new flow should be specified
+     *  in the <code>function</code> property of the custom action mapping
+     *  class, <code>FlowMapping</code>
+     *
+     *@param  request        the request send by the client to the server
+     *@param  response       the response send by the server to the client
+     *@param  mapping        the action mapping
+     *@param  form           the action form
+     *@return                the action forward
+     *@exception  Exception  If something goes wrong
+     */
+    public ActionForward execute(ActionMapping mapping,
+            ActionForm form,
+            HttpServletRequest request,
+            HttpServletResponse response)
+             throws Exception {
+
+        FlowMapping flowMapping = null;
+        if (mapping instanceof FlowMapping) {
+            flowMapping = (FlowMapping) mapping;
+        } else {
+            throw new ServletException("FlowMapping implementation of ActionMapping required");
+        }
+        // Create and populate a Context for this request
+        ServletWebContext context = new ServletWebContext();
+        context.initialize(servlet.getServletContext(), request, response);
+        context.put(Constants.ACTION_SERVLET_KEY,
+                this.servlet);
+        context.put(Constants.ACTION_CONFIG_KEY,
+                mapping);
+        context.put(Constants.ACTION_FORM_KEY,
+                form);
+        context.put(Constants.MESSAGE_RESOURCES_KEY,
+                getResources(request));
+        context.put(Constants.ACTION_KEY, this);
+
+        String contid = request.getParameter("contid");
+       
+        JavaScriptInterpreter interp = null;
+        if (flowMapping.getScript() == null) {
+            interp = getInterpreter();
+        } else {
+            interp = getInterpreter(flowMapping.getScript());
+        }
+
+        String func = flowMapping.getFunction();
+        if (func == null || func.length() == 0) {
+            func = mapping.getParameter();
+        }
+ 
+        if (contid == null || contid.length() == 0) {
+
+            // --- start a new flow
+
+            List args = new LinkedList();
+
+            if (func == null || func.length() == 0) {
+                throw new ServletException("You must specify a function name to call");
+            } else {
+                // call control script function
+                interp.callFunction(func, args, context);
+
+                // retrieve page, continuation ID, and attributes from chain context
+                String page = (String) JSContext.jsobjectToObject(context.get(Constants.FORWARD_NAME_KEY));
+                contid = (String) context.get(Constants.CONTINUATION_ID_KEY);
+                Scriptable bizdata = (Scriptable) context.get(Constants.BIZ_DATA_KEY);
+                Map atts = null;
+                if (bizdata != null) {
+                    atts = JSContext.jsobjectToMap(bizdata);
+                }    
+                return dispatchToPage(request, response, mapping, page, contid, atts);
+            }
+        } else {
+            // --- continue an existing flow
+
+            // kick off continuation
+            context.put("id", "5");
+            interp.handleContinuation(
+                    request.getParameter("contid"), new LinkedList(), context);
+
+            // retrieve page, continuation ID, and attributes from chain context
+            String page = (String) context.get(Constants.FORWARD_NAME_KEY);
+            contid = (String) context.get(Constants.CONTINUATION_ID_KEY);
+            Scriptable bizdata = (Scriptable) context.get(Constants.BIZ_DATA_KEY);
+            Map atts = null;
+            if (bizdata != null) {
+                atts = JSContext.jsobjectToMap(bizdata);
+            }    
+            return dispatchToPage(request, response, mapping, page, contid, atts);
+        }
+    }
+
+
+    /**
+     *  Add continuation ID and attributes to request scope, dispatch to page.
+     *
+     *@param  request            The request
+     *@param  response           The response
+     *@param  page               The action forward name
+     *@param  contid             Continuation ID to be set in request.
+     *@param  atts               Attributes to be set in request.
+     *@param  mapping            The action mapping
+     *@return
+     *@throws  ServletException
+     *@throws  IOException
+     */
+    private ActionForward dispatchToPage(
+            HttpServletRequest request, HttpServletResponse response, ActionMapping mapping,
+            String page, String contid, Map atts)
+             throws ServletException, IOException {
+
+        // Probably only need to process if the response hasn't already been committed.  This
+        // should let flow code be able to completely handle a request if desired.
+        if (!response.isCommitted()) {
+            request.setAttribute("contid", contid);
+
+            if (atts != null) {
+                Iterator attkeys = atts.keySet().iterator();
+                while (attkeys.hasNext()) {
+                    String attkey = (String) attkeys.next();
+                    request.setAttribute(attkey, JSContext.jsobjectToObject(atts.get(attkey)));
+                }
+            }    
+
+            ActionForward af = mapping.findForward(page);
+            if (af == null) {
+                af = new ActionForward(page);
+            }
+            return af;
+        }   
+        return null;
+    }
+
+
+    // These methods seem necessary as some scripting engines are not able to
+    // access Action's protected methods.
+
+    /**
+     *  Saves a token
+     *
+     *@param  req  The request object
+     */
+    public void saveToken(HttpServletRequest req) {
+        super.saveToken(req);
+    }
+
+
+    /**
+     *  Checks to see if the request is cancelled
+     *
+     *@param  req  The request object
+     *@return      True if cancelled
+     */
+    public boolean isCancelled(HttpServletRequest req) {
+        return super.isCancelled(req);
+    }
+
+
+    /**
+     *  Checks to see if the token is valid
+     *
+     *@param  req  The request object
+     *@return      True if valid
+     */
+    public boolean isTokenValid(HttpServletRequest req) {
+        return super.isTokenValid(req);
+    }
+
+
+    /**
+     *  Resets the token
+     *
+     *@param  req  The request object
+     */
+    public void resetToken(HttpServletRequest req) {
+        super.resetToken(req);
+    }
+
+
+    /**
+     *  Saves the messages to the request
+     *
+     *@param  req  The request object
+     *@param  mes  The action messages
+     */
+    public void saveMessages(HttpServletRequest req, ActionMessages mes) {
+        super.saveMessages(req, mes);
+    }
+
+
+    /**
+     *  Saves the errors to the request
+     *
+     *@param  req   The request object
+     *@param  errs  The action errors
+     */
+    public void saveErrors(HttpServletRequest req, ActionErrors errs) {
+        super.saveErrors(req, errs);
+    }
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/FlowAction.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow;
+
+import org.apache.struts.action.ActionMapping;
+
+/**
+ *  <p>
+ *
+ *  The extension of a Struts action mapping adds support for the <code>function</code>
+ *  property which contains the JavaScript Flow function to execute.</p>
+ *
+ *@version    $Revision: 1.3 $ $Date: 2004/06/14 18:46:34 $
+ */
+
+public class FlowMapping extends ActionMapping {
+
+    private String func;
+    private String script;
+
+
+    /**
+     *  Returns the value of script.
+     *
+     *@return    The script value
+     */
+    public String getScript() {
+        return script;
+    }
+
+
+    /**
+     *  Sets the value of script.
+     *
+     *@param  script  The value to assign script.
+     */
+    public void setScript(String script) {
+        this.script = script;
+    }
+
+
+    /**
+     *  Sets the function attribute of the FlowMapping object
+     *
+     *@param  f  The new function value
+     */
+    public void setFunction(String f) {
+        this.func = f;
+    }
+
+
+    /**
+     *  Gets the function attribute of the FlowMapping object
+     *
+     *@return    The function value
+     */
+    public String getFunction() {
+        return func;
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/FlowMapping.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,243 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow;
+
+import org.apache.struts.flow.core.JavaScriptInterpreter;
+import org.apache.struts.flow.core.Factory;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.*;
+import java.util.ArrayList;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.struts.action.ActionServlet;
+import org.apache.struts.action.PlugIn;
+import org.apache.struts.config.ModuleConfig;
+
+/**
+ *  Initializes the Flow interpreter and loads system and user scripts. There
+ *  are two mutually exclusive ways to specify scripts:
+ *  <ol>
+ *    <li> <code>scripts</code> - A comma-delimited list of scripts to load. All
+ *    loaded scripts share the same script scope.</li>
+ *    <li> <code>scriptBase</code> - The base path to use when resolving
+ *    scripts. Each action mapping then needs to set the <code>script</code>
+ *    property for the name of the actual script. The scripts will be looked up
+ *    by concatinating the script base with the script name. Each script gets
+ *    its own scope.</li>
+ *  </ol>
+ *  <p>
+ *
+ *  Scripts can be located either in the webapp directory, as an absolute path
+ *  on the filesystem, or in the classpath like in a jar file. </p> <p>
+ *
+ *  The following optional properties can be specified:</p>
+ *  <ul>
+ *    <li> <code>debugger</code> - Whether to enable the Swing debugger</li>
+ *
+ *    <li> <code>reloadScripts</code> - Whether to enable the reloading of
+ *    scripts if their contents have been modified. The check for modification
+ *    occurs every <code>checkTime</code> interval</li>
+ *    <li> <code>checkTime</code> - The interval time in milliseconds between
+ *    checking for script modifications, if enabled</li>
+ *    <li> <code>timeToLive</code> - The length in milliseconds continuations
+ *    will live from when they were last accessed</li>
+ *  </ul>
+ *
+ */
+public final class FlowPlugIn implements PlugIn {
+
+    /**  Servlet context key flow interpreter is stored under */
+    public final static String INTERPRETER_KEY = "interpreter";
+
+    /**  Servlet context key flow interpreters are stored under */
+    public final static String INTERPRETERS_KEY = "interpreters";
+
+    /**  Commons Logging instance. */
+    private static Log log = LogFactory.getLog(FlowPlugIn.class);
+
+    private ServletContext context;
+    private String scripts = null;
+    private String scriptBase = null;
+
+    private boolean debugger = false;
+    private boolean reloadScripts;
+    private long checkTime;
+
+    private int ttl;
+
+
+    /**
+     *  Gets a comma delimitted list of user scripts.
+     *
+     *@return    comma delimited list of user script path names
+     */
+    public String getScripts() {
+        return scripts;
+    }
+
+
+    /**
+     *  Sets a comma delimitted list of user scripts.
+     *
+     *@param  scripts  delimited list of user script path names
+     */
+    public void setScripts(String scripts) {
+        this.scripts = scripts;
+    }
+
+
+    /**
+     *  Sets the base path to resolve scripts against
+     *
+     *@param  scriptBase  The base path
+     */
+    public void setScriptBase(String scriptBase) {
+        this.scriptBase = scriptBase;
+    }
+
+
+    /**
+     *  Sets the value of reloadScripts.
+     *
+     *@param  reloadScripts  The value to assign reloadScripts.
+     */
+    public void setReloadScripts(boolean reloadScripts) {
+        this.reloadScripts = reloadScripts;
+    }
+
+
+    /**
+     *  Sets the value of checkTime.
+     *
+     *@param  checkTime  The value to assign checkTime.
+     */
+    public void setCheckTime(long checkTime) {
+        this.checkTime = checkTime;
+    }
+
+
+    /**
+     *  Sets the debugger attribute of the FlowPlugIn object
+     *
+     *@param  val  The new debugger value
+     */
+    public void setDebugger(boolean val) {
+        debugger = val;
+    }
+
+
+    /**
+     *  Sets the timeToLive attribute of the FlowPlugIn object
+     *
+     *@param  ttl  The new timeToLive value
+     */
+    public void setTimeToLive(int ttl) {
+        this.ttl = ttl;
+    }
+
+
+    /**
+     *  Initialize the flow interpreter
+     *
+     *@param  servlet               The ActionServlet for this web application
+     *@param  config                The ModuleConfig for our owning module
+     *@exception  ServletException  if we cannot configure ourselves correctly
+     */
+    public void init(ActionServlet servlet, ModuleConfig config)
+             throws ServletException {
+
+        if ((scripts == null || scripts.length() == 0) && scriptBase == null) {
+            throw new ServletException("No scripts or script base defined");
+        }
+        context = servlet.getServletContext();
+        Factory.setLogger(new CommonsLogger());
+        Factory.getContinuationsManager().setDefaultTimeToLive(ttl);
+
+        if (scripts != null && scripts.length() > 0) {
+            StringTokenizer st = new StringTokenizer(scripts, ",");
+            List streamList = new ArrayList();
+            try {
+                JavaScriptInterpreter interp = createInterpreter();
+                context.setAttribute(INTERPRETER_KEY, interp);
+                while (st.hasMoreTokens()) {
+                    String scriptPath = st.nextToken().trim();
+                    if (log.isInfoEnabled()) {
+                        log.info("Registering script '" + scriptPath + "'");
+                    }
+                    interp.register(scriptPath);
+                }
+            } catch (Exception ex) {
+                throw new ServletException("Unable to create global JavaScript interpreter", ex);
+            }
+        } else {
+            Map map =
+                new HashMap() {
+                    public Object get(Object key) {
+                        JavaScriptInterpreter interp = (JavaScriptInterpreter) super.get(key);
+                        if (interp == null) {
+                            if (log.isDebugEnabled()) {
+                                log.debug("Creating interpreter for " + key);
+                            }
+                            interp = createInterpreter();
+                            interp.register(scriptBase + key);
+                            put(key, interp);
+                        }
+                        return interp;
+                    }
+                };
+            context.setAttribute(INTERPRETERS_KEY, map);
+        }
+    }
+
+
+    private JavaScriptInterpreter createInterpreter() {
+        JavaScriptInterpreter interp = new JavaScriptInterpreter();
+        interp.setDebugger(debugger);
+        interp.setCheckTime(checkTime);
+        interp.setReloadScripts(reloadScripts);
+        interp.initialize();
+        interp.register("/system.js");
+        interp.register("/struts.js");
+        return interp;
+    }
+
+
+    /**
+     *  Release any resources that were allocated at initialization, including
+     *  any continuations.
+     */
+    public void destroy() {
+
+        log.info("Finalizing flow plug in");
+        Factory.getContinuationsManager().destroy();
+
+        context.removeAttribute(INTERPRETER_KEY);
+        context.removeAttribute(INTERPRETERS_KEY);
+        scriptBase = null;
+        context = null;
+        scripts = null;
+    }
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/FlowPlugIn.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,65 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+/**  Stores an argument to be passed into the method called for flow execution */
+public class Argument {
+    private String name;
+    private Object value;
+
+
+    /**
+     *  Constructor for the Argument object
+     *
+     *@param  name   The argument name
+     *@param  value  The argument value
+     */
+    public Argument(String name, Object value) {
+        this.name = name;
+        this.value = value;
+    }
+
+
+    /**
+     *  Returns the value of name.
+     *
+     *@return    The name value
+     */
+    public String getName() {
+        return name;
+    }
+
+
+    /**
+     *  Returns the value of value.
+     *
+     *@return    The value value
+     */
+    public Object getValue() {
+        return value;
+    }
+
+
+    /**
+     *  Prints the string value of the state
+     *
+     *@return    The string state
+     */
+    public String toString() {
+        return name + ": " + value;
+    }
+
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/Argument.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,137 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.mozilla.javascript.Context;
+import org.mozilla.javascript.Script;
+import org.mozilla.javascript.Scriptable;
+
+/**
+ *  This is a base class for all interpreters compiling the scripts
+ *
+ *@author     <a href="mailto:ovidiu@apache.org">Ovidiu Predescu</a>
+ *@author     <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
+ *@author     <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+ *@version    CVS $Id: CompilingInterpreter.java,v 1.2 2004/06/02 21:56:54 mrdon
+ *      Exp $
+ */
+public abstract class CompilingInterpreter {
+
+    /**
+     *  Mapping of String objects (absolute script paths) to ScriptSourceEntry's
+     */
+    protected Map compiledScripts = new HashMap();
+
+
+    /**
+     *  TODO - This is a little bit strange, the interpreter calls get Script on
+     *  the ScriptSourceEntry which in turn calls reallyCompileScript on the
+     *  interpreter. I think we need more refactoring here.
+     *
+     *@param  context          The script context
+     *@param  source           The script file
+     *@return                  A compiled script object
+     *@exception  IOException  If anything goes wrong
+     */
+    protected abstract Script compileScript(Context context,
+            File source) throws IOException;
+
+
+    /**
+     *  Compiles the script
+     *
+     *@param  context          The script context
+     *@param  source           The script file
+     *@return                  The compiled script object
+     *@exception  IOException  If anything goes wrong
+     */
+    protected abstract Script reallyCompileScript(Context context,
+            File source) throws IOException;
+
+
+    /**
+     *  An association between the script source and the compiled Script. This
+     *  class also calles the parent class to perform compilation lazily
+     */
+    protected class ScriptSourceEntry {
+        private final File source;
+        private Script script;
+        private long compileTime;
+
+
+        /**
+         *  Constructor for the ScriptSourceEntry object
+         *
+         *@param  source  Script source file
+         */
+        public ScriptSourceEntry(File source) {
+            this.source = source;
+        }
+
+
+        /**
+         *  Constructor for the ScriptSourceEntry object
+         *
+         *@param  source  Script source file
+         *@param  script  Compiled script
+         *@param  t       Compile time in milliseconds
+         */
+        public ScriptSourceEntry(File source, Script script, long t) {
+            this.source = source;
+            this.script = script;
+            this.compileTime = t;
+        }
+
+
+        /**
+         *  Gets the script source
+         *
+         *@return    The source value
+         */
+        public File getSource() {
+            return source;
+        }
+
+
+        /**
+         *  Gets the compiled script. The source is compiled if it hasn't been
+         *  already.
+         *
+         *@param  context          The script context
+         *@param  scope            The script scope
+         *@param  refresh          Whether to check to see if script needs to be
+         *      reloaded by looking at the lastModified property
+         *@param  interpreter      The compiling interpreter
+         *@return                  The script value
+         *@exception  IOException  If anything goes wrong
+         */
+        public Script getScript(Context context, Scriptable scope,
+                boolean refresh, CompilingInterpreter interpreter)
+                 throws IOException {
+            if (script == null || (compileTime < source.lastModified() && refresh)) {
+                script = interpreter.reallyCompileScript(context, source);
+                compileTime = source.lastModified();
+            }
+            return script;
+        }
+    }
+
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/CompilingInterpreter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+/**
+ * ContinuationsDisposer declares the contract for the clean-up of specfic 
+ * continuations.
+ * <p>
+ * Typically an Interpreter implementation that produces continuation 
+ * objects which require proper clean up will implement this interface to get
+ * a call-back in the event of the ContinuationsManager deciding to invalidate 
+ * a WebContinuation. 
+ */
+public interface ContinuationsDisposer {
+    /**
+     * Disposes the passed continuation object.
+     * <p>
+     * This method is called from the ContinuationsManager in the event of
+     * the invalidation of a continuation upon the {@link ContinuationsDisposer}
+     * object passed during the creation of the WebContinuation.
+     * 
+     * @param webContinuation the {@link WebContinuation} value representing the  
+     * continuation object. 
+     */
+    public void disposeContinuation(WebContinuation webContinuation);
+}

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsDisposer.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+/**
+ *  The interface of the Continuations manager. The continuation manager
+ *  maintains a forrest of {@link WebContinuation} trees. Each tree defines the
+ *  flow of control for a user within the application. A <code>WebContinuation</code>
+ *  is created for a continuation object from the scripting language used. A
+ *  continuation object in the implementation of the scripting language is an
+ *  opaque object here. It is only stored inside the <code>WebContinuation</code>
+ *  , without being interpreted in any way.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@since      March 19, 2002
+ *@see        WebContinuation
+ *@version    CVS $Id: ContinuationsManager.java,v 1.3 2004/06/02 21:56:54 mrdon
+ *      Exp $
+ */
+public interface ContinuationsManager {
+
+    /**
+     *  Create a <code>WebContinuation</code> object given a native continuation
+     *  object and its parent. If the parent continuation is null, the <code>WebContinuation</code>
+     *  returned becomes the root of a tree in the forrest.
+     *
+     *@param  kont        an <code>Object</code> value
+     *@param  parentKont  a <code>WebContinuation</code> value
+     *@param  timeToLive  an <code>int</code> value indicating how long in
+     *      seconds this continuation will live in the server if not accessed
+     *@param  disposer    a <code>ContinuationsDisposer</code> instance to
+     *      called when the continuation gets cleaned up.
+     *@return             a <code>WebContinuation</code> value
+     *@see                WebContinuation
+     */
+    public WebContinuation createWebContinuation(Object kont,
+            WebContinuation parentKont,
+            int timeToLive,
+            ContinuationsDisposer disposer);
+
+
+    /**
+     *  Invalidates a <code>WebContinuation</code>. This effectively means that
+     *  the continuation object associated with it will no longer be accessible
+     *  from Web pages. Invalidating a <code>WebContinuation</code> invalidates
+     *  all the <code>WebContinuation</code>s which are children of it.
+     *
+     *@param  k  a <code>WebContinuation</code> value
+     */
+    public void invalidateWebContinuation(WebContinuation k);
+
+
+    /**
+     *  Given a <code>WebContinuation</code> id, retrieve the associated <code>WebContinuation</code>
+     *  object.
+     *
+     *@param  id  a <code>String</code> value
+     *@return     a <code>WebContinuation</code> object, or null if no such
+     *      <code>WebContinuation</code> could be found.
+     */
+    public WebContinuation lookupWebContinuation(String id);
+
+
+    /**
+     *  Prints debug information about all web continuations into the log file.
+     *
+     *@see    WebContinuation#display()
+     */
+    public void displayAllContinuations();
+
+
+    /**
+     *  Set the default time to live value
+     *
+     *@param  ttl  The time-to-live in milliseconds
+     */
+    public void setDefaultTimeToLive(int ttl);
+
+
+    /**  Destroys all continuations and any other resident objects  */
+    public void destroy();
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManager.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,407 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+import java.security.SecureRandom;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ *  The default implementation of {@link ContinuationsManager}.
+ *
+ *@author     <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
+ *@author     <a href="mailto:Michael.Melhem@managesoft.com">Michael Melhem</a>
+ *@since      March 19, 2002
+ *@see        ContinuationsManager
+ *@version    CVS $Id: ContinuationsManagerImpl.java,v 1.3 2004/06/02 21:56:54
+ *      mrdon Exp $
+ */
+public class ContinuationsManagerImpl
+         implements ContinuationsManager {
+
+    private final static int CONTINUATION_ID_LENGTH = 20;
+
+    /**  Random object for creating continuation ids */
+    protected SecureRandom random = null;
+
+    /**
+     *  How long a continuation exists in memory since the last access. The
+     *  time is in miliseconds, and the default is 1 hour.
+     */
+    protected int defaultTimeToLive = 1 * 60 * 60 * 1000;
+
+    /**  Maintains the forrest of <code>WebContinuation</code> trees. */
+    protected Set forrest = Collections.synchronizedSet(new HashSet());
+
+    /**
+     *  Association between <code>WebContinuation</code> ids and the
+     *  corresponding <code>WebContinuation</code> object.
+     */
+    protected Map idToWebCont = Collections.synchronizedMap(new HashMap());
+
+    /**
+     *  Sorted set of <code>WebContinuation</code> instances, based on their
+     *  expiration time. This is used by the background thread to invalidate
+     *  continuations.
+     */
+    protected SortedSet expirations = Collections.synchronizedSortedSet(new TreeSet());
+
+    private Thread expireThread;
+
+    /**
+     *  Gets the logger 
+     *
+     *@return    The logger value
+     */
+    public Logger getLogger() {
+        return Factory.getLogger();
+    }
+
+
+    /**
+     *  Constructor for the ContinuationsManagerImpl object.  Initializes the random
+     *  seed for continuation ids and starts the expiration thread.
+     *
+     *@exception  Exception  If anything goes wrong
+     */
+    public ContinuationsManagerImpl() throws Exception {
+        try {
+            random = SecureRandom.getInstance("SHA1PRNG");
+        } catch (java.security.NoSuchAlgorithmException nsae) {
+            // maybe we are on IBM's SDK
+            random = SecureRandom.getInstance("IBMSecureRandom");
+        }
+        random.setSeed(System.currentTimeMillis());
+        expireThread = new Thread(
+            new Runnable() {
+                public void run() {
+                    boolean shouldKeepRunning = true;
+                    while (shouldKeepRunning) {
+                        try {
+                            Thread.sleep(60 * 1000);
+                        } catch (InterruptedException ex) {
+                            getLogger().debug("Continuation expiration thread interrupted");
+                            shouldKeepRunning = false;
+                        }
+                        if (shouldKeepRunning) {
+                            expireContinuations();
+                        }
+                    }
+                }
+            });
+
+        getLogger().debug("Starting continuation expiration thread");
+        expireThread.setName("Flow continuations expiration thread");
+        expireThread.setPriority(Thread.MIN_PRIORITY);
+        expireThread.start();
+    }
+
+
+    /**
+     *  Set the default time to live value
+     *
+     *@param  ttl  The time-to-live in milliseconds
+     */
+    public void setDefaultTimeToLive(int ttl) {
+        this.defaultTimeToLive = ttl;
+    }
+
+
+    /**
+     *  Create a <code>WebContinuation</code> object given a native continuation
+     *  object and its parent. If the parent continuation is null, the <code>WebContinuation</code>
+     *  returned becomes the root of a tree in the forrest.
+     *
+     *@param  kont        an <code>Object</code> value
+     *@param  parent  a <code>WebContinuation</code> value
+     *@param  timeToLive  an <code>int</code> value indicating how long in
+     *      seconds this continuation will live in the server if not accessed
+     *@param  disposer    a <code>ContinuationsDisposer</code> instance to
+     *      called when the continuation gets cleaned up.
+     *@return             a <code>WebContinuation</code> value
+     *@see                WebContinuation
+     */
+    public WebContinuation createWebContinuation(Object kont,
+            WebContinuation parent,
+            int timeToLive,
+            ContinuationsDisposer disposer) {
+        int ttl = (timeToLive == 0 ? defaultTimeToLive : timeToLive);
+
+        WebContinuation wk = generateContinuation(kont, parent, ttl, disposer);
+
+        if (parent == null) {
+            forrest.add(wk);
+        }
+
+        // REVISIT: This Places only the "leaf" nodes in the expirations Sorted Set.
+        // do we really want to do this?
+        if (parent != null) {
+            if (wk.getParentContinuation().getChildren().size() < 2) {
+                expirations.remove(wk.getParentContinuation());
+            }
+        }
+
+        expirations.add(wk);
+
+        // No need to add the WebContinuation in idToWebCont as it was
+        // already done during its construction.
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK: Just Created New Continuation " + wk.getId());
+        }
+
+        return wk;
+    }
+
+
+    /**
+     *  Invalidates a <code>WebContinuation</code>. This effectively means that
+     *  the continuation object associated with it will no longer be accessible
+     *  from Web pages. Invalidating a <code>WebContinuation</code> invalidates
+     *  all the <code>WebContinuation</code>s which are children of it.
+     *
+     *@param  wk  a <code>WebContinuation</code> value
+     */
+    public void invalidateWebContinuation(WebContinuation wk) {
+        WebContinuation parent = wk.getParentContinuation();
+        if (parent == null) {
+            forrest.remove(wk);
+        } else {
+            List parentKids = parent.getChildren();
+            parentKids.remove(wk);
+        }
+
+        _invalidate(wk);
+    }
+
+
+    private void _invalidate(WebContinuation wk) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK: Manual Expire of Continuation " + wk.getId());
+        }
+        disposeContinuation(wk);
+        expirations.remove(wk);
+
+        // Invalidate all the children continuations as well
+        List children = wk.getChildren();
+        int size = children.size();
+        for (int i = 0; i < size; i++) {
+            _invalidate((WebContinuation) children.get(i));
+        }
+    }
+
+
+    /**
+     *  Makes the continuation inaccessible for lookup, and triggers possible
+     *  needed cleanup code through the ContinuationsDisposer interface.
+     *
+     *@param  wk  the continuation to dispose.
+     */
+    private void disposeContinuation(WebContinuation wk) {
+        idToWebCont.remove(wk.getId());
+
+        // Call specific possible implementation-specific clean-up on this continuation.
+        ContinuationsDisposer disposer = wk.getDisposer();
+        if (disposer != null) {
+            disposer.disposeContinuation(wk);
+        }
+    }
+
+
+    /**
+     *  Given a <code>WebContinuation</code> id, retrieve the associated <code>WebContinuation</code>
+     *  object.
+     *
+     *@param  id  a <code>String</code> value
+     *@return     a <code>WebContinuation</code> object, or null if no such
+     *      <code>WebContinuation</code> could be found.
+     */
+    public WebContinuation lookupWebContinuation(String id) {
+        // REVISIT: Is the folliwing check needed to avoid threading issues:
+        // return wk only if !(wk.hasExpired) ?
+        return (WebContinuation) idToWebCont.get(id);
+    }
+
+
+    /**
+     *  Create <code>WebContinuation</code> and generate unique identifier for
+     *  it. The identifier is generated using a cryptographically strong
+     *  algorithm to prevent people to generate their own identifiers. <p>
+     *
+     *  It has the side effect of interning the continuation object in the
+     *  <code>idToWebCont</code> hash table.
+     *
+     *@param  kont      an <code>Object</code> value representing continuation
+     *@param  parent    value representing parent <code>WebContinuation</code>
+     *@param  ttl       <code>WebContinuation</code> time to live
+     *@param  disposer  <code>ContinuationsDisposer</code> instance to use for
+     *      cleanup of the continuation.
+     *@return           the generated <code>WebContinuation</code> with unique
+     *      identifier
+     */
+    private WebContinuation generateContinuation(Object kont,
+            WebContinuation parent,
+            int ttl,
+            ContinuationsDisposer disposer) {
+
+        byte[] bytes = new byte[CONTINUATION_ID_LENGTH];
+        char[] result = new char[bytes.length * 2];
+        WebContinuation wk = null;
+
+        while (true) {
+            random.nextBytes(bytes);
+
+            for (int i = 0; i < CONTINUATION_ID_LENGTH; i++) {
+                byte ch = bytes[i];
+                result[2 * i] = Character.forDigit(Math.abs(ch >> 4), 16);
+                result[2 * i + 1] = Character.forDigit(Math.abs(ch & 0x0f), 16);
+            }
+
+            String id = new String(result);
+            synchronized (idToWebCont) {
+                if (!idToWebCont.containsKey(id)) {
+                    wk = new WebContinuation(id, kont, parent, ttl, disposer);
+                    idToWebCont.put(id, wk);
+                    break;
+                }
+            }
+        }
+
+        return wk;
+    }
+
+
+    /**
+     *  Removes an expired leaf <code>WebContinuation</code> node from its
+     *  continuation tree, and recursively removes its parent(s) if it they have
+     *  expired and have no (other) children.
+     *
+     *@param  wk  <code>WebContinuation</code> node
+     */
+    private void removeContinuation(WebContinuation wk) {
+        if (wk.getChildren().size() != 0) {
+            return;
+        }
+
+        // remove access to this contination
+        disposeContinuation(wk);
+
+        WebContinuation parent = wk.getParentContinuation();
+        if (parent == null) {
+            forrest.remove(wk);
+        } else {
+            List parentKids = parent.getChildren();
+            parentKids.remove(wk);
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK: deleted this WK: " + wk.getId());
+        }
+
+        // now check if parent needs to be removed.
+        if (null != parent && parent.hasExpired()) {
+            removeContinuation(parent);
+        }
+    }
+
+
+    /**
+     *  Dump to Log file the current contents of the expirations <code>SortedSet</code>
+     */
+    private void displayExpireSet() {
+        Iterator iter = expirations.iterator();
+        StringBuffer wkSet = new StringBuffer("\nWK; Expire Set Size: " + expirations.size());
+        while (iter.hasNext()) {
+            final WebContinuation wk = (WebContinuation) iter.next();
+            final long lat = wk.getLastAccessTime() + wk.getTimeToLive();
+            wkSet.append("\nWK: ")
+                    .append(wk.getId())
+                    .append(" ExpireTime [");
+
+            if (lat < System.currentTimeMillis()) {
+                wkSet.append("Expired");
+            } else {
+                wkSet.append(lat);
+            }
+            wkSet.append("]");
+        }
+
+        getLogger().debug(wkSet.toString());
+    }
+
+
+    /**
+     *  Dump to Log file all <code>WebContinuation</code>s in the system
+     */
+    public void displayAllContinuations() {
+        Iterator iter = forrest.iterator();
+        while (iter.hasNext()) {
+            ((WebContinuation) iter.next()).display();
+        }
+    }
+
+
+    /**  Destroys all continuations and any other resident objects  */
+    public void destroy() {
+        expirations.clear();
+        Set clone = new HashSet(forrest);
+        for (Iterator i = clone.iterator(); i.hasNext(); ) {
+            removeContinuation((WebContinuation) i.next());
+        }
+
+        if (expireThread != null && expireThread.isAlive()) {
+            expireThread.interrupt();
+        }
+    }
+
+
+    /**  Remove all continuations which have already expired */
+    private void expireContinuations() {
+        // log state before continuations clean up
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK: Forrest size: " + forrest.size());
+            displayAllContinuations();
+            displayExpireSet();
+        }
+
+        // clean up
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK CurrentSystemTime[" + System.currentTimeMillis() +
+                    "]: Cleaning up expired Continuations....");
+        }
+        WebContinuation wk;
+        Iterator iter = expirations.iterator();
+        while (iter.hasNext() && ((wk = (WebContinuation) iter.next()).hasExpired())) {
+            iter.remove();
+            this.removeContinuation(wk);
+        }
+
+        // log state after continuations clean up
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("WK: Forrest size: " + forrest.size());
+            displayAllContinuations();
+            displayExpireSet();
+        }
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/ContinuationsManagerImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java
URL: http://svn.apache.org/viewcvs/struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java?view=auto&rev=153960
==============================================================================
--- struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java (added)
+++ struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java Tue Feb 15 13:09:29 2005
@@ -0,0 +1,65 @@
+/*
+ *  Copyright 1999-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.
+ */
+package org.apache.struts.flow.core;
+
+/**
+ *  Simple static factory for getting interface implementations. Should be
+ *  replaced later by something more pluggable.
+ *
+ *@author    <a href="mailto:davjon@sas.com">David M Johnson</a>
+ */
+public class Factory {
+    
+    private static Logger logger = new Logger();
+    private static ContinuationsManager continuationsManager = null;
+
+    /**
+     *  Sets the logger 
+     *
+     *@param  log  The new logger value
+     */
+    public static void setLogger(Logger log) {
+        logger = log;
+    }
+
+
+    /**
+     *  Gets the logger
+     *
+     *@return    The logger value
+     */
+    public static Logger getLogger() {
+        return logger;
+    }
+
+
+    /**
+     *  Gets the continuationsManager 
+     *
+     *@return    The continuationsManager value
+     */
+    public static ContinuationsManager getContinuationsManager() {
+        if (continuationsManager == null) {
+            try {
+                continuationsManager = new ContinuationsManagerImpl();
+            } catch (Exception e) {
+                throw new RuntimeException("ERROR initializing ContinationsManager", e);
+            }
+        }
+        return continuationsManager;
+    }
+}
+

Propchange: struts/flow/trunk/src/java/org/apache/struts/flow/core/Factory.java
------------------------------------------------------------------------------
    svn:executable = *



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