ivelin      2002/10/27 00:23:18

  Modified:    src/java/org/apache/cocoon/components/xmlform Form.java
  Log:
  Implement automated population with default values of unchecked check-boxes
  
  Revision  Changes    Path
  1.12      +235 -48   
xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/Form.java
  
  Index: Form.java
  ===================================================================
  RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/xmlform/Form.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- Form.java 5 Oct 2002 16:32:00 -0000       1.11
  +++ Form.java 27 Oct 2002 07:23:18 -0000      1.12
  @@ -62,35 +62,32 @@
   
   package org.apache.cocoon.components.xmlform;
   
  +import java.util.ArrayList;
   import java.util.Collection;
  +import java.util.Collections;
   import java.util.Enumeration;
  -import java.util.SortedSet;
  -import java.util.Set;
  +import java.util.HashMap;
   import java.util.HashSet;
  -import java.util.TreeSet;
  -import java.util.List;
  -import java.util.LinkedList;
  -import java.util.ArrayList;
   import java.util.Iterator;
  +import java.util.LinkedList;
  +import java.util.List;
   import java.util.Map;
  -import java.util.Collections;
  -
  -import org.apache.commons.jxpath.JXPathContext;
  -import org.apache.commons.jxpath.Pointer;
  -import org.apache.commons.jxpath.JXPathException;
  -//import org.apache.commons.jxpath.ri.model.dom.DOMAttributePointer;
  +import java.util.Set;
  +import java.util.SortedSet;
  +import java.util.TreeSet;
   
   import org.apache.cocoon.Constants;
  +import org.apache.cocoon.components.validation.Validator;
  +import org.apache.cocoon.components.validation.Violation;
   import org.apache.cocoon.environment.ObjectModelHelper;
   import org.apache.cocoon.environment.Request;
   import org.apache.cocoon.environment.Session;
  -import org.apache.cocoon.environment.Session;
  -import org.apache.cocoon.components.validation.Validator;
  -import org.apache.cocoon.components.validation.Violation;
  -
  -import org.w3c.dom.*;
  -import javax.xml.parsers.*;
  -import javax.xml.transform.*;
  +import org.apache.cocoon.transformation.XMLFormTransformer;
  +import org.apache.commons.jxpath.JXPathContext;
  +import org.apache.commons.jxpath.JXPathException;
  +import org.apache.commons.jxpath.Pointer;
  +import org.w3c.dom.Element;
  +import org.w3c.dom.Text;
   
   /**
    * <p>
  @@ -401,7 +398,7 @@
      *  radio button, text area, file upload, etc.
      * </p>
      */
  -    public void populate( Map objectModel )
  +    public void populate( Map sitemapObjectModel )
         {
           // clean violations_ set
           clearViolations();
  @@ -418,18 +415,19 @@
           // while the request parameter name points to an int attribute
           List pviolations = new ArrayList();
   
  -        Request request = getRequest( objectModel );
  -
  -        Enumeration enum = request.getParameterNames ();
  -        while (enum.hasMoreElements ())
  -          {
  -            String path = (String) enum.nextElement ();
  +        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 = request.getParameterValues ( path );
  +            Object[] values = (Object[]) entry.getValue();
   
               try
               {
  @@ -439,13 +437,14 @@
               {
                 Violation v = new Violation();
                 v.setPath( path );
  -              v.setMessage( VIOLATION_MESSAGE_DATA_FORMAT_ERROR );
  +              String message = VIOLATION_MESSAGE_DATA_FORMAT_ERROR;
  +              v.setMessage( message );
                 pviolations.add( v );
               }
            } // while
         
          // validate form model
  -      autoValidate( objectModel );
  +      autoValidate( sitemapObjectModel );
         
         // merge violation sets
         if ( violations_ != null)
  @@ -464,6 +463,81 @@
       }
   
   
  +    /**
  +     * 
  +     * 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 );
  +      
  +      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 ();
  +    
  +          // 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()
  @@ -488,13 +562,13 @@
      * this method to change the behaviour.
      *
      */
  -    protected void autoValidate( Map objectModel )
  +    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( objectModel );
  +      String formView = getFormView( sitemapObjectModel );
         if ( formView != null) 
         {
           validate( formView );
  @@ -555,10 +629,10 @@
        * Try to extract from the request
        * and return the current form view
        */
  -    public String getFormView( Map objectModel )
  +    public String getFormView( Map sitemapObjectModel )
       {
  -      Request request =getRequest( objectModel );
  -      return (String) getRequest( objectModel ).getParameter ( Form.FORM_VIEW_PARAM 
);
  +      Request request = getRequest( sitemapObjectModel );
  +      return (String) getRequest( sitemapObjectModel ).getParameter ( 
Form.FORM_VIEW_PARAM );
       }
       
       
  @@ -598,9 +672,9 @@
      * @param objectMap
      * @param id the form id
      */  
  -  public static Form lookup ( Map objectModel, String id )
  +  public static Form lookup ( Map sitemapObjectModel, String id )
     {
  -    Request request =getRequest( objectModel );
  +    Request request = getRequest( sitemapObjectModel );
       Form form = (Form) request.getAttribute( id );
       if (form != null) return form;
       else
  @@ -622,9 +696,9 @@
      * @param objectMap
      * @param id the form id
      */  
  -  public static void remove ( Map objectModel, String id )
  +  public static void remove ( Map sitemapObjectModel, String id )
     {
  -    Request request =getRequest( objectModel );
  +    Request request =getRequest( sitemapObjectModel );
       request.removeAttribute( id );
   
       Session session = request.getSession( false );
  @@ -638,11 +712,11 @@
      * @param objectMap 
      * @param isSessionScope if true the form will be bound in the session, otherwise 
request
      */
  -  public void save ( Map objectModel, String scope )
  +  public void save ( Map sitemapObjectModel, String scope )
     {
  -    Request request =getRequest( objectModel );
  +    Request request =getRequest( sitemapObjectModel );
   
  -    if ( lookup( objectModel, id_ ) != null )
  +    if ( lookup( sitemapObjectModel, id_ ) != null )
         throw new java.lang.IllegalStateException( "Form [id=" + id_ + "] already 
bound in request or session " );
   
       if (SCOPE_REQUEST.equals ( scope ) )
  @@ -676,9 +750,9 @@
       formListeners_.remove( formListener );
     }
   
  -  protected final static Request getRequest( Map objectModel )
  +  protected final static Request getRequest( Map sitemapObjectModel )
     {
  -    return (Request)objectModel.get(ObjectModelHelper.REQUEST_OBJECT);
  +    return (Request)sitemapObjectModel.get(ObjectModelHelper.REQUEST_OBJECT);
     }
   
     
  @@ -688,6 +762,113 @@
     }
     
     
  +  /**
  +   * <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 );
  +  }
  +
  +  /**
  +   * 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();
  +  }
  +  
  +  
  +  /**
  +   * 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( viewName );
  +        viewStateMap_.put( viewName, formViewState );
  +      }
  +    return formViewState;
  +  }
  +  
  +    
  +  
  +  
  +  /**
  +   * Internal class used for keeping state information
  +   * during the life cycle of a form.
  +   * 
  +   * Used only for session scoped forms
  +   * 
  +   */
  +  class FormViewState 
  +  {
  +    
  +    
  +    FormViewState( String viewName )
  +    {
  +      viewName_ = viewName;
  +    }
  +    
  +    /**
  +     * 
  +     * @return Map of (String modelPropertyReference, String inputType) pairs 
  +     * 
  +     */
  +    Map getModelReferenceMap()
  +    {
  +      return modelReferences_;
  +    }
  +    
  +    void addModelReferenceAndInputType( String modelPropertyReference, String 
inputType)
  +    {
  +      modelReferences_.put( modelPropertyReference, inputType );
  +    }
  +    
  +    void clear()
  +    {
  +      modelReferences_.clear();
  +    }
  +
  +    private Map modelReferences_ = new HashMap();
  +    
  +    private String viewName_;
  +    
  +  }
  +    
  +  
     /** the set of violations the model commited during validation */
     private List violations_ = null;  
     
  @@ -724,7 +905,13 @@
      *
      */
     private Validator validator_ = null;
  -  
  +
  +  /**
  +   * Keeps a state information for
  +   * each form view that has been processed
  +   * 
  +   */
  +  private Map viewStateMap_ = new HashMap();
     
   }
   
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     [EMAIL PROTECTED]
To unsubscribe, e-mail:          [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to