Thanks a lot Richard for your Code. I think instead of marking Just the final Steps, we should define the whole order of the EventHandlers.
This would allow stripes to ensure that the user passes trough step by step. Another benefit we would get is, that we can allow "backward navigation" without Displaying invalid error messages. I have opened a jira ticket and illustrated my thoughts in a gist: Ticket: http://www.stripesframework.org/jira/browse/STS-737 Gist: https://gist.github.com/1072357cbedbcbf0f587 Cheers, Yves Senn -----Ursprüngliche Nachricht----- Von: Richard Hauswald [mailto:[email protected]] Gesendet: Dienstag, 9. Februar 2010 14:27 An: Stripes Users List Betreff: Re: [Stripes-users] Skip pages in Wizards 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 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.
smime.p7s
Description: S/MIME Cryptographic Signature
------------------------------------------------------------------------------ SOLARIS 10 is the OS for Data Centers - provides features such as DTrace, Predictive Self Healing and Award Winning ZFS. Get Solaris 10 NOW http://p.sf.net/sfu/solaris-dev2dev
_______________________________________________ Stripes-users mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/stripes-users
