Hello Stripes Users,
I set up a test case and it proves Yves Senn 's statement.
You can solve this issue temporarily by using a custom PropertyBinder
and a new Annotation marking the method called at the end of a wizard.
Cheers,
Richard

Example:

web.xml
<init-param>
        <param-name>ActionBeanPropertyBinder.Class</param-name>
        <param-value>x.y.z.WizardPropertyBinder</param-value>
</init-param>


LastWizardPage.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LastWizardPage {

}

WizardPropertyBinder.java
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.Wizard;
import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.ActionResolver;
import net.sourceforge.stripes.controller.DefaultActionBeanPropertyBinder;
import net.sourceforge.stripes.controller.ParameterName;
import net.sourceforge.stripes.controller.StripesRequestWrapper;
import net.sourceforge.stripes.exception.StripesServletException;
import net.sourceforge.stripes.util.Log;
import net.sourceforge.stripes.validation.ValidationErrors;
import net.sourceforge.stripes.validation.ValidationMetadata;

public class WizardPropertyBinder extends DefaultActionBeanPropertyBinder {
        private static final Log log =
Log.getInstance(DefaultActionBeanPropertyBinder.class);

        @Override
        protected void validateRequiredFields(Map<ParameterName, String[]>
parameters, ActionBean bean, ValidationErrors errors) {
                log.debug("Running required field validation on bean class ",
bean.getClass().getName());

                // Assemble a set of names that we know have indexed 
parameters, so
we won't check
                // for required-ness the regular way
                Set<String> indexedParams = new HashSet<String>();
                for (ParameterName name : parameters.keySet()) {
                        if (name.isIndexed()) {
                                indexedParams.add(name.getStrippedName());
                        }
                }

                Map<String, ValidationMetadata> validationInfos =
getConfiguration().getValidationMetadataProvider().getValidationMetadata(bean.getClass());
                ActionBeanContext context = bean.getContext();
                HttpServletRequest request = context.getRequest();
                StripesRequestWrapper stripesReq =
StripesRequestWrapper.findStripesWrapper(request);

                if (validationInfos != null) {
                        boolean wizard = 
bean.getClass().getAnnotation(Wizard.class) != null;
                        boolean lastWizardPage = 
isLastWizardPage(getConfiguration(), context, bean);
                        Collection<String> fieldsOnPage = 
getFieldsPresentInfo(bean);

                        for (Map.Entry<String, ValidationMetadata> entry :
validationInfos.entrySet()) {
                                String propertyName = entry.getKey();
                                ValidationMetadata validationInfo = 
entry.getValue();

                                // If the field is required, and we don't have 
index params that collapse
                                // to that property name, check that it was 
supplied
                                if 
(validationInfo.requiredOn(context.getEventName()) &&
!indexedParams.contains(propertyName)) {

                                        // Make the added check that if the 
form is a wizard, the required field is
                                        // in the set of fields that were on 
the page
                                        if (!wizard || lastWizardPage || 
fieldsOnPage.contains(propertyName)) {
                                                String[] values = 
trim(request.getParameterValues(propertyName),
validationInfo);
                                                log.debug("Checking required 
field: ", propertyName, ", with
values: ", values);
                                                
checkSingleRequiredField(propertyName, propertyName, values,
stripesReq, errors);
                                        }
                                }
                        }
                }

                // Now the easy work is done, figure out which rows of indexed 
props
had values submitted
                // and what to flag up as failing required field validation
                if (indexedParams.size() > 0) {
                        Map<String, Row> rows = new HashMap<String, Row>();

                        for (Map.Entry<ParameterName, String[]> entry : 
parameters.entrySet()) {
                                ParameterName name = entry.getKey();
                                String[] values = entry.getValue();

                                if (name.isIndexed()) {
                                        String rowKey = 
name.getName().substring(0,
name.getName().indexOf(']') + 1);
                                        if (!rows.containsKey(rowKey)) {
                                                rows.put(rowKey, new Row());
                                        }

                                        rows.get(rowKey).put(name, values);
                                }
                        }

                        for (Row row : rows.values()) {
                                if (row.hasNonEmptyValues()) {
                                        for (Map.Entry<ParameterName, String[]> 
entry : row.entrySet()) {
                                                ParameterName name = 
entry.getKey();
                                                String[] values = 
entry.getValue();
                                                ValidationMetadata 
validationInfo =
validationInfos.get(name.getStrippedName());

                                                if (validationInfo != null &&
validationInfo.requiredOn(context.getEventName())) {
                                                        
checkSingleRequiredField(name.getName(),
name.getStrippedName(), values, stripesReq, errors);
                                                }
                                        }
                                } else {
                                        // If the row is full of empty data, 
get rid of it all to
                                        // prevent problems in downstream 
validation
                                        for (ParameterName name : row.keySet()) 
{
                                                parameters.remove(name);
                                        }
                                }
                        }

                }
        }

        protected boolean isLastWizardPage(Configuration config,
ActionBeanContext context, ActionBean bean) {
                try {
                        ActionResolver resolver = config.getActionResolver();

                        // Then lookup the event name and handler method etc.
                        String eventName = context.getEventName();

                        final Method handler;
                        if (eventName != null) {
                                handler = resolver.getHandler(bean.getClass(), 
eventName);
                        } else {
                                handler = 
resolver.getDefaultHandler(bean.getClass());
                                if (handler != null) {
                                        
context.setEventName(resolver.getHandledEvent(handler));
                                }
                        }
                        return 
handler.isAnnotationPresent(LastWizardPage.class);
                } catch (StripesServletException e) {
                        throw new RuntimeException("This should never happen 
:-) - only a
quick fix");
                }

        }
        /**
         * An inner class that represents a "row" of form properties that all
have the same index
         * so that we can validate all those properties together.
         */
        protected static class Row extends HashMap<ParameterName, String[]> {
                private static final long serialVersionUID = 1L;

                private boolean hasNonEmptyValues = false;

                /**
                 * Adds the value to the map, along the way checking to see if 
there
are any non-null values for
                 * the row so far.
                 */
                @Override
                public String[] put(ParameterName key, String[] values) {
                        if (!hasNonEmptyValues) {
                                hasNonEmptyValues = (values != null) && 
(values.length > 0) &&
(values[0] != null) && (values[0].trim().length() > 0);

                        }
                        return super.put(key, values);
                }

                /** Returns true if the row had any non-empty values in it,
otherwise false. */
                public boolean hasNonEmptyValues() {
                        return this.hasNonEmptyValues;
                }
        }
}


On Mon, Feb 8, 2010 at 2:37 PM,  <[email protected]> wrote:
> Hey Stripes Users
>
> We have a lot of multi-page forms implemented with the @Wizard Annotation.
> This allows us to split required fields over multiple pages. We just noticed 
> that it
> Is possible to jump over given pages when changing the name="" Attribute of 
> the submit button.
>
> Since Stripes just validates the fields contained within "__fp" it is 
> possible to just enter the data
> On the first page and skip over the whole form process to the last page. The 
> last page then gets
> Displayed accordingly. Is this behavior intended?
>
> Is there a way to mark an EventHandler in a Wizard to validate all fields and 
> ignore the "__fp" parameter?
> We need to be sure that the user passed all steps in the process.
>
> Cheers,
> Yves Senn
>
>
> Sicherheitshinweis:
> Dieses E-Mail von PostFinance ist signiert. Weitere Informationen finden Sie 
> unter:
> https://www.postfinance.ch/e-signature.
> Geben Sie Ihre Sicherheitselemente niemals Dritten bekannt.
> ------------------------------------------------------------------------------
> The Planet: dedicated and managed hosting, cloud storage, colocation
> Stay online with enterprise data centers and the best network in the business
> Choose flexible plans and management services without long-term contracts
> Personal 24x7 support from experience hosting pros just a phone call away.
> http://p.sf.net/sfu/theplanet-com
> _______________________________________________
> Stripes-users mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/stripes-users
>
>



-- 
Richard Hauswald
Blog: http://tnfstacc.blogspot.com/
LinkedIn: http://www.linkedin.com/in/richardhauswald
Xing: http://www.xing.com/profile/Richard_Hauswald

------------------------------------------------------------------------------
The Planet: dedicated and managed hosting, cloud storage, colocation
Stay online with enterprise data centers and the best network in the business
Choose flexible plans and management services without long-term contracts
Personal 24x7 support from experience hosting pros just a phone call away.
http://p.sf.net/sfu/theplanet-com
_______________________________________________
Stripes-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-users

Reply via email to