/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package de.unioninvestment.eai.portal.support.vaadin.validation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.unioninvestment.eai.portal.support.vaadin.context.Context;
/**
*
* Erzeugt Feld-Validatoren aufgrund von kommaseparierten Validierungsregeln.
*
* @author max.hartmann
*/
public class FieldValidatorFactory {
private static final Logger LOG = LoggerFactory
.getLogger(FieldValidatorFactory.class);
private Map<String, Class<? extends FieldValidator>> validatorClassesByName = new HashMap<String, Class<? extends FieldValidator>>();
/**
* Registriert default-Validatoren.
*/
public FieldValidatorFactory() {
List<Class<? extends FieldValidator>> defaultValidators = new LinkedList<Class<? extends FieldValidator>>();
defaultValidators.add(RequiredValidator.class);
defaultValidators.add(MaxlenValidator.class);
defaultValidators.add(RegexpValidator.class);
setValidators(defaultValidators);
}
/**
* @param validatorClasses
* registriert die angegebenen Validatoren anhand der Annotation
* {@link ValidatorKeyword}
*/
public final void setValidators(
List<Class<? extends FieldValidator>> validatorClasses) {
validatorClassesByName.clear();
for (Class<? extends FieldValidator> clazz : validatorClasses) {
ValidatorKeyword keywordAnnotation = clazz
.getAnnotation(ValidatorKeyword.class);
if (keywordAnnotation != null) {
validatorClassesByName.put(keywordAnnotation.value(), clazz);
} else {
throw new IllegalArgumentException("Validator Klasse " + clazz
+ " hat keine @Validator Annotation");
}
}
}
/**
* @param commaSeparatedRules
* komma-separierte Liste an Regeln
* @param validationMessage
* Fehlermeldung, die im Falle eines Validierungsfehlers
* angezeigt werden soll
* @return Liste von Validatoren, die gemäß der Regeln konfiguriert wurden
*/
public List<FieldValidator> createValidators(String commaSeparatedRules,
String validationMessage) {
if (commaSeparatedRules == null) {
return null;
}
String msg = validationMessage;
if (msg == null) {
msg = Context.getMessage("portlet.crud.error.validation.defaultMessage", commaSeparatedRules);
}
String[] ruleList = commaDelimitedListToStringArray(
commaSeparatedRules, "\\");
List<FieldValidator> validators = new ArrayList<FieldValidator>();
for (String rule : ruleList) {
parseAndAddRule(validators, msg, rule);
}
return validators;
}
private void parseAndAddRule(List<FieldValidator> validators,
String validationMessage, String rule) {
String[] ruleParts = rule.split("=", 2);
Class<? extends FieldValidator> validatorClass = validatorClassesByName
.get(ruleParts[0]);
if (validatorClass != null) {
try {
if (ruleParts.length == 2) {
addValidatorWithParam(validators, validatorClass,
validationMessage, ruleParts[1]);
} else {
addValidatorWithoutParam(validators, validatorClass,
validationMessage);
}
} catch (ValidationException e) {
throw e;
} catch (InvocationTargetException e) {
throwOriginalError(e);
} catch (Exception e) {
throwInternalError(e);
}
} else {
throw new ValidationException(
"portlet.crud.error.validation.unknownRule", rule);
}
}
private void throwOriginalError(InvocationTargetException e) {
if (e.getTargetException() instanceof ValidationException) {
throw (ValidationException) e.getTargetException();
} else {
throwInternalError(e);
}
}
private void addValidatorWithoutParam(List<FieldValidator> validators,
Class<? extends FieldValidator> validatorClass,
String validationMessage) throws InstantiationException,
IllegalAccessException, InvocationTargetException {
try {
Constructor<? extends FieldValidator> constructor = validatorClass
.getConstructor(String.class);
validators.add(constructor.newInstance(validationMessage));
} catch (NoSuchMethodException e) {
LOG.info("Error calling validator constructor", e);
throw new ValidationException(
"portlet.crud.error.validation.missingParameter",
validatorClass.getSimpleName());
}
}
private void addValidatorWithParam(List<FieldValidator> validators,
Class<? extends FieldValidator> validatorClass,
String validationMessage, String parameter)
throws InstantiationException, IllegalAccessException,
InvocationTargetException {
try {
Constructor<? extends FieldValidator> constructor = validatorClass
.getConstructor(String.class, String.class);
validators.add(constructor
.newInstance(parameter, validationMessage));
} catch (NoSuchMethodException e) {
LOG.info("Error calling validator constructor", e);
throw new ValidationException(
"portlet.crud.error.validation.parameterNotSupported",
validatorClass.getSimpleName());
}
}
private void throwInternalError(Exception e) {
LOG.error("Fehler beim Instanzieren eines FieldValidators", e);
throw new ValidationException("portlet.crud.error.internal");
}
/**
*
* @param str
* der kommaseparierte String von Validierungsregeln
* @param escapeChar
* das Escape Zeichen.
* @return Ein Array mit den gespliteten Regeln.
*/
static String[] commaDelimitedListToStringArray(String str,
String escapeChar) {
// these characters need to be escaped in a regular expression
String regularExpressionSpecialChars = "/.*+?|()[]{}\\";
String escapedEscapeChar = escapeChar;
// if the escape char for our comma separated list needs to be escaped
// for the regular expression, escape it using the \ char
if (regularExpressionSpecialChars.indexOf(escapeChar) != -1) {
escapedEscapeChar = "\\" + escapeChar;
}
// see
// http://stackoverflow.com/questions/820172/how-to-split-a-comma-separated-string-while-ignoring-escaped-commas
String[] temp = str.split("(?<!" + escapedEscapeChar + "),", -1);
// remove the escapeChar for the end result
String[] result = new String[temp.length];
for (int i = 0; i < temp.length; i++) {
result[i] = temp[i].replaceAll(escapedEscapeChar + ",", ",");
}
return result;
}
}