/* | |
* 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; | |
import org.apache.myfaces.extensions.validator.util.CrossValidationUtils; | |
import org.apache.myfaces.extensions.validator.util.JsfUtils; | |
import org.apache.myfaces.extensions.validator.util.ReflectionUtils; | |
import org.apache.myfaces.extensions.validator.util.ExtValUtils; | |
import org.apache.myfaces.extensions.validator.util.ProxyUtils; | |
import org.apache.myfaces.extensions.validator.internal.UsageInformation; | |
import org.apache.myfaces.extensions.validator.internal.UsageCategory; | |
import org.apache.myfaces.extensions.validator.crossval.strategy.AbstractCrossValidationStrategy; | |
import org.apache.myfaces.extensions.validator.crossval.storage.CrossValidationStorage; | |
import org.apache.myfaces.extensions.validator.crossval.storage.CrossValidationStorageEntry; | |
import org.apache.myfaces.extensions.validator.PropertyValidationModuleKey; | |
import javax.faces.application.FacesMessage; | |
import javax.faces.event.PhaseEvent; | |
import javax.faces.event.PhaseId; | |
import javax.faces.event.PhaseListener; | |
import javax.faces.validator.ValidatorException; | |
import javax.faces.FacesException; | |
import javax.faces.context.FacesContext; | |
/** | |
* This phase listener processes cross validation as soon as it finds a special request scoped storage.<br/> | |
* So it's possible to add information during the process validation phase. At the end of this phase it gets processed. | |
* After that the storage gets reseted.<p/> | |
* If you provide a custom extension and you add the same storage type within a different phase, | |
* it also gets processed at the end of that phase. | |
* | |
* @author Gerhard Petracek | |
* @since 1.x.1 | |
*/ | |
@UsageInformation(UsageCategory.INTERNAL) | |
public class CrossValidationPhaseListener implements PhaseListener | |
{ | |
private boolean isInitialized = false; | |
private static final long serialVersionUID = -5333405897635742732L; | |
public void afterPhase(PhaseEvent event) | |
{ | |
try | |
{ | |
CrossValidationStorage crossValidationStorage = CrossValidationUtils.getOrInitCrossValidationStorage(); | |
FacesContext facesContext = FacesContext.getCurrentInstance(); | |
for (CrossValidationStorageEntry entry : crossValidationStorage.getCrossValidationStorageEntries()) | |
{ | |
try | |
{ | |
if(!ExtValUtils.executeGlobalBeforeValidationInterceptors( | |
facesContext, | |
entry.getComponent(), | |
entry.getConvertedObject(), | |
CrossValidationStorageEntry.class.getName(), | |
entry, | |
PropertyValidationModuleKey.class)) | |
{ | |
continue; | |
} | |
//call init-method | |
if(entry.getValidationStrategy() instanceof AbstractCrossValidationStrategy) | |
{ | |
ReflectionUtils.tryToInvokeMethod( | |
entry.getValidationStrategy(), | |
ReflectionUtils.tryToGetMethod( | |
ProxyUtils.getUnproxiedClass(entry.getValidationStrategy().getClass()), | |
"initCrossValidation", | |
CrossValidationStorageEntry.class), | |
entry); | |
} | |
/* | |
* validation | |
*/ | |
entry.getValidationStrategy().processCrossValidation(entry, crossValidationStorage); | |
} | |
catch (ValidatorException validatorException) | |
{ | |
boolean addMessage = true; | |
if(entry.getValidationStrategy() instanceof AbstractCrossValidationStrategy) | |
{ | |
try | |
{ | |
addMessage = (Boolean)ReflectionUtils.tryToInvokeMethod( | |
entry.getValidationStrategy(), | |
ReflectionUtils.tryToGetMethod( | |
ProxyUtils.getUnproxiedClass(entry.getValidationStrategy().getClass()), | |
"processAfterCrossValidatorException", | |
CrossValidationStorageEntry.class, | |
validatorException.getClass()), | |
entry, | |
validatorException); | |
} | |
catch (Exception e) | |
{ | |
throw new FacesException(e); | |
} | |
} | |
if(addMessage) | |
{ | |
FacesMessage facesMessage = validatorException.getFacesMessage(); | |
if (facesMessage != null && | |
facesMessage.getSummary() != null && facesMessage.getDetail() != null) | |
{ | |
ExtValUtils.tryToAddViolationMessageForComponentId(entry.getClientId(), facesMessage); | |
} | |
ExtValUtils.tryToBlocksNavigationForComponentId(entry.getClientId(), facesMessage); | |
} | |
} | |
finally | |
{ | |
ExtValUtils.executeGlobalAfterValidationInterceptors( | |
facesContext, | |
entry.getComponent(), | |
entry.getConvertedObject(), | |
CrossValidationStorageEntry.class.getName(), | |
entry, | |
PropertyValidationModuleKey.class); | |
} | |
} | |
} | |
finally | |
{ | |
CrossValidationUtils.resetCrossValidationStorage(); | |
} | |
} | |
public void beforePhase(PhaseEvent event) | |
{ | |
if (!isInitialized) | |
{ | |
if (ExtValCrossValidationModuleConfiguration.get().deactivateCrossvalidation()) | |
{ | |
JsfUtils.deregisterPhaseListener(this); | |
} | |
else | |
{ | |
isInitialized = true; | |
} | |
} | |
} | |
public PhaseId getPhaseId() | |
{ | |
return PhaseId.ANY_PHASE; | |
} | |
@Override | |
public boolean equals(Object o) | |
{ | |
if (this == o) | |
{ | |
return true; | |
} | |
if (!(o instanceof CrossValidationPhaseListener)) | |
{ | |
return false; | |
} | |
return true; | |
} | |
@Override | |
public int hashCode() | |
{ | |
return super.hashCode(); | |
} | |
} |