blob: bd28874c315b223c1d437a253d808ea445bb7b2f [file] [log] [blame]
/*
* 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 org.apache.myfaces.extensions.validator.crossval.strategy;
import org.apache.myfaces.extensions.validator.core.ProcessedInformationEntry;
import org.apache.myfaces.extensions.validator.crossval.CrossValidationStorage;
import org.apache.myfaces.extensions.validator.crossval.CrossValidationStorageEntry;
import org.apache.myfaces.extensions.validator.crossval.referencing.strategy.AbstractAliasCompareStrategy;
import org.apache.myfaces.extensions.validator.crossval.referencing.strategy.AbstractELCompareStrategy;
import org.apache.myfaces.extensions.validator.crossval.referencing.strategy.AbstractLocalCompareStrategy;
import org.apache.myfaces.extensions.validator.crossval.referencing.strategy.ReferencingStrategy;
import org.apache.myfaces.extensions.validator.util.ClassUtils;
import org.apache.myfaces.extensions.validator.util.ExtValUtils;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import java.lang.annotation.Annotation;
import java.util.*;
/**
* @author Gerhard Petracek
*/
public abstract class AbstractCompareStrategy extends AbstractCrossValidationStrategy {
protected static List<ReferencingStrategy> referencingStrategies;
protected Map<Object, Object> violationResultStorage = new HashMap<Object, Object>();
public AbstractCompareStrategy() {
initReferencingStrategies();
}
protected void initReferencingStrategies() {
if (referencingStrategies == null) {
referencingStrategies = new ArrayList<ReferencingStrategy>();
String customReferencingStrategyClassName = ExtValUtils.getBasePackage() + "ReferencingStrategy";
ReferencingStrategy customReferencingStrategy = (ReferencingStrategy) ClassUtils.tryToInstantiateClassForName(customReferencingStrategyClassName);
if (customReferencingStrategy != null) {
referencingStrategies.add(customReferencingStrategy);
}
referencingStrategies.add(new AbstractELCompareStrategy());
referencingStrategies.add(new AbstractAliasCompareStrategy());
referencingStrategies.add(new AbstractLocalCompareStrategy());
}
}
public void processCrossValidation(CrossValidationStorageEntry crossValidationStorageEntry, CrossValidationStorage crossValidationStorage) throws ValidatorException {
String[] validationTargets = getValidationTargets(crossValidationStorageEntry.getAnnotationEntry().getAnnotation());
for (String validationTarget : validationTargets) {
validationTarget = validationTarget.trim();
//select validation method
tryToValidate(crossValidationStorageEntry, crossValidationStorage, validationTarget);
}
}
private boolean tryToValidate(CrossValidationStorageEntry crossValidationStorageEntry, CrossValidationStorage crossValidationStorage, String validationTarget) {
for (ReferencingStrategy referencingStrategy : referencingStrategies) {
if (referencingStrategy.evalReferenceAndValidate(crossValidationStorageEntry, crossValidationStorage, validationTarget, this)) {
return true;
}
}
return false;
}
//has to be public for custom referencing strategies!!!
public void handleTargetViolation(CrossValidationStorageEntry crossValidationStorageEntry, CrossValidationStorageEntry entry) {
FacesContext facesContext = FacesContext.getCurrentInstance();
//get validation error messages for the target component
String summary = getErrorMessageSummary(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), true);
String details = getErrorMessageDetails(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), true);
//validation target isn't bound to a component withing the current page (see validateFoundEntry, tryToValidateLocally and tryToValidateBindingOnly)
if (entry == null) {
entry = crossValidationStorageEntry;
}
FacesMessage message;
if (entry.getAnnotationEntry() != null) {
message = getTargetComponentErrorMessage(entry.getAnnotationEntry().getAnnotation(), summary, details);
} else {
//TODO document possible side effects
//due to a missing target annotation (see: tryToValidateLocally)
message = getTargetComponentErrorMessage(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), summary, details);
}
if (message.getSummary() != null || message.getDetail() != null) {
facesContext.addMessage(entry.getComponent().getClientId(facesContext), message);
}
}
//has to be public for custom referencing strategies!!!
public void processSourceComponentAfterViolation(CrossValidationStorageEntry crossValidationStorageEntry) {
//get validation error messages for the current component
String summary = getErrorMessageSummary(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), false);
String details = getErrorMessageDetails(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), false);
FacesMessage message = getSourceComponentErrorMessage(crossValidationStorageEntry.getAnnotationEntry().getAnnotation(), summary, details);
if (message.getSummary() != null || message.getDetail() != null) {
//TODO
throw new ValidatorException(message);
} else {
throw new ValidatorException(new FacesMessage());
}
}
//has to be public for custom referencing strategies!!!
public FacesMessage getSourceComponentErrorMessage(Annotation annotation, String summary, String details) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary(summary);
message.setDetail(details);
return message;
}
//has to be public for custom referencing strategies!!!
public FacesMessage getTargetComponentErrorMessage(Annotation foundAnnotation, String summary, String details) {
FacesMessage message = new FacesMessage();
message.setSeverity(FacesMessage.SEVERITY_ERROR);
message.setSummary(summary);
message.setDetail(details);
return message;
}
//has to be public for custom referencing strategies!!!
public ProcessedInformationEntry resolveValidationTargetEntry(Map<String, ProcessedInformationEntry> valueBindingConvertedValueMapping, String targetValueBinding, Object bean) {
ProcessedInformationEntry processedInformationEntry = valueBindingConvertedValueMapping.get(targetValueBinding);
//simple case
if (processedInformationEntry.getFurtherEntries() == null) {
return processedInformationEntry;
}
//process complex component entries (e.g. a table)
//supported: cross-component but no cross-entity validation (= locale validation)
if (processedInformationEntry.getBean().equals(bean)) {
return processedInformationEntry;
}
for (ProcessedInformationEntry entry : processedInformationEntry.getFurtherEntries()) {
if (entry.getBean().equals(bean)) {
return entry;
}
}
return null;
}
protected String getErrorMessageSummary(Annotation annotation, boolean isTargetComponent) {
return resolveMessage(getValidationErrorMsgKey(annotation, isTargetComponent));
}
protected String getErrorMessageDetails(Annotation annotation, boolean isTargetComponent) {
try {
String key = getValidationErrorMsgKey(annotation, isTargetComponent);
return (key != null) ? resolveMessage(key + DETAIL_MESSAGE_KEY_POSTFIX) : null;
} catch (MissingResourceException e) {
logger.warn("couldn't find key " + getValidationErrorMsgKey(annotation, isTargetComponent) + DETAIL_MESSAGE_KEY_POSTFIX, e);
}
return null;
}
protected String getValidationErrorMsgKey(Annotation annotation) {
return getValidationErrorMsgKey(annotation, false);
}
/*
* recommended methods to override - have to be public for custom referencing strategies!!!
*/
/*
* abstract methods
*/
protected abstract String getValidationErrorMsgKey(Annotation annotation, boolean isTargetComponent);
public abstract boolean useTargetComponentToDisplayErrorMsg(CrossValidationStorageEntry crossValidationStorageEntry);
/*
* implements the specific validation logic
*/
public abstract boolean isViolation(Object object1, Object object2, Annotation annotation);
/*
* returns the referenced validation targets of the annotation
* e.g. @DateIs(type = DateIsType.before, value = "finalExam")
* -> method returns an array with one value ("finalExam")
*/
public abstract String[] getValidationTargets(Annotation annotation);
}