| /* |
| * 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.core; |
| |
| import org.apache.myfaces.extensions.validator.core.factory.DefaultFactoryFinder; |
| import org.apache.myfaces.extensions.validator.core.factory.FactoryFinder; |
| import org.apache.myfaces.extensions.validator.core.initializer.component.ComponentInitializer; |
| import org.apache.myfaces.extensions.validator.core.initializer.configuration.StaticConfiguration; |
| import org.apache.myfaces.extensions.validator.core.initializer.configuration.StaticConfigurationNames; |
| import org.apache.myfaces.extensions.validator.core.interceptor.MetaDataExtractionInterceptor; |
| import org.apache.myfaces.extensions.validator.core.interceptor.PropertyValidationInterceptor; |
| import org.apache.myfaces.extensions.validator.core.interceptor.RendererInterceptor; |
| import org.apache.myfaces.extensions.validator.core.interceptor.ValidationExceptionInterceptor; |
| import org.apache.myfaces.extensions.validator.core.metadata.MetaDataEntry; |
| import org.apache.myfaces.extensions.validator.core.recorder.ProcessedInformationRecorder; |
| import org.apache.myfaces.extensions.validator.core.validation.SkipValidationEvaluator; |
| import org.apache.myfaces.extensions.validator.core.validation.parameter.ViolationSeverityInterpreter; |
| import org.apache.myfaces.extensions.validator.core.validation.strategy.ValidationStrategy; |
| import org.apache.myfaces.extensions.validator.internal.UsageCategory; |
| import org.apache.myfaces.extensions.validator.internal.UsageInformation; |
| import org.apache.myfaces.extensions.validator.util.ClassUtils; |
| |
| import javax.faces.component.UIComponent; |
| import javax.faces.context.FacesContext; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.logging.Logger; |
| |
| import static org.apache.myfaces.extensions.validator.util.WebXmlUtils.getInitParameter; |
| |
| /** |
| * @since 1.x.1 |
| */ |
| @UsageInformation(UsageCategory.API) |
| public class ExtValContext |
| { |
| private final Logger logger = Logger.getLogger(getClass().getName()); |
| |
| private static ExtValContext extValContext; |
| |
| //don't try to resolve it dynamically e.g. via InformationProviderBean - there's a mojarra issue |
| private static final String CUSTOM_EXTVAL_CONTEXT_CLASS_NAME = |
| ExtValContext.class.getName().replace(".core.", ".custom."); |
| |
| private static final String CUSTOM_EXTVAL_MODULE_CONFIGURATION_RESOLVER_CLASS_NAME = |
| ExtValModuleConfigurationResolver.class.getName().replace(".core.", ".custom."); |
| |
| private ViolationSeverityInterpreter violationSeverityInterpreter; |
| private FactoryFinder factoryFinder = DefaultFactoryFinder.getInstance(); |
| private Map<String, RendererInterceptor> rendererInterceptors = |
| new ConcurrentHashMap<String, RendererInterceptor>(); |
| private List<String> deniedInterceptors = new CopyOnWriteArrayList<String>(); |
| private List<ProcessedInformationRecorder> processedInformationRecorders = |
| new CopyOnWriteArrayList<ProcessedInformationRecorder>(); |
| |
| private SkipValidationEvaluator skipValidationEvaluator; |
| |
| private List<RendererInterceptor> rendererInterceptorCache = null; |
| |
| private Map<String, Object> globalProperties = new HashMap<String, Object>(); |
| |
| /** |
| * Storage for all configuration objects. |
| * @since r4 |
| */ |
| private Map<Class<? extends ExtValModuleConfiguration>, ExtValModuleConfiguration> extValConfig = |
| new ConcurrentHashMap<Class<? extends ExtValModuleConfiguration>, ExtValModuleConfiguration>(); |
| |
| /** |
| * Configured Module Configuration resolver. |
| * @since r4 |
| */ |
| private ExtValModuleConfigurationResolver defaultModuleConfigurationResolver; |
| |
| private Map<StaticConfigurationNames, List<StaticConfiguration<String, String>>> staticConfigMap |
| = new HashMap<StaticConfigurationNames, List<StaticConfiguration<String, String>>>(); |
| |
| private ExtValContextInternals contextHelper; |
| private ExtValContextInvocationOrderAwareInternals invocationOrderAwareContextHelper; |
| |
| protected ExtValContext() |
| { |
| this.contextHelper = new ExtValContextInternals(); |
| this.invocationOrderAwareContextHelper = new ExtValContextInvocationOrderAwareInternals(this.contextHelper); |
| |
| retrieveModuleConfigurationResolver(); |
| } |
| |
| /** |
| * Retrieves the Module Configuration Resolver. Code looks first for a resolver located under the ExtVal Custom |
| * package (org.apache.myfaces.extensions.validator.custom.ExtValModuleConfigurationResolver) and then for a |
| * web.xml defined initialization parameter org.apache.myfaces.extensions.validator.core. |
| * ExtValModuleConfigurationResolver |
| * for a fully qualified class name. The resolver configured by the web.xml overrides the custom defined one. |
| */ |
| private void retrieveModuleConfigurationResolver() |
| { |
| Object customExtValModuleConfigurationResolver = |
| ClassUtils.tryToInstantiateClassForName(CUSTOM_EXTVAL_MODULE_CONFIGURATION_RESOLVER_CLASS_NAME); |
| |
| if(customExtValModuleConfigurationResolver instanceof ExtValModuleConfigurationResolver) |
| { |
| this.defaultModuleConfigurationResolver = |
| (ExtValModuleConfigurationResolver)customExtValModuleConfigurationResolver; |
| } |
| |
| String customExtValModuleConfigurationResolverClassName = |
| getInitParameter(null, ExtValModuleConfigurationResolver.class.getName()); |
| |
| if(customExtValModuleConfigurationResolverClassName != null) |
| { |
| customExtValModuleConfigurationResolver = |
| ClassUtils.tryToInstantiateClassForName(customExtValModuleConfigurationResolverClassName); |
| |
| if(customExtValModuleConfigurationResolver instanceof ExtValModuleConfigurationResolver) |
| { |
| this.defaultModuleConfigurationResolver = |
| (ExtValModuleConfigurationResolver)customExtValModuleConfigurationResolver; |
| } |
| } |
| } |
| |
| public static ExtValContext getContext() |
| { |
| if (extValContext == null) |
| { |
| extValContext = new ExtValContext(); |
| |
| tryToCreateCustomExtValContext(); |
| } |
| return extValContext; |
| } |
| |
| private static void tryToCreateCustomExtValContext() |
| { |
| Object customExtValContext = ClassUtils.tryToInstantiateClassForName(CUSTOM_EXTVAL_CONTEXT_CLASS_NAME); |
| |
| if (customExtValContext instanceof ExtValContext) |
| { |
| extValContext = (ExtValContext) customExtValContext; |
| } |
| } |
| |
| public void setViolationSeverityInterpreter(ViolationSeverityInterpreter violationSeverityInterpreter) |
| { |
| setViolationSeverityInterpreter(violationSeverityInterpreter, true); |
| } |
| |
| public void setViolationSeverityInterpreter( |
| ViolationSeverityInterpreter violationSeverityInterpreter, boolean forceOverride) |
| { |
| if (this.violationSeverityInterpreter == null || forceOverride) |
| { |
| if (violationSeverityInterpreter != null) |
| { |
| this.logger.info(violationSeverityInterpreter.getClass() + " is used"); |
| } |
| this.violationSeverityInterpreter = violationSeverityInterpreter; |
| } |
| } |
| |
| public ViolationSeverityInterpreter getViolationSeverityInterpreter() |
| { |
| ViolationSeverityInterpreter requestScopedInterpreter = this.contextHelper |
| .getRequestScopedViolationSeverityInterpreter(); |
| |
| if(requestScopedInterpreter != null) |
| { |
| return requestScopedInterpreter; |
| } |
| |
| return this.violationSeverityInterpreter; |
| } |
| |
| /* |
| * FactoryFinder |
| */ |
| public FactoryFinder getFactoryFinder() |
| { |
| return this.factoryFinder; |
| } |
| |
| public void setFactoryFinder(FactoryFinder factoryFinder) |
| { |
| if (factoryFinder != null) |
| { |
| this.factoryFinder = factoryFinder; |
| } |
| } |
| |
| /* |
| * SkipValidationEvaluator |
| */ |
| public void setSkipValidationEvaluator(SkipValidationEvaluator skipValidationEvaluator) |
| { |
| setSkipValidationEvaluator(skipValidationEvaluator, true); |
| } |
| |
| public void setSkipValidationEvaluator(SkipValidationEvaluator skipValidationEvaluator, boolean forceOverride) |
| { |
| if (this.skipValidationEvaluator == null || forceOverride) |
| { |
| if (skipValidationEvaluator != null) |
| { |
| this.logger.info(skipValidationEvaluator.getClass() + " is used"); |
| } |
| this.skipValidationEvaluator = skipValidationEvaluator; |
| } |
| } |
| |
| public SkipValidationEvaluator getSkipValidationEvaluator() |
| { |
| if (this.skipValidationEvaluator == null) |
| { |
| return new SkipValidationEvaluator() |
| { |
| public boolean skipValidation(FacesContext facesContext, UIComponent uiComponent, |
| ValidationStrategy validationStrategy, MetaDataEntry entry) |
| { |
| return false; |
| } |
| }; |
| } |
| |
| return this.skipValidationEvaluator; |
| } |
| |
| /* |
| * RendererInterceptors |
| */ |
| public List<RendererInterceptor> getRendererInterceptors() |
| { |
| if (this.rendererInterceptorCache == null) |
| { |
| this.rendererInterceptorCache = new ArrayList<RendererInterceptor>(this.rendererInterceptors.values()); |
| } |
| |
| return this.rendererInterceptorCache; |
| } |
| |
| public boolean registerRendererInterceptor(RendererInterceptor rendererInterceptor) |
| { |
| synchronized (ExtValContext.class) |
| { |
| if (this.deniedInterceptors.contains(rendererInterceptor.getInterceptorId())) |
| { |
| return false; |
| } |
| |
| this.rendererInterceptors.put(rendererInterceptor.getInterceptorId(), rendererInterceptor); |
| this.rendererInterceptorCache = new ArrayList<RendererInterceptor>(this.rendererInterceptors.values()); |
| } |
| return true; |
| } |
| |
| public void deregisterRendererInterceptor(Class<? extends RendererInterceptor> rendererInterceptorClass) |
| { |
| RendererInterceptor rendererInterceptor = ClassUtils.tryToInstantiateClass(rendererInterceptorClass); |
| |
| synchronized (ExtValContext.class) |
| { |
| this.rendererInterceptors.remove(rendererInterceptor.getInterceptorId()); |
| this.rendererInterceptorCache = new ArrayList<RendererInterceptor>(this.rendererInterceptors.values()); |
| } |
| } |
| |
| //if an interceptor hasn't been registered so far, it should be denied at future registrations |
| public void denyRendererInterceptor(Class<? extends RendererInterceptor> rendererInterceptorClass) |
| { |
| RendererInterceptor rendererInterceptor = ClassUtils.tryToInstantiateClass(rendererInterceptorClass); |
| |
| synchronized (ExtValContext.class) |
| { |
| if (!this.deniedInterceptors.contains(rendererInterceptor.getInterceptorId())) |
| { |
| this.deniedInterceptors.add(rendererInterceptor.getInterceptorId()); |
| } |
| } |
| deregisterRendererInterceptor(rendererInterceptorClass); |
| } |
| |
| /* |
| * ComponentInitializers |
| */ |
| public void addComponentInitializer(ComponentInitializer componentInitializer) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitComponentInitializers(); |
| this.invocationOrderAwareContextHelper.addComponentInitializer(componentInitializer); |
| } |
| |
| public List<ComponentInitializer> getComponentInitializers() |
| { |
| this.invocationOrderAwareContextHelper.lazyInitComponentInitializers(); |
| return this.invocationOrderAwareContextHelper.getComponentInitializers(); |
| } |
| |
| /* |
| * ValidationExceptionInterceptors |
| */ |
| public void addValidationExceptionInterceptor(ValidationExceptionInterceptor validationExceptionInterceptor) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitValidationExceptionInterceptors(); |
| this.invocationOrderAwareContextHelper.addValidationExceptionInterceptor(validationExceptionInterceptor); |
| } |
| |
| public List<ValidationExceptionInterceptor> getValidationExceptionInterceptors() |
| { |
| this.invocationOrderAwareContextHelper.lazyInitValidationExceptionInterceptors(); |
| return this.invocationOrderAwareContextHelper.getValidationExceptionInterceptors(); |
| } |
| |
| /* |
| * PropertyValidationInterceptors |
| */ |
| public void addPropertyValidationInterceptor(PropertyValidationInterceptor propertyValidationInterceptor) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitPropertyValidationInterceptors(); |
| this.invocationOrderAwareContextHelper.addPropertyValidationInterceptor(propertyValidationInterceptor); |
| } |
| |
| /** |
| * @return all global validation interceptors |
| */ |
| public List<PropertyValidationInterceptor> getPropertyValidationInterceptors() |
| { |
| this.invocationOrderAwareContextHelper.lazyInitPropertyValidationInterceptors(); |
| return this.invocationOrderAwareContextHelper.getPropertyValidationInterceptors(); |
| } |
| |
| public List<PropertyValidationInterceptor> getPropertyValidationInterceptorsFor(Class moduleKey) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitPropertyValidationInterceptors(); |
| return this.invocationOrderAwareContextHelper.getPropertyValidationInterceptorsFor(moduleKey); |
| } |
| |
| /* |
| * MetaDataExtractionInterceptors |
| */ |
| public void addMetaDataExtractionInterceptor(MetaDataExtractionInterceptor metaDataExtractionInterceptor) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitMetaDataExtractionInterceptors(); |
| this.invocationOrderAwareContextHelper.addMetaDataExtractionInterceptor(metaDataExtractionInterceptor); |
| } |
| |
| /** |
| * @return all global meta-data extraction interceptors |
| */ |
| public List<MetaDataExtractionInterceptor> getMetaDataExtractionInterceptors() |
| { |
| this.invocationOrderAwareContextHelper.lazyInitMetaDataExtractionInterceptors(); |
| return this.invocationOrderAwareContextHelper.getMetaDataExtractionInterceptors(); |
| } |
| |
| public List<MetaDataExtractionInterceptor> getMetaDataExtractionInterceptorsFor(Class moduleKey) |
| { |
| Map<String, Object> properties = new HashMap<String, Object>(); |
| |
| if(moduleKey != null) |
| { |
| properties.put(ValidationModuleKey.class.getName(), moduleKey); |
| } |
| return getMetaDataExtractionInterceptorsWith(properties); |
| } |
| |
| public List<MetaDataExtractionInterceptor> getMetaDataExtractionInterceptorsWith(Map<String, Object> properties) |
| { |
| this.invocationOrderAwareContextHelper.lazyInitMetaDataExtractionInterceptors(); |
| return this.invocationOrderAwareContextHelper.getMetaDataExtractionInterceptorsWith(properties); |
| } |
| |
| /* |
| * ProcessedInformationRecorders |
| */ |
| public List<ProcessedInformationRecorder> getProcessedInformationRecorders() |
| { |
| return this.processedInformationRecorders; |
| } |
| |
| public void addProcessedInformationRecorder(ProcessedInformationRecorder processedInformationRecorder) |
| { |
| this.processedInformationRecorders.add(processedInformationRecorder); |
| } |
| |
| /* |
| * InformationProviderBean |
| */ |
| public InformationProviderBean getInformationProviderBean() |
| { |
| return this.contextHelper.getInformationProviderBean(); |
| } |
| |
| /* |
| * StaticConfiguration |
| */ |
| public List<StaticConfiguration<String, String>> getStaticConfiguration(StaticConfigurationNames name) |
| { |
| if (!this.staticConfigMap.containsKey(name)) |
| { |
| List<StaticConfiguration<String, String>> staticConfigList = |
| new ArrayList<StaticConfiguration<String, String>>(); |
| this.staticConfigMap.put(name, staticConfigList); |
| } |
| return this.staticConfigMap.get(name); |
| } |
| |
| public void addStaticConfiguration(StaticConfigurationNames name, StaticConfiguration<String, String> staticConfig) |
| { |
| synchronized (this) |
| { |
| List<StaticConfiguration<String, String>> staticConfigList; |
| if (!this.staticConfigMap.containsKey(name)) |
| { |
| staticConfigList = new ArrayList<StaticConfiguration<String, String>>(); |
| this.staticConfigMap.put(name, staticConfigList); |
| } |
| this.staticConfigMap.get(name).add(staticConfig); |
| } |
| } |
| |
| /* |
| * Global properties |
| */ |
| public boolean addGlobalProperty(String name, Object value) |
| { |
| return addGlobalProperty(name, value, true); |
| } |
| |
| public boolean addGlobalProperty(String name, Object value, boolean forceOverride) |
| { |
| if (this.globalProperties.containsKey(name)) |
| { |
| if (!forceOverride) |
| { |
| return false; |
| } |
| |
| this.logger.info("override global property '" + name + "'"); |
| } |
| |
| if(JsfProjectStage.is(JsfProjectStage.Development)) |
| { |
| this.logger.info("global property [" + name + "] added"); |
| } |
| |
| this.globalProperties.put(name, value); |
| return true; |
| } |
| |
| public Object getGlobalProperty(String name) |
| { |
| return this.globalProperties.get(name); |
| } |
| |
| /** |
| * Retrieves the configuration object of the type specified by the parameter 'targetType'. The type should be |
| * direct descendants of ExtValModuleConfiguration and the same as the type you used to register the configuration |
| * (see addModuleConfiguration). |
| * |
| * @param targetType Key that specifies the type of configuration, should be direct descendants of |
| * ExtValModuleConfiguration |
| * @param <T> |
| * @return configuration object |
| * @since r4 |
| */ |
| public <T extends ExtValModuleConfiguration> T getModuleConfiguration(Class<T> targetType) |
| { |
| ExtValModuleConfiguration result = this.extValConfig.get(targetType); |
| |
| //noinspection unchecked |
| return (T)result; |
| } |
| |
| /** |
| * Registers the configuration object specified in the parameter 'config' for the type 'key' within ExtVal |
| * overriding |
| * possible another registration. |
| * |
| * @param key Key that specifies the type of configuration, should be direct descendants of |
| * ExtValModuleConfiguration |
| * @param extValConfig Configuration object to register |
| * @return true |
| * @since r4 |
| */ |
| public boolean addModuleConfiguration(Class<? extends ExtValModuleConfiguration> key, |
| ExtValModuleConfiguration extValConfig) |
| { |
| return addModuleConfiguration(key, extValConfig, true); |
| } |
| |
| /** |
| * Registers the configuration object specified in the parameter 'config' for the type 'key' within ExtVal. When a |
| * configuration object already exist for the key and we don't specify to override it (parameter forceOverride) the |
| * configuration isn't registered. |
| * @param key Key that specifies the type of configuration, should be direct descendants of |
| * ExtValModuleConfiguration |
| * @param config Configuration object to register |
| * @param forceOverride Do we override another custom configuration that is already registered. |
| * @return true is the configuration is registered or false if already existed and no ofrce override specified. |
| * @since r4 |
| */ |
| public boolean addModuleConfiguration(Class<? extends ExtValModuleConfiguration> key, |
| ExtValModuleConfiguration config, |
| boolean forceOverride) |
| { |
| // Check if it already exists. |
| if (this.extValConfig.containsKey(key)) |
| { |
| if (!forceOverride) |
| { |
| // Don't forced, so not registered |
| return false; |
| } |
| |
| this.logger.info("override config for key '" + config.getClass() + "'"); |
| } |
| |
| //anonymous class are only supported for test-cases and |
| //there we don't need a custom config defined in the web.xml |
| // or from a resolver |
| if(!config.getClass().isAnonymousClass()) |
| { |
| config = tryToLoadCustomConfigImplementation(config); |
| } |
| |
| // Store the configuration |
| this.extValConfig.put(key, config); |
| |
| // Logging when in Development Stage. |
| if(JsfProjectStage.is(JsfProjectStage.Development)) |
| { |
| this.logger.info("config for key [" + config.getClass() + "] added"); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Tries to load a custom configuration implementation by looking for a web.xml initialization parameter. The method |
| * returns the configuration object that should be used. That is, the custom defined version or the specified |
| * as parameter of the method. |
| * |
| * @param config The configuration object for which we try to load another version |
| * @return The custom configuration object or parameter specified if no alternative found. |
| * @since r4 |
| */ |
| private ExtValModuleConfiguration tryToLoadCustomConfigImplementation(ExtValModuleConfiguration config) |
| { |
| // Get the parent if the parameter. For the default version, like DefaultExtValCoreConfiguration, it is |
| // the abstract base class. |
| Class configClass = config.getClass().getSuperclass(); |
| |
| // To be on the safe side that the parent still belongs to the configuration part of ExtVal. |
| if(!ExtValModuleConfiguration.class.isAssignableFrom(configClass)) |
| { |
| return config; |
| } |
| |
| @SuppressWarnings({"unchecked"}) |
| Class<? extends ExtValModuleConfiguration> configDefinitionClass = |
| (Class<? extends ExtValModuleConfiguration>)configClass; |
| |
| // If we have a resolver, use it to retrieve the configuration |
| if(this.defaultModuleConfigurationResolver != null) |
| { |
| config = this.defaultModuleConfigurationResolver.getCustomConfiguration(configDefinitionClass); |
| } |
| |
| // Lookup the web.xml initialization parameter |
| String customConfigClassName = getInitParameter(null, configDefinitionClass.getName()); |
| |
| if(customConfigClassName != null) |
| { |
| // If specified, see if it exists and can be used. |
| Object customConfig = ClassUtils.tryToInstantiateClassForName(customConfigClassName); |
| |
| if(customConfig instanceof ExtValModuleConfiguration) |
| { |
| return (ExtValModuleConfiguration)customConfig; |
| } |
| } |
| // return the parameter or resolver one. |
| return config; |
| } |
| } |