package org.wicketstuff.jsr303.validator; import org.apache.wicket.Application; import org.apache.wicket.Component; import org.apache.wicket.Localizer; import org.apache.wicket.injection.Injector; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.ValidationErrorFeedback; import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.string.Strings; import org.apache.wicket.util.string.interpolator.MapVariableInterpolator; import org.apache.wicket.validation.IErrorMessageSource; import org.apache.wicket.validation.IValidationError; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.wicketstuff.jsr303.BeanValidationErrorBuilder; import javax.validation.ConstraintViolation; import javax.validation.Validator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; /** * BeanValidator is not actually a Wicket IValidator. The reason for this is the fact, that values * must have been written back into the Bean for it to be able to validate. This is supposed to be * used manually within the onSubmit call of a form, for example. It may report the error to the * component being passed on construction. */ public class BeanValidator { private final static Logger log = LoggerFactory.getLogger(BeanValidator.class); private final Form<?> context; @SpringBean(name = "wicketValidator") private Validator validator; public BeanValidator(final Form<?> contextOrNull) { context = contextOrNull; Injector.get().inject(this); } public <U> boolean isValid(final U e) { if (e == null) { return true; } final Set<ConstraintViolation<U>> s = validator.validate(e); if (s.isEmpty()) { return true; } for (final ConstraintViolation<U> v : s) { log.debug("Constraint violation: " + v); if (context != null) { final IValidationError ve = new BeanValidationErrorBuilder<U>(v).createError(); context.error(new ValidationErrorFeedback(ve, ve.getErrorMessage(new MessageSource()))); } } return false; } class MessageSource implements IErrorMessageSource { private final Set<String> triedKeys = new LinkedHashSet<String>(); // basically copied from FormComponent, suggestions welcome public String getMessage(final String key) { // Use the following log4j config for detailed logging on the // property resolution // process // log4j.logger.org.apache.wicket.resource.loader=DEBUG // log4j.logger.org.apache.wicket.Localizer=DEBUG final Localizer localizer = context.getLocalizer(); // retrieve prefix that will be used to construct message keys final String prefix = context.getValidatorKeyPrefix(); String message = null; // first try the full form of key [form-component-id].[key] String resource = context.getId() + "." + prefix(prefix, key); message = getString(localizer, resource, context); // if not found, try a more general form (without prefix) // [form-component-id].[prefix].[key] if (Strings.isEmpty(message) && Strings.isEmpty(prefix)) { resource = context.getId() + "." + key; message = getString(localizer, resource, context); } // If not found try a more general form [prefix].[key] if (Strings.isEmpty(message)) { resource = prefix(prefix, key); message = getString(localizer, resource, context); } // If not found try the most general form [key] if (Strings.isEmpty(message)) { // Try a variation of the resource key message = getString(localizer, key, context); } // convert empty string to null in case our default value of "" was // returned from localizer if (Strings.isEmpty(message)) { message = null; } return message; } private String prefix(final String prefix, final String key) { if (!Strings.isEmpty(prefix)) { return prefix + "." + key; } else { return key; } } /** * @param localizer * @param key * @param component * @return string */ private String getString(final Localizer localizer, final String key, final Component component) { triedKeys.add(key); // Note: It is important that the default value of "" is // provided to getString() not to throw a MissingResourceException // or to // return a default string like "[Warning: String ..." return localizer.getString(key, component, ""); } /** * @see org.apache.wicket.validation.IErrorMessageSource#substitute(String, * java.util.Map) */ public String substitute(final String string, final Map<String, Object> vars) throws IllegalStateException { return new MapVariableInterpolator(string, vars, Application.get() .getResourceSettings() .getThrowExceptionOnMissingResource()).toString(); } } }