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]