Didn't know about gist... :-( Promise not posting code in emails again... The solution I posted is just a quick fix - not the solution. I thought adding a "endEvents" property to the Wizard Annotation and a check in the ActionBeanPropertyBinder would solve the problem quickly without loosing backwards compatibility. But hey, this is up to the stripes developers :-)
On Wed, Feb 10, 2010 at 9:28 AM, <[email protected]> wrote: > 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. > ------------------------------------------------------------------------------ > 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 > > -- Richard Hauswald Blog: http://tnfstacc.blogspot.com/ LinkedIn: http://www.linkedin.com/in/richardhauswald Xing: http://www.xing.com/profile/Richard_Hauswald ------------------------------------------------------------------------------ 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
