I'm going to throw my .02 in this conversation with regards to backwards
navigation in a wizard.

The way we figured out how to handle this was to create an "Observer" class.
 Every time an action bean is called, in the @Before method we would update
our Observer with the action bean class and any parameters in the url.  We
created a "Link" object that would hold this information and put the
Observer in the user's session.  This way when we click the back button in
our wizard the Observer gets called to get the Link object out of its
history and adds the parameters back to the Resolution using the
addParameter() method and then sends the user off to the previous page.

This approach works perfectly for us.

On Wed, Feb 10, 2010 at 3:28 AM, Richard Hauswald <
[email protected]> wrote:

> I totally agree with you. Solving the root of a problem is the best
> solution. A little addition:
>
> Correct me if I'm wrong:
> I think the core problem is that stripes has no knowledge about what
> fields are required for the single wizard steps and in which order the
> steps are executed. Using only @WizardStep would not be enough. But
> combined with the @Validate(on="", ...) annotation and a match to the
> @WizardStep (by searching the method by name and get its annotations)
> would enable the validation logic to build lists of required fields
> for each step.
>
> If step one needs userName and password and step two email and step
> three nickName:
> @WizardStep(1) would require userName and password
> @WizardStep(2) would require userName and password and email, since
> userName and password are required by Step 1
> @WizardStep(3) would require userName and password and email nickName,
> since userName and password are required by Step 1 and email by Step 2
>
> What do you think?
>
> On Wed, Feb 10, 2010 at 10:02 AM,  <[email protected]> wrote:
> > I really appreciate your solution. I just think we should solve the
> problem
> > Once and for all not just working around the core.
> >
> > The order definition of Wizard ActionBeans should be optional. So we can
> > maintain backward compatibility too.
> >
> > If you didn't know Gist, you should definitely check out www.github.com.
> > It's an awesome place to host and share your code.
> >
> > -----Ursprüngliche Nachricht-----
> > Von: Richard Hauswald [mailto:[email protected]]
> > Gesendet: Mittwoch, 10. Februar 2010 09:48
> > An: Stripes Users List
> > Betreff: Re: [Stripes-users] Skip pages in Wizards
> >
> > 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
> >
> > 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
>



-- 
"Innovation is the enemy of the status quo - it puts people out of
business."
--John Piña Craven
------------------------------------------------------------------------------
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

Reply via email to