blob: a3e971f1d9fc140a6821a9c90fcaa05ad1826f0d [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 java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
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;
/**
* @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);
}