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