You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by an...@apache.org on 2004/06/07 03:04:18 UTC

cvs commit: cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/flow/groovy GroovyCompilingClassLoader.java GroovyInterpreter.java

antonio     2004/06/06 18:04:18

  Modified:    .        gump.xml blocks.properties
               lib      jars.xml
               src/blocks/scratchpad/samples scratchpad-samples.xml
  Added:       src/blocks/scratchpad/samples/groovyflow/flow
                        CalculatorFlow.gy PersistenceFlow.gy FormFlow.gy
               lib/optional asm-util-1.4.2.jar asm-1.4.2.jar
                        groovy-1.0-beta-5.jar
               src/blocks/scratchpad/samples/groovyflow samples.xml
                        sitemap.xmap
               src/blocks/scratchpad/conf groovyflow.xconf
                        groovyflow.xsamples
               src/blocks/scratchpad/java/org/apache/cocoon/components/flow/groovy
                        GroovyCompilingClassLoader.java
                        GroovyInterpreter.java
  Removed:     src/blocks/bsf/lib asm-util-1.4.2.jar asm-1.4.2.jar
                        groovy-1.0-beta-5.jar
  Log:
  Groovy Flow Engine (scratchpad)
  
  Revision  Changes    Path
  1.160     +8 -6      cocoon-2.1/gump.xml
  
  Index: gump.xml
  ===================================================================
  RCS file: /home/cvs//cocoon-2.1/gump.xml,v
  retrieving revision 1.159
  retrieving revision 1.160
  diff -u -r1.159 -r1.160
  --- gump.xml	4 Jun 2004 07:30:49 -0000	1.159
  +++ gump.xml	7 Jun 2004 01:04:18 -0000	1.160
  @@ -153,6 +153,7 @@
       <depend project="cocoon-block-cron"/>
       <depend project="cocoon-block-batik" type="samples"/>
       <depend project="cocoon-block-xsp"/>
  +    <depend project="cocoon-block-javaflow"/>
   
       <work nested="tools/anttasks"/>
       <home nested="build/cocoon-@@DATE@@"/>
  @@ -775,7 +776,7 @@
       <jar name="blocks/woody-block.jar"/>
   
       <nag from="Gump" to="dev@cocoon.apache.org"/>
  -  </project>  
  +  </project>
   
     <project name="cocoon-block-qdox" status="unstable">
       <package>org.apache.cocoon</package>
  @@ -909,10 +910,10 @@
         <property name="block-name" value="eventcache"/>
         <property name="version" value="@@DATE@@"/>
       </ant>
  -    
  +
       <depend project="cocoon" inherit="all"/>
       <depend project="cocoon-block-xsp" type="samples"/>
  -    
  +
       <work nested="build/cocoon-@@DATE@@/blocks/eventcache/dest"/>
       <work nested="build/cocoon-@@DATE@@/blocks/eventcache/test"/>
       <work nested="tools/anttasks"/>
  @@ -1010,6 +1011,7 @@
       <depend project="cocoon-block-forms" type="samples"/>
   
       <work nested="tools/anttasks"/>
  +    <work nested="build/cocoon-@@DATE@@/blocks/ojb/mocks"/>
       <home nested="build/cocoon-@@DATE@@"/>
   
       <jar name="blocks/ojb-block.jar"/>
  @@ -1047,10 +1049,10 @@
       </ant>
   
       <depend project="cocoon" inherit="all"/>
  -    
  +
       <depend project="cocoon-block-databases" />
       <depend project="cocoon-block-eventcache" />
  -    
  +
       <work nested="tools/anttasks"/>
       <home nested="build/cocoon-@@DATE@@"/>
   
  
  
  
  1.80      +3 -3      cocoon-2.1/blocks.properties
  
  Index: blocks.properties
  ===================================================================
  RCS file: /home/cvs//cocoon-2.1/blocks.properties,v
  retrieving revision 1.79
  retrieving revision 1.80
  diff -u -r1.79 -r1.80
  --- blocks.properties	4 Jun 2004 07:30:24 -0000	1.79
  +++ blocks.properties	7 Jun 2004 01:04:18 -0000	1.80
  @@ -66,7 +66,6 @@
   #include.block.itext=false
   #include.block.jfor=false
   #include.block.jsp=false
  -#-----[dependency]: "linkrewriter" depends on "xsp".
   #include.block.linkrewriter=false
   #include.block.lucene=false
   #include.block.naming=false
  @@ -86,7 +85,7 @@
   #include.block.web3=false
   #-----[dependency]: "xmldb" depends on "databases".
   #include.block.xmldb=false
  -#-----[dependency]: "xsp" is needed by "chaperon", "databases", "eventcache", "forms", "linkrewriter", "python", "scratchpad", "session-fw", "woody".
  +#-----[dependency]: "xsp" is needed by "chaperon", "databases", "eventcache", "forms", "python", "scratchpad", "session-fw", "woody".
   #include.block.xsp=false
   
   # Unstable blocks --------------------------------------------------------------
  @@ -114,6 +113,7 @@
   #-----[dependency]: "forms" is needed by "apples", "javaflow", "ojb", "petstore", "tour".
   #include.block.forms=false
   #-----[dependency]: "javaflow" depends on "forms", "ojb".
  +#-----[dependency]: "javaflow" is needed by "scratchpad".
   #include.block.javaflow=false
   #-----[dependency]: "jms" depends on "databases" (for samples), "eventcache", "hsqldb".
   #-----[dependency]: "jms" is needed by "slide".
  @@ -134,7 +134,7 @@
   #-----[dependency]: "repository" depends on "databases", "eventcache".
   #-----[dependency]: "repository" is needed by "slide", "webdav".
   #include.block.repository=false
  -#-----[dependency]: "scratchpad" depends on "batik" (for samples), "cron", "velocity", "xsp".
  +#-----[dependency]: "scratchpad" depends on "batik" (for samples), "cron", "javaflow", "velocity", "xsp".
   #-----[dependency]: "scratchpad" is needed by "mail".
   #include.block.scratchpad=false
   #include.block.serializers=false
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/samples/groovyflow/flow/CalculatorFlow.gy
  
  Index: CalculatorFlow.gy
  ===================================================================
  /*
   * 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.cocoon.samples.flow.groovy
  
  import org.apache.cocoon.components.flow.java.AbstractContinuable
  
  public class CalculatorFlow extends AbstractContinuable {
  
      count = 1
  
      public void doCalculator() {
          a = getNumber "a", 0, 0    // This is a method call
          b = getNumber("b", a, 0)
          op = getOperator(a, b)
  
          result = 0
          switch (op) {
              case "plus":
                  result= a + b
                  break
              case "minus":
                  result = a - b
                  break
              case "multiply":
                  result = a * b
                  break
               case "divide":
                  if (b != 0) {
                      sendMessage "Error: Cannot divide by zero!"
                  } else {
                      result = a / b
                  }
                  break
               default:
                  sendMessage "Error: Unkown operator!"
          }
          sendPage("page/calculator-result", ["a" :  a, "b":  b, "operator": op, "result": result, "count" : count])
          count++
      }
  
      private getNumber(name, a, b) {
          uri = "page/calculator-" + name.toLowerCase()
          sendPageAndWait(uri, ["a" :  a, "b":  b, "count" : count])
          getRequest().getParameter(name)
      }
  
      private getOperator(a, b) {
          sendPageAndWait("page/calculator-operator", ["a" :  a, "b":  b, "count" : count])
          getRequest().getParameter("operator")
      }
  
      private void sendMessage(message) {
          sendPageAndWait("page/calculator-message", ["message" : message, "count" : count])
      }
  }
  
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/samples/groovyflow/flow/PersistenceFlow.gy
  
  Index: PersistenceFlow.gy
  ===================================================================
  /*
   * 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.cocoon.samples.flow.groovy;
  
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.Iterator;
  
  import org.apache.cocoon.components.flow.java.AbstractContinuable;
  import org.apache.cocoon.components.flow.java.Continuable;
  import org.apache.cocoon.components.flow.java.VarMap;
  import org.apache.cocoon.forms.binding.BindingException;
  import org.apache.cocoon.forms.flow.java.FormInstance;
  import org.apache.cocoon.ojb.broker.components.PBFactory;
  import org.apache.cocoon.ojb.samples.bean.Employee;
  import org.apache.ojb.broker.Identity;
  import org.apache.ojb.broker.PersistenceBroker;
  import org.apache.ojb.broker.query.Criteria;
  import org.apache.ojb.broker.query.QueryByCriteria;
  
  public class PersistenceFlow extends AbstractContinuable {
  
      private transient PersistenceBroker broker = null;
  
      public PersistenceFlow() {
          PBFactory factory = (PBFactory)getComponent(PBFactory.ROLE)
          broker = factory.defaultPersistenceBroker()
          releaseComponent(factory)
      }
  
      public void doInsertEmployee() { //throws BindingException {
  
          // Create a empty Bean
          Employee employee = new Employee()
          // Fill some initial data to the bean
          employee.setId(1)
          // Load form descriptor
          FormInstance form = new FormInstance("forms/employee.xml")
          // Load form binding
          form.createBinding("forms/employee-binding.xml")
          // Load the Bean to the form
          form.load(employee)
          // Let Cocoon Forms handle the form
          form.show("form/employee")
          // Update the Bean based on user input
          form.save(employee)
          // Update Bean in Database
          broker.store(employee)
          // Send response to the user
          doShowEmployee()
      }
  
      public void doUpdateEmployee() { //throws BindingException {
  
          // Get id as parameter
          int id = 1
          if (getRequest().getParameter("id")!=null)
              id = Integer.parseInt(getRequest().getParameter("id"))
          else
              throw new IllegalStateException("No parameter 'id'")
  
          // Create a empty Bean
          Employee employee = new Employee()
          // Fill some initial data to the bean
          employee.setId(id)
          // Load bean based on the given PrimaryKey
          employee = (Employee) broker.getObjectByIdentity(new Identity(employee, broker))
          // Load form descriptor
          FormInstance form = new FormInstance("forms/employee.xml")
          // Load form binding
          form.createBinding("forms/employee-binding.xml")
          // Load the Bean to the form
          form.load(employee)
          // Let Cocoon Forms handle the form
          form.show("form/employee")
          // Update the Bean based on user input
          form.save(employee)
  
          // Update Bean in Database
          broker.store(employee)
  
          // Send response to the user
          doShowEmployee()
      }
  
      public void doRemoveEmployee() {
  
          // Get id as parameter
          int id = 1
          if (getRequest().getParameter("id")!=null)
              id = Integer.parseInt(getRequest().getParameter("id"))
          else
              throw new IllegalStateException("No parameter 'id'")
  
          // Create a empty Bean
          Employee employee = new Employee()
          // Fill some initial data to the bean
          employee.setId(id)
          // Load bean based on the given PrimaryKey
          employee = (Employee) broker.getObjectByIdentity(new Identity(employee, broker))
          // Remove bean
          broker.delete(employee)
          // Send response to the user
          doShowEmployee()
      }
  
      public void doShowEmployee() {
  
          // Query all objects
          ArrayList results = new ArrayList()
          QueryByCriteria query = new QueryByCriteria(Employee.class, new Criteria())
          for(Iterator i=broker.getCollectionByQuery(query).iterator(); i.hasNext();) {
              results.add(i.next())
          }
          // Sort result
          Collections.sort(results, new EmployeeComparator())
          // Send response to the user
          sendPage("page/employee-result", new VarMap().add("employee", results))
      }
  
      public class EmployeeComparator implements Comparator, Continuable {
          public int compare(Object o1, Object o2) {
              return ((Employee)o1).getId()-((Employee)o2).getId()
          }
  
          public boolean equals(Object obj) {
              return true
          }
      }
  }
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/samples/groovyflow/flow/FormFlow.gy
  
  Index: FormFlow.gy
  ===================================================================
  /*
   * 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.cocoon.samples.flow.groovy;
  
  import java.util.Date;
  
  import org.apache.cocoon.components.flow.java.AbstractContinuable;
  import org.apache.cocoon.forms.binding.BindingException;
  import org.apache.cocoon.forms.flow.java.FormInstance;
  import org.apache.cocoon.forms.formmodel.BooleanField;
  import org.apache.cocoon.forms.formmodel.Field;
  import org.apache.cocoon.forms.formmodel.Repeater;
  import org.apache.cocoon.forms.samples.Contact;
  import org.apache.cocoon.forms.samples.Form2Bean;
  import org.apache.cocoon.forms.samples.Sex;
  
  public class FormFlow extends AbstractContinuable {
  
      public void doEditForm1() {
  
          FormInstance form = new FormInstance("forms/form1.xml")
  
          Field birthDate = (Field) form.getWidget("birthdate")
          birthDate.setValue(new Date())
  
          Repeater repeater = (Repeater) form.getWidget("contacts")
          repeater.addRow()
          Field field = (Field) repeater.getWidget(0, "firstname")
          field.setValue("Jules")
  
          repeater.addRow();
          field = (Field) repeater.getWidget(1, "firstname");
          field.setValue("Lucien");
  
          form.show("form/form1");
  
          sendPage("page/form1-result", ["email" : ((Field)form.getWidget("email")).getValue(),
                                                    "somebool" : ((BooleanField)form.getWidget("somebool")).getValue(),
                                                    "firstname" : ((Field)((Repeater)form.getWidget("contacts")).getWidget(1, "firstname")).getValue()]);
      }
  
      public void doEditForm2() { // throws BindingException {
          Form2Bean bean = new Form2Bean()
  
          // fill bean with some data to avoid users having to type to much
          bean.setEmail("yourname@yourdomain.com")
          bean.setIpAddress("10.0.0.1")
          bean.setPhoneCountry("32")
          bean.setPhoneZone("2")
          bean.setPhoneNumber("123456")
          bean.setBirthday(new java.util.Date())
          bean.setSex(Sex.FEMALE)
          Contact contact = new Contact()
          contact.setId(1)
          contact.setFirstName("Hermann")
          bean.addContact(contact)
  
          FormInstance form = new FormInstance("forms/form2.xml", "forms/form2-binding.xml")
          form.load(bean)
          form.show("form/form2")
          form.save(bean)
  
          sendPage("page/form2-result", ["form2bean" : bean]);
      }
  }
  
  
  
  1.1                  cocoon-2.1/lib/optional/asm-util-1.4.2.jar
  
  	<<Binary file>>
  
  
  1.1                  cocoon-2.1/lib/optional/asm-1.4.2.jar
  
  	<<Binary file>>
  
  
  1.1                  cocoon-2.1/lib/optional/groovy-1.0-beta-5.jar
  
  	<<Binary file>>
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/samples/groovyflow/samples.xml
  
  Index: samples.xml
  ===================================================================
  <?xml version="1.0"?>
  <!--
    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.
  -->
  <!-- $Id: samples.xml,v 1.1 2004/06/07 01:04:18 antonio Exp $-->
  <samples name="Java Flow Block Samples">
   <group name="Back">
     <sample name="Back" href="../../..">to Cocoon Samples main page</sample>
     <sample name="Back" href="../..">to Cocoon Blocks Samples main page</sample>
   </group>
  
   <group name="Groovy Flow">
    <sample name="Calculator" href="calculator.do">
     Example for the Java Flow implementation
    </sample>
    <sample name="Cocoon Forms" href="editForm1.do">
     Example for the Cocoon Forms and Java Flow.
    </sample>
    <sample name="Cocoon Forms Binding" href="editForm2.do">
     Example for the Cocoon Forms Binding and Java Flow.
    </sample>
    <sample name="Apache OJB" href="showEmployee.do">
     Example for the Cocoon Forms and Java Flow and Apache OJB.
    </sample>
   </group>
  </samples>
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/samples/groovyflow/sitemap.xmap
  
  Index: sitemap.xmap
  ===================================================================
  <?xml version="1.0"?>
  <!--
    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.
  -->
  
  <map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
  
   <map:components>
    <map:transformers default="xalan">
     <map:transformer name="i18n" src="org.apache.cocoon.transformation.I18nTransformer">
      <catalogues default="other">
       <catalogue id="other" name="OtherMessages" location="context://samples/blocks/forms/messages"/>
       <catalogue id="forms" name="FormsMessages" location="context://samples/blocks/forms/messages"/>
      </catalogues>
      <cache-at-startup>true</cache-at-startup>
     </map:transformer>
    </map:transformers>
   </map:components>
  
   <!-- indicates what flow classes to attach to this sitemap -->
   <map:flow language="groovy">
    <map:script src="flow/CalculatorFlow.gy"/>
    <map:script src="flow/FormFlow.gy"/>
    <map:script src="flow/PersistenceFlow.gy"/>
   </map:flow>
  
   <map:pipelines>
    <map:pipeline>
     <!--+
         | produces the screens called by the flowscript
         +-->
     <map:match pattern="page/*">
      <map:generate type="jx" src="../screens/{1}.xml"/>
      <map:transform src="context://samples/common/style/xsl/html/complex-page2html.xsl">
       <map:parameter name="contextPath" value="{request:contextPath}"/>
      </map:transform>
      <map:serialize/>
     </map:match>
  
     <map:match pattern="form/*">
      <map:generate src="../forms/{1}-template.xml"/>
      <map:transform type="forms"/>
      <map:transform type="i18n">
       <map:parameter name="locale" value="en-US"/>
      </map:transform>
      <map:transform src="context://samples/common/style/xsl/html/complex-page2html.xsl">
       <map:parameter name="contextPath" value="{request:contextPath}"/>
      </map:transform>
      <map:transform src="context://samples/blocks/forms/resources/forms-samples-styling.xsl"/>
      <map:serialize/>
     </map:match>
  
    </map:pipeline>
  
    <map:pipeline>
     <map:match pattern="">
      <map:generate src="samples.xml"/>
      <map:transform src="context://samples/common/style/xsl/html/simple-samples2html.xsl">
       <map:parameter name="contextPath" value="{request:contextPath}"/>
      </map:transform>
      <map:serialize/>
     </map:match>
  
     <!--+
         | matches the page with the continuation ID and calls the flowscript
         | associated to this sitemap with the given continuation ID. The flow
         | engine will then look into the continuation store, retrieve
         | the correct continuation and resume execution of the flowscript
         | with that continuation. This guarantees transparent state
         | resumption between requests without the need for anything else
         | (cookies or URL-encoded session IDs)
         +-->
     <map:match pattern="*.cont">
      <map:call continuation="{1}"/>
     </map:match>
  
     <!--+
         | matches the call to the beginning of the flow and calls the flow
         | from its entry point which, in this case is the 'calculator()'
         | javascript function.
         +-->
     <map:match pattern="*.do">
      <map:call function="{1}"/>
     </map:match>
  
     <map:match pattern="resources/**">
      <map:redirect-to uri="/samples/blocks/forms/resources/{1}"/>
     </map:match>
  
    </map:pipeline>
   </map:pipelines>
  </map:sitemap>
  
  
  
  1.224     +5 -5      cocoon-2.1/lib/jars.xml
  
  Index: jars.xml
  ===================================================================
  RCS file: /home/cvs//cocoon-2.1/lib/jars.xml,v
  retrieving revision 1.223
  retrieving revision 1.224
  diff -u -r1.223 -r1.224
  --- jars.xml	6 Jun 2004 04:04:29 -0000	1.223
  +++ jars.xml	7 Jun 2004 01:04:18 -0000	1.224
  @@ -398,7 +398,7 @@
         available to the Java developers using a Java-like syntax.
       </description>
       <used-by>BSF Block (Script generator, script action)</used-by>
  -    <lib>bsf/lib/groovy-1.0-beta-5.jar</lib>
  +    <lib>optional/groovy-1.0-beta-5.jar</lib>
       <homepage>http://groovy.codehaus.org/</homepage>
     </file>
   
  @@ -411,7 +411,7 @@
   	  before they are loaded into the Java Virtual Machine.
       </description>
       <used-by>BSF Block (Script generator, script action)</used-by>
  -    <lib>bsf/lib/asm-1.4.2.jar</lib>
  +    <lib>optional/asm-1.4.2.jar</lib>
       <homepage>http://asm.objectweb.org/</homepage>
     </file>
   
  @@ -422,7 +422,7 @@
         class visitors that can be useful for programming and debugging purposes.
       </description>
       <used-by>BSF Block (Script generator, script action)</used-by>
  -    <lib>bsf/lib/asm-util-1.4.2.jar</lib>
  +    <lib>optional/asm-util-1.4.2.jar</lib>
       <homepage>http://asm.objectweb.org/</homepage>
     </file>
   
  @@ -463,7 +463,7 @@
       </description>
       <used-by>Jakarta Commons HttpClient, Chaperon</used-by>
       <lib>optional/commons-logging-1.0.3.jar</lib>
  -    <homepage>http://jakarta.apache.org/commons/logging.html</homepage>
  +    <homepage>http://jakarta.apache.org/commons/logging/</homepage>
     </file>
   
     <file>
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/conf/groovyflow.xconf
  
  Index: groovyflow.xconf
  ===================================================================
  <?xml version="1.0"?>
  <!--
    Copyright 2002-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.
  -->
  <xconf xpath="/cocoon/flow-interpreters" unless="component-instance[@name='groovy']">
    <component-instance name="groovy" class="org.apache.cocoon.components.flow.groovy.GroovyInterpreter"/>
  </xconf>
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/conf/groovyflow.xsamples
  
  Index: groovyflow.xsamples
  ===================================================================
  <?xml version="1.0"?>
  <!--
    Copyright 2002-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.
  -->
  
  <xsamples xpath="/samples" unless="group[@name='Groovy Flow']">
  
    <group name="groovy Flow">
      <sample name="Groovy Flow Block" href="javaflow/groovy/">
        Cocoon Groovy Flow examples.
      </sample>
    </group>
  
  </xsamples>
  
  
  
  1.13      +41 -36    cocoon-2.1/src/blocks/scratchpad/samples/scratchpad-samples.xml
  
  Index: scratchpad-samples.xml
  ===================================================================
  RCS file: /home/cvs//cocoon-2.1/src/blocks/scratchpad/samples/scratchpad-samples.xml,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -u -r1.12 -r1.13
  --- scratchpad-samples.xml	5 Apr 2004 12:25:36 -0000	1.12
  +++ scratchpad-samples.xml	7 Jun 2004 01:04:18 -0000	1.13
  @@ -24,24 +24,27 @@
       <sample name="Back" href="..">to Cocoon Blocks Samples main page</sample>
     </group>
   
  - <group name="Garbage">
  -    <sample name="Garbage" href="garbage/">
  -      Flowscript Calculator Sample using Garbage Template Generator
  +  <group name="Betwixt">
  +    <sample name="Example" href="betwixt/">
  +      Show the usage of the Betwixt Transformer
       </sample>
     </group>
  -  
  +
     <group name="Castor">
       <sample name="CastorTransformer" href="castor/">
         Show the usage of the Castor Transformer.
       </sample>
     </group>
  -
  -  <group name="Jelly">
  -    <sample name="Test 1" href="jelly/test1">
  -      A test of the Jelly generator - you have to download and install the jelly.jar first!
  +  
  +  <group name="Garbage">
  +    <sample name="Garbage" href="garbage/">
  +      Flowscript Calculator Sample using Garbage Template Generator
       </sample>
  -    <sample name="Test 2" href="jelly/test2">
  -      A test of the Jelly generator - you have to download and install the jelly.jar first!
  +  </group>
  +  
  +  <group name="Groovy Flow Engine">
  +    <sample name="Groovy" href="groovyflow/">
  +      An experimental Groovy Flow Engine based on the JavaFlow Engine
       </sample>
     </group>
   
  @@ -57,22 +60,42 @@
         Make sure the Batik block is included before testing this sample.
       </sample>
     </group>
  -
  -  <group name="Betwixt">
  -    <sample name="Example" href="betwixt/">
  -      Show the usage of the Betwixt Transformer
  +  
  +  <group name="Jelly">
  +    <sample name="Test 1" href="jelly/test1">
  +      A test of the Jelly generator - you have to download and install the jelly.jar first!
  +    </sample>
  +    <sample name="Test 2" href="jelly/test2">
  +      A test of the Jelly generator - you have to download and install the jelly.jar first!
       </sample>
     </group>
   
  -  <group name="Sitemap Viewer">
  -    <sample name="Sitemap Viewer" href="sitemap-viewer/">
  -        Experimental sitemap viewer
  +  <group name="Module Source">
  +    <sample name="Request URI"
  +            href="module-source/test1">
  +      Use a source that reads from a request URI.
  +    </sample>
  +    <sample name="Text field"
  +            href="module-source/test2">
  +      Use a source that reads from a input text field.
  +    </sample>
  +    <sample name="XML text field"
  +            href="module-source/test4">
  +      Read XML data from a text field. Also demonstrates the use of
  +      input from multi part mime posts and require that uploads are
  +      enabled in web.xml.
       </sample>
     </group>
     
     <group name="Othello">
       <sample name="Example" href="othello/">Template based static web site.</sample>
     </group>
  +  
  +  <group name="Sitemap Viewer">
  +    <sample name="Sitemap Viewer" href="sitemap-viewer/">
  +        Experimental sitemap viewer
  +    </sample>
  +  </group>
   
     <group name="Sources">
       <sample name="Simple ZIP source example" href="sources/simple-zip.xml">Read file from ZIP archive</sample>
  @@ -101,22 +124,4 @@
           session attribute "test".
       </sample>
     </group>
  -
  -  <group name="Module Source">
  -    <sample name="Request URI"
  -            href="module-source/test1">
  -      Use a source that reads from a request URI.
  -    </sample>
  -    <sample name="Text field"
  -            href="module-source/test2">
  -      Use a source that reads from a input text field.
  -    </sample>
  -    <sample name="XML text field"
  -            href="module-source/test4">
  -      Read XML data from a text field. Also demonstrates the use of
  -      input from multi part mime posts and require that uploads are
  -      enabled in web.xml.
  -    </sample>
  -  </group>
  -
   </samples>
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/flow/groovy/GroovyCompilingClassLoader.java
  
  Index: GroovyCompilingClassLoader.java
  ===================================================================
  /*
   * 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.cocoon.components.flow.groovy;
  
  import groovy.lang.GroovyClassLoader;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.MalformedURLException;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.Serviceable;
  import org.apache.commons.lang.StringUtils;
  import org.apache.excalibur.source.Source;
  import org.apache.excalibur.source.SourceResolver;
  import org.codehaus.groovy.control.CompilationFailedException;
  import org.codehaus.groovy.control.CompilationUnit;
  import org.codehaus.groovy.control.Phases;
  import org.codehaus.groovy.tools.GroovyClass;
  
  /**
   * Class Loader for Groovy source files.
   * Compiles the scripts and store the resulting java class and the original Groovy scripts.
   *
   * @version CVS $Id: GroovyCompilingClassLoader.java,v 1.1 2004/06/07 01:04:18 antonio Exp $ 
   * 
   */
  public class GroovyCompilingClassLoader extends ClassLoader implements Serviceable {
  
      private Map sources = new HashMap();			// Store the Groovy source file
      private Map compiledClasses = new HashMap();	// Store the compiled classes of the Groovy script
      private SourceResolver resolver;
      private GroovyClassLoader groovyClassLoader;	// A groovyClassLoader
  
      /**
       * Compile groovy scripts and load classes as needed.
       * @param classloader
       */
      public GroovyCompilingClassLoader(ClassLoader classloader) {
          super(classloader);
          groovyClassLoader = new GroovyClassLoader(classloader);
      }
  
      /* 
       * Intercept the Class Loader for Groovy compiled script.
       * (non-Javadoc)
       * @see java.lang.ClassLoader#findClass(java.lang.String)
       */
      protected Class findClass(String classname) throws ClassNotFoundException {
          System.out.println("groovy: find class " + classname);
          Class groovyClass = (Class) sources.get(classname);
          if (groovyClass == null) {
              return super.findClass(classname);
          }
          return groovyClass;
      }
  
      /**
       * Parse the Groovy script into a Java class.
       * @param uri - The location of the groovy script file to be compiled
       * @return The java class compiled from the Groovy script source file at the given uri
       */
      public Class getGroovyClass(String uri) {
          try {
  	        Source source = resolver.resolveURI(uri);
              Class clazz = groovyClassLoader.parseClass(source.getInputStream());
  	        sources.put(clazz.getName(), clazz);
  	        // Prepare the byte code to be returned for bcel (the *.class")
              String resouceFileName = StringUtils.replaceChars(clazz.getName(), '.', '/') + ".class";
  	        CompilationUnit c = new CompilationUnit();
              c.addSource(null, source.getInputStream());
              c.compile(Phases.CLASS_GENERATION); 
              Iterator classiterator = c.getClasses().iterator();
              GroovyClass groovyClass = (GroovyClass)classiterator.next();
              compiledClasses.put(resouceFileName, groovyClass);
  	        return clazz;
          } catch (MalformedURLException e) {
              throw new IllegalArgumentException(e.getMessage());
          } catch (IOException e) {
              throw new IllegalArgumentException(e.getMessage());
          } catch (CompilationFailedException e) {
              throw new IllegalArgumentException(e.getMessage());
          }
      }
  
      /* 
       * This method is need to intercept the calls done by BCEL.
       * BCEL use it to get the ".class" file of the compiled Groovy script.
       * (non-Javadoc)
       * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
       */
      public InputStream getResourceAsStream(String name) {
          GroovyClass groovyClass = (GroovyClass)compiledClasses.get(name);
          if (groovyClass == null) {
              return super.getResourceAsStream(name);
          }
  	    return new ByteArrayInputStream(groovyClass.getBytes());
      }
  
      public void service(ServiceManager manager) throws ServiceException {
          resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
      }
  }
  
  
  
  1.1                  cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/components/flow/groovy/GroovyInterpreter.java
  
  Index: GroovyInterpreter.java
  ===================================================================
  /*
   * 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.cocoon.components.flow.groovy;
  
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.components.ContextHelper;
  import org.apache.cocoon.components.flow.AbstractInterpreter;
  import org.apache.cocoon.components.flow.FlowHelper;
  import org.apache.cocoon.components.flow.InvalidContinuationException;
  import org.apache.cocoon.components.flow.WebContinuation;
  import org.apache.cocoon.components.flow.java.Continuable;
  import org.apache.cocoon.components.flow.java.Continuation;
  import org.apache.cocoon.components.flow.java.ContinuationClassLoader;
  import org.apache.cocoon.components.flow.java.ContinuationContext;
  import org.apache.cocoon.components.flow.java.VarMap;
  import org.apache.cocoon.components.flow.java.VarMapHandler;
  import org.apache.cocoon.environment.Redirector;
  import org.apache.cocoon.environment.Request;
  import org.apache.cocoon.environment.Session;
  import org.apache.commons.jxpath.JXPathIntrospector;
  
  /**
   * Implementation of the groovy flow interpreter.
   *
   * @version CVS $Id: GroovyInterpreter.java,v 1.1 2004/06/07 01:04:18 antonio Exp $
   */
  public class GroovyInterpreter extends AbstractInterpreter implements Configurable {
  
      private boolean initialized = false;
      private int timeToLive = 600000;
      private static final String ACTION_METHOD_PREFIX = "do";
  
      /**
       * Key for storing a global scope object in the Cocoon session
       */
      public static final String USER_GLOBAL_SCOPE = "JAVA GLOBAL SCOPE";
      private ContinuationClassLoader continuationclassloader;
      private HashMap flowableMethods = new HashMap(); // Store flowableMehods found in all classes on the sitemap.
      private GroovyCompilingClassLoader groovyClassLoader;
  
      static {
          JXPathIntrospector.registerDynamicClass(VarMap.class, VarMapHandler.class);
      }
  
      public void configure(Configuration config) throws ConfigurationException {
          super.configure(config);
  
          groovyClassLoader = new GroovyCompilingClassLoader(Thread.currentThread().getContextClassLoader());
          try {
              groovyClassLoader.service(this.manager);
          } catch (ServiceException e) {
              throw new ConfigurationException(e.getMessage());
          }
          continuationclassloader = new ContinuationClassLoader(groovyClassLoader);
  
          Configuration[] includes = config.getChildren("include");
          for (int i = 0; i < includes.length; i++) {
              continuationclassloader.addIncludeClass(includes[i].getAttribute("class"));
          }
      }
  
      private static String removePrefix(String name) {
          int prefixLen = ACTION_METHOD_PREFIX.length();
          return name.substring(prefixLen, prefixLen + 1).toLowerCase() + name.substring(prefixLen + 1);
      }
  
      /**
       * Initialize the Groovy interpreter by compiling all the groovy scripts defined in the sitemap.
       * @throws Exception
       */
      public void initialize() throws Exception {
  
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("initialize java flow interpreter");
          }
          initialized = true;
  
          for (Iterator scripts = needResolve.iterator(); scripts.hasNext();) {
              String className = (String) scripts.next();
              Class groovyClass;
  
              if (className.endsWith(".gy")) {
                  groovyClass = groovyClassLoader.getGroovyClass(className);
                  className = groovyClass.getName();
              }
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("registered java class \"" + className + "\" for flow");
              }
              Class clazz = continuationclassloader.loadClass(className);
              if (!Continuable.class.isAssignableFrom(clazz)) {
                  getLogger().error("java class \"" + className + "\" doesn't implement Continuable");
                  continue;
              }
              // Detect methods that are "Flowable" and build a list of them
              try {
                  Method[] classMethods = clazz.getMethods();
                  for (int i = 0; i < classMethods.length; i++) {
                      String methodName = classMethods[i].getName();
                      if (methodName.startsWith(ACTION_METHOD_PREFIX)) {
                          String function = removePrefix(methodName);
                          flowableMethods.put(function, classMethods[i]);
                          if (getLogger().isDebugEnabled()) {
                              getLogger().debug("registered method \"" + methodName + "\" as function \"" + function + "\"");
                          }
                      }
                  }
              } catch (Exception e) {
                  throw new ConfigurationException("cannot get methods by reflection", e);
              }
          }
      }
  
      /**
       * Calls a groovy function, passing <code>params</code> as its
       * arguments. In addition to this, it makes available the parameters
       * through the <code>cocoon.parameters</code> Java array
       * (indexed by the parameter names).
       *
       * @param function a <code>String</code> value
       * @param params a <code>List</code> value
       * @param redirector
       * @exception Exception if an error occurs
       */
      public void callFunction(String function, List params, Redirector redirector) throws Exception {
          if (!initialized) {
              initialize();
          }
          Method method = (Method)flowableMethods.get(function);
          if (method == null) {
              throw new ProcessingException("No method found for '" + function + "'");
          }
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("calling method \"" + method + "\"");
          }
          Request request = ContextHelper.getRequest(this.avalonContext);
          Session session = request.getSession(true);
          HashMap userScopes = (HashMap) session.getAttribute(USER_GLOBAL_SCOPE);
          if (userScopes == null) {
              userScopes = new HashMap();
          }
          Continuable flow = (Continuable) userScopes.get(method.getDeclaringClass());
          ContinuationContext context = new ContinuationContext();
          context.setObject(flow);
          context.setMethod(method);
          context.setAvalonContext(avalonContext);
          context.setLogger(getLogger());
          context.setServiceManager(manager);
          context.setRedirector(redirector);
  
          Continuation continuation = new Continuation(context);
  
          WebContinuation wk = continuationsMgr.createWebContinuation(continuation, null, timeToLive, null);
          FlowHelper.setWebContinuation(ContextHelper.getObjectModel(this.avalonContext), wk);
  
          continuation.registerThread();
          try {
              if (flow == null) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("create new instance of \"" + method.getDeclaringClass() + "\"");
                  }
                  flow = (Continuable) method.getDeclaringClass().newInstance();
                  context.setObject(flow);
              }
              method.invoke(flow, new Object[0]);
          } catch (InvocationTargetException ite) {
              if (ite.getTargetException() != null) {
                  if (ite.getTargetException() instanceof Exception) {
                      throw (Exception) ite.getTargetException();
                  } else if (ite.getTargetException() instanceof Error) {
                      throw new ProcessingException("An internal error occured", ite.getTargetException());
                  } else if (ite.getTargetException() instanceof RuntimeException) {
                      throw (RuntimeException) ite.getTargetException();
                  } else {
                      throw ite;
                  }
              } else {
                  throw ite;
              }
          } finally {
              // remove last object reference, which is not needed to
              // reconstruct the invocation path
              if (continuation.isCapturing()) {
                  continuation.getStack().popReference();
              }
              continuation.deregisterThread();
          }
          userScopes.put(method.getDeclaringClass(), flow);
          session.setAttribute(USER_GLOBAL_SCOPE, userScopes);
      }
  
      public void handleContinuation(String id, List params, Redirector redirector) throws Exception {
          if (!initialized) {
              initialize();
          }
          WebContinuation parentwk = continuationsMgr.lookupWebContinuation(id);
          if (parentwk == null) {
          /*
           * Throw an InvalidContinuationException to be handled inside the
           * <map:handle-errors> sitemap element.
           */
          throw new InvalidContinuationException("The continuation ID " + id + " is invalid."); }
  
          Continuation parentContinuation = (Continuation) parentwk.getContinuation();
          ContinuationContext parentContext = (ContinuationContext) parentContinuation.getContext();
          ContinuationContext context = new ContinuationContext();
          context.setObject(parentContext.getObject());
          context.setMethod(parentContext.getMethod());
          context.setAvalonContext(avalonContext);
          context.setLogger(getLogger());
          context.setServiceManager(manager);
          context.setRedirector(redirector);
          Continuation continuation = new Continuation(parentContinuation, context);
  
          Request request = ContextHelper.getRequest(this.avalonContext);
          Session session = request.getSession(true);
          HashMap userScopes = (HashMap) session.getAttribute(USER_GLOBAL_SCOPE);
  
          Continuable flow = (Continuable) context.getObject();
          Method method = context.getMethod();
  
          WebContinuation wk = continuationsMgr.createWebContinuation(continuation, parentwk, timeToLive, null);
          FlowHelper.setWebContinuation(ContextHelper.getObjectModel(this.avalonContext), wk);
  
          continuation.registerThread();
          try {
  
              method.invoke(flow, new Object[0]);
  
          } catch (InvocationTargetException ite) {
              if (ite.getTargetException() != null) {
                  if (ite.getTargetException() instanceof Exception) {
                      throw (Exception) ite.getTargetException();
                  } else if (ite.getTargetException() instanceof Error) {
                      throw new ProcessingException("An internal error occured", ite.getTargetException());
                  } else if (ite.getTargetException() instanceof RuntimeException) {
                      throw (RuntimeException) ite.getTargetException();
                  } else {
                      throw ite;
                  }
              } else {
                  throw ite;
              }
          } finally {
              // remove last object reference, which is not needed to reconstruct
              // the invocation path
              if (continuation.isCapturing()) {
                  continuation.getStack().popReference();
              }
              continuation.deregisterThread();
          }
          userScopes.put(method.getDeclaringClass(), flow);
          session.setAttribute(USER_GLOBAL_SCOPE, userScopes);
      }
  }