You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by st...@apache.org on 2003/04/26 14:10:44 UTC

cvs commit: cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/transformation XMLFormTransformer.java

stephan     2003/04/26 05:10:44

  Modified:    src/blocks/xmlform/java/org/apache/cocoon/acting
                        AbstractXMLFormAction.java
               src/blocks/xmlform/java/org/apache/cocoon/components/modules/input
                        XMLFormInput.java
               src/blocks/xmlform/java/org/apache/cocoon/components/validation
                        Schema.java SchemaFactory.java Validator.java
                        Violation.java
               src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron
                        ActivePattern.java Assert.java Pattern.java
                        Phase.java Report.java Rule.java
                        SchematronFactory.java SchematronSchema.java
                        SchematronValidator.java ValidationResult.java
               src/blocks/xmlform/java/org/apache/cocoon/components/xmlform
                        Form.java FormListener.java
               src/blocks/xmlform/java/org/apache/cocoon/transformation
                        XMLFormTransformer.java
  Log:
  Beautify code.
  
  Revision  Changes    Path
  1.2       +139 -144  cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/acting/AbstractXMLFormAction.java
  
  Index: AbstractXMLFormAction.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/acting/AbstractXMLFormAction.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractXMLFormAction.java	25 Apr 2003 08:34:56 -0000	1.1
  +++ AbstractXMLFormAction.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -1,66 +1,54 @@
   /*
  - * $Revision$
  - * $Date$
  - *
  - * ====================================================================
  - * The Apache Software License, Version 1.1
  - *
  - *
  - *
  - * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  - * reserved.
  - *
  - * Redistribution and use in source and binary forms, with or without
  - * modification, are permitted provided that the following conditions
  - * are met:
  - *
  - * 1. Redistributions of source code must retain the above copyright
  - *    notice, this list of conditions and the following disclaimer.
  - *
  - * 2. Redistributions in binary form must reproduce the above copyright
  - *    notice, this list of conditions and the following disclaimer in
  - *    the documentation and/or other materials provided with the
  - *    distribution.
  - *
  - * 3. The end-user documentation included with the redistribution, if
  - *    any, must include the following acknowlegement:
  - *       "This product includes software developed by the
  - *        Apache Software Foundation (http://www.apache.org/)."
  - *    Alternately, this acknowlegement may appear in the software itself,
  - *    if and wherever such third-party acknowlegements normally appear.
  - *
  - * 4. The names "The Jakarta Project", "Commons", and "Apache Software
  - *    Foundation" must not be used to endorse or promote products derived
  - *    from this software without prior written permission. For written
  - *    permission, please contact apache@apache.org.
  - *
  - * 5. Products derived from this software may not be called "Apache"
  - *    nor may "Apache" appear in their names without prior written
  - *    permission of the Apache Group.
  - *
  - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  - * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  - * SUCH DAMAGE.
  - * ====================================================================
  - *
  - * This software consists of voluntary contributions made by many
  - * individuals on behalf of the Apache Software Foundation and was
  - * originally based on software copyright (c) 2001, Plotnix, Inc,
  - * <http://www.plotnix.com/>.
  - * For more information on the Apache Software Foundation, please see
  - * <http://www.apache.org/>.
  - */
  -package org.apache.cocoon.acting;
   
  + ============================================================================
  +                   The Apache Software License, Version 1.1
  + ============================================================================
  +
  + Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  +
  + Redistribution and use in source and binary forms, with or without modifica-
  + tion, are permitted provided that the following conditions are met:
  +
  + 1. Redistributions of  source code must  retain the above copyright  notice,
  +    this list of conditions and the following disclaimer.
  +
  + 2. Redistributions in binary form must reproduce the above copyright notice,
  +    this list of conditions and the following disclaimer in the documentation
  +    and/or other materials provided with the distribution.
  +
  + 3. The end-user documentation included with the redistribution, if any, must
  +    include  the following  acknowledgment:  "This product includes  software
  +    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  +    Alternately, this  acknowledgment may  appear in the software itself,  if
  +    and wherever such third-party acknowledgments normally appear.
  +
  + 4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
  +    used to  endorse or promote  products derived from  this software without
  +    prior written permission. For written permission, please contact
  +    apache@apache.org.
  +
  + 5. Products  derived from this software may not  be called "Apache", nor may
  +    "Apache" appear  in their name,  without prior written permission  of the
  +    Apache Software Foundation.
  +
  + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  + FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  + APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
  + INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
  + DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
  + OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
  + ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
  + (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
  + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  +
  + This software  consists of voluntary contributions made  by many individuals
  + on  behalf of the Apache Software  Foundation and was  originally created by
  + Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
  + Software Foundation, please see <http://www.apache.org/>.
  +
  +*/
  +package org.apache.cocoon.acting;
   
   import org.apache.avalon.excalibur.pool.Poolable;
   import org.apache.avalon.excalibur.pool.Recyclable;
  @@ -85,12 +73,9 @@
   import java.util.HashMap;
   import java.util.Map;
   
  -
  -
   /**
  - *
    * This is the base action class for
  - * xmlform handling
  + * xmlform handling.
    *
    * This action is Poolable which means that
    * subclasses of this class should not be
  @@ -109,16 +94,13 @@
    * @version CVS $Id$
    */
   public abstract class AbstractXMLFormAction
  -        extends ConfigurableComposerAction
  -        implements Poolable, Recyclable,
  -        FormListener
  -{
  +  extends ConfigurableComposerAction
  +  implements Poolable, Recyclable, FormListener {
   
       public static final String OBJECT_MAP_NEXT_PAGE = "page";
   
       protected static final Map PREPARE_RESULT_CONTINUE = null;
   
  -
       // action state objects
       private Redirector redirector_;
       private SourceResolver resolver_;
  @@ -127,21 +109,18 @@
       private String src_;
       private String command_;
   
  -
       /**
        * The first method which is called
        * when an action is invoked.
        *
        * It is called before population.
        *
  -     *
        * @return null if the Action is prepared to continue.
        * an objectModel map which will be immediately returned by the action.
        *
        * This method is a good place to handle buttons with Cancel
        * kind of semantics. For example
        * <pre>return page("input")</pre>
  -     *
        */
       protected Map prepare() {
           // by default, assume that there is
  @@ -159,14 +138,16 @@
        * This method should not handle unchecked check boxes
        * when the form is session scope, which is the most common case.
        * It should only do so, if the form is request scoped.
  +     *
  +     * @param form       
        */
  -    public void reset( Form form ) {
  +    public void reset(Form form) {
           // Do Nothing by default
           return;
       }
   
       /**
  -     * FormListener callback
  +     * FormListener callback.
        *
        * Invoked during Form.populate();
        *
  @@ -187,10 +168,12 @@
        * this kind of domain specific validation
        * instead of using this method.
        *
  +     * @param form       
  +     * @param parameterName
        * @return false if the request parameter should not be filtered.
        * true otherwise.
        */
  -    public boolean filterRequestParameter (Form form, String parameterName) {
  +    public boolean filterRequestParameter(Form form, String parameterName) {
           // in this example we do not expect "custom" parameters
           return false;
       }
  @@ -208,24 +191,25 @@
        *
        * @return Form the form object this action works with
        */
  -    protected Form getForm () {
  -        Form form = Form.lookup( getObjectModel(), getFormId() );
  +    protected Form getForm() {
  +        Form form = Form.lookup(getObjectModel(), getFormId());
   
  -        if (form != null) {
  +        if (form!=null) {
               return form;
           } else {
               // create new form
  -            form = new Form( getFormId(), getFormModel() );
  +            form = new Form(getFormId(), getFormModel());
               Validator v = getFormValidator();
  -            form.setValidator ( v );
  -            form.save ( getObjectModel(), getFormScope() );
  +
  +            form.setValidator(v);
  +            form.save(getObjectModel(), getFormScope());
               return form;
           }
       }
   
  -    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String src, Parameters params)
  -            throws Exception
  -    {
  +    public Map act(Redirector redirector, SourceResolver resolver,
  +                   Map objectModel, String src,
  +                   Parameters params) throws Exception {
           // populate action state objects
           redirector_ = redirector;
           resolver_ = resolver;
  @@ -236,8 +220,9 @@
           // ensure that there is a form available
           // through the rest of the flow
           Form form = getForm();
  -        if (form == null) {
  -            throw new IllegalStateException( "Action could not obtain the Form" );
  +
  +        if (form==null) {
  +            throw new IllegalStateException("Action could not obtain the Form");
           }
   
           // find and save the action command
  @@ -246,54 +231,55 @@
           // call the subclass prepare()
           // give it a chance to get ready for action
           Map prepareResult = prepare();
  -        if (prepareResult != null) {
  +
  +        if (prepareResult!=null) {
               return prepareResult;
           }
   
           // attache callback hooks to the form
           // in case the action subclasses are interested in
           // form events
  -        getForm().addFormListener( this );
  +        getForm().addFormListener(this);
           Map result = null;
   
           try {
               // populate form with request parameters
               // population is automatically followed by validation by default.
               // If this is not the desired behaviour, the Form class can be subclassed
  -            form.populate( objectModel );
  +            form.populate(objectModel);
   
               result = perform();
           } finally {
               // since the action may be recycled immediately after
               // the request. It is important that it's callback hooks
               // are removed from the Form.
  -            getForm().removeFormListener( this );
  +            getForm().removeFormListener(this);
           }
   
           return result;
       }
   
  -
       /**
        * Get the command which was submitted with the form.
        * It is extracted from the standard cocoon-action-* request parameter
  +     *
  +     * @return
        */
  -    public String getCommand()
  -    {
  +    public String getCommand() {
           return command_;
       }
   
       protected void findCommand() {
           command_ = null;
  -        Enumeration enum = getRequest().getParameterNames ();
  -        while (enum.hasMoreElements ())
  -        {
  -            String paramName = (String) enum.nextElement ();
  +        Enumeration enum = getRequest().getParameterNames();
  +
  +        while (enum.hasMoreElements()) {
  +            String paramName = (String) enum.nextElement();
  +
               // search for the command
  -            if ( paramName.startsWith ( Constants.ACTION_PARAM_PREFIX ) )
  -            {
  -                command_ =
  -                        paramName.substring ( Constants.ACTION_PARAM_PREFIX.length(), paramName.length() );
  +            if (paramName.startsWith(Constants.ACTION_PARAM_PREFIX)) {
  +                command_ = paramName.substring(Constants.ACTION_PARAM_PREFIX.length(),
  +                                               paramName.length());
               }
           }
       }
  @@ -306,21 +292,21 @@
        *
        */
       public String getFormView() {
  -        return getForm().getFormView( getObjectModel() );
  +        return getForm().getFormView(getObjectModel());
       }
   
  -
       /**
        * Called to determine the exit point of an action.
        * The pageName is made available in the objectMap,
        * which can be then referenced in the pipeline
  +
        * @param pageName logical name for a next page
        * @return Map a pipeline objectMap containing the pageName
  -     *
        */
  -    protected Map page( String pageName ) {
  +    protected Map page(String pageName) {
           Map objectModel = new HashMap();
  -        objectModel.put( OBJECT_MAP_NEXT_PAGE,  pageName );
  +
  +        objectModel.put(OBJECT_MAP_NEXT_PAGE, pageName);
           return objectModel;
       }
   
  @@ -328,15 +314,15 @@
        * Invoked after form population
        * unless a Cancel button was pressed,
        * in which case population is skipped and this method
  -     * is invoked immediately
  +     * is invoked immediately.
        *
        * Semanticly similar to Struts Action.perform()
        *
  -     * Take appropriate action based on the command
  +     * Take appropriate action based on the command.
        *
  +     * @return
        */
  -    public abstract Map perform ();
  -
  +    public abstract Map perform();
   
       protected SourceResolver getSourceResolver() {
           return resolver_;
  @@ -350,7 +336,6 @@
           return objectModel_;
       }
   
  -
       protected Parameters getParameters() {
           return params_;
       }
  @@ -360,18 +345,17 @@
       }
   
       protected Request getRequest() {
  -        return (Request) ( getObjectModel().get(ObjectModelHelper.REQUEST_OBJECT) );
  +        return (Request) (getObjectModel().get(ObjectModelHelper.REQUEST_OBJECT));
       }
   
  -    protected Session getSession( boolean shouldCreateNew ) {
  -        return getRequest().getSession( shouldCreateNew );
  +    protected Session getSession(boolean shouldCreateNew) {
  +        return getRequest().getSession(shouldCreateNew);
       }
   
       protected Session getSession() {
  -        return getSession( true );
  +        return getSession(true);
       }
   
  -
       /**
        * Extract action parameters and
        * instantiate a new validator based on them.
  @@ -381,67 +365,79 @@
        *
        * Subclasses may override this method
        * to use custom validators
  +     *
  +     * @return
        */
       protected Validator getFormValidator() {
           try {
               // initialize the Validor with a schema file
  -            String schNS = getParameters().getParameter("xmlform-validator-schema-ns", null);
  -            String schDoc = getParameters().getParameter("xmlform-validator-schema", null);
  +            String schNS = getParameters().getParameter("xmlform-validator-schema-ns",
  +                                                        null);
  +            String schDoc = getParameters().getParameter("xmlform-validator-schema",
  +                                null);
   
               // if validator params are not specified, then
               // there is no validation by default
  -            if (schNS == null || schDoc == null ) return null;
  +            if ((schNS==null) || (schDoc==null)) {
  +                return null;
  +            }
  +
  +            Source schemaSrc = getSourceResolver().resolveURI(schDoc);
   
  -            Source schemaSrc = getSourceResolver().resolveURI( schDoc );
               try {
                   InputSource is = SourceUtil.getInputSource(schemaSrc);
  -                SchemaFactory schf = SchemaFactory.lookup ( schNS );
  -                Schema sch = schf.compileSchema ( is );
  +                SchemaFactory schf = SchemaFactory.lookup(schNS);
  +                Schema sch = schf.compileSchema(is);
   
                   return sch.newValidator();
               } finally {
                   getSourceResolver().release(schemaSrc);
               }
  -        } catch ( Exception e) {
  +        } catch (Exception e) {
               // couldn't load the validator
  -            throw new CascadingRuntimeException( " Failed loading validating schema ", e );
  +            throw new CascadingRuntimeException(" Failed loading validating schema ",
  +                                                e);
           }
       }
   
  -
       /**
  -     * Extract xmlform-model
  -     * action parameter and
  +     * Extract xmlform-model action parameter and
        * instantiate a new form model it.
        *
  -     *
        * Subclasses may override this method
        * to use custom model instantiation technique
  +     *
  +     * @return
        */
       protected Object getFormModel() {
           try {
  -            String modelClassName = getParameters().getParameter("xmlform-model", null);
  -            Class modelClass = Class.forName ( modelClassName );
  -            Object o = modelClass.newInstance ();
  +            String modelClassName = getParameters().getParameter("xmlform-model",
  +                                        null);
  +            Class modelClass = Class.forName(modelClassName);
  +            Object o = modelClass.newInstance();
  +
               return o;
  -        } catch ( Exception e) {
  -            throw new CascadingRuntimeException( " Failed instantiating form model ", e );
  +        } catch (Exception e) {
  +            throw new CascadingRuntimeException(" Failed instantiating form model ",
  +                                                e);
           }
       }
   
  -
       protected String getFormId() {
           String formId = getParameters().getParameter("xmlform-id", null);
  -        if (formId == null)
  -            throw new RuntimeException( " xmlform-id not specified " );
  -        else
  +
  +        if (formId==null) {
  +            throw new RuntimeException(" xmlform-id not specified ");
  +        } else {
               return formId;
  +        }
       }
   
  -
       protected String getFormScope() {
  -        String formScope = getParameters().getParameter("xmlform-scope", null);
  -        if ( formScope == null ) {
  +        String formScope = getParameters().getParameter("xmlform-scope",
  +                               null);
  +
  +        if (formScope==null) {
               // default to request scope
               formScope = Form.SCOPE_REQUEST;
           }
  @@ -449,9 +445,8 @@
           return formScope;
       }
   
  -
       /**
  -     *  Recycle this component.
  +     * Recycle this component.
        */
       public void recycle() {
           redirector_ = null;
  
  
  
  1.2       +36 -29    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/modules/input/XMLFormInput.java
  
  Index: XMLFormInput.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/modules/input/XMLFormInput.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XMLFormInput.java	25 Apr 2003 08:34:57 -0000	1.1
  +++ XMLFormInput.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -1,36 +1,36 @@
   /*
  - 
  +
    ============================================================================
                      The Apache Software License, Version 1.1
    ============================================================================
  - 
  +
    Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  - 
  +
    Redistribution and use in source and binary forms, with or without modifica-
    tion, are permitted provided that the following conditions are met:
  - 
  +
    1. Redistributions of  source code must  retain the above copyright  notice,
       this list of conditions and the following disclaimer.
  - 
  +
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
  - 
  +
    3. The end-user documentation included with the redistribution, if any, must
       include  the following  acknowledgment:  "This product includes  software
       developed  by the  Apache Software Foundation  (http://www.apache.org/)."
       Alternately, this  acknowledgment may  appear in the software itself,  if
       and wherever such third-party acknowledgments normally appear.
  - 
  +
    4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
       used to  endorse or promote  products derived from  this software without
       prior written permission. For written permission, please contact
       apache@apache.org.
  - 
  +
    5. Products  derived from this software may not  be called "Apache", nor may
       "Apache" appear  in their name,  without prior written permission  of the
       Apache Software Foundation.
  - 
  +
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  @@ -41,13 +41,14 @@
    ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
    (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  - 
  +
    This software  consists of voluntary contributions made  by many individuals
    on  behalf of the Apache Software  Foundation and was  originally created by
    Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
    Software Foundation, please see <http://www.apache.org/>.
  - 
  - */
  +
  +*/
  +
   package org.apache.cocoon.components.modules.input;
   
   import java.util.Map;
  @@ -58,26 +59,27 @@
   import org.apache.cocoon.components.xmlform.Form;
   
   /**
  - * Accesses the form model of an 
  - * {@link org.apache.cocoon.components.xmlform.Form XMLForm Instance}. 
  - * The xmlform-id needs to be passed with the configuration. Additionally supports 
  + * Accesses the form model of an
  + * {@link org.apache.cocoon.components.xmlform.Form XMLForm Instance}.
  + * The xmlform-id needs to be passed with the configuration. Additionally supports
    * all configuration options from {@link AbstractJXPathModule AbstractJXPathModule}.
  - * This can be used for example to let the 
  - * <code>org.apache.cocoon.acting.modular.DatabaseAction</code> access 
  + * This can be used for example to let the
  + * <code>org.apache.cocoon.acting.modular.DatabaseAction</code> access
    * form data.
  - * 
  + *
    * <p>Configuration example:</p>
    * <table>
    * <tr><td><code>&lt;xmlform-id&gt;form-feedback&lt;/xmlform-id&gt;</td>
  - * <td>XMLForm ID to use.</td> 
  + * <td>XMLForm ID to use.</td>
    * </tr></table>
    *
    * @author <a href="mailto:haul@apache.org">Christian Haul</a>
    * @version CVS $Id$
    */
   public class XMLFormInput extends AbstractJXPathModule implements ThreadSafe {
  +
       String formId = null;
  -    
  +
       /**
        * Configure component. Preprocess list of packages and functions
        * to add to JXPath context later.
  @@ -85,25 +87,30 @@
        * @param config a <code>Configuration</code> value
        * @exception ConfigurationException if an error occurs
        */
  -    public void configure(Configuration config) throws ConfigurationException {
  +    public void configure(Configuration config)
  +      throws ConfigurationException {
           this.formId = config.getChild("xmlform-id").getValue(null);
           super.configure(config);
       }
  -    
  -    /** Returns the object which should be used as JXPath context.
  +
  +    /** 
  +     * Returns the object which should be used as JXPath context.
        * Descendants should override this method to return a specific object
        * that is requried by the implementing class.
        * Examples are: request, session and application context objects.
  -     *
        */
  -    protected Object getContextObject(Configuration modeConf, Map objectModel) throws ConfigurationException {
  +    protected Object getContextObject(Configuration modeConf,
  +                                      Map objectModel)
  +                                        throws ConfigurationException {
           String id = this.formId;
  -        if (modeConf != null) {
  +
  +        if (modeConf!=null) {
               id = modeConf.getChild("xmlform-id").getValue(this.formId);
           }
  -        Form form = Form.lookup(objectModel,id);
  +        Form form = Form.lookup(objectModel, id);
           Object tmp = null;
  -        if (form != null) { 
  +
  +        if (form!=null) {
               tmp = form.getModel();
           }
           return tmp;
  
  
  
  1.2       +8 -5      cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Schema.java
  
  Index: Schema.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Schema.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Schema.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Schema.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -52,13 +52,16 @@
   
   /**
    *
  - * Created on Sat, April 6, 2002
  - *
    * @author  ivelin@apache.org
    * @version CVS $Id$
    */
   public interface Schema {
  -  
  +
  +    /**
  +     *
  +     *
  +     * @return
  +     */
       Validator newValidator() throws InstantiationException;
  -    
  +
   }
  
  
  
  1.2       +38 -44    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/SchemaFactory.java
  
  Index: SchemaFactory.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/SchemaFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SchemaFactory.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ SchemaFactory.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -53,56 +53,50 @@
   import org.xml.sax.InputSource;
   
   /**
  - * 
    * Responsible for creating new instances of Schemas
  - * for different Schema languages
  + * for different Schema languages.
    *
    * @author  ivelin@apache.org
    * @version CVS $Id$
    */
   public abstract class SchemaFactory {
   
  -	public static String NAMESPACE_SCHEMATRON =
  -		"http://www.ascc.net/xml/schematron";
  +    public static String NAMESPACE_SCHEMATRON = "http://www.ascc.net/xml/schematron";
   
  -	/** Creates a new instance of ValidatorFactory */
  -	public SchemaFactory() {
  -	}
  -
  -	/**
  -	 * This method creates an instance of a ValidatorFactory
  -	 * using the JDK 1.3 META-INF/services mechanism.
  -	 * The idea is borrowed from JARV
  -	 * http://iso-relax.sourceforge.net/apiDoc/org/iso_relax/verifier/VerifierFactory.html
  -	 *
  -	 * @param ns the namespace of the schema language
  -	 * @return ValidatorFactory
  -	 * @throws InstantiationException when a factory could not be created
  -	 */
  -	public static SchemaFactory lookup(String ns)
  -		throws InstantiationException {
  -		// currently hardcoded implementation for Schematron
  -		// until another schema validator is implemented
  -		/* TODO: create SchematronValidatorFactory */
  -		if (ns.equals(NAMESPACE_SCHEMATRON))
  -			return new org
  -				.apache
  -				.cocoon
  -				.components
  -				.validation
  -				.schematron
  -				.SchematronFactory();
  -		return null;
  -	}
  -
  -	/**
  -	 * Loads and compiles a Schema instance
  -	 *
  -	 * @param InputSource the SAX input source containing the Schema document
  -	 * @return Schema the compiled schema instance
  -	 * @throws InstantiationException when the Schema could not be loaded or compiled
  -	 */
  -	public abstract Schema compileSchema(InputSource is)
  -		throws InstantiationException;
  +    /** Creates a new instance of ValidatorFactory */
  +    public SchemaFactory() {
  +    }
   
  +    /**
  +     * This method creates an instance of a ValidatorFactory
  +     * using the JDK 1.3 META-INF/services mechanism.
  +     * The idea is borrowed from JARV
  +     * http://iso-relax.sourceforge.net/apiDoc/org/iso_relax/verifier/VerifierFactory.html
  +     *
  +     * @param ns the namespace of the schema language
  +     * @return ValidatorFactory
  +     * @throws InstantiationException when a factory could not be created
  +     */
  +    public static SchemaFactory lookup(String ns)
  +      throws InstantiationException {
  +        // currently hardcoded implementation for Schematron
  +        // until another schema validator is implemented
  +
  +        /* TODO: create SchematronValidatorFactory */
  +
  +        if (ns.equals(NAMESPACE_SCHEMATRON)) {
  +            return new org.apache.cocoon.components.validation.schematron.SchematronFactory();
  +        }
  +        return null;
  +    }
  +
  +    /**
  +     * Loads and compiles a Schema instance
  +     *
  +     * @param is         
  +     * @return Schema the compiled schema instance
  +     * @throws InstantiationException when the Schema could not be loaded or compiled
  +     */
  +    public abstract Schema compileSchema(InputSource is)
  +      throws InstantiationException;
   }
  
  
  
  1.2       +33 -38    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Validator.java
  
  Index: Validator.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Validator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Validator.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Validator.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -61,43 +61,38 @@
    */
   public interface Validator {
   
  -  /**
  -   * Validates an instance against a schema and returns a set of errors.
  -   *
  -   * Validator is not thread safe and is not re-entrant.
  -   *
  -   * @param instance The instance can be either a DOM node or a JavaBean.
  -   * @return SortedSet of ValidityViolation(s). The set is sorted by
  -   * ValidityViolation.getPath()
  -   * 
  -   * @throws RuntimeException if the validation process fails
  -   * Should not happen in a normal environment.
  -   */
  -  List validate(Object instance);
  +    /**
  +     * Validates an instance against a schema and returns a set of errors.
  +     *
  +     * Validator is not thread safe and is not re-entrant.
  +     *
  +     * @param instance The instance can be either a DOM node or a JavaBean.
  +     * @return SortedSet of ValidityViolation(s). The set is sorted by
  +     * ValidityViolation.getPath()
  +     *
  +     */
  +    List validate(Object instance);
   
  -  /**
  -   * This property can be used for partial document validation.
  -   * The concept is borrowed from the Schematron schema
  -   * Not all schemas support partial validation
  -   */
  -  String PROPERTY_PHASE = "http://xml.apache.org/cocoon/validator/phase";
  +    /**
  +     * This property can be used for partial document validation.
  +     * The concept is borrowed from the Schematron schema
  +     * Not all schemas support partial validation
  +     */
  +    String PROPERTY_PHASE = "http://xml.apache.org/cocoon/validator/phase";
  +
  +    /**
  +     * @param property name
  +     * @param value property value
  +     * @throws IllegalArgumentException when the property is not supported
  +     */
  +    void setProperty(String property,
  +                     Object value) throws IllegalArgumentException;
  +
  +    /**
  +     * @param property name
  +     * @return the property value
  +     * @throws IllegalArgumentException when the property is not supported
  +     */
  +    Object getProperty(String property) throws IllegalArgumentException;
   
  -  /**
  -   * @param property name
  -   * @param value property value
  -   * @throws IllegalArgumentException when the property is not supported
  -   */
  -  void setProperty(String property, Object value)
  -                 throws IllegalArgumentException;
  -  
  -  /**
  -   * @param property name
  -   * @return the property value
  -   * @throws IllegalArgumentException when the property is not supported
  -   */
  -  Object getProperty(String property)
  -                 throws IllegalArgumentException;
  -  
  -                 
  -                 
   }
  
  
  
  1.2       +87 -74    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Violation.java
  
  Index: Violation.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/Violation.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Violation.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Violation.java	26 Apr 2003 12:10:43 -0000	1.2
  @@ -54,84 +54,97 @@
    * Encapsulates an error condition which was triggered
    * by a violation of the document validity during
    * validation
  - * 
  + *
    * @author  ivelin@apache.org
    * @version CVS $Id$
    */
   public class Violation implements Comparable {
   
  -	/** 
  -	* @return the XPath location of the Violation
  -	*/
  -	public String getPath() {
  -		return xpath_;
  -	}
  -
  -	/** 
  -	* set the XPath location of the Violation
  -	*/
  -	public void setPath(String xpath) {
  -		xpath_ = xpath;
  -	}
  -
  -	/**
  -	 * @return the error message
  -	 */
  -	public String getMessage() {
  -		return message_;
  -	}
  -
  -	/**
  -	 * set the error message
  -	 */
  -	public void setMessage(String message) {
  -		message_ = message;
  -	}
  -
  -	public boolean equals(Object obj) {
  -		if (obj == null)
  -			return false;
  -		if (obj == this)
  -			return true;
  -		if (!(obj instanceof Violation))
  -			throw new java.lang.IllegalArgumentException(
  -				"Can only compare to a Violation object");
  -		Violation v = (Violation) obj;
  -		if (getPath().equals(v.getPath())
  -			&& getMessage().equals(v.getMessage()))
  -			return true;
  -		else
  -			return false;
  -	}
  -
  -	public int hashCode() {
  -		return (getPath().hashCode() ^ getMessage().hashCode());
  -	}
  -
  -	public int compareTo(Object obj) {
  -		if (obj == null)
  -			return 1;
  -		if (obj == this)
  -			return 0;
  -		if (!(obj instanceof Violation))
  -			throw new java.lang.IllegalArgumentException(
  -				"Can only compare to a Violation object");
  -		Violation v = (Violation) obj;
  -		int primaryResult = getPath().compareTo(v.getPath());
  -		if (primaryResult != 0)
  -			return primaryResult;
  -		else {
  -			if (getMessage() == null) {
  -				if (v.getMessage() == null)
  -					return 0;
  -				else
  -					return -1;
  -			} else
  -				return (getMessage().compareTo(v.getMessage()));
  -		}
  -	}
  +    /**
  +     * @return the XPath location of the Violation
  +     */
  +    public String getPath() {
  +        return xpath_;
  +    }
  +
  +    /**
  +     * set the XPath location of the Violation
  +     *
  +     * @param xpath      
  +     */
  +    public void setPath(String xpath) {
  +        xpath_ = xpath;
  +    }
  +
  +    /**
  +     * @return the error message
  +     */
  +    public String getMessage() {
  +        return message_;
  +    }
  +
  +    /**
  +     * set the error message
  +     *
  +     * @param message    
  +     */
  +    public void setMessage(String message) {
  +        message_ = message;
  +    }
  +
  +    public boolean equals(Object obj) {
  +        if (obj==null) {
  +            return false;
  +        }
  +        if (obj==this) {
  +            return true;
  +        }
  +        if ( !(obj instanceof Violation)) {
  +            throw new java.lang.IllegalArgumentException("Can only compare to a Violation object");
  +        }
  +        Violation v = (Violation) obj;
  +
  +        if (getPath().equals(v.getPath()) &&
  +            getMessage().equals(v.getMessage())) {
  +            return true;
  +        } else {
  +            return false;
  +        }
  +    }
  +
  +    public int hashCode() {
  +        return (getPath().hashCode()^getMessage().hashCode());
  +    }
  +
  +    public int compareTo(Object obj) {
  +        if (obj==null) {
  +            return 1;
  +        }
  +        if (obj==this) {
  +            return 0;
  +        }
  +        if ( !(obj instanceof Violation)) {
  +            throw new java.lang.IllegalArgumentException("Can only compare to a Violation object");
  +        }
  +        Violation v = (Violation) obj;
  +        int primaryResult = getPath().compareTo(v.getPath());
  +
  +        if (primaryResult!=0) {
  +            return primaryResult;
  +        } else {
  +            if (getMessage()==null) {
  +                if (v.getMessage()==null) {
  +                    return 0;
  +                } else {
  +                    return -1;
  +                }
  +            } else {
  +                return (getMessage().compareTo(v.getMessage()));
  +            }
  +        }
  +    }
   
  -	private String xpath_;
  -	private String message_;
  +    private String xpath_;
  +    private String message_;
   
   }
  
  
  
  1.2       +16 -17    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/ActivePattern.java
  
  Index: ActivePattern.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/ActivePattern.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ActivePattern.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ ActivePattern.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -51,28 +51,27 @@
   package org.apache.cocoon.components.validation.schematron;
   
   /**
  - * Represents a Schematron phase 
  - * <active pattern="some"> element
  + * Represents a Schematron phase
  + * <active pattern="some"> element.
    *
    * @author  Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @version CVS $Id$
    */
   public class ActivePattern {
   
  -	private String pattern_;
  +    private String pattern_;
   
  -	/**
  -	 * Returns the active pattern name
  -	 */
  -	public String getPattern() {
  -		return pattern_;
  -	}
  -
  -	/**
  -	 * Sets the active pattern name
  -	 */
  -	public void setPattern(String pattern) {
  -		pattern_ = pattern;
  -	}
  +    /**
  +     * Returns the active pattern name
  +     */
  +    public String getPattern() {
  +        return pattern_;
  +    }
   
  +    /**
  +     * Sets the active pattern name
  +     */
  +    public void setPattern(String pattern) {
  +        pattern_ = pattern;
  +    }
   }
  
  
  
  1.2       +49 -50    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Assert.java
  
  Index: Assert.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Assert.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Assert.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Assert.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -51,60 +51,59 @@
   package org.apache.cocoon.components.validation.schematron;
   
   /**
  - * Represents a Schematron assert element 
  - * 
  + * Represents a Schematron assert element.
  + *
    * example:
  - * <assert test="count(ear)=2">A <name/> element should contain two <emph>ear</emph> elements.</assert> 
  + * <assert test="count(ear)=2">A <name/> element should contain two <emph>ear</emph> elements.</assert>
    *
    * @author  Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @version CVS $Id$
    */
   public class Assert {
   
  -	private String test_;
  -	private String message_;
  -	private String diagnostics_;
  -
  -	/**
  -	 * Returns the test attribute 
  -	 */
  -	public String getTest() {
  -		return test_;
  -	}
  -
  -	/**
  -	 * Sets the test attribute 
  -	 */
  -	public void setTest(String newTest) {
  -		test_ = newTest;
  -	}
  -
  -	/**
  -	 * Returns the message for to the element 
  -	 */
  -	public String getMessage() {
  -		return message_;
  -	}
  -
  -	/**
  -	 * Sets the message for to the element 
  -	 */
  -	public void setMessage(String newMessage) {
  -		message_ = newMessage;
  -	}
  -
  -	/**
  -	 * Returns the diagnostics list 
  -	 */
  -	public String getDiagnostics() {
  -		return diagnostics_;
  -	}
  -
  -	/**
  -	 * Sets the diagnostics list 
  -	 */
  -	public void setDiagnostics(String newDiagnostics) {
  -		diagnostics_ = newDiagnostics;
  -	}
  -
  +    private String test_;
  +    private String message_;
  +    private String diagnostics_;
  +
  +    /**
  +     * Returns the test attribute
  +     */
  +    public String getTest() {
  +        return test_;
  +    }
  +
  +    /**
  +     * Sets the test attribute
  +     */
  +    public void setTest(String newTest) {
  +        test_ = newTest;
  +    }
  +
  +    /**
  +     * Returns the message for to the element
  +     */
  +    public String getMessage() {
  +        return message_;
  +    }
  +
  +    /**
  +     * Sets the message for to the element
  +     */
  +    public void setMessage(String newMessage) {
  +        message_ = newMessage;
  +    }
  +
  +    /**
  +     * Returns the diagnostics list
  +     */
  +    public String getDiagnostics() {
  +        return diagnostics_;
  +    }
  +
  +    /**
  +     * Sets the diagnostics list
  +     */
  +    public void setDiagnostics(String newDiagnostics) {
  +        diagnostics_ = newDiagnostics;
  +    }
   }
  
  
  
  1.2       +56 -57    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Pattern.java
  
  Index: Pattern.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Pattern.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Pattern.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Pattern.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -55,65 +55,64 @@
   import java.util.List;
   
   /**
  - * Represents a Schematron pattern 
  - * 
  + * Represents a Schematron pattern.
  + *
    * @author  Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @version CVS $Id$
    */
   public class Pattern {
   
  -	private String name_;
  -	private String id_;
  -	private ArrayList rules_ = new ArrayList();
  -
  -	/**
  -	 * Returns the id of the pattern
  -	 */
  -	public String getId() {
  -		return id_;
  -	}
  -
  -	/**
  -	 * Sets the id of the pattern
  -	 */
  -	public void setId(String newId) {
  -		id_ = newId;
  -	}
  -
  -	/**
  -	 * Returns the name of the pattern
  -	 */
  -	public String getName() {
  -		return name_;
  -	}
  -
  -	/**
  -	 * Sets the name of the pattern
  -	 */
  -	public void setName(String newName) {
  -		name_ = newName;
  -	}
  -
  -	/**
  -	 * Returns the list of rules 
  -	 */
  -	public List getRule() {
  -		return rules_;
  -	}
  -
  -	/**
  -	 * Sets the list of rules 
  -	 */
  -	public void setRule(Collection newRules) {
  -		rules_ = new ArrayList();
  -		rules_.addAll(newRules);
  -	}
  -
  -	/**
  -	 * Add a rule to the list 
  -	 */
  -	public void addRule(Rule r) {
  -		rules_.add(r);
  -	}
  -
  +    private String name_;
  +    private String id_;
  +    private ArrayList rules_ = new ArrayList();
  +
  +    /**
  +     * Returns the id of the pattern.
  +     */
  +    public String getId() {
  +        return id_;
  +    }
  +
  +    /**
  +     * Sets the id of the pattern.
  +     */
  +    public void setId(String newId) {
  +        id_ = newId;
  +    }
  +
  +    /**
  +     * Returns the name of the pattern.
  +     */
  +    public String getName() {
  +        return name_;
  +    }
  +
  +    /**
  +     * Sets the name of the pattern.
  +     */
  +    public void setName(String newName) {
  +        name_ = newName;
  +    }
  +
  +    /**
  +     * Returns the list of rules.
  +     */
  +    public List getRule() {
  +        return rules_;
  +    }
  +
  +    /**
  +     * Sets the list of rules.
  +     */
  +    public void setRule(Collection newRules) {
  +        rules_ = new ArrayList();
  +        rules_.addAll(newRules);
  +    }
  +
  +    /**
  +     * Add a rule to the list.
  +     */
  +    public void addRule(Rule r) {
  +        rules_.add(r);
  +    }
   }
  
  
  
  1.2       +39 -41    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Phase.java
  
  Index: Phase.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Phase.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Phase.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Phase.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -55,7 +55,7 @@
   import java.util.List;
   
   /**
  - * Represents a Schematron phase element
  + * Represents a Schematron phase element.
    *
    * Example:
    * <phase id="basicValidation">
  @@ -64,49 +64,47 @@
    *   <active pattern="attributePresence" />
    * </phase>
    *
  - *
    * @author  Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @version CVS $Id$
    */
   public class Phase {
   
  -	private String id_;
  -	private ArrayList active_ = new ArrayList();
  -
  -	/**
  -	 * Returns the id of the phase
  -	 */
  -	public String getId() {
  -		return id_;
  -	}
  -
  -	/**
  -	 * Sets the id of the phase
  -	 */
  -	public void setId(String newId) {
  -		id_ = newId;
  -	}
  -
  -	/**
  -	 * Returns the list of active patterns
  -	 */
  -	public List getActive() {
  -		return active_;
  -	}
  -
  -	/**
  -	 * Sets the list of active patterns
  -	 */
  -	public void setActive(Collection newActivePatterns) {
  -		active_ = new ArrayList();
  -		active_.addAll(newActivePatterns);
  -	}
  -
  -	/**
  -	 * Add a pattern to the list of active patterns
  -	 */
  -	public void addActive(ActivePattern p) {
  -		active_.add(p);
  -	}
  +    private String id_;
  +    private ArrayList active_ = new ArrayList();
   
  +    /**
  +     * Returns the id of the phase.
  +     */
  +    public String getId() {
  +        return id_;
  +    }
  +
  +    /**
  +     * Sets the id of the phase.
  +     */
  +    public void setId(String newId) {
  +        id_ = newId;
  +    }
  +
  +    /**
  +     * Returns the list of active patterns.
  +     */
  +    public List getActive() {
  +        return active_;
  +    }
  +
  +    /**
  +     * Sets the list of active patterns.
  +     */
  +    public void setActive(Collection newActivePatterns) {
  +        active_ = new ArrayList();
  +        active_.addAll(newActivePatterns);
  +    }
  +
  +    /**
  +     * Add a pattern to the list of active patterns.
  +     */
  +    public void addActive(ActivePattern p) {
  +        active_.add(p);
  +    }
   }
  
  
  
  1.2       +5 -5      cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Report.java
  
  Index: Report.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Report.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Report.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Report.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -51,12 +51,12 @@
   package org.apache.cocoon.components.validation.schematron;
   
   /**
  - * Represents a Schematron report element 
  + * Represents a Schematron report element.
    *
  - * <report test="when">message</report> 
  + * <report test="when">message</report>
    * is equivalent to
  - * <assert test="not(when)">message</assert> 
  - * 
  + * <assert test="not(when)">message</assert>
  + *
    * example:
    * <report test="bone">This dog has a bone.</report>
    *
  
  
  
  1.2       +64 -65    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Rule.java
  
  Index: Rule.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/Rule.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Rule.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ Rule.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -55,8 +55,8 @@
   import java.util.List;
   
   /**
  - * Represents a Schematron rule element 
  - * 
  + * Represents a Schematron rule element.
  + *
    * From the Schematron specification:
    *
    * example:
  @@ -70,66 +70,65 @@
    */
   public class Rule {
   
  -	private String context_;
  -	private ArrayList asserts_ = new ArrayList();
  -	private ArrayList reports_ = new ArrayList();
  -
  -	/**
  -	 * Returns the context of the pattern
  -	 */
  -	public String getContext() {
  -		return context_;
  -	}
  -
  -	/**
  -	 * Sets the context of the pattern
  -	 */
  -	public void setContext(String newContext) {
  -		context_ = newContext;
  -	}
  -
  -	/**
  -	 * Returns the list of the assertion rules 
  -	 */
  -	public List getAssert() {
  -		return asserts_;
  -	}
  -
  -	/**
  -	 * Sets the the list of the assertion rules 
  -	 */
  -	public void setAssert(Collection newAsserts) {
  -		asserts_ = new ArrayList();
  -		asserts_.addAll(newAsserts);
  -	}
  -
  -	/**
  -	 * Add an assert rule 
  -	 */
  -	public void addAssert(Assert a) {
  -		asserts_.add(a);
  -	}
  -
  -	/**
  -	 * Returns the list of the report rules 
  -	 */
  -	public List getReport() {
  -		return reports_;
  -	}
  -
  -	/**
  -	 * Sets the list of the report rules 
  -	 */
  -	public void setReport(Collection newReports) {
  -		reports_ = new ArrayList();
  -		reports_.addAll(newReports);
  -	}
  -
  -	/**
  -	 * Add a report rule 
  -	 */
  -	public void addReport(Report r) {
  -		reports_.add(r);
  -	}
  -
  +    private String context_;
  +    private ArrayList asserts_ = new ArrayList();
  +    private ArrayList reports_ = new ArrayList();
  +
  +    /**
  +     * Returns the context of the pattern.
  +     */
  +    public String getContext() {
  +        return context_;
  +    }
  +
  +    /**
  +     * Sets the context of the pattern.
  +     */
  +    public void setContext(String newContext) {
  +        context_ = newContext;
  +    }
  +
  +    /**
  +     * Returns the list of the assertion rules.
  +     */
  +    public List getAssert() {
  +        return asserts_;
  +    }
  +
  +    /**
  +     * Sets the the list of the assertion rules.
  +     */
  +    public void setAssert(Collection newAsserts) {
  +        asserts_ = new ArrayList();
  +        asserts_.addAll(newAsserts);
  +    }
  +
  +    /**
  +     * Add an assert rule.
  +     */
  +    public void addAssert(Assert a) {
  +        asserts_.add(a);
  +    }
  +
  +    /**
  +     * Returns the list of the report rules.
  +     */
  +    public List getReport() {
  +        return reports_;
  +    }
  +
  +    /**
  +     * Sets the list of the report rules.
  +     */
  +    public void setReport(Collection newReports) {
  +        reports_ = new ArrayList();
  +        reports_.addAll(newReports);
  +    }
  +
  +    /**
  +     * Add a report rule.
  +     */
  +    public void addReport(Report r) {
  +        reports_.add(r);
  +    }
   }
  
  
  
  1.2       +374 -384  cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronFactory.java
  
  Index: SchematronFactory.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SchematronFactory.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ SchematronFactory.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -66,7 +66,7 @@
   
   /**
    * A helper class which builds a SchematronSchema instance object
  - * from a DOM source
  + * from a DOM source.
    *
    * @author Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @author Michael Ratliff, mratliff@collegenet.com <mr...@collegenet.com>, May 2002
  @@ -74,386 +74,376 @@
    */
   public class SchematronFactory extends SchemaFactory {
   
  -	/**
  -	 * the schema name space prefix used in the schema document
  -	 */
  -	private String schemaPrefix_;
  -
  -	/**
  -	 * the default schema name space prefix
  -	 */
  -	private String defaultSchemaPrefix_ = "sch";
  -
  -	/**
  -	 * private logger
  -	 */
  -	private Logger logger = setupLogger();
  -
  -	//
  -	// Constructors
  -	//
  -
  -	/**
  -	 * initialize logger
  -	 */
  -	protected Logger setupLogger() {
  -		Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm");
  -		logger.setPriority(Priority.ERROR);
  -		return logger;
  -	}
  -
  -	/**
  -	 * Builds a new Schema instance from
  -	 * the given XML InputSource
  -	 *
  -	 * @param schemaSrc
  -	 *        the Schema document XML InputSource
  -	 */
  -	public Schema compileSchema(InputSource schemaSrc)
  -		throws InstantiationException {
  -		SchematronSchema schema = null;
  -		try {
  -			// load Schema file into a DOM document
  -			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  -			DocumentBuilder dbld = dbf.newDocumentBuilder();
  -			Document document = dbld.parse(schemaSrc);
  -
  -			schema = buildSchema(document);
  -		} catch (Exception e) {
  -			logger.error("!!! Failed loading Schematron schema", e);
  -			throw new CascadingRuntimeException(
  -				" !!! Failed loading Schematron schema",
  -				e);
  -		}
  -		return schema;
  -	} // build
  -
  -	/**
  -	 * Build Schematron schema object from a DOM document
  -	 * @param doc DOM document containing the schema
  -	 *
  -	 */
  -	protected SchematronSchema buildSchema(Document doc) {
  -		SchematronSchema schema = new SchematronSchema();
  -
  -		doc.getNamespaceURI();
  -		doc.getPrefix();
  -
  -		// Initialize the JXPath context
  -		Element root = doc.createElement("root");
  -		Element schemaElement = doc.getDocumentElement();
  -		schemaPrefix_ = schemaElement.getPrefix();
  -		root.appendChild(schemaElement);
  -		JXPathContext jxpContext = JXPathContext.newContext(root);
  -		jxpContext.setLenient(false);
  -
  -		// Bind sch:schema element
  -
  -		// schema title
  -		String title =
  -			(String) jxpContext.getValue("/schema/title", String.class);
  -		schema.setTitle(title);
  -		logger.debug("Schema title: " + schema.getTitle());
  -
  -		bindPatterns(schema, jxpContext);
  -		bindPhases(schema, jxpContext);
  -
  -		return schema;
  -	}
  -
  -	/**
  -	 * populates the patterns elements from the dom tree
  -	 *
  -	 * @param schema the schema instance
  -	 * @param jxpContext
  -	 */
  -	protected void bindPatterns(
  -		SchematronSchema schema,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// schema patterns
  -		int ptCount =
  -			((Integer) jxpContext
  -				.getValue("count(/schema/pattern)", Integer.class))
  -				.intValue();
  -		logger.debug("\nNumber of patterns:  " + ptCount);
  -		for (int i = 1; i <= ptCount; i++) {
  -			logger.debug("Pattern# :  " + i);
  -			Pattern pattern = new Pattern();
  -			String ptprefix = "/schema/pattern[" + i + "]";
  -
  -			String name =
  -				(String) jxpContext.getValue(ptprefix + "/@name", String.class);
  -			pattern.setName(name);
  -			logger.debug("Pattern name :  " + pattern.getName());
  -
  -			String id =
  -				(String) jxpContext.getValue(ptprefix + "/@id", String.class);
  -			pattern.setId(id);
  -			logger.debug("Pattern id :  " + pattern.getId());
  -
  -			bindRules(pattern, ptprefix, jxpContext);
  -
  -			schema.addPattern(pattern);
  -		}
  -	}
  -
  -	/**
  -	 * populates the rules elements for a pattern
  -	 * from the dom tree
  -	 *
  -	 * @param pattern
  -	 * @param pathPrefix pattern path prefix
  -	 * @param jxpContext JXPathContext
  -	 */
  -	protected void bindRules(
  -		Pattern pattern,
  -		String pathPrefix,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// schema rules
  -		int ruleCount =
  -			((Integer) jxpContext
  -				.getValue("count(" + pathPrefix + "/rule)", Integer.class))
  -				.intValue();
  -		logger.debug("\nNumber of rules:  " + ruleCount);
  -		for (int i = 1; i <= ruleCount; i++) {
  -			logger.debug("Rule# :  " + i);
  -			Rule rule = new Rule();
  -			String rulePrefix = pathPrefix + "/rule[" + i + "]";
  -
  -			String context =
  -				(String) jxpContext.getValue(
  -					rulePrefix + "/@context",
  -					String.class);
  -			rule.setContext(context);
  -			logger.debug("Rule context :  " + rule.getContext());
  -
  -			bindAsserts(rule, rulePrefix, jxpContext);
  -
  -			// Patch to make reports work in schematron
  -			// Note change to name of bindRerports [sic] function
  -			bindReports(rule, rulePrefix, jxpContext);
  -
  -			pattern.addRule(rule);
  -		}
  -	}
  -
  -	/**
  -	 * populates the assert elements for a rule
  -	 * from the dom tree
  -	 *
  -	 * @param rule
  -	 * @param pathPrefix rule path prefix
  -	 * @param jxpContext JXPathContext
  -	 */
  -	protected void bindAsserts(
  -		Rule rule,
  -		String pathPrefix,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// schema reports
  -		int elementCount =
  -			((Integer) jxpContext
  -				.getValue("count(" + pathPrefix + "/assert)", Integer.class))
  -				.intValue();
  -		logger.debug("\nNumber of asserts:  " + elementCount);
  -		for (int i = 1; i <= elementCount; i++) {
  -			logger.debug("Assert# :  " + i);
  -			Assert assertion = new Assert();
  -			String assertPrefix = pathPrefix + "/assert[" + i + "]";
  -
  -			String test =
  -				(String) jxpContext.getValue(
  -					assertPrefix + "/@test",
  -					String.class);
  -			assertion.setTest(test);
  -			logger.debug("Assert test :  " + assertion.getTest());
  -
  -			// since diagnostics is a non-mandatory element
  -			// we will try to get its value in a lenient mode
  -			jxpContext.setLenient(true);
  -			String diagnostics =
  -				(String) jxpContext.getValue(
  -					assertPrefix + "/@diagnostics",
  -					String.class);
  -			assertion.setDiagnostics(diagnostics);
  -			logger.debug("Assert diagnostics :  " + assertion.getDiagnostics());
  -			jxpContext.setLenient(false);
  -
  -			// now read the report message
  -			// TODO: The current implementation does not 
  -			// read xml tags used within the assert message.
  -			// Solution is to use JXPath NodePointer to get 
  -			// to the DOM node and then convert it to a String.
  -			// e.g.
  -			// NodePointer nptr = (NodePointer) jxpContext.locateValue( assertPrefix );
  -			// Node msgNode = (Node) nptr.getNodeValue();
  -			// convery DOMNode to String
  -
  -			String message =
  -				(String) jxpContext.getValue(assertPrefix, String.class);
  -			assertion.setMessage(message);
  -			logger.debug("Assert message :  " + assertion.getMessage());
  -
  -			rule.addAssert(assertion);
  -		}
  -	}
  -
  -	/**
  -	 * populates the report elements for a rule
  -	 * from the dom tree
  -	 *
  -	 * @param rule
  -	 * @param pathPrefix rule path prefix
  -	 * @param jxpContext JXPathContext
  -	 */
  -
  -	protected void bindReports(
  -		Rule rule,
  -		String pathPrefix,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// schema reports
  -		int elementCount =
  -			((Integer) jxpContext
  -				.getValue("count(" + pathPrefix + "/report)", Integer.class))
  -				.intValue();
  -		logger.debug("\nNumber of reports:  " + elementCount);
  -		for (int i = 1; i <= elementCount; i++) {
  -			logger.debug("Report# :  " + i);
  -			Report report = new Report();
  -			String assertPrefix = pathPrefix + "/report[" + i + "]";
  -
  -			String test =
  -				(String) jxpContext.getValue(
  -					assertPrefix + "/@test",
  -					String.class);
  -			report.setTest(test);
  -			logger.debug("Report test :  " + report.getTest());
  -
  -			// since diagnostics is a non-mandatory element
  -			// we will try to get its value in a lenient mode
  -			jxpContext.setLenient(true);
  -			String diagnostics =
  -				(String) jxpContext.getValue(
  -					assertPrefix + "/@diagnostics",
  -					String.class);
  -			report.setDiagnostics(diagnostics);
  -			logger.debug("Report diagnostics :  " + report.getDiagnostics());
  -			jxpContext.setLenient(false);
  -
  -			String message =
  -				(String) jxpContext.getValue(assertPrefix, String.class);
  -			report.setMessage(message);
  -			logger.debug("Report message :  " + report.getMessage());
  -
  -			rule.addReport(report);
  -		}
  -	}
  -
  -	/**
  -	 * populates the phases elements from the dom tree
  -	 *
  -	 * @param schema the schema instance
  -	 * @param jxpContext
  -	 */
  -	protected void bindPhases(
  -		SchematronSchema schema,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// schema phases
  -		int phaseCount =
  -			((Integer) jxpContext
  -				.getValue("count(/schema/phase)", Integer.class))
  -				.intValue();
  -		logger.debug("\nNumber of phases:  " + phaseCount);
  -
  -		for (int i = 1; i <= phaseCount; i++) {
  -			logger.debug("phase# :  " + i);
  -			Phase phase = new Phase();
  -			String phprefix = "/schema/phase[" + i + "]";
  -
  -			String id =
  -				(String) jxpContext.getValue(phprefix + "/@id", String.class);
  -			phase.setId(id);
  -			logger.debug("phase id :  " + phase.getId());
  -
  -			bindPhaseActivePatterns(phase, phprefix, jxpContext);
  -
  -			schema.addPhase(phase);
  -		}
  -	}
  -
  -	protected void bindPhaseActivePatterns(
  -		Phase phase,
  -		String pathPrefix,
  -		JXPathContext jxpContext) {
  -		// ensure that mandatory elements which are not found
  -		// will result in Exception
  -		jxpContext.setLenient(false);
  -
  -		// phase active patterns
  -		int elementCount =
  -			((Integer) jxpContext
  -				.getValue("count(" + pathPrefix + "/active)", Integer.class))
  -				.intValue();
  -		logger.debug("Number of active patterns:  " + elementCount);
  -		for (int i = 1; i <= elementCount; i++) {
  -			logger.debug("active pattern # :  " + i);
  -			ActivePattern activePattern = new ActivePattern();
  -			String assertPrefix = pathPrefix + "/active[" + i + "]";
  -
  -			String pt =
  -				(String) jxpContext.getValue(
  -					assertPrefix + "/@pattern",
  -					String.class);
  -			activePattern.setPattern(pt);
  -			logger.debug(
  -				"Phase active pattern :  " + activePattern.getPattern());
  -
  -			phase.addActive(activePattern);
  -		}
  -	}
  -
  -	/**
  -	 * Replace all occurances of sch: with the actual Schema prefix used in the document
  -	 *
  -	 * TODO: fix this implementaion. There are problems with DOM.
  -	 * Returns null instead of the actual namespace prefix (e.g. "sch") as expected.
  -	 */
  -	protected String fixns(String path) {
  -		// Ironicly, at the time I am writing this
  -		// JDK 1.4 is offering String.replaceAll(regex, str)
  -		// I don't use it however for backward compatibility
  -		StringBuffer strbuf = new StringBuffer(path);
  -		int i = 0;
  -		int j = 0;
  -		String dprefix = defaultSchemaPrefix_ + ":";
  -		int dplen = dprefix.length();
  -		while ((j = path.indexOf(dprefix, i)) >= 0) {
  -			strbuf.append(path.substring(i, j));
  -			strbuf.append(schemaPrefix_);
  -			strbuf.append(':');
  -			i = j + dplen;
  -		}
  -		strbuf.append(path.substring(i));
  -		return strbuf.toString();
  -	}
  -
  +    /**
  +     * The schema name space prefix used in the schema document.
  +     */
  +    private String schemaPrefix_;
  +
  +    /**
  +     * The default schema name space prefix.
  +     */
  +    private String defaultSchemaPrefix_ = "sch";
  +
  +    /**
  +     * Private logger.
  +     */
  +    private Logger logger = setupLogger();
  +
  +    // 
  +    // Constructors
  +    // 
  +
  +    /**
  +     * Initialize logger.
  +     */
  +    protected Logger setupLogger() {
  +        Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm");
  +
  +        logger.setPriority(Priority.ERROR);
  +        return logger;
  +    }
  +
  +    /**
  +     * Builds a new Schema instance from
  +     * the given XML InputSource.
  +     *
  +     * @param schemaSrc
  +     *        the Schema document XML InputSource
  +     */
  +    public Schema compileSchema(InputSource schemaSrc)
  +      throws InstantiationException {
  +        SchematronSchema schema = null;
  +
  +        try {
  +            // load Schema file into a DOM document
  +            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  +            DocumentBuilder dbld = dbf.newDocumentBuilder();
  +            Document document = dbld.parse(schemaSrc);
  +
  +            schema = buildSchema(document);
  +        } catch (Exception e) {
  +            logger.error("!!! Failed loading Schematron schema", e);
  +            throw new CascadingRuntimeException(" !!! Failed loading Schematron schema",
  +                                                e);
  +        }
  +        return schema;
  +    } // build
  +
  +    /**
  +     * Build Schematron schema object from a DOM document.
  +     *
  +     * @param doc DOM document containing the schema
  +     */
  +    protected SchematronSchema buildSchema(Document doc) {
  +        SchematronSchema schema = new SchematronSchema();
  +
  +        doc.getNamespaceURI();
  +        doc.getPrefix();
  +
  +        // Initialize the JXPath context
  +        Element root = doc.createElement("root");
  +        Element schemaElement = doc.getDocumentElement();
  +
  +        schemaPrefix_ = schemaElement.getPrefix();
  +        root.appendChild(schemaElement);
  +        JXPathContext jxpContext = JXPathContext.newContext(root);
  +
  +        jxpContext.setLenient(false);
  +
  +        // Bind sch:schema element
  +
  +        // schema title
  +        String title = (String) jxpContext.getValue("/schema/title",
  +                                                    String.class);
  +
  +        schema.setTitle(title);
  +        logger.debug("Schema title: "+schema.getTitle());
  +
  +        bindPatterns(schema, jxpContext);
  +        bindPhases(schema, jxpContext);
  +
  +        return schema;
  +    }
  +
  +    /**
  +     * Populates the patterns elements from the dom tree.
  +     *
  +     * @param schema the schema instance
  +     * @param jxpContext
  +     */
  +    protected void bindPatterns(SchematronSchema schema,
  +                                JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // schema patterns
  +        int ptCount = ((Integer) jxpContext.getValue("count(/schema/pattern)",
  +                          Integer.class)).intValue();
  +
  +        logger.debug("\nNumber of patterns:  "+ptCount);
  +        for (int i = 1; i<=ptCount; i++) {
  +            logger.debug("Pattern# :  "+i);
  +            Pattern pattern = new Pattern();
  +            String ptprefix = "/schema/pattern["+i+"]";
  +
  +            String name = (String) jxpContext.getValue(ptprefix+"/@name",
  +                                                       String.class);
  +
  +            pattern.setName(name);
  +            logger.debug("Pattern name :  "+pattern.getName());
  +
  +            String id = (String) jxpContext.getValue(ptprefix+"/@id",
  +                                                     String.class);
  +
  +            pattern.setId(id);
  +            logger.debug("Pattern id :  "+pattern.getId());
  +
  +            bindRules(pattern, ptprefix, jxpContext);
  +
  +            schema.addPattern(pattern);
  +        }
  +    }
  +
  +    /**
  +     * Populates the rules elements for a pattern
  +     * from the dom tree.
  +     *
  +     * @param pattern
  +     * @param pathPrefix pattern path prefix
  +     * @param jxpContext JXPathContext
  +     */
  +    protected void bindRules(Pattern pattern, String pathPrefix,
  +                             JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // schema rules
  +        int ruleCount = ((Integer) jxpContext.getValue("count("+pathPrefix+
  +                            "/rule)", Integer.class)).intValue();
  +
  +        logger.debug("\nNumber of rules:  "+ruleCount);
  +        for (int i = 1; i<=ruleCount; i++) {
  +            logger.debug("Rule# :  "+i);
  +            Rule rule = new Rule();
  +            String rulePrefix = pathPrefix+"/rule["+i+"]";
  +
  +            String context = (String) jxpContext.getValue(rulePrefix+
  +                                 "/@context", String.class);
  +
  +            rule.setContext(context);
  +            logger.debug("Rule context :  "+rule.getContext());
  +
  +            bindAsserts(rule, rulePrefix, jxpContext);
  +
  +            // Patch to make reports work in schematron
  +            // Note change to name of bindRerports [sic] function
  +            bindReports(rule, rulePrefix, jxpContext);
  +
  +            pattern.addRule(rule);
  +        }
  +    }
  +
  +    /**
  +     * Populates the assert elements for a rule
  +     * from the dom tree.
  +     *
  +     * @param rule
  +     * @param pathPrefix rule path prefix
  +     * @param jxpContext JXPathContext
  +     */
  +    protected void bindAsserts(Rule rule, String pathPrefix,
  +                               JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // schema reports
  +        int elementCount = ((Integer) jxpContext.getValue("count("+pathPrefix+
  +                               "/assert)", Integer.class)).intValue();
  +
  +        logger.debug("\nNumber of asserts:  "+elementCount);
  +        for (int i = 1; i<=elementCount; i++) {
  +            logger.debug("Assert# :  "+i);
  +            Assert assertion = new Assert();
  +            String assertPrefix = pathPrefix+"/assert["+i+"]";
  +
  +            String test = (String) jxpContext.getValue(assertPrefix+"/@test",
  +                                                       String.class);
  +
  +            assertion.setTest(test);
  +            logger.debug("Assert test :  "+assertion.getTest());
  +
  +            // since diagnostics is a non-mandatory element
  +            // we will try to get its value in a lenient mode
  +            jxpContext.setLenient(true);
  +            String diagnostics = (String) jxpContext.getValue(assertPrefix+
  +                                     "/@diagnostics", String.class);
  +
  +            assertion.setDiagnostics(diagnostics);
  +            logger.debug("Assert diagnostics :  "+assertion.getDiagnostics());
  +            jxpContext.setLenient(false);
  +
  +            // now read the report message
  +            // TODO: The current implementation does not
  +            // read xml tags used within the assert message.
  +            // Solution is to use JXPath NodePointer to get
  +            // to the DOM node and then convert it to a String.
  +            // e.g.
  +            // NodePointer nptr = (NodePointer) jxpContext.locateValue( assertPrefix );
  +            // Node msgNode = (Node) nptr.getNodeValue();
  +            // convery DOMNode to String
  +
  +            String message = (String) jxpContext.getValue(assertPrefix,
  +                                 String.class);
  +
  +            assertion.setMessage(message);
  +            logger.debug("Assert message :  "+assertion.getMessage());
  +
  +            rule.addAssert(assertion);
  +        }
  +    }
  +
  +    /**
  +     * Populates the report elements for a rule
  +     * from the dom tree.
  +     *
  +     * @param rule
  +     * @param pathPrefix rule path prefix
  +     * @param jxpContext JXPathContext
  +     */
  +    protected void bindReports(Rule rule, String pathPrefix,
  +                               JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // schema reports
  +        int elementCount = ((Integer) jxpContext.getValue("count("+pathPrefix+
  +                               "/report)", Integer.class)).intValue();
  +
  +        logger.debug("\nNumber of reports:  "+elementCount);
  +        for (int i = 1; i<=elementCount; i++) {
  +            logger.debug("Report# :  "+i);
  +            Report report = new Report();
  +            String assertPrefix = pathPrefix+"/report["+i+"]";
  +
  +            String test = (String) jxpContext.getValue(assertPrefix+"/@test",
  +                                                       String.class);
  +
  +            report.setTest(test);
  +            logger.debug("Report test :  "+report.getTest());
  +
  +            // since diagnostics is a non-mandatory element
  +            // we will try to get its value in a lenient mode
  +            jxpContext.setLenient(true);
  +            String diagnostics = (String) jxpContext.getValue(assertPrefix+
  +                                     "/@diagnostics", String.class);
  +
  +            report.setDiagnostics(diagnostics);
  +            logger.debug("Report diagnostics :  "+report.getDiagnostics());
  +            jxpContext.setLenient(false);
  +
  +            String message = (String) jxpContext.getValue(assertPrefix,
  +                                 String.class);
  +
  +            report.setMessage(message);
  +            logger.debug("Report message :  "+report.getMessage());
  +
  +            rule.addReport(report);
  +        }
  +    }
  +
  +    /**
  +     * Populates the phases elements from the dom tree.
  +     *
  +     * @param schema the schema instance
  +     * @param jxpContext
  +     */
  +    protected void bindPhases(SchematronSchema schema,
  +                              JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // schema phases
  +        int phaseCount = ((Integer) jxpContext.getValue("count(/schema/phase)",
  +                             Integer.class)).intValue();
  +
  +        logger.debug("\nNumber of phases:  "+phaseCount);
  +
  +        for (int i = 1; i<=phaseCount; i++) {
  +            logger.debug("phase# :  "+i);
  +            Phase phase = new Phase();
  +            String phprefix = "/schema/phase["+i+"]";
  +
  +            String id = (String) jxpContext.getValue(phprefix+"/@id",
  +                                                     String.class);
  +
  +            phase.setId(id);
  +            logger.debug("phase id :  "+phase.getId());
  +
  +            bindPhaseActivePatterns(phase, phprefix, jxpContext);
  +
  +            schema.addPhase(phase);
  +        }
  +    }
  +
  +    protected void bindPhaseActivePatterns(Phase phase, String pathPrefix,
  +                                           JXPathContext jxpContext) {
  +        // ensure that mandatory elements which are not found
  +        // will result in Exception
  +        jxpContext.setLenient(false);
  +
  +        // phase active patterns
  +        int elementCount = ((Integer) jxpContext.getValue("count("+pathPrefix+
  +                               "/active)", Integer.class)).intValue();
  +
  +        logger.debug("Number of active patterns:  "+elementCount);
  +        for (int i = 1; i<=elementCount; i++) {
  +            logger.debug("active pattern # :  "+i);
  +            ActivePattern activePattern = new ActivePattern();
  +            String assertPrefix = pathPrefix+"/active["+i+"]";
  +
  +            String pt = (String) jxpContext.getValue(assertPrefix+
  +                                                     "/@pattern", String.class);
  +
  +            activePattern.setPattern(pt);
  +            logger.debug("Phase active pattern :  "+
  +                         activePattern.getPattern());
  +
  +            phase.addActive(activePattern);
  +        }
  +    }
  +
  +    /**
  +     * Replace all occurances of sch: with the actual Schema prefix used in the document.
  +     *
  +     * TODO: fix this implementaion. There are problems with DOM.
  +     * Returns null instead of the actual namespace prefix (e.g. "sch") as expected.
  +     *
  +     * @param path       
  +     *
  +     * @return
  +     */
  +    protected String fixns(String path) {
  +        // Ironicly, at the time I am writing this
  +        // JDK 1.4 is offering String.replaceAll(regex, str)
  +        // I don't use it however for backward compatibility
  +        StringBuffer strbuf = new StringBuffer(path);
  +        int i = 0;
  +        int j = 0;
  +        String dprefix = defaultSchemaPrefix_+":";
  +        int dplen = dprefix.length();
  +
  +        while ((j = path.indexOf(dprefix, i))>=0) {
  +            strbuf.append(path.substring(i, j));
  +            strbuf.append(schemaPrefix_);
  +            strbuf.append(':');
  +            i = j+dplen;
  +        }
  +        strbuf.append(path.substring(i));
  +        return strbuf.toString();
  +    }
   }
  
  
  
  1.2       +70 -71    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronSchema.java
  
  Index: SchematronSchema.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronSchema.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SchematronSchema.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ SchematronSchema.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -58,82 +58,81 @@
   import java.util.List;
   
   /**
  - * Represents a Schematron Schema 
  + * Represents a Schematron Schema.
    *
    * Specification:
    * http://www.ascc.net/xml/resource/schematron/Schematron2000.html
  - * 
  + *
    * @author  Ivelin Ivanov, ivelin@acm.org, ivelin@iname.com
    * @version CVS $Id$
    */
   public class SchematronSchema implements Schema {
   
  -	private String title_;
  -	private ArrayList patterns_ = new ArrayList();
  -	private ArrayList phases_ = new ArrayList();
  -
  -	/**
  -	* Returns the message for to the element 
  -	*/
  -	public String getTitle() {
  -		return title_;
  -	}
  -
  -	/**
  -	 * Sets the message for to the element 
  -	 */
  -	public void setTitle(String newTitle) {
  -		title_ = newTitle;
  -	}
  -
  -	/**
  -	 * Returns a list of the patterns which
  -	 * contain messages that failed during validation
  -	 */
  -	public List getPattern() {
  -		return patterns_;
  -	}
  -
  -	/**
  -	 * Sets the list of the patterns which
  -	 * contain messages that failed during validation
  -	 */
  -	public void setPattern(Collection newPatterns) {
  -		patterns_ = new ArrayList();
  -		patterns_.addAll(newPatterns);
  -	}
  -
  -	/**
  -	 * Add a pattern to the list
  -	 */
  -	public void addPattern(Pattern p) {
  -		patterns_.add(p);
  -	}
  -
  -	/**
  -	 * Returns the list of schema phases 
  -	 */
  -	public List getPhase() {
  -		return phases_;
  -	}
  -
  -	/**
  -	 * Sets the list of schema phases 
  -	 */
  -	public void setPhase(Collection newPhases) {
  -		phases_ = new ArrayList();
  -		phases_.addAll(newPhases);
  -	}
  -
  -	/**
  -	 * Add a pattern to the list
  -	 */
  -	public void addPhase(Phase p) {
  -		phases_.add(p);
  -	}
  -
  -	public Validator newValidator() throws InstantiationException {
  -		return new SchematronValidator(this);
  -	}
  -
  +    private String title_;
  +    private ArrayList patterns_ = new ArrayList();
  +    private ArrayList phases_ = new ArrayList();
  +
  +    /**
  +     * Returns the message for to the element.
  +     */
  +    public String getTitle() {
  +        return title_;
  +    }
  +
  +    /**
  +     * Sets the message for to the element.
  +     */
  +    public void setTitle(String newTitle) {
  +        title_ = newTitle;
  +    }
  +
  +    /**
  +     * Returns a list of the patterns which
  +     * contain messages that failed during validation.
  +     */
  +    public List getPattern() {
  +        return patterns_;
  +    }
  +
  +    /**
  +     * Sets the list of the patterns which
  +     * contain messages that failed during validation.
  +     */
  +    public void setPattern(Collection newPatterns) {
  +        patterns_ = new ArrayList();
  +        patterns_.addAll(newPatterns);
  +    }
  +
  +    /**
  +     * Add a pattern to the list.
  +     */
  +    public void addPattern(Pattern p) {
  +        patterns_.add(p);
  +    }
  +
  +    /**
  +     * Returns the list of schema phases.
  +     */
  +    public List getPhase() {
  +        return phases_;
  +    }
  +
  +    /**
  +     * Sets the list of schema phases.
  +     */
  +    public void setPhase(Collection newPhases) {
  +        phases_ = new ArrayList();
  +        phases_.addAll(newPhases);
  +    }
  +
  +    /**
  +     * Add a pattern to the list.
  +     */
  +    public void addPhase(Phase p) {
  +        phases_.add(p);
  +    }
  +
  +    public Validator newValidator() throws InstantiationException {
  +        return new SchematronValidator(this);
  +    }
   }
  
  
  
  1.2       +298 -279  cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronValidator.java
  
  Index: SchematronValidator.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/SchematronValidator.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SchematronValidator.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ SchematronValidator.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -76,282 +76,301 @@
    */
   public class SchematronValidator implements Validator {
   
  -	/** The schema instance for this Validator
  -	 * It is initialized once when a new Validator instance
  -	 * is created and used multiple times for validating
  -	 * different JavaBeans/DOM objects against the schema
  -	 */
  -	private SchematronSchema schema_;
  -
  -	/**
  -	 * lookup map, with phase id keys.
  -	 * Used for efficiency when validating by phase
  -	 */
  -	private Map phaseMap_ = new HashMap();
  -
  -	/*
  -	 * Schematron Phase property
  -	 */
  -	private String phaseProperty_ = null;
  -
  -	/*
  -	 * private logger
  -	 */
  -	private Logger logger = setupLogger();
  -
  -	//
  -	// Constructors
  -	//
  -
  -	/**
  -	 * Constructs a new Validator object for a given Schematron schema.
  -	 *
  -	 * @param schema 
  -	 *        The Schematron schema
  -	 */
  -	public SchematronValidator(SchematronSchema schema) {
  -		schema_ = schema;
  -		preparePhaseMap();
  -	}
  -
  -	//
  -	// helper methods for the constructors
  -	//
  -
  -	/**
  -	 * initialize logger
  -	 */
  -	protected Logger setupLogger() {
  -		Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm");
  -		logger.setPriority(Priority.ERROR);
  -		return logger;
  -	}
  -
  -	protected void preparePhaseMap() {
  -		Map patternMap = new HashMap();
  -
  -		Iterator ptiter = schema_.getPattern().iterator();
  -		while (ptiter.hasNext()) {
  -			Pattern pattern = (Pattern) ptiter.next();
  -			patternMap.put(pattern.getId(), pattern);
  -		}
  -
  -		Iterator phiter = schema_.getPhase().iterator();
  -		while (phiter.hasNext()) {
  -			Phase phase = (Phase) phiter.next();
  -			List activePatterns = new ArrayList();
  -			phaseMap_.put(phase.getId(), activePatterns);
  -
  -			Iterator activeIter = phase.getActive().iterator();
  -			while (activeIter.hasNext()) {
  -				ActivePattern active = (ActivePattern) activeIter.next();
  -				activePatterns.add(patternMap.get(active.getPattern()));
  -			}
  -		}
  -
  -	}
  -
  -	//
  -	// public methods
  -	//
  -
  -	/**
  -	 * Performs validation of the passed JavaBean or DOM object.
  -	 *
  -	 * This method tries to find the "phase" attribute
  -	 * and runs the active patterns for the phase.
  -	 * If phase not found, the method will try to match all patterns
  -	 *
  -	 *
  -	 * @param jbean The JavaBean or DOM object to be validated.
  -	 * @param props Properties which control different aspects of the 
  -	 * validation process. This method only looks for the phase property.
  -	 * Another implementation may use other.
  -	 *
  -	 * @return A Result object which represents the result
  -	 *         of the validation.
  -	 */
  -	public List validate(Object jbean) {
  -		List patterns = null;
  -		if (phaseProperty_ != null) {
  -			patterns = getPatternsForPhase(phaseProperty_);
  -			logger.debug(" Validating for phase: " + phaseProperty_);
  -		} else {
  -			patterns = schema_.getPattern();
  -			logger.debug(" Validating all patterns. No phase provided ");
  -		}
  -
  -		ValidationResult vres = new ValidationResult();
  -
  -		if (patterns != null) {
  -			// create the JXPathContext
  -			// which will be used to validate each rule
  -			JXPathContext jxpContext = JXPathContext.newContext(jbean);
  -
  -			Iterator iter = patterns.iterator();
  -			while (iter.hasNext()) {
  -				Pattern resultPattern =
  -					evalPattern(jxpContext, (Pattern) iter.next());
  -				// if the resultPattern is null,
  -				// then it passed successfully
  -				if (resultPattern != null)
  -					vres.addPattern(resultPattern);
  -			}
  -		}
  -
  -		return vres.toList();
  -	}
  -
  -	/**
  -	 * return the list of patterns listed
  -	 * as <active/> elements of <phase/>
  -	 *
  -	 * @param phase name of the phase
  -	 * @return List of patterns
  -	 */
  -	protected List getPatternsForPhase(String phase) {
  -		return (List) phaseMap_.get(phase);
  -	}
  -
  -	/** 
  -	* Returns pattern with rules which failed during validation.
  -	* The context attribute of each rule in the result pattern
  -	* contains the exact location of the failed element
  -	* unlike the context attribute of the original pattern which
  -	* is an XSLT production pattern
  -	*
  -	* @param jxpContext The JXPathContext being validated
  -	* @param pattern The production schema pattern to be evaluated
  -	* @return pattern with rules wich failed during validation.
  -	*/
  -	protected Pattern evalPattern(JXPathContext jxpContext, Pattern pattern) {
  -		// copy attributes
  -		Pattern resultPattern = new Pattern();
  -		resultPattern.setName(pattern.getName());
  -		resultPattern.setId(pattern.getId());
  -
  -		// evaluate rules
  -		Iterator iter = pattern.getRule().iterator();
  -		while (iter.hasNext()) {
  -			List failedRules = evalRule(jxpContext, (Rule) iter.next());
  -			// if there were failed rules
  -			// add them to the list of other failed rules
  -			if (failedRules.size() > 0) {
  -				failedRules.addAll(resultPattern.getRule());
  -				resultPattern.setRule(failedRules);
  -			}
  -		}
  -
  -		// if there are no failed rules return null
  -		if (resultPattern.getRule().size() == 0)
  -			return null;
  -		else
  -			return resultPattern;
  -	}
  -
  -	/** 
  -	* Returns rules with asserts or reports which failed during validation.
  -	* The context attribute of each rule in the result pattern
  -	* contains the exact location of the failed element
  -	* unlike the context attribute of the original pattern which
  -	* is an XSLT production pattern
  -	*
  -	* @param jxpContext The JXPath context being validated
  -	* @param rule The original pattern rule to be evaluated
  -	* @return pattern with rules wich failed during validation.
  -	*/
  -	protected List evalRule(JXPathContext jxpContext, Rule rule) {
  -		List failedRules = new ArrayList();
  -
  -		Iterator pointerIter = jxpContext.iteratePointers(rule.getContext());
  -		while (pointerIter.hasNext()) {
  -
  -			Pointer ptr = (Pointer) pointerIter.next();
  -
  -			// prepare result Rule
  -			Rule nextFailedRule = new Rule();
  -			nextFailedRule.setContext(ptr.asPath());
  -
  -			// switch to the context of the rule
  -			JXPathContext localJxpContext =
  -				JXPathContext.newContext(jxpContext, ptr.getValue());
  -
  -			// evaluate asserts
  -			Iterator assertIter = rule.getAssert().iterator();
  -			while (assertIter.hasNext()) {
  -				Assert assertion = (Assert) assertIter.next();
  -				// if an assert test fails, then it should be added
  -				// to the result
  -				boolean passed = evalTest(localJxpContext, assertion.getTest());
  -				if (!passed) {
  -					nextFailedRule.addAssert(assertion);
  -				}
  -			}
  -
  -			// evaluate reports
  -			Iterator reportIter = rule.getReport().iterator();
  -			while (reportIter.hasNext()) {
  -				Report report = (Report) reportIter.next();
  -				// if a report test passes, then it should be added
  -				// to the result
  -				boolean passed = evalTest(localJxpContext, report.getTest());
  -				if (passed) {
  -					nextFailedRule.addReport(report);
  -				}
  -			}
  -
  -			// if the nextFailedRule is non empty,
  -			// then add it to the list of failed rules
  -			if (nextFailedRule.getAssert().size() > 0
  -				|| nextFailedRule.getReport().size() > 0) {
  -				failedRules.add(nextFailedRule);
  -			}
  -		}
  -
  -		return failedRules;
  -	}
  -
  -	/** 
  -	* Test an XPath expression in a context
  -	 *
  -	* @param jxpContext The JXPath context being validated
  -	* @param String The XPath expression
  -	* @return boolean result of evaluation
  -	*/
  -	protected boolean evalTest(JXPathContext jxpContext, String test) {
  -		Boolean passed = (Boolean) jxpContext.getValue(test, Boolean.class);
  -		return passed.booleanValue();
  -	}
  -
  -	/**
  -	 * @param property name
  -	 * @return the property value
  -	 * @throws IllegalArgumentException when the property is not supported
  -	 */
  -	public Object getProperty(String property)
  -		throws IllegalArgumentException {
  -		if (property.equals(Validator.PROPERTY_PHASE))
  -			return phaseProperty_;
  -		else
  -			throw new IllegalArgumentException(
  -				" Property " + property + " is not supported");
  -	}
  -
  -	/**
  -	 * @param property name
  -	 * @param value property value
  -	 * @throws IllegalArgumentException when the property is not supported
  -	 */
  -	public void setProperty(String property, Object value)
  -		throws IllegalArgumentException {
  -		if (property.equals(Validator.PROPERTY_PHASE)
  -			&& (value == null || (value instanceof String))) {
  -			phaseProperty_ = (String) value;
  -		} else
  -			throw new IllegalArgumentException(
  -				" Property "
  -					+ property
  -					+ " is not supported or value is invalid");
  -	}
  -
  +    /** 
  +     * The schema instance for this Validator.
  +     * It is initialized once when a new Validator instance
  +     * is created and used multiple times for validating
  +     * different JavaBeans/DOM objects against the schema
  +     */
  +    private SchematronSchema schema_;
  +
  +    /**
  +     * Lookup map, with phase id keys.
  +     * Used for efficiency when validating by phase
  +     */
  +    private Map phaseMap_ = new HashMap();
  +
  +    /**
  +     * Schematron Phase property.
  +     */
  +    private String phaseProperty_ = null;
  +
  +    /**
  +     * Private logger.
  +     */
  +    private Logger logger = setupLogger();
  +
  +    // 
  +    // Constructors
  +    // 
  +
  +    /**
  +     * Constructs a new Validator object for a given Schematron schema.
  +     *
  +     * @param schema
  +     *        The Schematron schema
  +     */
  +    public SchematronValidator(SchematronSchema schema) {
  +        schema_ = schema;
  +        preparePhaseMap();
  +    }
  +
  +    // 
  +    // helper methods for the constructors
  +    // 
  +
  +    /**
  +     * Initialize logger.
  +     */
  +    protected Logger setupLogger() {
  +        Logger logger = Hierarchy.getDefaultHierarchy().getLoggerFor("XmlForm");
  +
  +        logger.setPriority(Priority.ERROR);
  +        return logger;
  +    }
  +
  +    protected void preparePhaseMap() {
  +        Map patternMap = new HashMap();
  +
  +        Iterator ptiter = schema_.getPattern().iterator();
  +
  +        while (ptiter.hasNext()) {
  +            Pattern pattern = (Pattern) ptiter.next();
  +
  +            patternMap.put(pattern.getId(), pattern);
  +        }
  +
  +        Iterator phiter = schema_.getPhase().iterator();
  +
  +        while (phiter.hasNext()) {
  +            Phase phase = (Phase) phiter.next();
  +            List activePatterns = new ArrayList();
  +
  +            phaseMap_.put(phase.getId(), activePatterns);
  +
  +            Iterator activeIter = phase.getActive().iterator();
  +
  +            while (activeIter.hasNext()) {
  +                ActivePattern active = (ActivePattern) activeIter.next();
  +
  +                activePatterns.add(patternMap.get(active.getPattern()));
  +            }
  +        }
  +
  +    }
  +
  +    // 
  +    // public methods
  +    // 
  +
  +    /**
  +     * Performs validation of the passed JavaBean or DOM object.
  +     *
  +     * This method tries to find the "phase" attribute
  +     * and runs the active patterns for the phase.
  +     * If phase not found, the method will try to match all patterns
  +     *
  +     *
  +     * @param jbean The JavaBean or DOM object to be validated.
  +     *
  +     * @return A Result object which represents the result
  +     *         of the validation.
  +     */
  +    public List validate(Object jbean) {
  +        List patterns = null;
  +
  +        if (phaseProperty_!=null) {
  +            patterns = getPatternsForPhase(phaseProperty_);
  +            logger.debug(" Validating for phase: "+phaseProperty_);
  +        } else {
  +            patterns = schema_.getPattern();
  +            logger.debug(" Validating all patterns. No phase provided ");
  +        }
  +
  +        ValidationResult vres = new ValidationResult();
  +
  +        if (patterns!=null) {
  +            // create the JXPathContext
  +            // which will be used to validate each rule
  +            JXPathContext jxpContext = JXPathContext.newContext(jbean);
  +
  +            Iterator iter = patterns.iterator();
  +
  +            while (iter.hasNext()) {
  +                Pattern resultPattern = evalPattern(jxpContext,
  +                                                    (Pattern) iter.next());
  +
  +                // if the resultPattern is null,
  +                // then it passed successfully
  +                if (resultPattern!=null) {
  +                    vres.addPattern(resultPattern);
  +                }
  +            }
  +        }
  +
  +        return vres.toList();
  +    }
  +
  +    /**
  +     * Return the list of patterns listed
  +     * as <active/> elements of <phase/>.
  +     *
  +     * @param phase name of the phase
  +     * @return List of patterns
  +     */
  +    protected List getPatternsForPhase(String phase) {
  +        return (List) phaseMap_.get(phase);
  +    }
  +
  +    /**
  +     * Returns pattern with rules which failed during validation.
  +     * The context attribute of each rule in the result pattern
  +     * contains the exact location of the failed element
  +     * unlike the context attribute of the original pattern which
  +     * is an XSLT production pattern.
  +     *
  +     * @param jxpContext The JXPathContext being validated.
  +     * @param pattern The production schema pattern to be evaluated.
  +     * @return Pattern with rules wich failed during validation.
  +     */
  +    protected Pattern evalPattern(JXPathContext jxpContext, Pattern pattern) {
  +        // copy attributes
  +        Pattern resultPattern = new Pattern();
  +
  +        resultPattern.setName(pattern.getName());
  +        resultPattern.setId(pattern.getId());
  +
  +        // evaluate rules
  +        Iterator iter = pattern.getRule().iterator();
  +
  +        while (iter.hasNext()) {
  +            List failedRules = evalRule(jxpContext, (Rule) iter.next());
  +
  +            // if there were failed rules
  +            // add them to the list of other failed rules
  +            if (failedRules.size()>0) {
  +                failedRules.addAll(resultPattern.getRule());
  +                resultPattern.setRule(failedRules);
  +            }
  +        }
  +
  +        // if there are no failed rules return null
  +        if (resultPattern.getRule().size()==0) {
  +            return null;
  +        } else {
  +            return resultPattern;
  +        }
  +    }
  +
  +    /**
  +     * Returns rules with asserts or reports which failed during validation.
  +     * The context attribute of each rule in the result pattern
  +     * contains the exact location of the failed element
  +     * unlike the context attribute of the original pattern which
  +     * is an XSLT production pattern.
  +     *
  +     * @param jxpContext The JXPath context being validated.
  +     * @param rule The original pattern rule to be evaluated.
  +     * @return Pattern with rules wich failed during validation.
  +     */
  +    protected List evalRule(JXPathContext jxpContext, Rule rule) {
  +        List failedRules = new ArrayList();
  +
  +        Iterator pointerIter = jxpContext.iteratePointers(rule.getContext());
  +
  +        while (pointerIter.hasNext()) {
  +            Pointer ptr = (Pointer) pointerIter.next();
  +
  +            // prepare result Rule
  +            Rule nextFailedRule = new Rule();
  +
  +            nextFailedRule.setContext(ptr.asPath());
  +
  +            // switch to the context of the rule
  +            JXPathContext localJxpContext = JXPathContext.newContext(jxpContext,
  +                                                ptr.getValue());
  +
  +            // evaluate asserts
  +            Iterator assertIter = rule.getAssert().iterator();
  +
  +            while (assertIter.hasNext()) {
  +                Assert assertion = (Assert) assertIter.next();
  +                // if an assert test fails, then it should be added
  +                // to the result
  +                boolean passed = evalTest(localJxpContext,
  +                                          assertion.getTest());
  +
  +                if ( !passed) {
  +                    nextFailedRule.addAssert(assertion);
  +                }
  +            }
  +
  +            // evaluate reports
  +            Iterator reportIter = rule.getReport().iterator();
  +
  +            while (reportIter.hasNext()) {
  +                Report report = (Report) reportIter.next();
  +                // if a report test passes, then it should be added
  +                // to the result
  +                boolean passed = evalTest(localJxpContext, report.getTest());
  +
  +                if (passed) {
  +                    nextFailedRule.addReport(report);
  +                }
  +            }
  +
  +            // if the nextFailedRule is non empty,
  +            // then add it to the list of failed rules
  +            if ((nextFailedRule.getAssert().size()>0) ||
  +                (nextFailedRule.getReport().size()>0)) {
  +                failedRules.add(nextFailedRule);
  +            }
  +        }
  +
  +        return failedRules;
  +    }
  +
  +    /**
  +     * Test an XPath expression in a context.
  +     *
  +     * @param jxpContext The JXPath context being validated
  +     * @param test       
  +     * @return boolean result of evaluation
  +     */
  +    protected boolean evalTest(JXPathContext jxpContext, String test) {
  +        Boolean passed = (Boolean) jxpContext.getValue(test, Boolean.class);
  +
  +        return passed.booleanValue();
  +    }
  +
  +    /**
  +     * @param property Name.
  +     * @return The property value.
  +     * @throws IllegalArgumentException When the property is not supported.
  +     */
  +    public Object getProperty(String property)
  +      throws IllegalArgumentException {
  +        if (property.equals(Validator.PROPERTY_PHASE)) {
  +            return phaseProperty_;
  +        } else {
  +            throw new IllegalArgumentException(" Property "+property+
  +                                               " is not supported");
  +        }
  +    }
  +
  +    /**
  +     * @param property Name.
  +     * @param value Property value.
  +     * @throws IllegalArgumentException When the property is not supported
  +     */
  +    public void setProperty(String property,
  +                            Object value) throws IllegalArgumentException {
  +        if (property.equals(Validator.PROPERTY_PHASE) &&
  +            ((value==null) || (value instanceof String))) {
  +            phaseProperty_ = (String) value;
  +        } else {
  +            throw new IllegalArgumentException(" Property "+property+
  +                                               " is not supported or value is invalid");
  +        }
  +    }
   }
  
  
  
  1.2       +87 -81    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/ValidationResult.java
  
  Index: ValidationResult.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/validation/schematron/ValidationResult.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ValidationResult.java	25 Apr 2003 08:51:11 -0000	1.1
  +++ ValidationResult.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -59,8 +59,8 @@
   import java.util.List;
   
   /**
  - * Represents the result of a Schematron validation process
  - * 
  + * Represents the result of a Schematron validation process.
  + *
    * <validationResult>
    *   list of <pattern> elements with <rule> subelements
    * </validationResult>
  @@ -70,83 +70,89 @@
    */
   public class ValidationResult {
   
  -	private ArrayList patterns_ = new ArrayList();
  -
  -	/**
  -	 * Returns a list of the patterns which
  -	 * contain rules that failed during validation
  -	 */
  -	public List getPattern() {
  -		return patterns_;
  -	}
  -
  -	/**
  -	 * Sets the list of the patterns which
  -	 * contain rules that failed during validation
  -	 */
  -	public void setPattern(Collection newPatterns) {
  -		patterns_ = new ArrayList();
  -		patterns_.addAll(newPatterns);
  -	}
  -
  -	/**
  -	 * Add a pattern to the list
  -	 */
  -	public void addPattern(Pattern p) {
  -		patterns_.add(p);
  -	}
  -
  -	public boolean isEmpty() {
  -		return patterns_.isEmpty();
  -	}
  -
  -	/**
  -	 * adds all errors to a sorted list
  -	 * Key is XPath of each error location
  -	 * @return SortedSet
  -	 */
  -	public List toList() {
  -
  -		if (isEmpty())
  -			return null;
  -
  -		List violations = new LinkedList();
  -
  -		Iterator piter = getPattern().iterator();
  -		while (piter.hasNext()) {
  -			Pattern pattern = (Pattern) piter.next();
  -			// System.out.println("Pattern name: " + pattern.getName() + ", id: " + pattern.getId() );
  -			Iterator ruleIter = pattern.getRule().iterator();
  -			while (ruleIter.hasNext()) {
  -				Rule rule = (Rule) ruleIter.next();
  -				// System.out.println("    Rule name: " + rule.getContext() );
  -
  -				Iterator assertIter = rule.getAssert().iterator();
  -				while (assertIter.hasNext()) {
  -					Assert assertion = (Assert) assertIter.next();
  -
  -					// add the next assert to the violations set
  -					Violation v = new Violation();
  -					v.setPath(rule.getContext());
  -					v.setMessage(assertion.getMessage());
  -					violations.add(v);
  -					// System.out.println("        Assert test: " + assertion.getTest() + ", message: " + assertion.getMessage() );
  -				}
  -
  -				Iterator reportIter = rule.getReport().iterator();
  -				while (reportIter.hasNext()) {
  -					Report report = (Report) reportIter.next();
  -
  -					// add the next report to the violations set
  -					Violation v = new Violation();
  -					v.setPath(rule.getContext());
  -					v.setMessage(report.getMessage());
  -					violations.add(v);
  -					// System.out.println("        Report test: " + report.getTest() + ", message: " + report.getMessage() );
  -				}
  -			}
  -		}
  -		return violations;
  -	}
  +    private ArrayList patterns_ = new ArrayList();
   
  +    /**
  +     * Returns a list of the patterns which
  +     * contain rules that failed during validation.
  +     */
  +    public List getPattern() {
  +        return patterns_;
  +    }
  +
  +    /**
  +     * Sets the list of the patterns which
  +     * contain rules that failed during validation.
  +     */
  +    public void setPattern(Collection newPatterns) {
  +        patterns_ = new ArrayList();
  +        patterns_.addAll(newPatterns);
  +    }
  +
  +    /**
  +     * Add a pattern to the list.
  +     */
  +    public void addPattern(Pattern p) {
  +        patterns_.add(p);
  +    }
  +
  +    public boolean isEmpty() {
  +        return patterns_.isEmpty();
  +    }
  +
  +    /**
  +     * Adds all errors to a sorted list.
  +     * Key is XPath of each error location
  +     * @return SortedSet
  +     */
  +    public List toList() {
  +
  +        if (isEmpty()) {
  +            return null;
  +        }
  +
  +        List violations = new LinkedList();
  +
  +        Iterator piter = getPattern().iterator();
  +
  +        while (piter.hasNext()) {
  +            Pattern pattern = (Pattern) piter.next();
  +            // System.out.println("Pattern name: " + pattern.getName() + ", id: " + pattern.getId() );
  +            Iterator ruleIter = pattern.getRule().iterator();
  +
  +            while (ruleIter.hasNext()) {
  +                Rule rule = (Rule) ruleIter.next();
  +                // System.out.println("    Rule name: " + rule.getContext() );
  +
  +                Iterator assertIter = rule.getAssert().iterator();
  +
  +                while (assertIter.hasNext()) {
  +                    Assert assertion = (Assert) assertIter.next();
  +
  +                    // add the next assert to the violations set
  +                    Violation v = new Violation();
  +
  +                    v.setPath(rule.getContext());
  +                    v.setMessage(assertion.getMessage());
  +                    violations.add(v);
  +                    // System.out.println("        Assert test: " + assertion.getTest() + ", message: " + assertion.getMessage() );
  +                }
  +
  +                Iterator reportIter = rule.getReport().iterator();
  +
  +                while (reportIter.hasNext()) {
  +                    Report report = (Report) reportIter.next();
  +
  +                    // add the next report to the violations set
  +                    Violation v = new Violation();
  +
  +                    v.setPath(rule.getContext());
  +                    v.setMessage(report.getMessage());
  +                    violations.add(v);
  +                    // System.out.println("        Report test: " + report.getTest() + ", message: " + report.getMessage() );
  +                }
  +            }
  +        }
  +        return violations;
  +    }
   }
  
  
  
  1.2       +723 -670  cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/xmlform/Form.java
  
  Index: Form.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/xmlform/Form.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Form.java	25 Apr 2003 08:34:57 -0000	1.1
  +++ Form.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -76,741 +76,794 @@
    * <b>NOTE: This class is NOT thread safe</b>
    *
    * @author Ivelin Ivanov, ivelin@apache.org
  - * @author michael_hampel@sonynetservices.com 
  + * @author michael_hampel@sonynetservices.com
    * @version CVS $Id$
    */
   public class Form {
   
  -        public static String SCOPE_REQUEST = "request";
  -        public static String SCOPE_SESSION = "session";
  +    public static String SCOPE_REQUEST = "request";
   
  -        public static String FORM_VIEW_PARAM = "cocoon-xmlform-view";
  +    public static String SCOPE_SESSION = "session";
   
  -        public static String VIOLATION_MESSAGE_DATA_FORMAT_ERROR =
  -                "Invalid data format";
  +    public static String FORM_VIEW_PARAM = "cocoon-xmlform-view";
   
  -        /**
  -         * an XMLForm is only usable when it has an id and an underlying model
  -         */
  -        public Form(String id, Object model) {
  +    public static String VIOLATION_MESSAGE_DATA_FORMAT_ERROR = "Invalid data format";
   
  -                if ((id == null) || (model == null))
  -                        throw new java.lang.IllegalStateException(
  -                                "Form cannot be created with null id or null model ");
  -                setId(id);
  -                setModel(model);
  -        }
  +    /**
  +     * An XMLForm is only usable when it has an id and an underlying model.
  +     *
  +     * @param id         
  +     * @param model      
  +     */
  +    public Form(String id, Object model) {
  +
  +        if ((id==null) || (model==null)) {
  +            throw new java.lang.IllegalStateException("Form cannot be created with null id or null model ");
  +        }
  +        setId(id);
  +        setModel(model);
  +    }
  +
  +    public String getId() {
  +        return id_;
  +    }
  +
  +    public void setId(String newId) {
  +        id_ = newId;
  +    }
  +
  +    public Object getModel() {
  +        return model_;
  +    }
  +
  +    public void setModel(Object newModel) {
  +        model_ = newModel;
  +        jxcontext_ = JXPathContext.newContext(model_);
  +        jxcontext_.setLenient(false);
  +    }
  +
  +    public Validator getValidator() {
  +        return validator_;
  +    }
  +
  +    public void setValidator(Validator newValidator) {
  +        validator_ = newValidator;
  +    }
  +
  +    public List getViolations() {
  +        return violations_;
  +    }
  +
  +    /**
  +     * This method allows custom validations to be added
  +     * after population and after a call to validate
  +     * (either automatic or explicit).
  +     * Usually used from within the perform method of
  +     * a concrete XMLFormAction.
  +     *
  +     * @param newViolations
  +     */
  +    public void addViolations(List newViolations) {
  +
  +        if (violations_!=null) {
  +            violations_.addAll(newViolations);
  +        } else {
  +            violations_ = newViolations;
  +        }
  +        updateViolationsAsSortedSet();
  +
  +    }
  +
  +    public SortedSet getViolationsAsSortedSet() {
  +        return violationsAsSortedSet_;
  +    }
  +
  +    public void clearViolations() {
  +        violations_ = null;
  +        violationsAsSortedSet_ = null;
  +    }
   
  -        public String getId() {
  -                return id_;
  +    /**
  +     * Encapsulates access to the model.
  +     *
  +     * @param xpath to the model attribute.
  +     * @param value to be set.
  +     */
  +    public void setValue(String xpath, Object value) {
  +        if (model_==null) {
  +            throw new IllegalStateException("Form model not set");
  +        }
  +        jxcontext_.setValue(xpath, value);
  +    }
  +
  +    public void setValue(String xpath, Object[] values) {
  +
  +        // // Dmitri Plotnikov's patch
  +        // 
  +        // // if there are multiple values to set
  +        // // (like in the selectMany case),
  +        // // iterate over the array and set individual values
  +        // if ( values.length > 1  )
  +        // {
  +        // Iterator iter = jxcontext_.iteratePointers(xpath);
  +        // for (int i = 0; i < values.length; i++ )
  +        // {
  +        // Pointer ptr = (Pointer)iter.next();
  +        // ptr.setValue(values[i]);
  +        // }
  +        // }
  +        // else
  +        // {
  +        // // This is supposed to do the right thing
  +        // jxcontext_.setValue(xpath, values);
  +        // }
  +        // 
  +
  +        Pointer pointer = jxcontext_.getPointer(xpath);
  +        Object property = pointer.getNode();
  +
  +        // if there are multiple values to set
  +        // (like in the selectMany case),
  +        // iterate over the array and set individual values
  +
  +        // when the instance property is array
  +        if ((property!=null) && property.getClass().isArray()) {
  +            Class componentType = property.getClass().getComponentType();
  +
  +            property = java.lang.reflect.Array.newInstance(componentType,
  +                values.length);
  +            java.lang.System.arraycopy(values, 0, property, 0, values.length);
  +            pointer.setValue(property);
  +        } else if (property instanceof Collection) {
  +            Collection cl = (Collection) property;
  +
  +            cl.clear();
  +            cl.addAll(java.util.Arrays.asList(values));
  +        } else if (property instanceof NativeArray) {
  +            Context.enter();
  +            try {
  +                NativeArray arr = (NativeArray) property;
  +
  +                ScriptableObject.putProperty(arr, "length", new Integer(0));
  +                ScriptableObject.putProperty(arr, "length",
  +                                             new Integer(values.length));
  +                for (int i = 0; i<values.length; i++) {
  +                    Object val = values[i];
  +
  +                    if ( !((val==null) || (val instanceof String) ||
  +                           (val instanceof Number) ||
  +                           (val instanceof Boolean))) {
  +                        val = Context.toObject(val, arr);
  +                    }
  +                    ScriptableObject.putProperty(arr, i, val);
  +                }
  +            } catch (Exception willNotBeThrown) {
  +                // shouldn't happen
  +                willNotBeThrown.printStackTrace();
  +            } finally {
  +                Context.exit();
  +            }
  +        } else {
  +            jxcontext_.setValue(xpath, values[0]);
           }
  +    }
   
  -        public void setId(String newId) {
  -                id_ = newId;
  -        }
  +    /**
  +     * Encapsulates access to the model.
  +     *
  +     * @param xpath of the model attribute
  +     */
  +    public Object getValue(String xpath) {
  +        if (model_==null) {
  +            throw new IllegalStateException("Form model not set");
  +        }
  +        Object result = jxcontext_.getValue(xpath);
  +
  +        if (result instanceof NativeArray) {
  +            // Convert JavaScript array to Collection
  +            NativeArray arr = (NativeArray) result;
  +            int len = (int) arr.jsGet_length();
  +            List list = new ArrayList(len);
  +
  +            for (int i = 0; i<len; i++) {
  +                Object obj = arr.get(i, arr);
  +
  +                if (obj==Context.getUndefinedValue()) {
  +                    obj = null;
  +                }
  +                list.add(obj);
  +            }
  +            result = list;
  +        }
  +        return result;
  +    }
  +
  +    /**
  +     * Resolves a nodeset selector
  +     * into a list of concrete node locations.
  +     * @param xpathSelector the nodeset selector
  +     *
  +     * @return a Set of XPath strings pointing to
  +     * each nodeset satisfying the nodeset selector
  +     *
  +     * <p>
  +     * TODO: the Collection return type should be replaced with a Set.
  +     * LinkedHashSet implementation should be used. All resolved
  +     * nodes are unique in the resulting set, therefore Set is more appropriate.
  +     * Since LinkedHashSet is only available in JDK 1.4 or later, it is not
  +     * appropriate to make the change immediately.
  +     */
  +    public Collection locate(String xpathSelector) {
  +        if (model_==null) {
  +            throw new IllegalStateException("Form model not set");
  +        }
  +        List nodeset = new LinkedList();
  +        Iterator iter = jxcontext_.iteratePointers(xpathSelector);
  +
  +        while (iter.hasNext()) {
  +            Pointer nextPointer = (Pointer) iter.next();
  +            String path = nextPointer.asPath();
  +
  +            nodeset.add(path);
  +        }
  +        return nodeset;
  +    }
  +
  +    /**
  +     * Performs complete validation
  +     * of the form model.
  +     *
  +     * @return
  +     */
  +    public boolean validate() {
  +        return validate(null);
  +    }
   
  -        public Object getModel() {
  -                return model_;
  +    /**
  +     *
  +     * @param phase the validation phase
  +     *
  +     * @return If validation finishes without any violations,
  +     *         return true otherwise return false and save 
  +     *         all violations.
  +     */
  +    public boolean validate(String phase) {
  +        if (validator_==null) {
  +            return true;
  +        }
  +
  +        validator_.setProperty(Validator.PROPERTY_PHASE, phase);
  +        List vs = validator_.validate(model_);
  +
  +        if (vs!=null) {
  +            if (violations_!=null) {
  +                violations_.addAll(vs);
  +            } else {
  +                if ( !vs.isEmpty()) {
  +                    violations_ = vs;
  +                }
  +            }
  +        }
  +        if (violations_==null) {
  +            return true;
  +        } else {
  +            updateViolationsAsSortedSet();
  +            return false;
           }
  +    }
   
  -        public void setModel(Object newModel) {
  -                model_ = newModel;
  -                jxcontext_ = JXPathContext.newContext(model_);
  -                jxcontext_.setLenient(false);
  -        }
  +    /**
  +     * Populates an HTML Form POST into the XMLForm model (JavaBean or DOM node).
  +     *
  +     * <p>
  +     * Expects that all request parameter names are XPath expressions
  +     * to attributes of the model.
  +     * For each request parameter, finds and assigns its value to the
  +     * JavaBean property corresponding to the parameter's name
  +     * </p>
  +     *
  +     * TODO: provide a more sophisticated examples with checkboxes, multi choice,
  +     * radio button, text area, file upload, etc.
  +     *
  +     * @param sitemapObjectModel
  +     */
  +    public void populate(Map sitemapObjectModel) {
  +        // clean violations_ set
  +        clearViolations();
  +
  +        // let listeners know that
  +        // population is about to start
  +        reset();
  +
  +        // data format violations
  +        // gathered during population
  +        // For example when
  +        // a request parameter value is "saymyname"
  +        // while the request parameter name points to an int attribute
  +        List pviolations = new ArrayList();
  +
  +        Map filteredParameters = getFilteredRequestParameters(sitemapObjectModel);
  +        Iterator iter = filteredParameters.entrySet().iterator();
  +
  +        while (iter.hasNext()) {
  +            Map.Entry entry = (Map.Entry) iter.next();
  +
  +            String path = (String) entry.getKey();
  +
  +            // filter custom request parameter
  +            // not refering to the model
  +            if (filterRequestParameter(path)) {
  +                continue;
  +            }
  +
  +            Object[] values = (Object[]) entry.getValue();
  +
  +            try {
  +                setValue(path, values);
  +            } catch (JXPathException ex) {
  +                Violation v = new Violation();
  +
  +                v.setPath(path);
  +                v.setMessage(ex.getMessage());
  +                pviolations.add(v);
  +            }
  +        } // while
  +
  +        // validate form model
  +        autoValidate(sitemapObjectModel);
  +
  +        // merge violation sets
  +        if (violations_!=null) {
  +            violations_.addAll(pviolations);
  +        } else {
  +            if ( !pviolations.isEmpty()) {
  +                violations_ = pviolations;
  +            }
  +        }
  +        if (violations_!=null) {
  +            updateViolationsAsSortedSet();
  +        }
  +    }
  +
  +    /**
  +     * Filters request parameters which are not references to model properties.
  +     * Sets default values for parameters which were expected in the request,
  +     * but did not arrive (e.g. check boxes).
  +     *
  +     * @param sitemapObjectModel
  +     * @return filtered request parameters
  +     */
  +    protected Map getFilteredRequestParameters(Map sitemapObjectModel) {
   
  -        public Validator getValidator() {
  -                return validator_;
  -        }
  +        Request request = getRequest(sitemapObjectModel);
   
  -        public void setValidator(Validator newValidator) {
  -                validator_ = newValidator;
  -        }
  +        Map filteredParameters = new HashMap();
   
  -        public List getViolations() {
  -                return violations_;
  -        }
  +        // first filter out request parameters which do not refer to model properties
  +        Enumeration enum = request.getParameterNames();
   
  -        /**
  -         * 
  -         * This method allows custom validations to be added
  -         * after population and after a call to validate
  -         * (either automatic or explicit).
  -         * Usually used from within the perform method of 
  -         * a concrete XMLFormAction.
  -         * 
  -         * @param newViolations
  -         *   
  -         */
  -        public void addViolations(List newViolations) {
  +        while (enum.hasMoreElements()) {
  +            String path = (String) enum.nextElement();
   
  -                if (violations_ != null)
  -                        violations_.addAll(newViolations);
  -                else
  -                        violations_ = newViolations;
  -                updateViolationsAsSortedSet();
  +            // filter custom request parameter
  +            // not refering to the model
  +            if (filterRequestParameter(path)) {
  +                continue;
  +            }
   
  -        }
  +            Object[] values = request.getParameterValues(path);
   
  -        public SortedSet getViolationsAsSortedSet() {
  -                return violationsAsSortedSet_;
  +            filteredParameters.put(path, values);
           }
   
  -        public void clearViolations() {
  -                violations_ = null;
  -                violationsAsSortedSet_ = null;
  -        }
  +        // now, find expected parameters which did not arrive
  +        // and set default values for them
  +        String viewName = getFormView(sitemapObjectModel);
  +        Map expectedReferences = getFormViewState(viewName).getModelReferenceMap();
   
  -        /**
  -         * Encapsulates access to the model
  -         *
  -         * @param xpath to the model attribute
  -         * @param value to be set
  -         */
  -        public void setValue(String xpath, Object value) {
  -                if (model_ == null)
  -                        throw new IllegalStateException("Form model not set");
  -                jxcontext_.setValue(xpath, value);
  -        }
  -
  -        public void setValue(String xpath, Object[] values) {
  -
  -                //    // Dmitri Plotnikov's patch
  -                //    
  -                //    // if there are multiple values to set
  -                //    // (like in the selectMany case),
  -                //    // iterate over the array and set individual values
  -                //    if ( values.length > 1  ) 
  -                //    {
  -                //      Iterator iter = jxcontext_.iteratePointers(xpath);      
  -                //      for (int i = 0; i < values.length; i++ )
  -                //      {
  -                //        Pointer ptr = (Pointer)iter.next();
  -                //        ptr.setValue(values[i]);
  -                //      }
  -                //    }
  -                //    else 
  -                //    {
  -                //      // This is supposed to do the right thing
  -                //      jxcontext_.setValue(xpath, values);
  -                //    }    
  -                //    
  -
  -                Pointer pointer = jxcontext_.getPointer(xpath);
  -                Object property = pointer.getNode();
  -                // if there are multiple values to set
  -                // (like in the selectMany case),
  -                // iterate over the array and set individual values
  -
  -                // when the instance property is array
  -                if (property != null && property.getClass().isArray()) {
  -                        Class componentType = property.getClass().getComponentType();
  -                        property =
  -                                java.lang.reflect.Array.newInstance(
  -                                        componentType,
  -                                        values.length);
  -                        java.lang.System.arraycopy(values, 0, property, 0, values.length);
  -                        pointer.setValue(property);
  -                } else if (property instanceof Collection) {
  -                        Collection cl = (Collection) property;
  -                        cl.clear();
  -                        cl.addAll(java.util.Arrays.asList(values));
  -                } else if (property instanceof NativeArray) {
  -                    Context.enter();
  -                    try {
  -                        NativeArray arr = (NativeArray)property;
  -                        ScriptableObject.putProperty(arr, "length", 
  -                                                     new Integer(0));
  -                        ScriptableObject.putProperty(arr, "length", 
  -                                                     new Integer(values.length));
  -                        for (int i = 0; i < values.length; i++) {
  -                            Object val = values[i];
  -                            if (!(val == null
  -                                  || val instanceof String
  -                                  || val instanceof Number 
  -                                  || val instanceof Boolean)) {
  -                                val = Context.toObject(val, arr);
  -                            }
  -                            ScriptableObject.putProperty(arr, i, val);
  -                        }
  -                    } catch (Exception willNotBeThrown) {
  -                        // shouldn't happen
  -                        willNotBeThrown.printStackTrace();
  -                    } finally {
  -                        Context.exit();
  -                    }
  -                } else {
  -                    jxcontext_.setValue(xpath, values[0]);
  -                }
  -        }
  +        Iterator iter = expectedReferences.entrySet().iterator();
   
  -        /**
  -         * Encapsulates access to the model
  -         *
  -         * @param xpath of the model attribute
  -         *
  -         * @throws RuntimeException if the xpath value 
  -         * has invalid XPath syntax or it doesn't point 
  -         * to an attribute of the model
  -         *
  -         */
  -        public Object getValue(String xpath) {
  -                if (model_ == null)
  -                        throw new IllegalStateException("Form model not set");
  -                Object result = jxcontext_.getValue(xpath);
  -                if (result instanceof NativeArray) {
  -                    // Convert JavaScript array to Collection
  -                    NativeArray arr = (NativeArray)result;
  -                    int len = (int)arr.jsGet_length();
  -                    List list = new ArrayList(len);
  -                    for (int i = 0; i < len; i++) {
  -                        Object obj = arr.get(i, arr);
  -                        if (obj == Context.getUndefinedValue()) {
  -                            obj = null;
  -                        }
  -                        list.add(obj);
  -                    }
  -                    result = list;
  -                }
  -                return result;
  -        }
  +        while (iter.hasNext()) {
  +            Map.Entry entry = (Map.Entry) iter.next();
  +            String propertyReference = (String) entry.getKey();
   
  -        /**
  -         * Resolves a nodeset selector
  -         * into a list of concrete node locations
  -         * @param xpathSelector the nodeset selector
  -         *
  -         * @return a Set of XPath strings pointing to 
  -         * each nodeset satisfying the nodeset selector
  -         *
  -         * <p>
  -         * TODO: the Collection return type should be replaced with a Set.
  -         * LinkedHashSet implementation should be used. All resolved 
  -         * nodes are unique in the resulting set, therefore Set is more appropriate.
  -         * Since LinkedHashSet is only available in JDK 1.4 or later, it is not
  -         * appropriate to make the change immediately.
  -         */
  -        public Collection locate(String xpathSelector) {
  -                if (model_ == null)
  -                        throw new IllegalStateException("Form model not set");
  -                List nodeset = new LinkedList();
  -                Iterator iter = jxcontext_.iteratePointers(xpathSelector);
  -                while (iter.hasNext()) {
  -                    Pointer nextPointer = (Pointer) iter.next();
  -                    String path = nextPointer.asPath();
  -                    nodeset.add(path);
  -                }
  -                return nodeset;
  -        }
  +            // check if the expected parameter actually arrived in the request
  +            if (filteredParameters.get(propertyReference)==null) {
  +                // Since it is not there, try to provide a default value
  +                String inputType = (String) entry.getValue();
   
  -        /**
  -         * Performs complete validation
  -         * of the form model
  -         */
  -        public boolean validate() {
  -                return validate(null);
  -        }
  +                Object defaultValue = null;
   
  -        /**
  -         *
  -         * @param phase the validation phase
  -         *
  -         * @return
  -         * if validation finishes without any violations, 
  -         * return true otherwise return false and save all violations
  -         *
  -         */
  -        public boolean validate(String phase) {
  -                if (validator_ == null)
  -                        return true;
  -
  -                validator_.setProperty(Validator.PROPERTY_PHASE, phase);
  -                List vs = validator_.validate(model_);
  -                if (vs != null) {
  -                    if (violations_ != null) {
  -                        violations_.addAll(vs);
  -                    } else {
  -                        if (!vs.isEmpty())
  -                            violations_ = vs;
  -                    }
  -                }
  -                if (violations_ == null)
  -                        return true;
  -                else {
  -                        updateViolationsAsSortedSet();
  -                        return false;
  -                }
  -        }
  -
  -        /**
  -         * Populates an HTML Form POST into the XMLForm model (JavaBean or DOM node).
  -         *
  -         * <p>
  -         * Expects that all request parameter names are XPath expressions
  -         * to attributes of the model.
  -         * For each request parameter, finds and assigns its value to the
  -         * JavaBean property corresponding to the parameter's name
  -         * </p>
  -         *
  -         * TODO: provide a more sophisticated examples with checkboxes, multi choice,
  -         * radio button, text area, file upload, etc.
  -         */
  -        public void populate(Map sitemapObjectModel) {
  -                // clean violations_ set
  -                clearViolations();
  -
  -                // let listeners know that 
  -                // population is about to start
  -                reset();
  -
  -                // data format violations
  -                // gathered during population
  -                // For example when 
  -                // a request parameter value is "saymyname"
  -                // while the request parameter name points to an int attribute
  -                List pviolations = new ArrayList();
  -
  -                Map filteredParameters =
  -                        getFilteredRequestParameters(sitemapObjectModel);
  -                Iterator iter = filteredParameters.entrySet().iterator();
  -                while (iter.hasNext()) {
  -                        Map.Entry entry = (Map.Entry) iter.next();
  -
  -                        String path = (String) entry.getKey();
  -
  -                        // filter custom request parameter
  -                        // not refering to the model
  -                        if (filterRequestParameter(path))
  -                                continue;
  -
  -                        Object[] values = (Object[]) entry.getValue();
  -
  -                        try {
  -                            setValue(path, values);
  -                        } catch (JXPathException ex) {
  -                                Violation v = new Violation();
  -                                v.setPath(path);
  -                                v.setMessage(ex.getMessage());
  -                                pviolations.add(v);
  -                        }
  -                } // while
  -
  -                // validate form model
  -                autoValidate(sitemapObjectModel);
  -
  -                // merge violation sets
  -                if (violations_ != null) {
  -                        violations_.addAll(pviolations);
  +                if (inputType.equals(XMLFormTransformer.TAG_SELECTBOOLEAN)) {
  +                    // false for boolean type (usually, single check-box)
  +                    defaultValue = new Object[]{ Boolean.FALSE };
  +                } else if (inputType.equals(XMLFormTransformer.TAG_SELECTMANY)) {
  +                    // empty array for select many (usually, multi check-box)
  +                    defaultValue = new Object[0];
                   } else {
  -                        if (!pviolations.isEmpty())
  -                                violations_ = pviolations;
  -                }
  -                if (violations_ != null) {
  -                        updateViolationsAsSortedSet();
  +                    // for all the rest, use a blank value and hope for the best
  +                    defaultValue = new Object[]{ "" };
                   }
  -        }
  -
  -        /**
  -         * 
  -         * Filters request parameters which are not references to model properties.
  -         * Sets default values for parameters which were expected in the request, 
  -         * but did not arrive (e.g. check boxes).
  -         * 
  -         * @return filtered request parameters
  -         * 
  -         */
  -        protected Map getFilteredRequestParameters(Map sitemapObjectModel) {
   
  -                Request request = getRequest(sitemapObjectModel);
  +                filteredParameters.put(propertyReference, defaultValue);
   
  -                Map filteredParameters = new HashMap();
  +            }
   
  -                // first filter out request parameters which do not refer to model properties
  -                Enumeration enum = request.getParameterNames();
  -                while (enum.hasMoreElements()) {
  -                        String path = (String) enum.nextElement();
  +        } // iterate over expectedReferences.entrySet()
   
  -                        // filter custom request parameter
  -                        // not refering to the model
  -                        if (filterRequestParameter(path))
  -                                continue;
  -
  -                        Object[] values = request.getParameterValues(path);
  -
  -                        filteredParameters.put(path, values);
  -                }
  -
  -                // now, find expected parameters which did not arrive 
  -                // and set default values for them
  -                String viewName = getFormView(sitemapObjectModel);
  -                Map expectedReferences =
  -                        getFormViewState(viewName).getModelReferenceMap();
  -
  -                Iterator iter = expectedReferences.entrySet().iterator();
  -                while (iter.hasNext()) {
  -                        Map.Entry entry = (Map.Entry) iter.next();
  -                        String propertyReference = (String) entry.getKey();
  -
  -                        // check if the expected parameter actually arrived in the request
  -                        if (filteredParameters.get(propertyReference) == null) {
  -                                // Since it is not there, try to provide a default value
  -                                String inputType = (String) entry.getValue();
  -
  -                                Object defaultValue = null;
  -                                if (inputType.equals(XMLFormTransformer.TAG_SELECTBOOLEAN)) {
  -                                        // false for boolean type (usually, single check-box)
  -                                        defaultValue = new Object[] { Boolean.FALSE };
  -                                } else if (
  -                                        inputType.equals(XMLFormTransformer.TAG_SELECTMANY)) {
  -                                        // empty array for select many (usually, multi check-box)
  -                                        defaultValue = new Object[0];
  -                                } else {
  -                                        // for all the rest, use a blank value and hope for the best
  -                                        defaultValue = new Object[] { "" };
  -                                }
  -
  -                                filteredParameters.put(propertyReference, defaultValue);
  -
  -                        }
  -
  -                } // iterate over expectedReferences.entrySet()
  -
  -                return filteredParameters;
  -
  -        } // getFilteredRequestParameters
  -
  -        /** create a SortedSet view of the violations collection
  -        * for convenience of processors down the pipeline
  -        * protected void updateViolationsAsSortedSet()
  -        */
  -        protected void updateViolationsAsSortedSet() {
  -                violationsAsSortedSet_ = new TreeSet(violations_);
  -        }
  -
  -        /**
  -        *
  -        * Convenience method invoked after populate()
  -        * By default it performs Form model validation.
  -        *
  -        * <br>
  -        * - If default validation is not necessary
  -        * setAutoValidate( false ) should be used
  -        *
  -        * <br>
  -        * If the validation
  -        * criteria needs to be different, subclasses can override
  -        * this method to change the behaviour.
  -        *
  -        */
  -        protected void autoValidate(Map sitemapObjectModel) {
  -                if (!autoValidateEnabled_)
  -                        return;
  -                // perform validation for the phase 
  -                // which matches the name of the current form view
  -                // if one is available
  -                String formView = getFormView(sitemapObjectModel);
  -                if (formView != null) {
  -                        validate(formView);
  -                }
  -        }
  -
  -        /**
  -        * Filters custom request parameter not refering to the model
  -        *
  -    * <p>
  -        * TODO: implement default filtering
  -        * for standard Cocoon parameters
  -        * like cocoon-action[-suffix]
  -        *
  -        */
  -        protected boolean filterRequestParameter(String name) {
  -                // filter standard cocoon-* parameters
  -                if (filterDefaultRequestParameter(name))
  -                        return true;
  -
  -                // then consult with FormListeners
  -                Set ls = new HashSet();
  -                ls.addAll(Collections.synchronizedSet(formListeners_));
  -                Iterator iter = ls.iterator();
  -                while (iter.hasNext()) {
  -                        FormListener fl = (FormListener) iter.next();
  -                        // if any of the listeners wants this parameter filtered
  -                        // then filter it (return true)
  -                        if (fl.filterRequestParameter(this, name))
  -                                return true;
  -                }
  -                // if none of the listeners wants this parameter filtered
  -                // then don't filter it
  -                return false;
  -        }
  -
  -        /**
  -        * Filters the standard cocoon request parameters.
  -        * If default filtering needs to be different,
  -        * subclasses can override this method.
  -        * It is invoked before all listeners are asked to filter the parameter
  -        */
  -        protected boolean filterDefaultRequestParameter(String paramName) {
  -                if (paramName.startsWith(Constants.ACTION_PARAM_PREFIX)
  -                        || paramName.startsWith(Constants.VIEW_PARAM))
  -                        return true;
  -                if (paramName.equals(FORM_VIEW_PARAM))
  -                        return true;
  -                else
  -                        return false;
  -        }
  +        return filteredParameters;
   
  -        /**
  -         * Try to extract from the request
  -         * and return the current form view
  -         */
  -        public String getFormView(Map sitemapObjectModel) {
  -                return getRequest(sitemapObjectModel).getParameter(Form.FORM_VIEW_PARAM);
  -        }
  +    } // getFilteredRequestParameters
   
  -        /**
  -         * This method is called before
  -         * the form is populated with request parameters.
  -         *
  -         * Semantically similar to that of the 
  -         * ActionForm.reset() in Struts
  -         *
  -         * Can be used for clearing checkbox fields,
  -         * because the browser will not send them when
  -         * not checked.
  -         *
  -         * Calls reset on all FormListeners
  -         */
  -        protected void reset() {
  -                // notify FormListeners
  -                Set ls = new HashSet();
  -                ls.addAll(Collections.synchronizedSet(formListeners_));
  -                Iterator iter = ls.iterator();
  -                while (iter.hasNext()) {
  -                        FormListener fl = (FormListener) iter.next();
  -                        fl.reset(this);
  -                }
  -                return;
  -        }
  +    /** 
  +     * Create a SortedSet view of the violations collection
  +     * for convenience of processors down the pipeline
  +     * protected void updateViolationsAsSortedSet()
  +     */
  +    protected void updateViolationsAsSortedSet() {
  +        violationsAsSortedSet_ = new TreeSet(violations_);
  +    }
   
  -        /**
  -         * Loads a form from the request or session
  -         *
  -         * @param sitemapObjectModel
  -         * @param id the form id
  -         */
  -        public static Form lookup(Map sitemapObjectModel, String id) {
  -                Request request = getRequest(sitemapObjectModel);
  -                Form form = (Form) request.getAttribute(id);
  -                if (form != null)
  -                        return form;
  -                else {
  -                        Session session = request.getSession(false);
  -                        if (session != null)
  -                                form = (Form) session.getAttribute(id);
  -                        return form;
  -                }
  -        }
  +    /**
  +     * Convenience method invoked after populate()
  +     * By default it performs Form model validation.
  +     *
  +     * <br>
  +     * - If default validation is not necessary
  +     * setAutoValidate( false ) should be used
  +     *
  +     * <br>
  +     * If the validation
  +     * criteria needs to be different, subclasses can override
  +     * this method to change the behaviour.
  +     *
  +     * @param sitemapObjectModel
  +     */
  +    protected void autoValidate(Map sitemapObjectModel) {
  +        if ( !autoValidateEnabled_) {
  +            return;
  +        }
  +        // perform validation for the phase
  +        // which matches the name of the current form view
  +        // if one is available
  +        String formView = getFormView(sitemapObjectModel);
   
  -        /**
  -         * Removes a form from the request and session.
  -         * This method will remove the attribute bindings
  -         * correspoding to the form id from both request
  -         * and session to ensure that a subsequent 
  -         * Form.lookup will not succeed.
  -         *
  -         * @param sitemapObjectModel
  -         * @param id the form id
  -         */
  -        public static void remove(Map sitemapObjectModel, String id) {
  -                Request request = getRequest(sitemapObjectModel);
  -                request.removeAttribute(id);
  -
  -                Session session = request.getSession(false);
  -                if (session != null)
  -                        session.removeAttribute(id);
  +        if (formView!=null) {
  +            validate(formView);
           }
  +    }
   
  -        /**
  -         * Saves the form in the request or session
  -         *
  -         * @param sitemapObjectModel
  -         * @param scope if true the form will be bound in the session, otherwise request
  -         */
  -        public void save(Map sitemapObjectModel, String scope) {
  -                Request request = getRequest(sitemapObjectModel);
  +    /**
  +     * Filters custom request parameter not refering to the model.
  +     *
  +     * TODO: implement default filtering
  +     * for standard Cocoon parameters
  +     * like cocoon-action[-suffix]
  +     *
  +     * @param name       
  +     *
  +     * @return
  +     */
  +    protected boolean filterRequestParameter(String name) {
  +        // filter standard cocoon-* parameters
  +        if (filterDefaultRequestParameter(name)) {
  +            return true;
  +        }
  +
  +        // then consult with FormListeners
  +        Set ls = new HashSet();
  +
  +        ls.addAll(Collections.synchronizedSet(formListeners_));
  +        Iterator iter = ls.iterator();
  +
  +        while (iter.hasNext()) {
  +            FormListener fl = (FormListener) iter.next();
  +
  +            // if any of the listeners wants this parameter filtered
  +            // then filter it (return true)
  +            if (fl.filterRequestParameter(this, name)) {
  +                return true;
  +            }
  +        }
  +        // if none of the listeners wants this parameter filtered
  +        // then don't filter it
  +        return false;
  +    }
  +
  +    /**
  +     * Filters the standard cocoon request parameters.
  +     * If default filtering needs to be different,
  +     * subclasses can override this method.
  +     * It is invoked before all listeners are asked to filter the parameter
  +     *
  +     * @param paramName  
  +     *
  +     * @return
  +     */
  +    protected boolean filterDefaultRequestParameter(String paramName) {
  +        if (paramName.startsWith(Constants.ACTION_PARAM_PREFIX) ||
  +            paramName.startsWith(Constants.VIEW_PARAM)) {
  +            return true;
  +        }
  +        if (paramName.equals(FORM_VIEW_PARAM)) {
  +            return true;
  +        } else {
  +            return false;
  +        }
  +    }
  +
  +    /**
  +     * Try to extract from the request
  +     * and return the current form view
  +     *
  +     * @param sitemapObjectModel
  +     *
  +     * @return
  +     */
  +    public String getFormView(Map sitemapObjectModel) {
  +        return getRequest(sitemapObjectModel).getParameter(Form.FORM_VIEW_PARAM);
  +    }
  +
  +    /**
  +     * This method is called before
  +     * the form is populated with request parameters.
  +     *
  +     * Semantically similar to that of the
  +     * ActionForm.reset() in Struts
  +     *
  +     * Can be used for clearing checkbox fields,
  +     * because the browser will not send them when
  +     * not checked.
  +     *
  +     * Calls reset on all FormListeners
  +     */
  +    protected void reset() {
  +        // notify FormListeners
  +        Set ls = new HashSet();
   
  -                if (lookup(sitemapObjectModel, id_) != null)
  -                        throw new java.lang.IllegalStateException(
  -                                "Form [id=" + id_ + "] already bound in request or session ");
  -
  -                if (SCOPE_REQUEST.equals(scope)) {
  -                        request.setAttribute(id_, this);
  -                } else // session scope
  -                        {
  -                        Session session = request.getSession(true);
  -                        session.setAttribute(id_, this);
  -                }
  +        ls.addAll(Collections.synchronizedSet(formListeners_));
  +        Iterator iter = ls.iterator();
   
  -        }
  +        while (iter.hasNext()) {
  +            FormListener fl = (FormListener) iter.next();
   
  -        /**
  -         * Add another FormListener
  -         *
  -         */
  -        public synchronized void addFormListener(FormListener formListener) {
  -                formListeners_.add(formListener);
  +            fl.reset(this);
           }
  +        return;
  +    }
   
  -        /**
  -         * Add another FormListener
  -         *
  -         */
  -        public synchronized void removeFormListener(FormListener formListener) {
  -                formListeners_.remove(formListener);
  -        }
  +    /**
  +     * Loads a form from the request or session
  +     *
  +     * @param sitemapObjectModel
  +     * @param id the form id
  +     *
  +     * @return
  +     */
  +    public static Form lookup(Map sitemapObjectModel, String id) {
  +        Request request = getRequest(sitemapObjectModel);
  +        Form form = (Form) request.getAttribute(id);
  +
  +        if (form!=null) {
  +            return form;
  +        } else {
  +            Session session = request.getSession(false);
  +
  +            if (session!=null) {
  +                form = (Form) session.getAttribute(id);
  +            }
  +            return form;
  +        }
  +    }
  +
  +    /**
  +     * Removes a form from the request and session.
  +     * This method will remove the attribute bindings
  +     * correspoding to the form id from both request
  +     * and session to ensure that a subsequent
  +     * Form.lookup will not succeed.
  +     *
  +     * @param sitemapObjectModel
  +     * @param id the form id
  +     */
  +    public static void remove(Map sitemapObjectModel, String id) {
  +        Request request = getRequest(sitemapObjectModel);
   
  -        protected final static Request getRequest(Map sitemapObjectModel) {
  -                return (Request) sitemapObjectModel.get(
  -                        ObjectModelHelper.REQUEST_OBJECT);
  -        }
  +        request.removeAttribute(id);
   
  -        public void setAutoValidate(boolean newAVFlag) {
  -                autoValidateEnabled_ = newAVFlag;
  -        }
  +        Session session = request.getSession(false);
   
  -        /**
  -         * <pre>
  -         * When the transformer renders a form view,
  -         * it lets the form wrapper know about each referenced model property.
  -         * This allows a precise tracking and can be used for multiple reasons:
  -         *   1) Verify that the client does not temper with the input fields as specified by the 
  -         *      form view author
  -         *   2) Allow default values to be used for properties which were expected to be send by the client,
  -         *      but for some reason were not. A typical example is a check box. When unchecked, the browser
  -         *      does not send any request parameter, leaving it to the server to handle the situation.
  -         *      This proves to be a very error prone problem when solved on a case by case basis.
  -         *      By having a list of expected property references, the model populator can detect
  -         *      a checkbox which was not send and set the property value to false.
  -         * 
  -         * NOTE: This added functionality is ONLY useful for SESSION scope forms.
  -         * Request scope forms are constructed anew for every request and therefore
  -         * cannot benefit from this extra feature.
  -         * With the high performance CPUs and cheap memory used in today's servers,
  -         * session scope forms are a safe choice.
  -         * 
  -         * </pre>
  -         * 
  -         */
  -        public void saveExpectedModelReferenceForView(
  -                String currentFormView,
  -                String ref,
  -                String inputType) {
  -                // if the form view is null, we are not interested in saving any references
  -                if (currentFormView == null)
  -                        return;
  -
  -                FormViewState formViewState = getFormViewState(currentFormView);
  -                formViewState.addModelReferenceAndInputType(ref, inputType);
  +        if (session!=null) {
  +            session.removeAttribute(id);
           }
  +    }
   
  -        /**
  -         * When the transformer starts rendering a new form element
  -         * It needs to reset previously saved references for another 
  -         * transformation of the same view.
  -         */
  -        public void clearSavedModelReferences(String currentFormView) {
  -                FormViewState formViewState = getFormViewState(currentFormView);
  -                formViewState.clear();
  -        }
  +    /**
  +     * Saves the form in the request or session.
  +     *
  +     * @param sitemapObjectModel
  +     * @param scope if true the form will be bound in the session, otherwise request
  +     */
  +    public void save(Map sitemapObjectModel, String scope) {
  +        Request request = getRequest(sitemapObjectModel);
  +
  +        if (lookup(sitemapObjectModel, id_)!=null) {
  +            throw new java.lang.IllegalStateException("Form [id="+id_+
  +                                                      "] already bound in request or session ");
  +        }
  +
  +        if (SCOPE_REQUEST.equals(scope)) {
  +            request.setAttribute(id_, this);
  +        } else // session scope
  +        {
  +            Session session = request.getSession(true);
  +
  +            session.setAttribute(id_, this);
  +        }
  +
  +    }
  +
  +    /**
  +     * Add another FormListener.
  +     */
  +    public synchronized void addFormListener(FormListener formListener) {
  +        formListeners_.add(formListener);
  +    }
  +
  +    /**
  +     * Add another FormListener
  +     */
  +    public synchronized void removeFormListener(FormListener formListener) {
  +        formListeners_.remove(formListener);
  +    }
  +
  +    protected final static Request getRequest(Map sitemapObjectModel) {
  +        return (Request) sitemapObjectModel.get(ObjectModelHelper.REQUEST_OBJECT);
  +    }
  +
  +    public void setAutoValidate(boolean newAVFlag) {
  +        autoValidateEnabled_ = newAVFlag;
  +    }
  +
  +    /**
  +     * <pre>
  +     * When the transformer renders a form view,
  +     * it lets the form wrapper know about each referenced model property.
  +     * This allows a precise tracking and can be used for multiple reasons:
  +     *   1) Verify that the client does not temper with the input fields as specified by the
  +     *      form view author
  +     *   2) Allow default values to be used for properties which were expected to be send by the client,
  +     *      but for some reason were not. A typical example is a check box. When unchecked, the browser
  +     *      does not send any request parameter, leaving it to the server to handle the situation.
  +     *      This proves to be a very error prone problem when solved on a case by case basis.
  +     *      By having a list of expected property references, the model populator can detect
  +     *      a checkbox which was not send and set the property value to false.
  +     *
  +     * NOTE: This added functionality is ONLY useful for SESSION scope forms.
  +     * Request scope forms are constructed anew for every request and therefore
  +     * cannot benefit from this extra feature.
  +     * With the high performance CPUs and cheap memory used in today's servers,
  +     * session scope forms are a safe choice.
  +     * </pre>
  +     *
  +     * @param currentFormView
  +     * @param ref        
  +     * @param inputType  
  +     */
  +    public void saveExpectedModelReferenceForView(String currentFormView,
  +        String ref, String inputType) {
  +        // if the form view is null, we are not interested in saving any references
  +        if (currentFormView==null) {
  +            return;
  +        }
  +
  +        FormViewState formViewState = getFormViewState(currentFormView);
  +
  +        formViewState.addModelReferenceAndInputType(ref, inputType);
  +    }
  +
  +    /**
  +     * When the transformer starts rendering a new form element.
  +     * It needs to reset previously saved references for another
  +     * transformation of the same view.
  +     *
  +     * @param currentFormView
  +     */
  +    public void clearSavedModelReferences(String currentFormView) {
  +        FormViewState formViewState = getFormViewState(currentFormView);
  +
  +        formViewState.clear();
  +    }
  +
  +    /**
  +     * We keep a map of ViewState objects which store
  +     * all references to model properties in a particular form view
  +     * which were rendered by the
  +     * XMLFormTansformer in the most recent transformation.
  +     *
  +     * @param viewName   
  +     *
  +     * @return
  +     */
  +    protected FormViewState getFormViewState(String viewName) {
  +        FormViewState formViewState = (FormViewState) viewStateMap_.get(viewName);
  +
  +        if (formViewState==null) {
  +            formViewState = new FormViewState();
  +            viewStateMap_.put(viewName, formViewState);
  +        }
  +        return formViewState;
  +    }
  +
  +    /**
  +     * Internal class used for keeping state information
  +     * during the life cycle of a form.
  +     *
  +     * <p>Used only for session scoped forms
  +     */
  +    class FormViewState {
  +        private Map modelReferences_ = new HashMap();
   
  -        /**
  -         * We keep a map of ViewState objects which store 
  -         * all references to model properties in a particular form view
  -         * which were rendered by the 
  -         * XMLFormTansformer in the most recent transformation.
  -         */
  -        protected FormViewState getFormViewState(String viewName) {
  -                FormViewState formViewState =
  -                        (FormViewState) viewStateMap_.get(viewName);
  -                if (formViewState == null) {
  -                        formViewState = new FormViewState();
  -                        viewStateMap_.put(viewName, formViewState);
  -                }
  -                return formViewState;
  +        FormViewState() {
           }
   
           /**
  -         * Internal class used for keeping state information
  -         * during the life cycle of a form.
  -         * 
  -         * <p>Used only for session scoped forms
  +         *
  +         * @return Map of (String modelPropertyReference, String inputType) pairs
            */
  -        class FormViewState {
  -        private Map modelReferences_ = new HashMap();
  -
  -                FormViewState() {
  +        Map getModelReferenceMap() {
  +            return modelReferences_;
           }
   
  -                /**
  -                 * 
  -                 * @return Map of (String modelPropertyReference, String inputType) pairs 
  -                 */
  -                Map getModelReferenceMap() {
  -                        return modelReferences_;
  -                }
  -
  -                void addModelReferenceAndInputType(String modelPropertyReference,
  +        void addModelReferenceAndInputType(String modelPropertyReference,
                                              String inputType) {
               modelReferences_.put(modelPropertyReference, inputType);
  -                }
  +        }
   
  -                void clear() {
  -                        modelReferences_.clear();
  -                }
  +        void clear() {
  +            modelReferences_.clear();
           }
  +    }
   
  -        /** the set of violations the model commited during validation */
  -        private List violations_ = null;
  +    /** the set of violations the model commited during validation */
  +    private List violations_ = null;
   
  -        /** another view of the violations_ collection */
  -        private SortedSet violationsAsSortedSet_ = null;
  +    /** another view of the violations_ collection */
  +    private SortedSet violationsAsSortedSet_ = null;
   
  -        /** flag allowing control over automatic validation on populate() */
  -        private boolean autoValidateEnabled_ = true;
  +    /** flag allowing control over automatic validation on populate() */
  +    private boolean autoValidateEnabled_ = true;
   
  -        /** The data model this form encapsulates */
  -        private Object model_ = null;
  +    /** The data model this form encapsulates */
  +    private Object model_ = null;
   
  -        /** The list of FormListeners */
  -        private Set formListeners_ = new HashSet();
  +    /** The list of FormListeners */
  +    private Set formListeners_ = new HashSet();
   
  -        /** 
  -         * The unique identifier for this form. Used when form is stored in request 
  -         * or session for reference by other components
  +    /**
  +     * The unique identifier for this form. Used when form is stored in request
  +     * or session for reference by other components
        *
  -         * <p>
  -         * TODO: a centralized form registry would be helpful to prevent from id collision
  -         */
  -        private String id_ = null;
  -
  -        /**
  -         * The JXPath context associated with the model
  -         * Used to traverse the model with XPath expressions
  -         */
  -        private JXPathContext jxcontext_ = null;
  -
  -        /**
  -         * Used to validate the content of the model
  -         * at various phases
  -         *
  -         */
  -        private Validator validator_ = null;
  -
  -        /**
  -         * Keeps a state information for
  -         * each form view that has been processed
  -         * 
  -         */
  -        private Map viewStateMap_ = new HashMap();
  +     * <p>
  +     * TODO: a centralized form registry would be helpful to prevent from id collision
  +     */
  +    private String id_ = null;
  +
  +    /**
  +     * The JXPath context associated with the model.
  +     * Used to traverse the model with XPath expressions
  +     */
  +    private JXPathContext jxcontext_ = null;
  +
  +    /**
  +     * Used to validate the content of the model
  +     * at various phases.
  +     */
  +    private Validator validator_ = null;
  +
  +    /**
  +     * Keeps a state information for
  +     * each form view that has been processed.
  +     */
  +    private Map viewStateMap_ = new HashMap();
   }
  
  
  
  1.2       +13 -13    cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/xmlform/FormListener.java
  
  Index: FormListener.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/components/xmlform/FormListener.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- FormListener.java	25 Apr 2003 08:34:57 -0000	1.1
  +++ FormListener.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -51,11 +51,7 @@
   package org.apache.cocoon.components.xmlform;
   
   /**
  - * <p>
  - *  Defines events fired by a Form object 
  - *  
  - * </p>
  - *
  + * Defines events fired by a Form object.
    *
    * @author Ivelin Ivanov, ivelin@apache.org
    * @version CVS $Id$
  @@ -63,10 +59,10 @@
   public interface FormListener {
   
       /**
  -     * This method is called before 
  +     * This method is called before
        * the form is populated with request parameters.
        *
  -     * Semantically similar to that of the 
  +     * Semantically similar to that of the
        * ActionForm.reset() in Struts
        *
        * Can be used for clearing checkbox fields,
  @@ -76,15 +72,19 @@
        * This method does nothing by default
        * Subclasses should override it to implement custom logic
        *
  +     * @param form       
        */
       void reset(Form form);
  -    
  +
       /**
  -     * filters custom request parameter
  -     * not refering to the model
  +     * Filters custom request parameter
  +     * not refering to the model.
  +     *
  +     * @param form       
  +     * @param parameterName
  +     *
  +     * @return
        */
       boolean filterRequestParameter(Form form, String parameterName);
  -
   }
  -
   
  
  
  
  1.2       +973 -1041 cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/transformation/XMLFormTransformer.java
  
  Index: XMLFormTransformer.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/xmlform/java/org/apache/cocoon/transformation/XMLFormTransformer.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- XMLFormTransformer.java	25 Apr 2003 08:34:58 -0000	1.1
  +++ XMLFormTransformer.java	26 Apr 2003 12:10:44 -0000	1.2
  @@ -8,14 +8,14 @@
   
    Redistribution and use in source and binary forms, with or without modifica-
    tion, are permitted provided that the following conditions are met:
  - 
  +
    1. Redistributions of  source code must  retain the above copyright  notice,
       this list of conditions and the following disclaimer.
  - 
  +
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
  - 
  +
    3. The end-user documentation included with the redistribution, if any, must
       include  the following  acknowledgment:  "This product includes  software
       developed  by the  Apache Software Foundation  (http://www.apache.org/)."
  @@ -76,7 +76,7 @@
    * Transforms a document with XMLForm
    * elements into a document in the same namespace,
    * but with populated values for the XPath references
  - * to the form's model attributes
  + * to the form's model attributes.
    *
    * @author Ivelin Ivanov <iv...@apache.org>, June 2002
    * @author Andrew Timberlake <an...@timberlake.co.za>, June 2002
  @@ -85,212 +85,213 @@
    * @author Simon Price <pr...@bristol.ac.uk>, September 2002
    * @version CVS $Id$
    */
  -public class XMLFormTransformer extends AbstractSAXTransformer
  -{
  +public class XMLFormTransformer extends AbstractSAXTransformer {
  +
  +    // TODO: implements CacheableProcessingComponent {
  +
  +    public final static String NS = "http://xml.apache.org/cocoon/xmlform/2002";
  +    private final static String NS_PREFIX = "xf";
  +
  +    public final static Attributes NOATTR = new AttributesImpl();
  +    private final static String XMLNS_PREFIX = "xmlns";
  +
  +    /**
  +     * The main tag in the XMLForm namespace
  +     * almost all other tags have to appear within the form tag.
  +     * The id attribute refers to a xmlform.Form object
  +     * available in the current Request or Session
  +     *
  +     * &lt;form id="form-feedback">
  +     *  &lt;output ref="user/age"/>
  +     *  &lt;textbox ref="user/name"/>
  +     * &lt;/form>
  +     */
  +    public final static String TAG_FORM = "form";
  +
  +    public final static String TAG_FORM_ATTR_ID = "id";
  +
  +    public final static String TAG_FORM_ATTR_VIEW = "view";
  +
  +    /**
  +     * The only tag which can be used outside of the form tag
  +     * with reference to the form id,
  +     * &lt;output ref="user/age" id="form-feedback"/>
  +     */
  +    public final static String TAG_OUTPUT = "output";
  +
  +    public final static String TAG_OUTPUT_ATTR_FORM = TAG_FORM;
  +
  +    /**
  +     * Can be used directly under the form tag
  +     * to enlist all field violations or
  +     * within a field tag to enlist only the violations for the field.
  +     * <br>
  +     * <pre>
  +     * &lt;form id="form-feedback">
  +     *  &lt;violations/>
  +     *  &lt;textbox ref="user/name">
  +     *    &lt;violations/>
  +     *  &lt;/textbox>
  +     * &lt;/form>
  +     * </pre>
  +     *
  +     * When used under the forms tag it is transformed to a set of:
  +     * <br>
  +     * &lt;violation ref="user/age">Age must be a positive number &lt;/violation>
  +     * <br>
  +     * and when used within a field it is transformed to a set of:
  +     * <br>
  +     * &lt;violation>Age must be a positive number &lt;/violation>
  +     * <br>
  +     * The only difference is that the ref tag is used in the first case,
  +     * while in the second it is omited.
  +     */
  +    public final static String TAG_INSERTVIOLATIONS = "violations";
  +
  +    /** the name of the elements which replace the violations tag */
  +    public final static String TAG_VIOLATION = "violation";
  +
  +    /** action buttons */
  +    public final static String TAG_SUBMIT = "submit";
  +
  +    public final static String TAG_CANCEL = "cancel";
  +
  +    public final static String TAG_RESET = "reset";
  +
  +    public final static String TAG_CAPTION = "caption";
  +
  +    public final static String TAG_HINT = "hint";
  +
  +    public final static String TAG_HELP = "help";
  +
  +    public final static String TAG_TEXTBOX = "textbox";
  +
  +    public final static String TAG_TEXTAREA = "textarea";
  +
  +    public final static String TAG_PASSWORD = "password";
  +
  +    public final static String TAG_SELECTBOOLEAN = "selectBoolean";
  +
  +    public final static String TAG_SELECTONE = "selectOne";
  +
  +    public final static String TAG_SELECTMANY = "selectMany";
  +
  +    public final static String TAG_ITEMSET = "itemset";
  +
  +    public final static String TAG_ITEM = "item";
  +
  +    public final static String TAG_VALUE = "value";
  +
  +    public final static String TAG_HIDDEN = "hidden";
  +
  +    /**
  +     * Grouping tag.
  +     *
  +     * <pre>
  +     *  <group ref="address">
  +     *   <caption>Shipping Address</caption>
  +     *     <input ref="line_1">
  +     *       <caption>Address line 1</caption>
  +     *     </input>
  +     *     <input ref="line_2">
  +     *       <caption>Address line 2</caption>
  +     *     </input>
  +     *     <input ref="postcode">
  +     *       <caption>Postcode</caption>
  +     *     </input>
  +     * </group>
  +     * </pre>
  +     */
  +    public final static String TAG_GROUP = "group";
  +
  +    /**
  +     * Repeat tag.
  +     *
  +     * <repeat nodeset="/cart/items/item">
  +     *    <input ref="." .../><html:br/>
  +     * </repeat>
  +     */
  +
  +    public final static String TAG_REPEAT = "repeat";
  +
  +    /**
  +     * This attribute is used within the
  +     * <code>repeat</code> tag
  +     * to represent an XPath node set selector from
  +     * the underlying xmlform model.
  +     */
  +    public final static String TAG_REPEAT_ATTR_NODESET = "nodeset";
  +
  +    /**
  +     * The current fully expanded reference
  +     * in the form model.
  +     */
  +    private String cannonicalRef = null;
  +
  +    /**
  +     * Tracks the current repeat tag depth,
  +     * when there is one in scope.
  +     */
  +    private int repeatTagDepth = -1;
   
  -  // TODO: implements CacheableProcessingComponent {
  +    /**
  +     * The nodeset selector string of the
  +     * currently processed repeat tag (if any).
  +     */
  +    private String nodeset = null;
   
  -  public final static String NS = "http://xml.apache.org/cocoon/xmlform/2002";
  -  private final static String NS_PREFIX = "xf";
  -  public final static Attributes NOATTR = new AttributesImpl();
  -  private final static String XMLNS_PREFIX = "xmlns";
  -
  -  /**
  -   * The main tag in the XMLForm namespace
  -   * almost all other tags have to appear within the form tag
  -   * The id attribute refers to a xmlform.Form object
  -   * available in the current Request or Session
  -   *
  -   * &lt;form id="form-feedback">
  -   *  &lt;output ref="user/age"/>
  -   *  &lt;textbox ref="user/name"/>
  -   * &lt;/form>
  -   */
  -  public final static String TAG_FORM = "form";
  -  public final static String TAG_FORM_ATTR_ID = "id";
  -  public final static String TAG_FORM_ATTR_VIEW = "view";
  -
  -  /**
  -   * the only tag which can be used outside of the form tag
  -   * with reference to the form id,
  -   * &lt;output ref="user/age" id="form-feedback"/>
  -   */
  -  public final static String TAG_OUTPUT = "output";
  -  public final static String TAG_OUTPUT_ATTR_FORM = TAG_FORM;
  -
  -  /**
  -   * can be used directly under the form tag
  -   * to enlist all field violations or
  -   * within a field tag to enlist only the violations for the field.
  -   * <br>
  -   * <pre>
  -   * &lt;form id="form-feedback">
  -   *  &lt;violations/>
  -   *  &lt;textbox ref="user/name">
  -   *    &lt;violations/>
  -   *  &lt;/textbox>
  -   * &lt;/form>
  -   * </pre>
  -   *
  -   * When used under the forms tag it is transformed to a set of:
  -   * <br>
  -   * &lt;violation ref="user/age">Age must be a positive number &lt;/violation>
  -   * <br>
  -   * and when used within a field it is transformed to a set of:
  -   * <br>
  -   * &lt;violation>Age must be a positive number &lt;/violation>
  -   * <br>
  -   * The only difference is that the ref tag is used in the first case,
  -   * while in the second it is omited.
  -   *
  -   */
  -  public final static String TAG_INSERTVIOLATIONS = "violations";
  -
  -  /** the name of the elements which replace the violations tag */
  -  public final static String TAG_VIOLATION = "violation";
  -
  -  /** action buttons */
  -  public final static String TAG_SUBMIT = "submit";
  -  public final static String TAG_CANCEL = "cancel";
  -  public final static String TAG_RESET = "reset";
  -
  -  public final static String TAG_CAPTION = "caption";
  -  public final static String TAG_HINT = "hint";
  -  public final static String TAG_HELP = "help";
  -  public final static String TAG_TEXTBOX = "textbox";
  -  public final static String TAG_TEXTAREA = "textarea";
  -  public final static String TAG_PASSWORD = "password";
  -  public final static String TAG_SELECTBOOLEAN = "selectBoolean";
  -  public final static String TAG_SELECTONE = "selectOne";
  -  public final static String TAG_SELECTMANY = "selectMany";
  -  public final static String TAG_ITEMSET = "itemset";
  -  public final static String TAG_ITEM = "item";
  -  public final static String TAG_VALUE = "value";
  -  public final static String TAG_HIDDEN = "hidden";
  -   
  -  /**
  -   * grouping tag
  -   *
  -   * <pre>
  -   *  <group ref="address">
  -   *   <caption>Shipping Address</caption>
  -   *     <input ref="line_1">
  -   *       <caption>Address line 1</caption>
  -   *     </input>
  -   *     <input ref="line_2">
  -   *       <caption>Address line 2</caption>
  -   *     </input>
  -   *     <input ref="postcode">
  -   *       <caption>Postcode</caption>
  -   *     </input>
  -   * </group>
  -   * </pre>
  -   *
  -   *
  -   */
  -  public final static String TAG_GROUP = "group";
  -
  -  /**
  -   *  repeat tag
  -   *
  -   *  <repeat nodeset="/cart/items/item">
  -   *    <input ref="." .../><html:br/>
  -   *  </repeat>
  -   *
  -   *
  -   */
  -
  -  public final static String TAG_REPEAT = "repeat";
  -
  -
  -  /**
  -   * this attribute is used within the
  -   * <code>repeat</code> tag
  -   * to represent an XPath node set selector from
  -   * the underlying xmlform model.
  -   */
  -  public final static String TAG_REPEAT_ATTR_NODESET = "nodeset";
  -
  -  /**
  -   * The current fully expanded reference
  -   * in the form model.
  -   *
  -   */
  -  private String cannonicalRef = null;
  -
  -  /**
  -   * Tracks the current repeat tag depth,
  -   * when there is one in scope
  -   */
  -  private int repeatTagDepth = -1;
  -
  -  /**
  -   * The nodeset selector string of the
  -   * currently processed repeat tag (if any)
  -   */
  -  private String nodeset = null;
  -
  -
  -  /**
  -   * The flag annotating if the transformer is
  -   * working on a repeat tag
  -   */
  -  private boolean isRecording = false;
  -
  -
  -  /**
  -   * Flag to let us know if the transformer is working
  -   * on a hidden tag
  -   */
  -  private boolean isHiddenTag = false;
  -
  -  /**
  -   * Flag to let us know that the hidden element contains
  -   * a value child element.
  -   */
  -  private boolean hasHiddenTagValue = false;
  -
  -  
  -  /**
  -   * the ref value of the current field
  -   * used by the violations tag
  -   */
  -  private Stack refStack = null;
  -
  -  /**
  -   * Tracks the current depth of the XML tree
  -   */
  -  private int currentTagDepth = 0;
  -
  -
  -  /**
  -   * this attribute is used within all field tags
  -   * to represent an XPath reference to the attribute of
  -   * the underlying model.
  -   */
  -  public final static String TAG_COMMON_ATTR_REF = "ref";
  -
  -
  -  /** the stack of nested forms. 
  -   * Although nested form tags are not allowed, it is possible 
  -   * that an output tag (with reference to another form) might be nested within a form tag.
  -   * In this case elements under the output tag (like caption) can reference properties
  -   * of the form of the enclosing output tag.
  -   */
  -
  -  private Stack formStack = null;
  -  
  -  
  -  /**
  -   * Since form elements cannot be nested,
  -   * at most one possible value for the current form view is available.
  -   */
  -  private String currentFormView = null;
  +    /**
  +     * The flag annotating if the transformer is
  +     * working on a repeat tag.
  +     */
  +    private boolean isRecording = false;
   
  +    /**
  +     * Flag to let us know if the transformer is working
  +     * on a hidden tag.
  +     */
  +    private boolean isHiddenTag = false;
   
  -  private Object value_;
  +    /**
  +     * Flag to let us know that the hidden element contains
  +     * a value child element.
  +     */
  +    private boolean hasHiddenTagValue = false;
   
  +    /**
  +     * The ref value of the current field
  +     * used by the violations tag.
  +     */
  +    private Stack refStack = null;
   
  +    /**
  +     * Tracks the current depth of the XML tree.
  +     */
  +    private int currentTagDepth = 0;
  +
  +    /**
  +     * this attribute is used within all field tags
  +     * to represent an XPath reference to the attribute of
  +     * the underlying model.
  +     */
  +    public final static String TAG_COMMON_ATTR_REF = "ref";
  +
  +    /** 
  +     * The stack of nested forms.
  +     * Although nested form tags are not allowed, it is possible
  +     * that an output tag (with reference to another form) might be nested within a form tag.
  +     * In this case elements under the output tag (like caption) can reference properties
  +     * of the form of the enclosing output tag.
  +     */
  +    private Stack formStack = null;
  +
  +    /**
  +     * Since form elements cannot be nested,
  +     * at most one possible value for the current form view is available.
  +     */
  +    private String currentFormView = null;
  +
  +    private Object value_;
   
       /**
        * Setup the next round.
  @@ -300,632 +301,593 @@
        * @param src The value of the src attribute in the sitemap.
        * @param par The parameters from the sitemap.
        */
  -  public void setup(
  -                      SourceResolver resolver,
  -                      Map                   objectModel,
  -                      String                 src,
  -                      Parameters        par)
  -    throws ProcessingException,
  -           SAXException,
  -           IOException
  -    {
  -      super.setup( resolver, objectModel, src, par );
  -      if (request == null)
  -      {
  -        getLogger().debug("no request object");
  -        throw new ProcessingException("no request object");
  -      }
  -
  -      // set the XMLForm namespace as the one
  -      // this transformer is interested to work on
  -      namespaceURI = NS;
  -
  -      // init tracking parameters
  -      formStack = new Stack();
  -      cannonicalRef = "";
  -      refStack = new Stack();
  -      currentTagDepth = 0;
  -      repeatTagDepth = -1;
  -      isRecording = false;
  -      nodeset = null;
  -  }
  +    public void setup(SourceResolver resolver, Map objectModel, String src,
  +                      Parameters par)
  +                        throws ProcessingException, SAXException,
  +                               IOException {
  +        super.setup(resolver, objectModel, src, par);
  +        if (request==null) {
  +            getLogger().debug("no request object");
  +            throw new ProcessingException("no request object");
  +        }
   
  +        // set the XMLForm namespace as the one
  +        // this transformer is interested to work on
  +        namespaceURI = NS;
  +
  +        // init tracking parameters
  +        formStack = new Stack();
  +        cannonicalRef = "";
  +        refStack = new Stack();
  +        currentTagDepth = 0;
  +        repeatTagDepth = -1;
  +        isRecording = false;
  +        nodeset = null;
  +    }
   
       /**
        *  Recycle this component.
        */
  -    public void recycle() 
  -    {
  -      // init tracking parameters
  -      formStack = null;
  -      cannonicalRef = null;
  -      refStack = null;
  -      currentTagDepth = 0;
  -      repeatTagDepth = -1;
  -      isRecording = false;
  -      nodeset = null;
  +    public void recycle() {
  +        // init tracking parameters
  +        formStack = null;
  +        cannonicalRef = null;
  +        refStack = null;
  +        currentTagDepth = 0;
  +        repeatTagDepth = -1;
  +        isRecording = false;
  +        nodeset = null;
   
  -      super.recycle();
  +        super.recycle();
       }
   
  -
       /**
        * Start processing elements of our namespace.
        * This hook is invoked for each sax event with our namespace.
        * @param uri The namespace of the element.
        * @param name The local name of the element.
        * @param raw The qualified name of the element.
  -     * @param attr The attributes of the element.
  +     * @param attributes 
        */
  -    public void startTransformingElement(String uri,
  -                                         String name,
  -                                         String raw,
  -                                         Attributes attributes )
  -    throws ProcessingException, IOException, SAXException
  -    {
  -      try
  -      {
  -        // avoid endless loop for elements in our namespace
  -        // when outputting the elements themselves
  -        this.ignoreHooksCount = 1;
  +    public void startTransformingElement(String uri, String name, String raw,
  +                                         Attributes attributes)
  +                                           throws ProcessingException,
  +                                               IOException, SAXException {
  +        try {
  +            // avoid endless loop for elements in our namespace
  +            // when outputting the elements themselves
  +            this.ignoreHooksCount = 1;
  +
  +            if (this.getLogger().isDebugEnabled()==true) {
  +                this.getLogger().debug("BEGIN startTransformingElement uri="+
  +                                       uri+", name="+name+", raw="+raw+
  +                                       ", attr="+attributes+")");
  +            }
  +
  +            // top level element in our namespace
  +            // set an xmlns:xf="XMLForm namespace..." attribute
  +            // to explicitely define the prefix to namespace binding
  +            if (currentTagDepth==0) {
  +                AttributesImpl atts;
  +
  +                if ((attributes==null) || (attributes.getLength()==0)) {
  +                    atts = new AttributesImpl();
  +                } else {
  +                    atts = new AttributesImpl(attributes);
  +                }
  +                // atts.addAttribute( null, NS_PREFIX, XMLNS_PREFIX + ":" + NS_PREFIX, "CDATA", NS);
  +                attributes = atts;
  +            }
  +
  +            // track the tree depth
  +            ++currentTagDepth;
  +
  +            // if within a repeat tag, keep recording
  +            // when recording, nothing is actively processed
  +            if (isRecording) {
  +                // just record the SAX event
  +                super.startElement(uri, name, raw, attributes);
  +            }
  +            // when a new repeat tag is discovered
  +            // start recording
  +            // the repeat will be unrolled after the repeat tag ends
  +            else if (TAG_REPEAT.equals(name)) {
  +                repeatTagDepth = currentTagDepth;
  +                isRecording = true;
  +
  +                // get the nodeset selector string
  +                nodeset = attributes.getValue(TAG_REPEAT_ATTR_NODESET);
  +
  +                if (nodeset==null) {
  +                    throw new SAXException(name+" element should provide a '"+
  +                                           TAG_REPEAT_ATTR_NODESET+
  +                                           "' attribute");
  +                }
  +
  +                // open the repeat tag in the output document
  +                super.startElement(uri, name, raw, attributes);
  +                // and start recording its content
  +                startRecording();
  +            }
  +            // when a new itemset tag (used within select) is discovered
  +            // start recording
  +            // the itemset will be unrolled after the tag ends
  +            // The difference with the repeat tag is that itemset is
  +            // unrolled in multiple item tags.
  +            else if (TAG_ITEMSET.equals(name)) {
  +                repeatTagDepth = currentTagDepth;
  +                isRecording = true;
  +
  +                // get the nodeset selector string
  +                nodeset = attributes.getValue(TAG_REPEAT_ATTR_NODESET);
  +
  +                if (nodeset==null) {
  +                    throw new SAXException(name+" element should provide a '"+
  +                                           TAG_REPEAT_ATTR_NODESET+
  +                                           "' attribute");
  +                }
  +
  +                // start recording its content
  +                startRecording();
  +            } else // if not a repeat tag
  +            {
  +                // if this tag has a "ref" attribute, then
  +                // add its value to the refStack
  +                String aref = attributes.getValue(TAG_COMMON_ATTR_REF);
  +
  +                if (aref!=null) {
  +                    // put on top of the ref stack the full ref
  +                    // append the new ref to the last stack top if not referencing the root
  +                    if ( !refStack.isEmpty()) {
  +                        // this is a nested reference
  +                        cannonicalRef = aref.startsWith("/")
  +                                        ? aref
  +                                        : (((Entry) refStack.peek()).getValue()+
  +                                           "/"+aref);
  +                    } else {
  +                        // top level reference
  +                        cannonicalRef = aref;
  +                    }
  +                    Entry entry = new Entry(new Integer(currentTagDepth),
  +                                            cannonicalRef);
  +
  +                    refStack.push(entry);
  +
  +                    // replace the ref attribute's value(path) with its full cannonical form
  +                    AttributesImpl atts = new AttributesImpl(attributes);
  +                    int refIdx = atts.getIndex(TAG_COMMON_ATTR_REF);
  +
  +                    atts.setValue(refIdx, cannonicalRef);
  +                    attributes = atts;
  +                }
  +
  +                // match tag name and apply transformation logic
  +                if (TAG_FORM.equals(name)) {
  +                    startElementForm(uri, name, raw, attributes);
  +                } else if (TAG_OUTPUT.equals(name)) {
  +                    startElementOutput(uri, name, raw, attributes);
  +                }  // end if TAG_OUTPUT
  +                    else if (TAG_INSERTVIOLATIONS.equals(name)) {
  +                    startElementViolations(uri, name, raw, attributes);
  +                }  // end if TAG_INSERTVIOLATIONS
  +                // if we're within a xf:hidden element
  +                // and a value sub-element has been provided
  +                // in the markup, then it will be left
  +                // unchanged. Otherwise we will
  +                // render the value of the referenced model
  +                // attribute
  +                else if (isHiddenTag && TAG_VALUE.equals(name)) {
  +                    hasHiddenTagValue = true;
  +                    super.startElement(uri, name, raw, attributes);
  +                }
  +                // if we are not within an enclosing form
  +                // then we can't process the following nested tags
  +                else if ( !formStack.isEmpty()) {
  +                    if (TAG_TEXTBOX.equals(name) ||
  +                        TAG_TEXTAREA.equals(name) ||
  +                        TAG_PASSWORD.equals(name) ||
  +                        TAG_SELECTBOOLEAN.equals(name) ||
  +                        TAG_SELECTONE.equals(name) ||
  +                        TAG_SELECTMANY.equals(name)) {
  +                        startElementInputField(uri, name, raw, attributes);
  +                    } else if (TAG_CAPTION.equals(name) ||
  +                               TAG_HINT.equals(name) ||
  +                               TAG_HELP.equals(name) ||
  +                               TAG_VALUE.equals(name)) {
  +                        startElementWithOptionalRefAndSimpleContent(uri,
  +                                                                    name,
  +                                                                    raw,
  +                                                                    attributes);
  +                    } else if (TAG_SUBMIT.equals(name)) {
  +                        String continuation = attributes.getValue("continuation");
  +
  +                        if (continuation!=null) {
  +                            WebContinuation kont = (WebContinuation) ((Environment) resolver).getAttribute("kont");
  +
  +                            if (kont!=null) {
  +                                int level = 0;
  +
  +                                if (continuation.equals("back")) {
  +                                    level = 3;
  +                                }
  +                                AttributesImpl impl = new AttributesImpl(attributes);
  +                                int index = impl.getIndex("id");
  +                                String id = impl.getValue(index);
  +                                String kId = kont.getContinuation(level).getId();
  +
  +                                id = kId+":"+id;
  +                                if (index>=0) {
  +                                    impl.setValue(index, id);
  +                                } else {
  +                                    impl.addAttribute("", "id", "id", "", id);
  +                                }
  +                                attributes = impl;
  +                            }
  +                        }
  +                        super.startElement(uri, name, raw, attributes);
  +                    } else if (TAG_CANCEL.equals(name) ||
  +                               TAG_RESET.equals(name) ||
  +                               TAG_ITEM.equals(name)) {
  +                        super.startElement(uri, name, raw, attributes);
  +                    } else if (TAG_HIDDEN.equals(name)) {
  +                        // raise the flag that we're within a hidden element
  +                        // since there are intricacies in
  +                        // handling the value sub-element
  +                        isHiddenTag = true;
  +                        startElementInputField(uri, name, raw, attributes);
  +                    } else {
  +                        getLogger().error("pass through element ["+
  +                                          String.valueOf(name)+"]");
  +                        super.startElement(uri, name, raw, attributes);
  +                    }
  +                }
  +            }      // end else (not a repeat tag)
  +        } finally {
  +            // reset ignore counter
  +            this.ignoreHooksCount = 0;
  +        }
   
  -        if (this.getLogger().isDebugEnabled() == true)
  -        {
  -            this.getLogger().debug("BEGIN startTransformingElement uri=" + uri + ", name=" + name + ", raw=" + raw + ", attr=" + attributes + ")");
  +        if (this.getLogger().isDebugEnabled()==true) {
  +            this.getLogger().debug("END startTransformingElement");
           }
  +    } // end of startTransformingElement
  +
  +    protected void startElementForm(String uri, String name, String raw,
  +                                    Attributes attributes)
  +                                      throws SAXException {
  +        String id = attributes.getValue(TAG_FORM_ATTR_ID);
  +
  +        // currently form elements cannot be nested
  +        if ( !formStack.isEmpty()) {
  +            String error = "Form nodes should not be nested ! Current form [id="+
  +                           formStack.peek()+"], nested form [id="+
  +                           String.valueOf(id)+"]";
  +
  +            getLogger().error(error);
  +            throw new IllegalStateException(error);
  +        }
  +
  +        super.startElement(uri, name, raw, attributes);
  +
  +        // load up the referenced form
  +        Form currentForm = Form.lookup(objectModel, id);
  +
  +        // if the form wasn't found, we're in trouble
  +        if (currentForm==null) {
  +            String error = "Form is null [id="+String.valueOf(id)+"]";
  +
  +            getLogger().error(error);
  +            throw new IllegalStateException(error);
  +        }
  +        ;
  +
  +        formStack.push(currentForm);
  +
  +        // memorize the current form view
  +        // it will be needed when saving expected references to properties
  +        currentFormView = attributes.getValue(TAG_FORM_ATTR_VIEW);
  +
  +        // clear previously saved form state for this view
  +        resetSavedModelReferences();
   
  -      // top level element in our namespace
  -      // set an xmlns:xf="XMLForm namespace..." attribute
  -      // to explicitely define the prefix to namespace binding
  -      if (currentTagDepth == 0)
  -      {
  -        AttributesImpl atts;
  -        if (attributes == null || attributes.getLength() == 0) {
  -            atts = new AttributesImpl();
  +    } // end of startElementForm
  +
  +    protected void startElementViolations(String uri, String name,
  +                                          String raw,
  +                                          Attributes attributes)
  +                                            throws SAXException {
  +
  +        // we will either use the locally referenced form id
  +        // or the global id. At least one of the two must be available
  +        Form form = null;
  +        String formAttr = attributes.getValue(TAG_OUTPUT_ATTR_FORM);
  +
  +        if (formAttr==null) {
  +            if (formStack.isEmpty()) {
  +                throw new SAXException("When used outside of a form tag, the output tag requires an '"+
  +                                       TAG_OUTPUT_ATTR_FORM+"' attribute");
  +            }
  +            form = (Form) formStack.peek();
           } else {
  -            atts = new AttributesImpl(attributes);
  +            form = Form.lookup(objectModel, formAttr);
           }
  -        //atts.addAttribute( null, NS_PREFIX, XMLNS_PREFIX + ":" + NS_PREFIX, "CDATA", NS);
  -        attributes = atts;
  -      }
  -
  -      // track the tree depth
  -      ++currentTagDepth;
  -
  -      // if within a repeat tag, keep recording
  -      // when recording, nothing is actively processed
  -      if (isRecording)
  -      {
  -        // just record the SAX event
  -        super.startElement( uri, name, raw, attributes);
  -      }
  -     // when a new repeat tag is discovered
  -     // start recording
  -     // the repeat will be unrolled after the repeat tag ends
  -     else if (TAG_REPEAT.equals( name ))
  -     {
  -       repeatTagDepth = currentTagDepth;
  -       isRecording = true;
  -
  -      // get the nodeset selector string
  -      nodeset = attributes.getValue(TAG_REPEAT_ATTR_NODESET);
  -
  -      if (nodeset == null)
  -      {
  -         throw new SAXException( name + " element should provide a '" + TAG_REPEAT_ATTR_NODESET + "' attribute" );
  -      }
  -
  -       // open the repeat tag in the output document
  -       super.startElement( uri, name, raw, attributes);
  -       // and start recording its content
  -       startRecording();
  -     }
  -     // when a new itemset tag (used within select) is discovered
  -     // start recording
  -     // the itemset will be unrolled after the tag ends
  -     // The difference with the repeat tag is that itemset is
  -     // unrolled in multiple item tags.
  -     else if ( TAG_ITEMSET.equals( name ) )
  -     {
  -       repeatTagDepth = currentTagDepth;
  -       isRecording = true;
  -
  -      // get the nodeset selector string
  -      nodeset = attributes.getValue(TAG_REPEAT_ATTR_NODESET);
  -
  -      if (nodeset == null)
  -      {
  -         throw new SAXException( name + " element should provide a '" + TAG_REPEAT_ATTR_NODESET + "' attribute" );
  -      }
  -
  -       // start recording its content
  -       startRecording();
  -     }
  -    else // if not a repeat tag
  -    {
  -        // if this tag has a "ref" attribute, then
  -        // add its value to the refStack
  -        String aref = attributes.getValue( TAG_COMMON_ATTR_REF );
  -        if ( aref != null )
  -        {
  -          // put on top of the ref stack the full ref
  -          // append the new ref to the last stack top if not referencing the root
  -          if ( !refStack.isEmpty() )
  -          {
  -          	// this is a nested reference 
  -  		      cannonicalRef = aref.startsWith ("/") ? aref : ( ((Entry) refStack.peek()).getValue() + "/" + aref );
  -          }
  -          else 
  -          {
  -            // top level reference
  -            cannonicalRef = aref;
  -          }
  -          Entry entry = new Entry( new Integer(currentTagDepth), cannonicalRef);
  -          refStack.push( entry );
  -
  -          // replace the ref attribute's value(path) with its full cannonical form
  -          AttributesImpl atts = new AttributesImpl( attributes );
  -          int refIdx = atts.getIndex ( TAG_COMMON_ATTR_REF );
  -          atts.setValue ( refIdx, cannonicalRef );
  -          attributes = atts;
  +
  +        SortedSet violations = form.getViolationsAsSortedSet();
  +
  +        // if there are no violations, there is nothing to show
  +        if (violations==null) {
  +            return;
           }
   
  -        // match tag name and apply transformation logic
  -        if (TAG_FORM.equals(name))
  -        {
  -          startElementForm( uri, name, raw, attributes );
  +        // if we're immediately under the form tag
  +        // and parent "ref" attribute is not available
  +        if (refStack.isEmpty()) {
  +            for (Iterator it = violations.iterator(); it.hasNext(); ) {
  +                Violation violation = (Violation) it.next();
  +
  +                // render <violation> tag
  +
  +                // set the ref attribute
  +                AttributesImpl atts;
  +
  +                if ((attributes==null) || (attributes.getLength()==0)) {
  +                    atts = new AttributesImpl();
  +                } else {
  +                    atts = new AttributesImpl(attributes);
  +                }
  +                // atts.addAttribute( NS, TAG_COMMON_ATTR_REF, NS_PREFIX + ":" + TAG_COMMON_ATTR_REF, "CDATA", violation.getPath());
  +                atts.addAttribute(null, TAG_COMMON_ATTR_REF,
  +                                  TAG_COMMON_ATTR_REF, "CDATA",
  +                                  violation.getPath());
  +
  +                // now start the element
  +                super.startElement(uri, TAG_VIOLATION,
  +                                   NS_PREFIX+":"+TAG_VIOLATION, atts);
  +
  +                // set message
  +                String vm = violation.getMessage();
  +
  +                super.characters(vm.toCharArray(), 0, vm.length());
  +
  +                super.endElement(uri, TAG_VIOLATION,
  +                                 NS_PREFIX+":"+TAG_VIOLATION);
  +            }
  +        } // end if (currentRef_ == null)
  +            else {
  +            Entry entry = (Entry) refStack.peek();
  +            String currentRef = (String) entry.getValue();
  +            Violation v = new Violation();
  +
  +            v.setPath(currentRef);
  +            Collection restViolations = violations.tailSet(v);
  +            Iterator rviter = restViolations.iterator();
  +
  +            while (rviter.hasNext()) {
  +                Violation nextViolation = (Violation) rviter.next();
  +
  +                // we're only interested in violations
  +                // with matching reference
  +                if ( !currentRef.equals(nextViolation.getPath())) {
  +                    break;
  +                }
  +
  +                // render <violation> tag
  +                super.startElement(uri, TAG_VIOLATION,
  +                                   NS_PREFIX+":"+TAG_VIOLATION, attributes);
  +                // set message
  +                String vm = nextViolation.getMessage();
  +
  +                super.characters(vm.toCharArray(), 0, vm.length());
  +                super.endElement(uri, TAG_VIOLATION,
  +                                 NS_PREFIX+":"+TAG_VIOLATION);
  +            }
           }
  -        else if ( TAG_OUTPUT.equals(name) )
  -        {
  -          startElementOutput( uri, name, raw, attributes );
  -        } // end if TAG_OUTPUT
  -        else if (TAG_INSERTVIOLATIONS.equals(name))
  -          {
  -            startElementViolations( uri, name, raw, attributes );
  -          } // end if TAG_INSERTVIOLATIONS
  -          
  -        // if we're within a xf:hidden element
  -        // and a value sub-element has been provided 
  -        // in the markup, then it will be left
  -        // unchanged. Otherwise we will 
  -        // render the value of the referenced model
  -        // attribute
  -        else if ( isHiddenTag && TAG_VALUE.equals( name ) )
  -        {
  -    			hasHiddenTagValue = true;
  -          super.startElement( uri, name, raw, attributes);
  +    }     // end of startElementViolations
  +
  +    /**
  +     * Since the ouput tag is the only one which can be used
  +     * outside of a form tag, it needs some special treatment
  +     */
  +    protected void startElementOutput(String uri, String name, String raw,
  +                                      Attributes attributes)
  +                                        throws SAXException {
  +
  +        // we will either use the locally referenced form id
  +        // or the global id. At least one of the two must be available
  +        Form form = null;
  +        String formAttr = attributes.getValue(TAG_OUTPUT_ATTR_FORM);
  +
  +        if (formAttr==null) {
  +            if (formStack.isEmpty()) {
  +                throw new SAXException("When used outside of a form tag, the output tag requires an '"+
  +                                       TAG_OUTPUT_ATTR_FORM+"' attribute");
  +            }
  +            form = (Form) formStack.peek();
  +        } else {
  +            form = Form.lookup(objectModel, formAttr);
           }
  -         
  -        // if we are not within an enclosing form
  -        // then we can't process the following nested tags
  -        else if (!formStack.isEmpty())
  -        {
  +        formStack.push(form);
   
  -          if (
  -                    TAG_TEXTBOX.equals(name) ||
  -                    TAG_TEXTAREA.equals(name) ||
  -                    TAG_PASSWORD.equals(name) ||
  -                    TAG_SELECTBOOLEAN.equals(name) ||
  -                    TAG_SELECTONE.equals(name) ||
  -                    TAG_SELECTMANY.equals(name)
  -             )
  -          {
  -            startElementInputField( uri, name, raw, attributes );
  -          }
  -          else if (
  -                    TAG_CAPTION.equals(name) ||
  -                    TAG_HINT.equals(name) ||
  -                    TAG_HELP.equals(name) ||
  -                    TAG_VALUE.equals(name) 
  -                   )
  -         {
  -           startElementWithOptionalRefAndSimpleContent( uri, name, raw, attributes );
  -         }
  -          else if (
  -		   TAG_SUBMIT.equals(name) )
  -	  {
  -	      String continuation = attributes.getValue("continuation");
  -	      if (continuation != null) {
  -		  WebContinuation kont
  -		      = (WebContinuation)((Environment)resolver).getAttribute("kont");
  -		  if (kont != null) {
  -		      int level = 0;
  -		      if (continuation.equals("back")) {
  -			  level = 3;
  -		      }
  -		      AttributesImpl impl = new AttributesImpl(attributes);
  -		      int index = impl.getIndex("id");
  -		      String id = impl.getValue(index);
  -		      String kId = kont.getContinuation(level).getId();
  -		      id = kId + ":"+id;
  -		      if (index >= 0) {
  -			  impl.setValue(index, id);
  -		      } else {
  -			  impl.addAttribute("", "id", "id", "", id);
  -		      }
  -		      attributes = impl;
  -		  }
  -	      } 
  -	      super.startElement(uri, name, raw, attributes);
  -	  }
  -          else if (
  -            TAG_CANCEL.equals(name) ||
  -            TAG_RESET.equals(name) ||
  -            TAG_ITEM.equals(name) 
  -            )
  -          {
  -            super.startElement(uri, name, raw, attributes);
  -          }
  -          else if (TAG_HIDDEN.equals(name))
  -          {
  -            // raise the flag that we're within a hidden element
  -            // since there are intricacies in 
  -            // handling the value sub-element
  -    			  isHiddenTag = true;
  -		    	  startElementInputField( uri, name, raw, attributes );
  -          }          
  -          else
  -          {
  -              getLogger().error("pass through element [" + String.valueOf(name) + "]");
  -              super.startElement(uri, name, raw, attributes);
  -          }
  +        startElementSimpleField(uri, name, raw, attributes);
  +
  +    } // end of startElementOutput
  +
  +    /**
  +     * Renders elements, which are used for input.
  +     *
  +     * TAG_TEXTBOX, TAG_TEXTAREA, TAG_PASSWORD, TAG_SELECTBOOLEAN,
  +     * TAG_SELECTONE, TAG_SELECTMANY
  +     */
  +    protected void startElementInputField(String uri, String name,
  +                                          String raw,
  +                                          Attributes attributes)
  +                                            throws SAXException {
  +        startElementSimpleField(uri, name, raw, attributes);
  +
  +        String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
  +
  +        if (ref==null) {
  +            throw new SAXException(name+" element should provide a '"+
  +                                   TAG_COMMON_ATTR_REF+"' attribute");
           }
  -      } // end else (not a repeat tag)
  -    }
  -    finally
  -    {
  -      // reset ignore counter
  -      this.ignoreHooksCount = 0;
  +        saveModelReferenceForFormView(ref, name);
       }
   
  +    protected void startElementSimpleField(String uri, String name,
  +                                           String raw,
  +                                           Attributes attributes)
  +                                             throws SAXException {
  +        String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
  +
  +        if (ref==null) {
  +            throw new SAXException(name+" element should provide a '"+
  +                                   TAG_COMMON_ATTR_REF+"' attribute");
  +        }
   
  -    if (this.getLogger().isDebugEnabled() == true)
  -    {
  -          this.getLogger().debug("END startTransformingElement");
  -    }
  -  } // end of startTransformingElement
  +        if (formStack.isEmpty()) {
  +            throw new SAXException(name+
  +                                   " element should be either nested within a form tag or provide a form attribute");
  +        }
   
  +        Form form = getCurrentForm();
   
  -  protected void startElementForm(String uri, String name, String raw, Attributes attributes) throws SAXException
  -  {
  -    String id = attributes.getValue(TAG_FORM_ATTR_ID);
  -
  -    // currently form elements cannot be nested
  -    if ( !formStack.isEmpty() )
  -    {
  -      String error = "Form nodes should not be nested ! Current form [id=" + formStack.peek() + "], nested form [id=" + String.valueOf(id) + "]";
  -      getLogger().error( error );
  -      throw new IllegalStateException( error );
  +        getLogger().debug("["+String.valueOf(name)+
  +                          "] getting value from form [id="+form.getId()+
  +                          ", ref="+String.valueOf(ref)+"]");
  +
  +        // retrieve current value of referenced property
  +        value_ = form.getValue(ref);
  +
  +        // we will only forward the SAX event once we know
  +        // that the value of the tag is available
  +        super.startElement(uri, name, raw, attributes);
  +
  +        getLogger().debug("Value of form [id="+form.getId()+", ref="+
  +                          String.valueOf(ref)+"] = ["+value_+"]");
  +
  +        // Only render value sub-elements
  +        // at this point
  +        // if this is not a xf:hidden element.
  +        if ( !isHiddenTag) {
  +            renderValueSubElements();
  +        }
  +    } // end of startElementSimpleField
  +
  +    /**
  +     * Let the form wrapper know that this reference should be expected
  +     * when data is submitted by the client for the current form view.
  +     * The name of the XML tag is also saved to help the form populator
  +     * find an appropriate default value when one is not provided in the http request.
  +     */
  +    protected void saveModelReferenceForFormView(String ref, String name) {
  +        // the xf:form/@view attribute is not mandatory
  +        // although it is strongly recommended
  +        if (currentFormView!=null) {
  +            Form form = getCurrentForm();
  +
  +            form.saveExpectedModelReferenceForView(currentFormView, ref,
  +                                                   name);
  +        }
       }
   
  -    super.startElement(uri, name, raw, attributes);
  +    /**
  +     * When the transformer starts rendering a new form element
  +     * It needs to reset previously saved references for another
  +     * transformation of the same view.
  +     */
  +    protected void resetSavedModelReferences() {
  +        if (currentFormView!=null) {
  +            Form form = getCurrentForm();
   
  -    // load up the referenced form
  -    Form currentForm =  Form.lookup( objectModel, id );
  -    
  -    // if the form wasn't found, we're in trouble
  -    if (currentForm == null)
  -    {
  -      String error = "Form is null [id=" + String.valueOf(id) + "]";
  -      getLogger().error( error );
  -      throw new IllegalStateException( error );
  -    };
  -    
  -    
  -    formStack.push( currentForm );
  -    
  -    // memorize the current form view
  -    // it will be needed when saving expected references to properties
  -    currentFormView = attributes.getValue(TAG_FORM_ATTR_VIEW);
  -    
  -    // clear previously saved form state for this view
  -    resetSavedModelReferences();
  -    
  -  } // end of startElementForm
  +            form.clearSavedModelReferences(currentFormView);
  +        }
   
  +    }
   
  +    /**
  +     * Used for elements which are not two directional.
  +     * They are displayed but cannot be used for submitting new values
  +     *
  +     * TAG_CAPTION, TAG_HINT, TAG_HELP, TAG_VALUE
  +     */
  +    protected void startElementWithOptionalRefAndSimpleContent(String uri,
  +        String name, String raw, Attributes attributes) throws SAXException {
  +        String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
   
  -  protected void startElementViolations(String uri, String name, String raw, Attributes attributes) throws SAXException
  -  {
  -
  -      // we will either use the locally referenced form id
  -      // or the global id. At least one of the two must be available
  -      Form form = null;
  -      String formAttr = attributes.getValue( TAG_OUTPUT_ATTR_FORM );
  -      if (formAttr == null)
  -      {
  -        if ( formStack.isEmpty() )
  +        if (ref==null) // ref attribute is not provided
           {
  -          throw new SAXException( "When used outside of a form tag, the output tag requires an '" + TAG_OUTPUT_ATTR_FORM + "' attribute" );
  +            super.startElement(uri, name, raw, attributes);
  +            return;
           }
  -        form = (Form) formStack.peek();
  -      }
  -      else
  -      {
  -        form = Form.lookup( objectModel, formAttr );
  -      }
  -
  -      SortedSet violations = form.getViolationsAsSortedSet();
  -
  -      // if there are no violations, there is nothing to show
  -      if (violations == null)  return;
  -
  -
  -      // if we're immediately under the form tag
  -      // and parent "ref" attribute is not available
  -      if ( refStack.isEmpty () )
  -      {
  -        for (Iterator it = violations.iterator(); it.hasNext();)
  -        {
  -          Violation violation = (Violation) it.next();
   
  -          // render <violation> tag
  +        if (formStack.isEmpty()) {
  +            throw new SAXException(name+
  +                                   " element should be either nested within a form tag or provide a form attribute");
  +        }
   
  -          // set the ref attribute
  -          AttributesImpl atts;
  -          if (attributes == null || attributes.getLength() == 0) {
  -              atts = new AttributesImpl();
  -          } else {
  -              atts = new AttributesImpl(attributes);
  -          }
  -          // atts.addAttribute( NS, TAG_COMMON_ATTR_REF, NS_PREFIX + ":" + TAG_COMMON_ATTR_REF, "CDATA", violation.getPath());
  -          atts.addAttribute( null, TAG_COMMON_ATTR_REF, TAG_COMMON_ATTR_REF, "CDATA", violation.getPath());
  -
  -          // now start the element
  -          super.startElement(uri, TAG_VIOLATION, NS_PREFIX + ":" + TAG_VIOLATION, atts);
  -
  -          // set message
  -          String vm = violation.getMessage();
  -          super.characters( vm.toCharArray(), 0, vm.length());
  -
  -          super.endElement(uri, TAG_VIOLATION, NS_PREFIX + ":" + TAG_VIOLATION);
  -        }
  -      } // end if (currentRef_ == null)
  -      else
  -      {
  -        Entry entry = (Entry) refStack.peek ();
  -        String currentRef = (String) entry.getValue ();
  -        Violation v = new Violation();
  -        v.setPath( currentRef );
  -        Collection restViolations = violations.tailSet ( v );
  -        Iterator rviter = restViolations.iterator ();
  -        while ( rviter.hasNext () )
  -        {
  -          Violation nextViolation = (Violation) rviter.next ();
  -          // we're only interested in violations
  -          // with matching reference
  -          if ( !currentRef.equals (nextViolation.getPath () ) ) break;
  -
  -          // render <violation> tag
  -          super.startElement(uri, TAG_VIOLATION, NS_PREFIX + ":" + TAG_VIOLATION, attributes );
  -          // set message
  -          String vm = nextViolation.getMessage();
  -          super.characters( vm.toCharArray(), 0, vm.length());
  -          super.endElement(uri, TAG_VIOLATION, NS_PREFIX + ":" + TAG_VIOLATION);
  -        }
  -      }
  -  } // end of startElementViolations
  +        Form form = (Form) formStack.peek();
   
  +        getLogger().debug("["+String.valueOf(name)+
  +                          "] getting value from form [id="+form.getId()+
  +                          ", ref="+String.valueOf(ref)+"]");
   
  +        Object value = form.getValue(ref);
   
  -  /**
  -   * Since the ouput tag is the only one which can be used
  -   * outside of a form tag, it needs some special treatment
  -   *
  -   */
  -  protected void startElementOutput(String uri, String name, String raw, Attributes attributes)
  -    throws SAXException
  -  {
  +        // we will only forward the SAX event once we know
  +        // that the value of the tag is available
  +        super.startElement(uri, name, raw, attributes);
   
  -        // we will either use the locally referenced form id
  -        // or the global id. At least one of the two must be available
  -        Form form = null;
  -        String formAttr = attributes.getValue( TAG_OUTPUT_ATTR_FORM );
  -        if (formAttr == null)
  -        {
  -          if ( formStack.isEmpty() )
  -          {
  -            throw new SAXException( "When used outside of a form tag, the output tag requires an '" + TAG_OUTPUT_ATTR_FORM + "' attribute" );
  -          }
  -          form = (Form) formStack.peek();
  -        }
  -        else
  -        {
  -          form = Form.lookup( objectModel, formAttr );
  -        }
  -        formStack.push( form );
  +        getLogger().debug("Value of form [id="+form.getId()+", ref="+
  +                          String.valueOf(ref)+"] = ["+value_+"]");
   
  -        startElementSimpleField( uri, name, raw, attributes );
  +        // Now render the character data inside the tag
  +        String v = String.valueOf(value);
   
  -  } // end of startElementOutput
  +        super.characters(v.toCharArray(), 0, v.length());
   
  +    } // end of startElementSimpleFieldWithOptionalRef
   
  -  /**
  -   * 
  -   * Renders elements, which are used for input
  -   * 
  -   * TAG_TEXTBOX, TAG_TEXTAREA, TAG_PASSWORD, TAG_SELECTBOOLEAN, 
  -   * TAG_SELECTONE, TAG_SELECTMANY
  -   * 
  -   */
  -  protected void startElementInputField(String uri, String name, String raw, Attributes attributes )
  -    throws SAXException
  -  {
  -    startElementSimpleField( uri, name, raw, attributes );
  -    
  -    String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
  -    if (ref == null)
  -    {
  -       throw new SAXException( name + " element should provide a '" + TAG_COMMON_ATTR_REF + "' attribute" );
  -    }
  -    saveModelReferenceForFormView( ref, name );
  -  }
  - 
  -
  -  protected void startElementSimpleField(String uri, String name, String raw, Attributes attributes )
  -    throws SAXException
  -  {
  -      String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
  -
  -      if (ref == null)
  -      {
  -         throw new SAXException( name + " element should provide a '" + TAG_COMMON_ATTR_REF + "' attribute" );
  -      }
  -
  -      if ( formStack.isEmpty() )
  -      {
  -         throw new SAXException( name + " element should be either nested within a form tag or provide a form attribute" );
  -      }
  -
  -      Form form = getCurrentForm();
  -
  -      getLogger().debug("[" + String.valueOf( name ) + "] getting value from form [id=" + form.getId() + ", ref=" + String.valueOf(ref) + "]");
  -
  -      // retrieve current value of referenced property
  -      value_ = form.getValue( ref );
  -
  -      // we will only forward the SAX event once we know
  -      // that the value of the tag is available
  -      super.startElement(uri, name, raw, attributes);
  -
  -      getLogger().debug("Value of form [id=" + form.getId() + ", ref=" + String.valueOf(ref) + "] = [" + value_ + "]") ;
  -
  -  	  // Only render value sub-elements
  -      // at this point
  -      // if this is not a xf:hidden element.
  -	    if( !isHiddenTag ) renderValueSubElements();
  -     } // end of startElementSimpleField
  -
  -
  -  /**
  -   * Let the form wrapper know that this reference should be expected
  -   * when data is submitted by the client for the current form view.
  -   * The name of the XML tag is also saved to help the form populator 
  -   * find an appropriate default value when one is not provided in the http request.
  -   */
  -  protected void saveModelReferenceForFormView( String ref, String name )
  -  {
  -    // the xf:form/@view attribute is not mandatory
  -    // although it is strongly recommended
  -    if (currentFormView != null)
  -      {
  -      Form form = getCurrentForm();
  -      form.saveExpectedModelReferenceForView( currentFormView, ref, name );
  -      }
  -  }
  -
  -  /**
  -   * When the transformer starts rendering a new form element
  -   * It needs to reset previously saved references for another 
  -   * transformation of the same view.
  -   */  
  -  protected void resetSavedModelReferences()
  -  {
  -    if ( currentFormView != null ) 
  -    {
  -      Form form = getCurrentForm();
  -      form.clearSavedModelReferences( currentFormView );
  +    /**
  +     * Renders one or more xf:value elements
  +     * depending on whether _value is a
  +     * collection, array or not.
  +     */
  +    private void renderValueSubElements() throws SAXException {
  +        // render the value subelement(s)
  +        if (value_ instanceof Collection) {
  +            Iterator i = ((Collection) value_).iterator();
  +
  +            while (i.hasNext()) {
  +                renderValueSubElement(i.next());
  +            }
  +        } else if ((value_!=null) && value_.getClass().isArray()) {
  +            int len = Array.getLength(value_);
  +
  +            for (int i = 0; i<len; i++) {
  +                renderValueSubElement(Array.get(value_, i));
  +            }
  +        } else {
  +            renderValueSubElement(value_);
  +        }
       }
  -    
  -  }
   
  -  /**
  -   * Used for elements which are not two directional.
  -   * They are displayed but cannot be used for submitting new values 
  -   * 
  -   * TAG_CAPTION, TAG_HINT, TAG_HELP, TAG_VALUE
  -   * 
  -   */
  -  protected void startElementWithOptionalRefAndSimpleContent(String uri, String name, String raw, Attributes attributes )
  -    throws SAXException
  -  {
  -      String ref = attributes.getValue(TAG_COMMON_ATTR_REF);
  -
  -      if (ref == null) // ref attribute is not provided
  -      {
  -         super.startElement( uri, name, raw, attributes );
  -         return;
  -      }
  -
  -      if ( formStack.isEmpty() )
  -      {
  -         throw new SAXException( name + " element should be either nested within a form tag or provide a form attribute" );
  -      }
  -
  -      Form form = (Form) formStack.peek();
  -
  -      getLogger().debug("[" + String.valueOf( name ) + "] getting value from form [id=" + form.getId() + ", ref=" + String.valueOf(ref) + "]");
  -
  -      Object value = form.getValue( ref );
  -
  -      // we will only forward the SAX event once we know
  -      // that the value of the tag is available
  -      super.startElement(uri, name, raw, attributes);
  -
  -      getLogger().debug("Value of form [id=" + form.getId() + ", ref=" + String.valueOf(ref) + "] = [" + value_ + "]") ;
  -
  -      // Now render the character data inside the tag
  -      String v = String.valueOf( value );
  -      super.characters(v.toCharArray(),0,v.length());      
  -    
  -  } // end of startElementSimpleFieldWithOptionalRef
  - 
  +    /**
  +     * Outputs a <xf:value> element.
  +     * Used when transforming XMLForm elements
  +     * with reference to the model
  +     *
  +     * @param vobj provides the text content
  +     * within the <xf:value> element
  +     */
  +    protected void renderValueSubElement(Object vobj) throws SAXException {
  +        super.startElement(NS, "value", NS_PREFIX+":"+"value", NOATTR);
  +        if (vobj!=null) {
  +            String v = String.valueOf(vobj);
   
  -	/**
  -	 * Renders one or more xf:value elements 
  -     * depending on whether _value is a
  -	 * collection, array or not.
  -	 *
  -	 * @throws SAXException
  -	 */
  -	private void renderValueSubElements() throws SAXException
  -	{
  -		// render the value subelement(s)
  -		if (value_ instanceof Collection)
  -		{
  -		  Iterator i=((Collection) value_).iterator();
  -		  while (i.hasNext())
  -		  {
  -			renderValueSubElement( i.next() );
  -		  }
  -		}
  -		else if ( value_ != null && value_.getClass().isArray () )
  -		{
  -		  int len = Array.getLength ( value_ );
  -		  for (int i = 0; i < len; i++ )
  -		  {
  -			renderValueSubElement( Array.get ( value_, i ) );
  -		  }
  -		}
  -		else
  -		{
  -		  renderValueSubElement( value_ );
  -		}
  -	}
  -
  - 
  -  
  -  
  -  /**
  -   * Outputs a <xf:value> element.
  -   * Used when transforming XMLForm elements
  -   * with reference to the model
  -   *
  -   * @param vobj provides the text content
  -   * within the <xf:value> element
  -   *
  -   */
  -  protected void renderValueSubElement( Object vobj )
  -    throws SAXException
  -  {
  -    super.startElement( NS, "value", NS_PREFIX + ":" + "value", NOATTR);
  -      if (vobj != null)
  -      {
  -        String v = String.valueOf( vobj );
  -        super.characters(v.toCharArray(),0,v.length());
  -      }
  -      super.endElement( NS, "value", NS_PREFIX + ":" + "value" );
  -  }
  +            super.characters(v.toCharArray(), 0, v.length());
  +        }
  +        super.endElement(NS, "value", NS_PREFIX+":"+"value");
  +    }
   
       /**
        * Start processing elements of our namespace.
  @@ -934,300 +896,270 @@
        * @param name The local name of the element.
        * @param raw The qualified name of the element.
        */
  -    public void endTransformingElement(
  -         String uri,
  -         String name,
  -         String raw)
  -    throws ProcessingException, IOException, SAXException
  -  {
  -    if (this.getLogger().isDebugEnabled() == true)
  -    {
  -        this.getLogger().debug("BEGIN endTransformingElement uri=" + uri + ", name=" + name + ", raw=" + raw + ")");
  -    }
  -
  -
  -    try
  -    {
  -        // avoid endless loop for elements in our namespace
  -        this.ignoreHooksCount = 1;
  -
  -
  -     // when the end of an active repeat tag is reached
  -     // stop recording, unroll the repeat tag content
  -     // for each node in the node set,
  -     // then close the repeat tag
  -     if ( (TAG_REPEAT.equals( name ) ) 
  -          && (repeatTagDepth == currentTagDepth))
  -     {
  -       isRecording = false;
  -       DocumentFragment docFragment = endRecording();
  -       unrollRepeatTag( docFragment );
  -       nodeset = null;
  -       // close the repeat tag
  -       super.endElement(uri, name, raw);
  -     }
  -     // similarly for an itemset tag
  -     else if ( (TAG_ITEMSET.equals( name )) 
  -          && (repeatTagDepth == currentTagDepth))
  -     {
  -       isRecording = false;
  -       DocumentFragment docFragment = endRecording();
  -       unrollItemSetTag( docFragment );
  -       nodeset = null;
  -     }
  -      // if within a repeat tag, keep recording
  -      // when recording, nothing is actively processed
  -     else  if (isRecording)
  -     {
  -        // just record the SAX event
  -        super.endElement(uri, name, raw);
  -     }
  -    else // if not a repeat tag
  -    {
  -
  -        // keep the ref stack in synch with the tree navigation
  -        if ( !refStack.isEmpty () )
  -        {
  -          Entry entry = (Entry) refStack.peek();
  -          Integer refDepth = (Integer) entry.getKey ();
  -          if ( currentTagDepth <= refDepth.intValue () )
  -          {
  -            refStack.pop();
  -            cannonicalRef = refStack.isEmpty () ? "" : (String)( (Entry) (refStack.peek ()) ).getValue();
  -          }
  +    public void endTransformingElement(String uri, String name,
  +                                       String raw)
  +                                         throws ProcessingException,
  +                                                IOException, SAXException {
  +        if (this.getLogger().isDebugEnabled()==true) {
  +            this.getLogger().debug("BEGIN endTransformingElement uri="+uri+
  +                                   ", name="+name+", raw="+raw+")");
           }
   
  +        try {
  +            // avoid endless loop for elements in our namespace
  +            this.ignoreHooksCount = 1;
  +
  +            // when the end of an active repeat tag is reached
  +            // stop recording, unroll the repeat tag content
  +            // for each node in the node set,
  +            // then close the repeat tag
  +            if ((TAG_REPEAT.equals(name)) &&
  +                (repeatTagDepth==currentTagDepth)) {
  +                isRecording = false;
  +                DocumentFragment docFragment = endRecording();
  +
  +                unrollRepeatTag(docFragment);
  +                nodeset = null;
  +                // close the repeat tag
  +                super.endElement(uri, name, raw);
  +            }
  +            // similarly for an itemset tag
  +            else if ((TAG_ITEMSET.equals(name)) &&
  +                     (repeatTagDepth==currentTagDepth)) {
  +                isRecording = false;
  +                DocumentFragment docFragment = endRecording();
  +
  +                unrollItemSetTag(docFragment);
  +                nodeset = null;
  +            }
  +            // if within a repeat tag, keep recording
  +            // when recording, nothing is actively processed
  +            else if (isRecording) {
  +                // just record the SAX event
  +                super.endElement(uri, name, raw);
  +            } else // if not a repeat tag
  +            {
  +                // keep the ref stack in synch with the tree navigation
  +                if ( !refStack.isEmpty()) {
  +                    Entry entry = (Entry) refStack.peek();
  +                    Integer refDepth = (Integer) entry.getKey();
  +
  +                    if (currentTagDepth<=refDepth.intValue()) {
  +                        refStack.pop();
  +                        cannonicalRef = refStack.isEmpty()
  +                                        ? ""
  +                                        : (String) ((Entry) (refStack.peek())).getValue();
  +                    }
  +                }
  +
  +                if (TAG_INSERTVIOLATIONS.equals(name)) {
  +                    // all violations were rendered completely in the startElement method
  +                } else if (TAG_FORM.equals(name)) {
  +                    // pop currentForm from stack since we're getting out of its scope
  +                    formStack.pop();
  +                    super.endElement(uri, name, raw);
  +                } else if (TAG_TEXTBOX.equals(name) ||
  +                           TAG_TEXTAREA.equals(name) ||
  +                           TAG_PASSWORD.equals(name) ||
  +                           TAG_SELECTBOOLEAN.equals(name) ||
  +                           TAG_SELECTONE.equals(name) ||
  +                           TAG_SELECTMANY.equals(name) ||
  +                           TAG_SUBMIT.equals(name) ||
  +                           TAG_CAPTION.equals(name) ||
  +                           TAG_VALUE.equals(name) || TAG_HINT.equals(name) ||
  +                           TAG_HELP.equals(name)) {
  +                    super.endElement(uri, name, raw);
  +                } else if (TAG_OUTPUT.equals(name)) {
  +                    formStack.pop();
  +                    super.endElement(uri, name, raw);
  +                } else if (TAG_HIDDEN.equals(name)) {
  +                    isHiddenTag = false;
  +                    hasHiddenTagValue = false;
  +                    // if value sub-element was not
  +                    // provided in the markup
  +                    // then render the value of the referenced
  +                    // model attribute, like normally done
  +                    // for other elements
  +                    if ( !hasHiddenTagValue) {
  +                        renderValueSubElements();
  +                    }
  +                    super.endElement(uri, name, raw);
  +                } else {
  +                    getLogger().error("unknown element ["+
  +                                      String.valueOf(name)+"]");
  +                    super.endElement(uri, name, raw);
  +                }
  +            }      // else (not in a recording tag)
  +        } finally {
  +            // reset ignore hooks counter
  +            this.ignoreHooksCount = 0;
   
  -        if (TAG_INSERTVIOLATIONS.equals(name))
  -        {
  -          // all violations were rendered completely in the startElement method
  -        }
  -        else if (TAG_FORM.equals(name))
  -        {
  -          // pop currentForm from stack since we're getting out of its scope
  -          formStack.pop();
  -          super.endElement(uri, name, raw);
  -        }
  -        else if (
  -                TAG_TEXTBOX.equals(name) ||
  -                TAG_TEXTAREA.equals(name) ||
  -                TAG_PASSWORD.equals(name) ||
  -                TAG_SELECTBOOLEAN.equals(name) ||
  -                TAG_SELECTONE.equals(name) ||
  -                TAG_SELECTMANY.equals(name) ||
  -                TAG_SUBMIT.equals(name) ||
  -                TAG_CAPTION.equals( name ) ||
  -                TAG_VALUE.equals( name ) ||
  -                TAG_HINT.equals( name ) ||
  -                TAG_HELP.equals( name ) 
  -                )
  -        { 
  -          super.endElement(uri, name, raw);
  -        }
  -        else if ( TAG_OUTPUT.equals(name) )
  -        {
  -          formStack.pop();
  -          super.endElement(uri, name, raw);
  +            // track the tree depth
  +            --currentTagDepth;
           }
  -        
  -        else if (TAG_HIDDEN.equals(name))
  -        {
  -    			isHiddenTag = false;
  -    			hasHiddenTagValue = false;
  -          // if value sub-element was not 
  -          // provided in the markup
  -          // then render the value of the referenced
  -          // model attribute, like normally done
  -          // for other elements
  -          if(! hasHiddenTagValue)
  -    			{
  -    				renderValueSubElements();
  -    			}
  -            super.endElement(uri, name, raw);
  -         }
  -        else
  -        {
  -          getLogger().error("unknown element [" + String.valueOf(name) + "]");
  -          super.endElement(uri, name, raw);
  +
  +        if (this.getLogger().isDebugEnabled()==true) {
  +            this.getLogger().debug("END endTransformingElement");
           }
  -      } // else (not in a recording tag)
  -    }
  -    finally
  -    {
  -      // reset ignore hooks counter
  -      this.ignoreHooksCount = 0;
   
  -      // track the tree depth
  -      --currentTagDepth;
  -    }
  +    } // end of endTransformingElement
   
  -    if (this.getLogger().isDebugEnabled() == true)
  -    {
  -      this.getLogger().debug("END endTransformingElement");
  -    }
  +    /**
  +     * Unroll the repeat tag.
  +     * For each node in the repeat tag's nodeset selector result,
  +     * render a <code>group</code> tag with a <code>ref</code>
  +     * attribute which points to the location of the current node
  +     * in the nodeset. Within each <code>group</code> tag,
  +     * output the content of the repeat tag,
  +     * by resolving all form model references within nested xmlform tags,
  +     * relative to the <code>ref</code> attribute of the <code>group</code> element.
  +     *
  +     * @param docFragment the content of the repeat tag
  +     */
  +    protected void unrollRepeatTag(DocumentFragment docFragment)
  +      throws SAXException {
  +        int oldIgnoreHooksCount = ignoreHooksCount;
  +
  +        try {
  +            // reset ignore hooks counter
  +            this.ignoreHooksCount = 0;
  +            Form currentForm = (Form) formStack.peek();
  +            Collection locations = currentForm.locate(nodeset);
  +            Iterator iter = locations.iterator();
  +
  +            // iterate over each node in the nodeset
  +            while (iter.hasNext()) {
  +                String nextNodeLocation = (String) iter.next();
  +
  +                // set the ref attribute to point to the current node
  +                AttributesImpl atts = new AttributesImpl();
  +
  +                atts.addAttribute(null, TAG_COMMON_ATTR_REF,
  +                                  TAG_COMMON_ATTR_REF, "CDATA",
  +                                  nextNodeLocation);
  +
  +                super.startElement(NS, TAG_GROUP, NS_PREFIX+":"+TAG_GROUP,
  +                                   atts);
  +                if (value_!=null) {
  +                    // stream back the recorder repeat content
  +                    DOMStreamer streamer = new DOMStreamer(this, this);
  +
  +                    streamer.stream(docFragment);
  +                }
  +
  +                super.endElement(NS, TAG_GROUP, NS_PREFIX+":"+TAG_GROUP);
  +
  +            }
  +        } finally {
  +            ignoreHooksCount = oldIgnoreHooksCount;
  +        }
  +    } // unrollRepeatTag
   
  -  } // end of endTransformingElement
  +    /**
  +     * Unroll the itemset tag.
  +     * For each node in the itemset tag's nodeset selector result,
  +     * render a <code>item</code> tag with a <code>ref</code>
  +     * attribute which points to the location of the current node
  +     * in the nodeset.
  +     * Within each <code>item</code> tag,
  +     * output the content of the itemset tag,
  +     * by resolving all model references within nested caption and value tags,
  +     * relative to the <code>ref</code> attribute of the <code>item</code> element.
  +     *
  +     * @param docFragment the content of the repeat tag
  +     */
  +    protected void unrollItemSetTag(DocumentFragment docFragment)
  +      throws SAXException {
  +        int oldIgnoreHooksCount = ignoreHooksCount;
   
  +        try {
  +            // reset ignore hooks counter
  +            this.ignoreHooksCount = 0;
   
  -  /**
  -   * Unroll the repeat tag.
  -   * For each node in the repeat tag's nodeset selector result,
  -   * render a <code>group</code> tag with a <code>ref</code>
  -   * attribute which points to the location of the current node
  -   * in the nodeset. Within each <code>group</code> tag,
  -   * output the content of the repeat tag,
  -   * by resolving all form model references within nested xmlform tags,
  -   * relative to the <code>ref</code> attribute of the <code>group</code> element.
  -   *
  -   * @param docFragment the content of the repeat tag
  -   * @param nodeset the nodeset selector string
  -   */
  -  protected void unrollRepeatTag( DocumentFragment docFragment )
  -    throws SAXException
  -  {
  -    int oldIgnoreHooksCount = ignoreHooksCount;
  -    try
  -    {
  -      // reset ignore hooks counter
  -      this.ignoreHooksCount = 0;
  -      Form currentForm = (Form) formStack.peek();
  -      Collection locations = currentForm.locate( nodeset );
  -      Iterator iter = locations.iterator();
  -      // iterate over each node in the nodeset
  -      while ( iter.hasNext() )
  -      {
  -        String nextNodeLocation = (String) iter.next ();
  -
  -        // set the ref attribute to point to the current node
  -        AttributesImpl atts = new AttributesImpl();
  -        atts.addAttribute( null, TAG_COMMON_ATTR_REF, TAG_COMMON_ATTR_REF, "CDATA", nextNodeLocation);
  +            Form currentForm = (Form) formStack.peek();
   
  -        super.startElement(NS, TAG_GROUP, NS_PREFIX + ":" + TAG_GROUP, atts);
  -        if (value_ != null)
  -        {
  -          // stream back the recorder repeat content
  -          DOMStreamer streamer = new DOMStreamer( this, this);
  -          streamer.stream( docFragment );
  -        }
  +            Collection locations = currentForm.locate(nodeset);
  +            Iterator iter = locations.iterator();
   
  -        super.endElement( NS, TAG_GROUP, NS_PREFIX + ":" + TAG_GROUP );
  +            // iterate over each node in the nodeset
  +            while (iter.hasNext()) {
  +                String nextNodeLocation = (String) iter.next();
   
  -      }
  -    }
  -    finally
  -    {
  -      ignoreHooksCount = oldIgnoreHooksCount;
  -    }
  -  } // unrollRepeatTag
  +                // set the ref attribute to point to the current node
  +                AttributesImpl atts = new AttributesImpl();
   
  +                atts.addAttribute(null, TAG_COMMON_ATTR_REF,
  +                                  TAG_COMMON_ATTR_REF, "CDATA",
  +                                  nextNodeLocation);
   
  +                super.startElement(NS, TAG_ITEM, NS_PREFIX+":"+TAG_ITEM,
  +                                   atts);
  +                if (value_!=null) {
  +                    // stream back the recorder repeat content
  +                    DOMStreamer streamer = new DOMStreamer(this, this);
   
  +                    streamer.stream(docFragment);
  +                }
   
  -  /**
  -   * Unroll the itemset tag.
  -   * For each node in the itemset tag's nodeset selector result,
  -   * render a <code>item</code> tag with a <code>ref</code>
  -   * attribute which points to the location of the current node
  -   * in the nodeset.
  -   * Within each <code>item</code> tag,
  -   * output the content of the itemset tag,
  -   * by resolving all model references within nested caption and value tags,
  -   * relative to the <code>ref</code> attribute of the <code>item</code> element.
  -   *
  -   * @param docFragment the content of the repeat tag
  -   * @param nodeset the nodeset selector string
  -   */
  -  protected void unrollItemSetTag( DocumentFragment docFragment )
  -    throws SAXException
  -  {
  -    int oldIgnoreHooksCount = ignoreHooksCount;
  -    try
  -    {
  -      // reset ignore hooks counter
  -      this.ignoreHooksCount = 0;
  -
  -      Form currentForm = (Form) formStack.peek();
  -
  -      Collection locations = currentForm.locate( nodeset );
  -      Iterator iter = locations.iterator();
  -      // iterate over each node in the nodeset
  -      while ( iter.hasNext() )
  -      {
  -        String nextNodeLocation = (String) iter.next ();
  -
  -        // set the ref attribute to point to the current node
  -        AttributesImpl atts = new AttributesImpl();
  -        atts.addAttribute( null, TAG_COMMON_ATTR_REF, TAG_COMMON_ATTR_REF, "CDATA", nextNodeLocation);
  +                super.endElement(NS, TAG_ITEM, NS_PREFIX+":"+TAG_ITEM);
   
  -        super.startElement(NS, TAG_ITEM, NS_PREFIX + ":" + TAG_ITEM, atts);
  -        if (value_ != null)
  -        {
  -          // stream back the recorder repeat content
  -          DOMStreamer streamer = new DOMStreamer( this, this);
  -          streamer.stream( docFragment );
  +            }
  +        } finally {
  +            ignoreHooksCount = oldIgnoreHooksCount;
           }
  +    } // unrollItemSetTag
   
  -        super.endElement( NS, TAG_ITEM, NS_PREFIX + ":" + TAG_ITEM );
  -
  -      }
  -    }
  -    finally
  -    {
  -      ignoreHooksCount = oldIgnoreHooksCount;
  +    protected Form getCurrentForm() {
  +        return (Form) formStack.peek();
       }
  -  } // unrollItemSetTag
  -
  -
  -  protected Form getCurrentForm()
  -  {
  -    return (Form) formStack.peek();    
  -  }
  -
   
       /**
        * refStack entry.
        */
  -  private static class Entry implements Map.Entry {
  -    Object key;
  -    Object value;
  -
  -    Entry(Object key, Object value) {
  -        this.key = key;
  -        this.value = value;
  -    }
  +    private static class Entry implements Map.Entry {
   
  -    // Map.Entry Ops
  +        Object key;
   
  -    public Object getKey() {
  -        return key;
  -    }
  +        Object value;
   
  -    public Object getValue() {
  -        return value;
  -    }
  +        Entry(Object key, Object value) {
  +            this.key = key;
  +            this.value = value;
  +        }
   
  -    public Object setValue(Object value) {
  -        Object oldValue = this.value;
  -        this.value = value;
  -        return oldValue;
  -    }
  +        // Map.Entry Ops
  +        public Object getKey() {
  +            return key;
  +        }
   
  -    public boolean equals(Object o) {
  -        if (!(o instanceof Map.Entry))
  -        return false;
  -        Map.Entry e = (Map.Entry)o;
  +        public Object getValue() {
  +            return value;
  +        }
   
  -        return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
  -           (value==null ? e.getValue()==null : value.equals(e.getValue()));
  -    }
  +        public Object setValue(Object value) {
  +            Object oldValue = this.value;
   
  -    public int hashCode() {
  -        return getKey().hashCode () ^ (value==null ? 0 : value.hashCode());
  -    }
  +            this.value = value;
  +            return oldValue;
  +        }
   
  -    public String toString() {
  -        return key+"="+value;
  -    }
  -}
  +        public boolean equals(Object o) {
  +            if ( !(o instanceof Map.Entry)) {
  +                return false;
  +            }
  +            Map.Entry e = (Map.Entry) o;
  +
  +            return ((key==null) ? e.getKey()==null : key.equals(e.getKey())) &&
  +                   ((value==null)
  +                    ? e.getValue()==null : value.equals(e.getValue()));
  +        }
  +
  +        public int hashCode() {
  +            return getKey().hashCode()^((value==null) ? 0 : value.hashCode());
  +        }
   
  +        public String toString() {
  +            return key+"="+value;
  +        }
  +    }
   }