You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lenya.apache.org by ne...@apache.org on 2006/10/27 19:44:56 UTC

svn commit: r468474 - in /lenya/trunk/src: modules-core/usecase/java/src/org/apache/lenya/cms/usecase/ modules/bxe/config/cocoon-xconf/ modules/cforms/ modules/cforms/config/cocoon-xconf/ modules/cforms/flow/ modules/cforms/java/ modules/cforms/java/sr...

Author: nettings
Date: Fri Oct 27 10:44:55 2006
New Revision: 468474

URL: http://svn.apache.org/viewvc?view=rev&rev=468474
Log:
usecase handler cleanup.

[1] remove all cforms-specific code from usecases.js and
UsecaseView.java
[2] split usecases.js into maintainable chunks
[3] introduce a mechanism to add custom flow code (see javadocs in
UsecaseView.java and read usecases.js for details)
[4] remove DummyCFormsUsecase.java and cforms-specific usecases-utils.js
from global code
[5] add CForms.java usecase to cforms module
[6] add custom flow to cforms module to restore functionality
[7] tweak bxe usecases to not create continuations (this restores their
original behaviour which was changed by the previous revision of
usecases.js)

HEADSUP: cforms saving is currently broken, and there is instrumentation
code left in modules/cforms/flow/customFlow.js.


Added:
    lenya/trunk/src/modules/cforms/flow/
    lenya/trunk/src/modules/cforms/flow/customFlow.js   (with props)
    lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js   (with props)
    lenya/trunk/src/modules/cforms/java/
    lenya/trunk/src/modules/cforms/java/src/
    lenya/trunk/src/modules/cforms/java/src/org/
    lenya/trunk/src/modules/cforms/java/src/org/apache/
    lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/
    lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/
    lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/
    lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/
    lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/CForms.java
      - copied, changed from r468313, lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/DummyCFormsUsecase.java
Removed:
    lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/DummyCFormsUsecase.java
    lenya/trunk/src/webapp/lenya/usecases/usecases-util.js
Modified:
    lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/UsecaseView.java
    lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe-close.xconf
    lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe.xconf
    lenya/trunk/src/modules/cforms/config/cocoon-xconf/usecase-edit.xconf
    lenya/trunk/src/modules/cforms/module.xml
    lenya/trunk/src/webapp/lenya/usecases/usecase.xmap
    lenya/trunk/src/webapp/lenya/usecases/usecases.js

Modified: lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/UsecaseView.java
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/UsecaseView.java?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/UsecaseView.java (original)
+++ lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/UsecaseView.java Fri Oct 27 10:44:55 2006
@@ -32,36 +32,100 @@
  * Information about a usecase view.
  * 
  * @version $Id$
+ * 
+ * Example configuration:
+ * <code>&lt;view uri="/modules/foo/usecases/foo-mogrify.jx"
+ *     customFlow="/modules/foo/flow/myflow.js"
+ *     menu="false|true"
+ *     createContinuation="false|true"
+ * &gt;
+ *   &lt;tab group="foo" name="bar"/&gt;      // optional
+ *   &lt;parameter name="foo" value="bar/&gt; // optional
+ * &lt;/view&gt;</code>
+ * <p>
+ * <code>uri</code> is the relative URL of the page to be sent back to the client. If the URI
+ * starts with a slash, it is resolved starting at the root sitemap, otherwise it
+ * is resolved relative to the current sitemap. The URI should not contain a
+ * scheme (such as cocoon:).
+ * </p>
+ * <p>
+ * <code>menu</code> is a boolean that governs whether the Lenya GUI menu is displayed while
+ * the usecase is running. The displaying of the menu is handled by the usecase.xmap sitemap;
+ * hence this option is only functional if <code>uri</code> does <em>not</em> start with a slash
+ * (or if you implement it yourself based on the <code>showMenu()</code> method of this object).<br>
+ * Default is <em>false</em>.
+ * </p>
+ * <p>
+ * <code>customFlow</code> is a javascript file where you can provide custom methods that will override
+ * those in the default usecase handler (<code>webapp/lenya/usecases/usecases.js</code>).
+ * Currently, it provides support for "customLoopFlow" and "customSubmitFlow". Refer to the default handler
+ * for function prototypes and more information.
+ * NB: the "menu" and "createContinuation" attributes will have no effect when you use custom flow code, unless
+ * you check for them and implement the respective functions yourself.
+ * </p>
+ * <p>
+ * <code>createContinuation</code> can be set to false, in which case the generic flowscript
+ * uses "sendPage" instead of "sendPageAndWait" and terminates after the view has been sent.
+ * When <code>createContinuation</code> is false, you must not specify <code>submitFlow</code> 
+ * or <code>loopFlow</code>.<br>
+ * Default is <em>true</em>.
+ * </p>
+ * <p>
+ * For tabbed usecases, you can optionally specify a tab group and name. Additional custom
+ * configuration can be passed via the generic "parameter" element. 
+ * </p>
+ * <p>
+ * For backwards compatibility with existing usecases, the constructor looks for a <code>template</code>
+ * attribute if no <code>uri</code> is present. It is mapped to the same field, viewUri, internally.
+ * </p>
  */
 public class UsecaseView implements Configurable, Serviceable {
 
-    protected static final String ATTRIBUTE_TEMPLATE_URI = "template";
+    protected static final String ATTRIBUTE_URI = "uri";
+    protected static final String ATTRIBUTE_TEMPLATE = "template"; // backwards compatibility, mapped to "uri"
+
+    protected static final String ATTRIBUTE_CUSTOM_FLOW = "customFlow";
     protected static final String ATTRIBUTE_SHOW_MENU = "menu";
+    protected static final String ATTRIBUTE_CREATE_CONT = "createContinuation";
+
+    // additional parameters:
     protected static final String ELEMENT_PARAMETER = "parameter";
     protected static final String ATTRIBUTE_NAME = "name";
     protected static final String ATTRIBUTE_VALUE = "value";
-    
-    protected static final String ATTRIBUTE_TYPE = "type";
-    protected static final String VIEW_CFORM = "cforms";
-    
-    protected static final String ELEMENT_CFORM_DEFINITION = "definition";
-    protected static final String ELEMENT_CFORM_BINDING = "binding";
-    protected static final String ELEMENT_CFORM_OUTRO = "outro";
-    protected static final String ELEMENT_CFORM_INTRO = "intro";
-    
-    protected static final String ATTRIBUTE_URI = "uri";
-    protected static final String ATTRIBUTE_GROUP = "group";
+
+    // tabbed usecases:
+    protected static final String ATTRIBUTE_GROUP = "group"; 
     protected static final String ELEMENT_TAB = "tab";
 
+
     private Map parameters = new HashMap();
+    private ServiceManager manager;
 
+    private String viewUri;
+    private String customFlow;
+    
+    private boolean showMenu;
+    private boolean createContinuation;
+    private Tab tab;
+
+
+    
     /**
      * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
      */
     public void configure(Configuration config) throws ConfigurationException {
-        this.templateUri = config.getAttribute(ATTRIBUTE_TEMPLATE_URI, null);
-        this.viewUri = config.getAttribute(ATTRIBUTE_URI, null);
-        
+        // get <view> attributes:
+        this.viewUri = config.getAttribute(ATTRIBUTE_URI, "");
+        if (this.viewUri == "") {
+           // fall back to "template" attribute for backwards compatibility (rip out eventually).
+           this.viewUri = config.getAttribute(ATTRIBUTE_TEMPLATE, "");
+        }
+        this.showMenu = config.getAttributeAsBoolean(ATTRIBUTE_SHOW_MENU, false);
+        this.customFlow = config.getAttribute(ATTRIBUTE_CUSTOM_FLOW, "");
+        this.createContinuation = config.getAttributeAsBoolean(ATTRIBUTE_CREATE_CONT, true);
+
+
+        // get <tab/> configuration:
         Configuration tabConfig = config.getChild(ELEMENT_TAB, false);
         if (tabConfig != null) {
             String tabName = tabConfig.getAttribute(ATTRIBUTE_NAME);
@@ -79,54 +143,18 @@
             }
         }
 
-        if (this.viewUri == null && this.templateUri == null) {
-            throw new ConfigurationException("Either uri or template attribute must be declared!");
-        }
-
-        this.showMenu = config.getAttributeAsBoolean(ATTRIBUTE_SHOW_MENU, false);
-        
-        this.viewType = config.getAttribute(ATTRIBUTE_TYPE, null);
-        
-        if (this.viewType!=null && this.viewType.equals(VIEW_CFORM)){
-            Configuration cformIntroConfig = config.getChild(ELEMENT_CFORM_INTRO, false);
-            if (cformIntroConfig!=null){
-                this.cformIntro = cformIntroConfig.getValue(null);
-            }
-            Configuration cformDefinitionConfig = config.getChild(ELEMENT_CFORM_DEFINITION, false);
-            if (cformDefinitionConfig!=null){
-                this.cformDefinition = cformDefinitionConfig.getAttribute(ATTRIBUTE_TEMPLATE_URI, null);
-                this.cformDefinitionBody = cformDefinitionConfig.getValue(null);
-            }
-            Configuration cformBindingConfig = config.getChild(ELEMENT_CFORM_BINDING, false);
-            if (cformBindingConfig!=null){
-                this.cformBinding = cformBindingConfig.getAttribute(ATTRIBUTE_TEMPLATE_URI, null);
-                this.cformBindingBody = cformBindingConfig.getValue(null);
-            }
-            Configuration cformOutroConfig = config.getChild(ELEMENT_CFORM_OUTRO, false);
-            if (cformOutroConfig!=null){
-                this.cformOutro = cformOutroConfig.getValue(null);
-            }
-        }
-
+        // get <parameter/> configuration
         Configuration[] parameterConfigs = config.getChildren(ELEMENT_PARAMETER);
         for (int i = 0; i < parameterConfigs.length; i++) {
             String name = parameterConfigs[i].getAttribute(ATTRIBUTE_NAME);
             String value = parameterConfigs[i].getAttribute(ATTRIBUTE_VALUE);
             this.parameters.put(name, value);
         }
-    }
 
-    private String templateUri;
+        checkConfig();
 
-    /**
-     * @return The URI of the JX template;
-     */
-    public String getTemplateURI() {
-        return this.templateUri;
     }
 
-    private String viewUri;
-
     /**
      * @return The URI of the JX template;
      */
@@ -134,16 +162,28 @@
         return this.viewUri;
     }
 
-    private boolean showMenu;
-
     /**
-     * @return If the menubar should be visible on usecase screens.
+     * @return whether the menubar should be visible on usecase screens.
      */
     public boolean showMenu() {
         return this.showMenu;
     }
 
     /**
+     * @return whether a continuation should be created.
+     */
+    public boolean createContinuation() {
+        return this.createContinuation;
+    }
+
+    /**
+     * @return the Flowscript snippet to be executed during the usecase view loop.
+     */
+    public String getCustomFlow() {
+        return this.customFlow;
+    }
+
+    /**
      * @param name The parameter name.
      * @return The parameter value.
      */
@@ -151,8 +191,6 @@
         return (String) this.parameters.get(name);
     }
 
-    private Tab tab;
-
     /**
      * @return The tab the usecase belongs to or <code>null</code>.
      */
@@ -181,8 +219,6 @@
         }
     }
 
-    private ServiceManager manager;
-
     /**
      * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
      */
@@ -190,117 +226,9 @@
         this.manager = manager;
     }
 
-    private String cformDefinition =null;
-
-	/**
-	 * @return Returns the cformDefinition.
-	 */
-	public String getCformDefinition() {
-		return cformDefinition;
-	}
-
-	/**
-	 * @param cformDefinition The cformDefinition to set.
-	 */
-	public void setCformDefinition(String cformDefinition) {
-		this.cformDefinition = cformDefinition;
-	}
-	
-    
-	private String cformBinding =null;
-    
-    private String cformOutro=null;
-    
-    private String cformIntro=null;
-    
-    private String cformDefinitionBody=null;
-    
-    private String cformBindingBody=null;
-
-    /**
-	 * @return Returns the cformBinding.
-	 */
-	public String getCformBinding() {
-		return cformBinding;
-	}
-
-	/**
-	 * @param cformBinding The cformBinding to set.
-	 */
-	public void setCformBinding(String cformBinding) {
-		this.cformBinding = cformBinding;
-	}
-	
-    private String viewType;
-    
-    /**
-     * @return Returns the viewType.
-     */
-    public String getViewType() {
-        return viewType;
-    }
-
-    /**
-     * @param viewType The viewType to set.
-     */
-    public void setViewType(String viewType) {
-        this.viewType = viewType;
-    }
-
-    /**
-     * @return Returns the cformOutro.
-     */
-    public String getCformOutro() {
-        return cformOutro;
-    }
-
-    /**
-     * @param cformOutro The cformOutro to set.
-     */
-    public void setCformOutro(String cformOutro) {
-        this.cformOutro = cformOutro;
-    }
-
-    /**
-     * @return Returns the cformIntro.
-     */
-    public String getCformIntro() {
-        return cformIntro;
-    }
-
-    /**
-     * @param cformIntro The cformIntro to set.
-     */
-    public void setCformIntro(String cformIntro) {
-        this.cformIntro = cformIntro;
-    }
-
-    /**
-     * @return Returns the cformBindingBody.
-     */
-    public String getCformBindingBody() {
-        return cformBindingBody;
-    }
-
-    /**
-     * @param cformBindingBody The cformBindingBody to set.
-     */
-    public void setCformBindingBody(String cformBindingBody) {
-        this.cformBindingBody = cformBindingBody;
-    }
-
-    /**
-     * @return Returns the cformDefinitionBody.
-     */
-    public String getCformDefinitionBody() {
-        return cformDefinitionBody;
-    }
-
-    /**
-     * @param cformDefinitionBody The cformDefinitionBody to set.
-     */
-    public void setCformDefinitionBody(String cformDefinitionBody) {
-        this.cformDefinitionBody = cformDefinitionBody;
+    private void checkConfig() throws ConfigurationException {
+        if (this.tab != null && this.viewUri == "") {
+            throw new ConfigurationException("When you specify a <tab/>, you must specify a <view uri=\"..\"/> as well!");
+        }
     }
-
-}
\ No newline at end of file
+}

Modified: lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe-close.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe-close.xconf?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe-close.xconf (original)
+++ lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe-close.xconf Fri Oct 27 10:44:55 2006
@@ -23,7 +23,7 @@
     
     <component-instance name="bxe.close" logger="lenya.publication" 
     class="org.apache.lenya.cms.usecase.DummyUsecase">
-      <view uri="cocoon://modules/bxe/bxe.close" menu="false"/>
+      <view uri="cocoon://modules/bxe/bxe.close" menu="false" createContinuation="false"/>
     </component-instance>
     
   </xconf>

Modified: lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe.xconf?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe.xconf (original)
+++ lenya/trunk/src/modules/bxe/config/cocoon-xconf/usecase-bxe.xconf Fri Oct 27 10:44:55 2006
@@ -23,7 +23,7 @@
     
     <component-instance name="bxe.edit" logger="lenya.publication" 
     class="org.apache.lenya.cms.workflow.usecases.CheckWorkflow">
-      <view uri="cocoon://modules/bxe/bxe.open" menu="false"/>
+      <view uri="cocoon://modules/bxe/bxe.open" menu="false" createContinuation="false"/>
       <event id="edit"/>
     </component-instance>
     

Modified: lenya/trunk/src/modules/cforms/config/cocoon-xconf/usecase-edit.xconf
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/cforms/config/cocoon-xconf/usecase-edit.xconf?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/modules/cforms/config/cocoon-xconf/usecase-edit.xconf (original)
+++ lenya/trunk/src/modules/cforms/config/cocoon-xconf/usecase-edit.xconf Fri Oct 27 10:44:55 2006
@@ -3,23 +3,11 @@
 <xconf xpath="/cocoon/usecases" unless="/cocoon/usecases/component-instance[@name = 'cforms.edit']">
   <component-instance name="cforms.edit"
                       logger="lenya.site"
-                      class="org.apache.lenya.cms.usecase.DummyCFormsUsecase">
-    <view template="modules/cforms/usecases/dynamicrepeater_template.xml" type="cforms">
-      <intro/>
-      <definition template="modules/cforms/usecases/dynamicrepeater.xml">
-          form.setAttribute("counter", new java.lang.Integer(0));
-      </definition>
-      <binding template="modules/cforms/usecases/dynamicrepeater_binding.xml">
-          generic.doc = loadDocument(generic.proxy.getParameter('sourceUri'));
-          form.load(generic.doc);
-      </binding>
-      <outro>
-        form.save(generic.doc);
-        var flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
-        flowHelper.triggerWorkflow(cocoon, 'edit');
-        saveDocument(generic.doc, generic.proxy.getParameter('sourceUri'));
-      </outro>
-    </view>
+                      class="org.apache.lenya.cms.editors.cforms.CForms">
+    <view 
+       uri="modules/cforms/usecases/dynamicrepeater_template.xml" 
+       customFlow="fallback://lenya/modules/cforms/flow/customFlow.js"
+    />
   </component-instance>
 </xconf>
 

Added: lenya/trunk/src/modules/cforms/flow/customFlow.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/cforms/flow/customFlow.js?view=auto&rev=468474
==============================================================================
--- lenya/trunk/src/modules/cforms/flow/customFlow.js (added)
+++ lenya/trunk/src/modules/cforms/flow/customFlow.js Fri Oct 27 10:44:55 2006
@@ -0,0 +1,92 @@
+function customLoopFlow(view,proxy,generic) {
+   // load some helper functions
+   // cocoon.load("fallback://lenya/modules/cforms/flow/lenyadoc-utils.js");
+    try {
+        var formDef = "fallback://lenya/modules/cforms/usecases/dynamicrepeater.xml";
+        var formBind = "fallback://lenya/modules/cforms/usecases/dynamicrepeater_binding.xml";
+        var formView = "usecases-view/menu/modules/cforms/usecases/dynamicrepeater_template.xml";
+        generic.form = new Form(formDef);
+        generic.form.setAttribute("counter", new java.lang.Integer(0));
+        generic.form.createBinding(formBind);
+        
+        try {
+                var parser = cocoon.getComponent(Packages.org.apache.excalibur.xml.dom.DOMParser.ROLE);
+                var resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+                var source = resolver.resolveURI(proxy.getParameter('sourceUri'));
+                var is = new Packages.org.xml.sax.InputSource(source.getInputStream());
+                is.setSystemId(source.getURI());
+                generic.doc = parser.parseDocument(is);
+        } finally {
+                if (source != null)
+                resolver.release(source);
+                cocoon.releaseComponent(parser);
+                cocoon.releaseComponent(resolver);
+        }
+        
+        generic.form.load(generic.doc);
+        generic.form.showForm(formView, {"usecase" : proxy});
+    } catch (exception) {
+        // if an exception was thrown by the view, allow the usecase to rollback the transition
+        log("error", "Exception during customLoopFlow: " + exception);
+        throw exception;
+    }
+}
+function customSubmitFlow(usecase, generic) {
+    generic.form.save(generic.doc);
+    var flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
+//    try {
+        flowHelper.triggerWorkflow(cocoon, 'edit');
+        //saveDocument(generic.doc, usecase.getSourceURL());
+//        try {
+            var resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+            var source = resolver.resolveURI(usecase.getSourceURL());
+            var tf = Packages.javax.xml.transform.TransformerFactory.newInstance();
+            log("debug", "source instanceof ModifiableSource ? " + (source instanceof Packages.org.apache.excalibur.source.ModifiableSource));
+            log("debug", "tf.getFeature(SAXTransformerFactory.FEATURE): " + tf.getFeature(Packages.javax.xml.transform.sax.SAXTransformerFactory.FEATURE));
+            if (source instanceof Packages.org.apache.excalibur.source.ModifiableSource
+                    && tf.getFeature(Packages.javax.xml.transform.sax.SAXTransformerFactory.FEATURE)) {
+                var outputStream = source.getOutputStream();
+                var transformerHandler = tf.newTransformerHandler();
+                var transformer = transformerHandler.getTransformer();
+                transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "true");
+                transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.METHOD, "xml");
+                transformerHandler.setResult(new Packages.javax.xml.transform.stream.StreamResult(outputStream));
+
+                var streamer = new Packages.org.apache.cocoon.xml.dom.DOMStreamer(transformerHandler);
+                streamer.stream(generic.doc);
+            } else {
+                throw new Packages.org.apache.cocoon.ProcessingException("Cannot write to source " + usecase.getSourceURL());
+            }
+/*        } catch (exception) {
+            log("error", "Something went wrong during saving: " + exception, usecase.getName());
+            log("debug", "usecase.getSourceURL(): " + usecase.getSourceURL(), usecase.getName());
+            log("debug", "source: " + source, usecase.getName());
+            log("debug", "tf: " + tf, usecase.getName());
+            log("debug", "generic.doc: " + generic.doc, usecase.getName());
+            log("debug", "outputStream: " + outputStream, usecase.getName());
+            //log("debug", "streamer.stream(generic.doc): " + streamer.stream(generic.doc), usecase.getName());
+            throw exception;
+        } finally {
+            if (source != null)
+            resolver.release(source);
+            cocoon.releaseComponent(resolver);
+            if (outputStream != null) {
+            try {
+                outputStream.flush();
+                outputStream.close();
+            } catch (exception) {
+                log("error", "Could not flush/close outputstream: " + exception, usecase.getName());
+                throw exception;
+            }
+            }
+        }
+
+    } catch (exception) {
+        log("error", "Exception during customSubmitFlow: " + exception, usecase.getName());
+        throw exception;
+    } finally {
+        cocoon.releaseComponent(flowHelper);
+    }
+*/
+    return "success";
+}

Propchange: lenya/trunk/src/modules/cforms/flow/customFlow.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js?view=auto&rev=468474
==============================================================================
--- lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js (added)
+++ lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js Fri Oct 27 10:44:55 2006
@@ -0,0 +1,162 @@
+/*
+ * Copyright  1999-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: usecases.js 265544 2005-08-31 18:40:31Z thorsten $ */
+
+var loadDocument;
+
+function loadDocument(uri) {
+    var parser = null;
+    var source = null;
+    var resolver = null;
+    try {
+        parser = cocoon.getComponent(Packages.org.apache.excalibur.xml.dom.DOMParser.ROLE);
+        resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+        source = resolver.resolveURI(uri);
+        var is = new Packages.org.xml.sax.InputSource(source.getInputStream());
+        is.setSystemId(source.getURI());
+        return parser.parseDocument(is);
+    } finally {
+        if (source != null)
+            resolver.release(source);
+        cocoon.releaseComponent(parser);
+        cocoon.releaseComponent(resolver);
+    }
+}
+
+var saveDocument;
+
+function saveDocument(document, uri) {
+    var source = null;
+    var resolver = null;
+    var outputStream = null;
+    try {
+        resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+        source = resolver.resolveURI(uri);
+
+        var tf = Packages.javax.xml.transform.TransformerFactory.newInstance();
+
+        if (source instanceof Packages.org.apache.excalibur.source.ModifiableSource
+            && tf.getFeature(Packages.javax.xml.transform.sax.SAXTransformerFactory.FEATURE)) {
+
+            outputStream = source.getOutputStream();
+            var transformerHandler = tf.newTransformerHandler();
+            var transformer = transformerHandler.getTransformer();
+            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "true");
+            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.METHOD, "xml");
+            transformerHandler.setResult(new Packages.javax.xml.transform.stream.StreamResult(outputStream));
+
+            var streamer = new Packages.org.apache.cocoon.xml.dom.DOMStreamer(transformerHandler);
+            streamer.stream(document);
+        } else {
+            throw new Packages.org.apache.cocoon.ProcessingException("Cannot write to source " + uri);
+        }
+    } finally {
+        if (source != null)
+            resolver.release(source);
+        cocoon.releaseComponent(resolver);
+        if (outputStream != null) {
+            try {
+                outputStream.flush();
+                outputStream.close();
+            } catch (error) {
+                cocoon.log.error("Could not flush/close outputstream: " + error);
+            }
+        }
+    }
+}
+/*
+ * Copyright  1999-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: usecases.js 265544 2005-08-31 18:40:31Z thorsten $ */
+
+var loadDocument;
+
+function loadDocument(uri) {
+    var parser = null;
+    var source = null;
+    var resolver = null;
+    try {
+        parser = cocoon.getComponent(Packages.org.apache.excalibur.xml.dom.DOMParser.ROLE);
+        resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+        source = resolver.resolveURI(uri);
+        var is = new Packages.org.xml.sax.InputSource(source.getInputStream());
+        is.setSystemId(source.getURI());
+        return parser.parseDocument(is);
+    } finally {
+        if (source != null)
+            resolver.release(source);
+        cocoon.releaseComponent(parser);
+        cocoon.releaseComponent(resolver);
+    }
+}
+
+var saveDocument;
+
+function saveDocument(document, uri) {
+    var source = null;
+    var resolver = null;
+    var outputStream = null;
+    try {
+        resolver = cocoon.getComponent(Packages.org.apache.cocoon.environment.SourceResolver.ROLE);
+        source = resolver.resolveURI(uri);
+
+        var tf = Packages.javax.xml.transform.TransformerFactory.newInstance();
+
+        if (source instanceof Packages.org.apache.excalibur.source.ModifiableSource
+            && tf.getFeature(Packages.javax.xml.transform.sax.SAXTransformerFactory.FEATURE)) {
+
+            outputStream = source.getOutputStream();
+            var transformerHandler = tf.newTransformerHandler();
+            var transformer = transformerHandler.getTransformer();
+            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.INDENT, "true");
+            transformer.setOutputProperty(Packages.javax.xml.transform.OutputKeys.METHOD, "xml");
+            transformerHandler.setResult(new Packages.javax.xml.transform.stream.StreamResult(outputStream));
+
+            var streamer = new Packages.org.apache.cocoon.xml.dom.DOMStreamer(transformerHandler);
+            streamer.stream(document);
+        } else {
+            throw new Packages.org.apache.cocoon.ProcessingException("Cannot write to source " + uri);
+        }
+    } finally {
+        if (source != null)
+            resolver.release(source);
+        cocoon.releaseComponent(resolver);
+        if (outputStream != null) {
+            try {
+                outputStream.flush();
+                outputStream.close();
+            } catch (error) {
+                cocoon.log.error("Could not flush/close outputstream: " + error);
+            }
+        }
+    }
+}

Propchange: lenya/trunk/src/modules/cforms/flow/lenyadoc-utils.js
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/CForms.java (from r468313, lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/DummyCFormsUsecase.java)
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/CForms.java?view=diff&rev=468474&p1=lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/DummyCFormsUsecase.java&r1=468313&p2=lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/CForms.java&r2=468474
==============================================================================
--- lenya/trunk/src/modules-core/usecase/java/src/org/apache/lenya/cms/usecase/DummyCFormsUsecase.java (original)
+++ lenya/trunk/src/modules/cforms/java/src/org/apache/lenya/cms/editors/cforms/CForms.java Fri Oct 27 10:44:55 2006
@@ -13,7 +13,7 @@
  *  limitations under the License.
  *
  */
-package org.apache.lenya.cms.usecase;
+package org.apache.lenya.cms.editors.cforms;
 
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.lenya.cms.publication.Document;
@@ -25,7 +25,7 @@
 /**
  * Dummy CForms usecase.
  */
-public class DummyCFormsUsecase extends DocumentUsecase {
+public class CForms extends DocumentUsecase {
     
     /**
      * @see org.apache.lenya.cms.usecase.AbstractUsecase#initParameters()

Modified: lenya/trunk/src/modules/cforms/module.xml
URL: http://svn.apache.org/viewvc/lenya/trunk/src/modules/cforms/module.xml?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/modules/cforms/module.xml (original)
+++ lenya/trunk/src/modules/cforms/module.xml Fri Oct 27 10:44:55 2006
@@ -19,6 +19,7 @@
 
 <module xmlns="http://apache.org/lenya/module/1.0">
   <id>org.apache.lenya.modules.cforms</id>
+  <depends module="org.apache.lenya.modules.usecase"/>
   <package>org.apache.lenya.modules</package>
   <version>0.1-dev</version>
   <name>CForms Editor</name>

Modified: lenya/trunk/src/webapp/lenya/usecases/usecase.xmap
URL: http://svn.apache.org/viewvc/lenya/trunk/src/webapp/lenya/usecases/usecase.xmap?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/webapp/lenya/usecases/usecase.xmap (original)
+++ lenya/trunk/src/webapp/lenya/usecases/usecase.xmap Fri Oct 27 10:44:55 2006
@@ -23,12 +23,12 @@
 
 <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
 
-  <map:components>
-    <map:transformers default="xslt">    
-      <map:transformer name="browser-update" src="org.apache.cocoon.ajax.BrowserUpdateTransformer"/>
-    </map:transformers>
-    <map:selectors>
-      <map:selector name="ajax-request" src="org.apache.cocoon.ajax.AjaxRequestSelector"/>
+  <map:components>
+    <map:transformers default="xslt">    
+      <map:transformer name="browser-update" src="org.apache.cocoon.ajax.BrowserUpdateTransformer"/>
+    </map:transformers>
+    <map:selectors>
+      <map:selector name="ajax-request" src="org.apache.cocoon.ajax.AjaxRequestSelector"/>
     </map:selectors>
   </map:components>
   
@@ -48,7 +48,7 @@
         executeUsecase() flowscript has completed and issued a redirect,
         which is matched here.
         -->
-      <map:match pattern="view/*/**" internal-only="true">
+      <map:match pattern="usecases-view/*/**" internal-only="true">
         
         <map:generate type="jx" src="fallback://lenya/{2}"/>
         <map:transform type="browser-update"/>
@@ -64,12 +64,12 @@
           <map:parameter name="resources-uri" value="{page-envelope:context-prefix}/cforms"/>
         </map:transform>
         <map:transform src="fallback://lenya/xslt/cforms/add-xhtml-namespace.xsl"/>
-        <map:match pattern="view/menu/**">
+        <map:match pattern="usecases-view/menu/**">
           <map:transform src="cocoon://lenya-page/{page-envelope:publication-id}/{page-envelope:area}/default.xml"/>
         </map:match>
-        <map:select type="ajax-request">
-          <map:when test="true">
-            <map:serialize type="xml"/>
+        <map:select type="ajax-request">
+          <map:when test="true">
+            <map:serialize type="xml"/>
           </map:when>
         </map:select>
         <map:select type="request-parameter">

Modified: lenya/trunk/src/webapp/lenya/usecases/usecases.js
URL: http://svn.apache.org/viewvc/lenya/trunk/src/webapp/lenya/usecases/usecases.js?view=diff&rev=468474&r1=468473&r2=468474
==============================================================================
--- lenya/trunk/src/webapp/lenya/usecases/usecases.js (original)
+++ lenya/trunk/src/webapp/lenya/usecases/usecases.js Fri Oct 27 10:44:55 2006
@@ -16,299 +16,347 @@
  */
 /* $Id$ */
  
- cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js");
- cocoon.load("fallback://lenya/usecases/usecases-util.js");
+cocoon.load("resource://org/apache/cocoon/forms/flow/javascript/Form.js");
 
-/* Helper method to add all request parameters to a usecase */
-function passRequestParameters(flowHelper, usecase) {
+//placeholders for custom flow code:
+var customLoopFlow = undefined;  
+var customSubmitFlow = undefined;
+
+/**
+ * Get the current usecase.
+ *
+ * @param the name of the usecase
+ * @return a org.apache.lenya.cms.usecase.Usecase object
+ */
+function getUsecase(usecaseName) {
+    var flowHelper;
+    var request;
+    var sourceUrl;
+    var usecaseResolver;
+    var usecase;
+    try {
+        flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
+        request = flowHelper.getRequest(cocoon);
+        sourceUrl = Packages.org.apache.lenya.util.ServletHelper.getWebappURI(request);
+        usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
+        usecase = usecaseResolver.resolve(sourceUrl, usecaseName);
+        usecase.setSourceURL(sourceUrl);
+        usecase.setName(usecaseName);
+    } catch (exception) {
+        log("error", "Error in getUsecase(): " + exception);
+        log("debug", "usecaseName = " + usecaseName);
+        log("debug", "flowHelper = " + flowHelper);
+        log("debug", "request = " + request);
+        log("debug", "sourceUrl = " + sourceUrl);
+        log("debug", "usecaseResolver = " + usecaseResolver);
+        log("debug", "usecase = " + usecase);
+
+        throw exception;
+    } finally {
+        cocoon.releaseComponent(flowHelper);
+        cocoon.releaseComponent(usecaseResolver);
+    }
+    return usecase;
+}
+
+/**
+ * Release a usecase. Since usecases are Avalon Components, they must
+ * be released before a continuation is created.
+ *
+ * @param a org.apache.lenya.cms.usecase.Usecase object
+ */
+function releaseUsecase(usecase) {
+    var usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
+    try {
+        usecaseResolver.release(usecase);
+    } finally {
+        cocoon.releaseComponent(usecaseResolver);
+    }
+}
+
+/**
+ * Pass all parameters from the current request to a usecase
+ * (except lenya.usecase, lenya.continuation and submit).
+ *
+ * @param a org.apache.lenya.cms.usecase.Usecase object
+ */
+function passRequestParameters(usecase) {
+    var flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
     var names = cocoon.request.getParameterNames();
     while (names.hasMoreElements()) {
         var name = names.nextElement();
-        if (!name.equals("lenya.usecase")
-            && !name.equals("lenya.continuation")
-            && !name.equals("submit")) {
-            
+        // some parameters are handled elsewhere:
+        if (!name.equals("lenya.usecase") 
+            && !name.equals("lenya.continuation") 
+            && !name.equals("submit")) { 
+            // pass the rest on:
             var value = flowHelper.getRequest(cocoon).get(name);
-            
             var string = new Packages.java.lang.String();
             var vector = new Packages.java.util.Vector();
             if (string.getClass().isInstance(value) || vector.getClass().isInstance(value)) {
                 // use getParameters() to avoid character encoding problems
                 var values = flowHelper.getRequest(cocoon).getParameterValues(name);
-				if (values.length < 2) {
+                if (values.length < 2) {
                     usecase.setParameter(name, values[0]);
-			    } else {
-					usecase.setParameter(name, values);
-				}
-            }
-            else {
+                } else {
+                    usecase.setParameter(name, values);
+                }
+            } else {
                 usecase.setPart(name, value);
             }
-            
         }
     }
+    cocoon.releaseComponent(flowHelper);
 }
 
+/**
+ * Load the custom flow functions as provided in the view 
+ * configuration, if any.
+ *
+ * @param a org.apache.lenya.cms.usecase.UsecaseView object
+ */
+function loadCustomFlow(view) {
+    var flowUri = view.getCustomFlow();
+    if (flowUri != null && flowUri != "") { // for some reason, flowUri is not correctly cast into a Boolean, so "if (flowUri)" does not work
+          log("debug", "customFlow uri: [" + flowUri + "]");
+          //loopFlow = new Function(prepareCustomFlow(flowUri));
+          cocoon.load(flowUri);
+    }
+}
 
-/*
- * Main function to execute a usecase.
+
+/**
+ * Log messages via cocoon.log.
  *
- * Uses request parameter "lenya.usecase" to determine what
- * usecase to execute.
+ * @param level, one of ("debug"|"warn"|"error")
+ * @param message (a string).
+ * @param usecaseName (a string).
+ */
+function log(level, message, usecaseName) {
+    var msg = "usecases.js::executeUsecase() "
+        + (usecaseName ? "with lenya.usecase=[" + usecaseName + "]" : "")
+        + ": " 
+        + message;
+    switch (level) {
+        case "debug":
+            if (cocoon.log.isDebugEnabled())
+                cocoon.log.debug(msg);
+            break;
+        case "info":
+            cocoon.log.info(msg);
+            break;
+       case "warn":
+            cocoon.log.warn(msg);
+            break;
+        case "error":
+            cocoon.log.error(msg);
+            break;
+        default:
+            cocoon.log.error(msg + "[Unknown log level " + level + "]"); 
+            break;
+    }
+}
+
+/**
+ * The Loop stage of the flow, in which a view is displayed. 
+ * <em>Note:</em> All Avalon components should be released before calling
+ * this function! This means especially that you cannot hold a usecase object,
+ * hence the proxy.
  * 
+ * @param a org.apache.lenya.cms.usecase.UsecaseView object
+ * @param a org.apache.lenya.cms.usecase.UsecaseProxy object
+ * @param a generic Javascript object for custom flow code to preserve state information (not used by default)
+ *
+ * This function invokes customLoopFlow if it exists.
+ * Otherwise it falls back to defaultLoopFlow.
  */
-function executeUsecase() {
+function loopFlow(view, proxy, generic) {
+    if (customLoopFlow != undefined) {
+        log("info", "Using customLoopFlow function", proxy.getName());
+        return customLoopFlow(view, proxy, generic);
+    } else{
+        return defaultLoopFlow(view, proxy);
+    }
+}
 
-    var usecaseName = cocoon.parameters["usecaseName"];
 
-    var view;
-    var proxy;
-    var menu = "nomenu";
-    
-    var usecaseResolver;
-    var usecase;
-    var sourceUrl;
-    
-    if (cocoon.log.isDebugEnabled())
-       cocoon.log.debug("usecases.js::executeUsecase() called, parameter lenya.usecase = [" + usecaseName + "]");
-    
-    try {
+/**
+ * The Submit stage of the flow, in which a user interaction is processed.
+ * and the usecase is advanced. If the user has submitted, the usecase is executed.
+ * 
+ * @param a org.apache.lenya.cms.usecase.Usecase object
+ * @param a generic Javascript object for custom flow code to preserve state information (not used by default)
+ * @return a string with the return state ("success"|"cancel"|"continue").
+ *
+ * This function invokes customSubmitFlow if it exists.
+ * Otherwise it falls back to defaultSubmitFlow.
+ */
+function submitFlow(usecase, generic) {
+    if (customSubmitFlow != null) {
+        log("info", "Using customSubmitFlow function", usecase.getName());
+        return customSubmitFlow(usecase, generic);
+    } else{
 
-        var flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
-        var request = flowHelper.getRequest(cocoon);
-        sourceUrl = Packages.org.apache.lenya.util.ServletHelper.getWebappURI(request);
+        return defaultSubmitFlow(usecase);
+    }
+}
 
-        usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
-        usecase = usecaseResolver.resolve(sourceUrl, usecaseName);
-        usecase.setSourceURL(sourceUrl);
-        usecase.setName(usecaseName);
-        view = usecase.getView();
-        if (view && view.showMenu()) {
-            menu = "menu";
+/**
+ * @see loopFlow.
+ */
+function defaultLoopFlow(view, proxy) {
+    var viewUri = view.getViewURI();
+    // we used to allow a cocoon:/ prefix (which sendPageXXX does not handle),
+    // but it is now deprecated!
+    if (viewUri.startsWith("cocoon:/")) {
+        viewUri = viewUri.substring(new Packages.java.lang.String("cocoon:/").length());
+        log("warn", "The use of the cocoon:/ protocol prefix in the <view uri=\"...\"> attribute is deprecated!");
+    }
+    if (! viewUri.startsWith("/")) {
+        // a local URI must be handled by usecase.xmap, which assumes a prefix "usecases-view/[menu|nomenu]/
+        // that determines whether the menu is to be displayed. this mechanism is used by most lenya core usecases.
+        viewUri = "usecases-view/" 
+            + (view.showMenu() ? "menu" : "nomenu")
+            + "/" + viewUri;
+    }
+    if (view.createContinuation()) {
+        log("debug", "Creating view and continuation, calling Cocoon with viewUri = [" + viewUri + "]");
+        cocoon.sendPageAndWait(viewUri, { "usecase" : proxy });
+    } else {
+        log("debug", "Creating view without continuation (!), calling Cocoon with viewUri = [" + viewUri + "]");
+        cocoon.sendPage(viewUri, { "usecase" : proxy});
+        cocoon.exit(); // we're done.
+    }
+}
+
+/**
+ * @see submitFlow
+ */
+function defaultSubmitFlow(usecase) {
+    usecase.advance();
+    if (cocoon.request.getParameter("submit")||cocoon.request.getParameter("lenya.submit")=="ok") {
+        usecase.checkExecutionConditions();
+        if (! usecase.hasErrors()) {
+            return executeFlow(usecase);
         }
+    } else if (cocoon.request.getParameter("cancel")) {
+        usecase.cancel();
+        return "cancel";
+    }
+    return "continue"
+}
 
-        passRequestParameters(flowHelper, usecase);
+/**
+ * The Execute stage of the flow, in which the usecase is finally executed.
+ *
+ * @param a org.apache.lenya.cms.usecase.Usecase object
+ * @return a string with the return state ("success"|"continue").
+ */
+function executeFlow(usecase) {
+    usecase.execute();
+    if (! usecase.hasErrors()) {
+        usecase.checkPostconditions();
+        if (! usecase.hasErrors()) {
+            return "success";
+        }
+    }
+    return "continue";
+}
+
+/**
+ * Redirect to target URL after finishing the usecase.
+ *
+ * @param the target URL
+ */
+function redirect(targetUrl) {
+    var flowHelper = cocoon.getComponent("org.apache.lenya.cms.cocoon.flow.FlowHelper");
+    var contextPath = flowHelper.getRequest(cocoon).getContextPath();
+    cocoon.releaseComponent(flowHelper);
+    cocoon.redirectTo(contextPath + targetUrl, true);
+}
+
+
+
+/**
+ * Main function to execute a usecase. This is called from <map:flow/>.
+ *
+ * Uses request parameter "lenya.usecase" to determine what
+ * usecase to execute.
+ * 
+ * Since "usecase" and "flowHelper" are avalon components, 
+ * they must be released before a continuation is created.
+ * In order to preserve state information, a "proxy" object
+ * is used.
+ */
+function executeUsecase() {
+
+    var usecaseName;
+    var usecase; // the Usecase object
+    var proxy; // a UsecaseProxy to make the usecase state persistent across continuations
+    var view; // the UsecaseView object that belongs to our usecase.
+    var state; // the state of the usecase ("continue"|"success"|"cancel");
+    var targetUrl; // URL to redirect to after completion.
+    var generic = new Object; // a generic helper object for custom flow code to preserve state information.
+
+    try {
+        usecaseName = cocoon.parameters["usecaseName"];
+        usecase = getUsecase(usecaseName);
+        passRequestParameters(usecase);
         usecase.checkPreconditions();
         usecase.lockInvolvedObjects();
+        // create proxy object to save usecase state
         proxy = new Packages.org.apache.lenya.cms.usecase.UsecaseProxy(usecase);
+        view = usecase.getView();
+        log("debug", "Successfully prepared usecase.", usecaseName);
+    } catch (exception) {
+        log("error", "Could not prepare usecase: " + exception, usecaseName);
+        throw exception;
+    } finally {
+        releaseUsecase(usecase);
     }
-    finally {
-        /* done with usecase component, tell usecaseResolver to release it */
-        if (usecaseResolver != null) {
-            if (usecase != null) {
-                usecaseResolver.release(usecase);
-                usecase = undefined;
-            }
-            cocoon.releaseComponent(usecaseResolver);
-        }
-    }
-    
-    var success = false;
-    var targetUrl;
-    var form;
-    var scriptString;
-    var evalFunc;
-    var generic;
-
-    /*
-     * If the usecase has a view, this means we want to display something 
-     * to the user before proceeding. This also means the usecase consists
-     * several steps; repeated until the user chooses to submit or cancel.
-     *
-     * If the usecase does not have a view, it is simply executed.
-     */
-
-    if (view) {
-        var ready = false;
-        while (!ready) {
-
+    loadCustomFlow(view);
+    if (view.getViewURI()) {
+        // If the usecase has a view uri, this means we want to display something 
+        // to the user before proceeding. This also means the usecase can consist
+        // of several steps; repeated until the user chooses to submit or cancel.
+        do {
+            // show the view:
             try {
-                var templateUri = view.getTemplateURI();
-                if (templateUri) {
-                    var viewUri = "view/" + menu + "/" + view.getTemplateURI();
-                    if (cocoon.log.isDebugEnabled())
-                        cocoon.log.debug("usecases.js::executeUsecase() in usecase " + usecaseName + ", creating view, calling Cocoon with viewUri = [" + viewUri + "]");
-                    if (view.getViewType()=="cforms"){
-                    /*
-                     * var generic - Generic object that can be used in all custom flow code
-                     * that is added by usecases. Right now it focus on document opertations
-                     *  but the properties should be extended through user/dev feedback.
-                     * The intention of this var is to provide a generic global flow object
-                     * (like in lots of cocoon examples) that can be accessed through out the different flow stages.
-                     * Alternatively one can use the invoking java class by providing bean properties methods 
-                     * (getter/setter methods) in this class and use them within the extensions (see usecase doc).
-                     * 
-                     * FIXME: Add cforms integration howto to the documentation.
-                     */
-                      generic={proxy:proxy,uri:null,doc:null,generic:null};
-                      var viewDef = "fallback://lenya/"+ view.getCformDefinition();
-                      if (cocoon.log.isDebugEnabled())
-                       cocoon.log.debug("usecases.js::executeUsecase()::cforms in usecase " + usecaseName + ", preparing formDefinition, calling Cocoon with viewUri = [" + viewDef + "]");
-                       
-                       // custom flowscript 
-                       if (view.getCformIntro()!=null){
-                          scriptString= view.getCformIntro();
-                          evalFunc = new Function (scriptString);
-                          evalFunc();
-                       }
-
-                       // form definition                       
-                       form = new Form(viewDef);
-                       
-                       // custom flowscript 
-                       if (view.getCformDefinitionBody()!=null){
-                          scriptString= view.getCformDefinitionBody();
-                          evalFunc = new Function ("form","generic",scriptString);
-                          evalFunc(form,generic);
-                       }
-
-                       // form binding
-                       if (view.getCformBinding() != null){
-                          var viewBind = "fallback://lenya/"+ view.getCformBinding();
-                          if (cocoon.log.isDebugEnabled())
-                             cocoon.log.debug("usecases.js::executeUsecase()::cforms in usecase " + usecaseName + ", preparing formDefinition, calling Cocoon with viewUri = [" + viewBind + "]");
-                          
-                          // form binding
-                          form.createBinding(viewBind);
-                          
-                          // custom flowscript 
-                          if (view.getCformBindingBody()!=null){
-                              scriptString= view.getCformBindingBody();
-                              evalFunc = new Function ("form","generic",scriptString);
-                              evalFunc(form,generic);
-                          }
-                       }
-                        // form template
-                          form.showForm(viewUri, {"usecase" : proxy});
-//DEBUG ajax="true"
-// print("form.showForm after");
-                    }
-                    else{
-                        cocoon.sendPageAndWait(viewUri, {
-                            "usecase" : proxy
-                        });
-                    }
-                }
-                else {
-                    var viewUri = view.getViewURI();
-                    if (viewUri.startsWith("cocoon:/")) {
-                        viewUri = viewUri.substring(new Packages.java.lang.String("cocoon:/").length());
-                    }
-                    if (cocoon.log.isDebugEnabled())
-                        cocoon.log.debug("usecases.js::executeUsecase() in usecase " + usecaseName + ", creating view, calling Cocoon with viewUri = [" + viewUri + "]");
-                    
-                    cocoon.sendPageAndWait(viewUri, {
-                        "usecase" : proxy
-                    });
-                }
-            }
-            catch (exception) {
-                /* if an exception was thrown by the view, allow the usecase to rollback the transition */
+                loopFlow(view, proxy, generic); //usecase must be released here!
+            } catch (exception) {
+                // if something went wrong, try and rollback the usecase:
+                log("error", "Exception during loopFlow(): " + exception, usecaseName);
                 try {
-                    usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
-                    usecase = usecaseResolver.resolve(sourceUrl, usecaseName);
+                    usecase = getUsecase(usecaseName);
                     proxy.setup(usecase);
                     usecase.cancel();
                     throw exception;
+                } finally {
+                    releaseUsecase(usecase);
                 }
-                finally {
-                    if (usecaseResolver != null) {
-                        if (usecase != null) {
-                            usecaseResolver.release(usecase);
-                            usecase = undefined;
-                        }
-                        cocoon.releaseComponent(usecaseResolver);
-                    }
-                }
-            }
-            
-            if (cocoon.log.isDebugEnabled())
-                cocoon.log.debug("usecases.js::executeUsecase() in usecase " + usecaseName + ", after view, now advancing in usecase");
-        
-            try {
-                usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
-                usecase = usecaseResolver.resolve(sourceUrl, usecaseName);
-                proxy.setup(usecase);
-            
-                passRequestParameters(flowHelper, usecase);
-                usecase.advance();
-                //HEADSUP: Cform do not allow id="submit" anymore. Use id="ok" for now (till it is settled on cocoon-dev).
-                if (cocoon.request.getParameter("submit")||cocoon.request.getParameter("lenya.submit")=="ok") {
-                    usecase.checkExecutionConditions();
-                    if (! usecase.hasErrors()) {
-                       if (view.getViewType()=="cforms"){
-                       // custom flowscript 
-                         if (view.getCformOutro()!=null){
-                            scriptString= view.getCformOutro();
-                            evalFunc = new Function ("form","generic",scriptString);
-                            evalFunc(form,generic);
-                         }
-                       }
-                        usecase.execute();
-                        if (! usecase.hasErrors()) {
-                            usecase.checkPostconditions();
-                            if (! usecase.hasErrors()) {
-                                ready = true;
-                                success = true;
-                            }
-                        }
-                    }
-                }
-                else if (cocoon.request.getParameter("cancel")) {
-                    usecase.cancel();
-                    ready = true;
-                }
-                if (!ready) {
-                    proxy = new Packages.org.apache.lenya.cms.usecase.UsecaseProxy(usecase);
-                }
-                targetUrl = usecase.getTargetURL(success);
             }
-            catch (exception) {
-                /* allow usecase to rollback the transition */
-                usecase.cancel();
-                throw exception;
-            }
-            finally {
-                if (usecaseResolver != null) {
-                    if (usecase != null) {
-                        usecaseResolver.release(usecase);
-                        usecase = undefined;
-                    }
-                    cocoon.releaseComponent(usecaseResolver);
-                }
-            }
-        }
-    }
-    else {
-        try {
-            usecaseResolver = cocoon.getComponent("org.apache.lenya.cms.usecase.UsecaseResolver");
-            usecase = usecaseResolver.resolve(sourceUrl, usecaseName);
+            log("debug", "Advancing in usecase.", usecaseName);
+            // restore the usecase state and handle the user input:
+            usecase = getUsecase(usecaseName);
             proxy.setup(usecase);
-                
-            usecase.execute();
-            if (! usecase.hasErrors()) {
-                usecase.checkPostconditions();
-                if (! usecase.hasErrors()) {
-                    success = true;
-                }
-            }
-            targetUrl = usecase.getTargetURL(success);
-        }
-        catch (exception) {
-            /* allow usecase to rollback the transition */
-            usecase.cancel();
-            throw exception;
-        }
-        finally {
-            usecaseResolver.release(usecase);
-            usecase = undefined;
-            cocoon.releaseComponent(usecaseResolver);
-        }
+            passRequestParameters(usecase);
+            state = submitFlow(usecase, generic);
+            // create a new proxy with the updated usecase state
+            proxy = new Packages.org.apache.lenya.cms.usecase.UsecaseProxy(usecase);
+            releaseUsecase(usecase);
+        } while (state == "continue");
+        // If the usecase does not have a view uri, we can directly jump to 
+        // executeFlow().
+    } else {
+        usecase = getUsecase(usecaseName);
+        proxy.setup(usecase);
+        passRequestParameters(usecase);
+        state = executeFlow(usecase);
+        releaseUsecase(usecase);
     }
-    var url = flowHelper.getRequest(cocoon).getContextPath() + targetUrl;
-
-    if (cocoon.log.isDebugEnabled())
-       cocoon.log.debug("usecases.js::executeUsecase() in usecase " + usecaseName + ", completed, redirecting to url = [" + url + "]");
-    cocoon.redirectTo(url, true);
-    
-}
+    //getTargetURL takes a boolean that is true on success:
+    targetUrl = usecase.getTargetURL(state == "success");
+    log("debug", "Completed, redirecting to url = [context:/" + targetUrl + "]", usecaseName);
+    // jump to the appropriate URL:
+    redirect(targetUrl);
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@lenya.apache.org
For additional commands, e-mail: commits-help@lenya.apache.org