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();
}
}
}