/* | |
* 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.storage; | |
import org.apache.myfaces.extensions.validator.core.ExtValCoreConfiguration; | |
import org.apache.myfaces.extensions.validator.internal.UsageInformation; | |
import org.apache.myfaces.extensions.validator.internal.ToDo; | |
import org.apache.myfaces.extensions.validator.internal.Priority; | |
import static org.apache.myfaces.extensions.validator.internal.UsageCategory.INTERNAL; | |
import org.apache.myfaces.extensions.validator.core.property.PropertyInformation; | |
import org.apache.myfaces.extensions.validator.core.property.PropertyDetails; | |
import org.apache.myfaces.extensions.validator.core.property.PropertyInformationKeys; | |
import org.apache.myfaces.extensions.validator.core.property.DefaultPropertyInformation; | |
import org.apache.myfaces.extensions.validator.core.metadata.MetaDataEntry; | |
import org.apache.myfaces.extensions.validator.core.CustomInformation; | |
import org.apache.myfaces.extensions.validator.core.ExtValContext; | |
import org.apache.myfaces.extensions.validator.util.ClassUtils; | |
import org.apache.myfaces.extensions.validator.util.ProxyUtils; | |
import org.apache.myfaces.extensions.validator.util.NullValueAwareConcurrentHashMap; | |
import java.util.Map; | |
import java.util.List; | |
import java.util.ArrayList; | |
import java.util.concurrent.ConcurrentHashMap; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
import java.util.logging.Logger; | |
/** | |
* @author Gerhard Petracek | |
* @since x.x.3 | |
*/ | |
@UsageInformation(INTERNAL) | |
public class DefaultMetaDataStorage implements MetaDataStorage | |
{ | |
protected final Logger logger = Logger.getLogger(getClass().getName()); | |
private Map<String, Map<String, PropertyInformation>> cachedPropertyInformation = | |
new ConcurrentHashMap<String, Map<String, PropertyInformation>>(); | |
private List<MetaDataStorageFilter> metaDataStorageFilters = new CopyOnWriteArrayList<MetaDataStorageFilter>(); | |
private List<Class<? extends MetaDataStorageFilter>> deniedMetaDataFilters = | |
new CopyOnWriteArrayList<Class<? extends MetaDataStorageFilter>>(); | |
public DefaultMetaDataStorage() | |
{ | |
initFilters(); | |
} | |
private void initFilters() | |
{ | |
List<String> metaDataStorageFilterClassNames = new ArrayList<String>(); | |
metaDataStorageFilterClassNames | |
.add(ExtValCoreConfiguration.get().customMetaDataStorageFilterClassName()); | |
metaDataStorageFilterClassNames | |
.add(ExtValContext.getContext().getInformationProviderBean().get( | |
CustomInformation.META_DATA_STORAGE_FILTER)); | |
MetaDataStorageFilter metaDataStorageFilter; | |
for (String validationExceptionInterceptorName : metaDataStorageFilterClassNames) | |
{ | |
metaDataStorageFilter = | |
(MetaDataStorageFilter)ClassUtils.tryToInstantiateClassForName(validationExceptionInterceptorName); | |
if (metaDataStorageFilter != null) | |
{ | |
this.metaDataStorageFilters.add(metaDataStorageFilter); | |
logAddedFilter(metaDataStorageFilter.getClass()); | |
} | |
} | |
} | |
public void storeMetaDataOf(PropertyInformation propertyInformation) | |
{ | |
invokeFilters(propertyInformation); | |
PropertyInformation propertyInformationToStore = new DefaultPropertyInformation(); | |
PropertyDetails propertyDetails = propertyInformation | |
.getInformation(PropertyInformationKeys.PROPERTY_DETAILS, PropertyDetails.class); | |
copyMetaData(propertyInformation, propertyInformationToStore); | |
getMapForClass(ProxyUtils.getUnproxiedClass(propertyDetails.getBaseObject().getClass())) | |
.put(propertyDetails.getProperty(), propertyInformationToStore); | |
} | |
private void invokeFilters(PropertyInformation propertyInformation) | |
{ | |
for(MetaDataStorageFilter filter : this.metaDataStorageFilters) | |
{ | |
filter.filter(propertyInformation); | |
} | |
} | |
public MetaDataEntry[] getMetaData(Class targetClass, String targetProperty) | |
{ | |
PropertyInformation propertyInformation = getMapForClass(targetClass).get(targetProperty); | |
PropertyInformation clonedPropertyInformation = new DefaultPropertyInformation(); | |
copyMetaData(propertyInformation, clonedPropertyInformation); | |
return clonedPropertyInformation.getMetaDataEntries(); | |
} | |
public boolean containsMetaDataFor(Class targetClass, String targetProperty) | |
{ | |
return getMapForClass(targetClass).containsKey(targetProperty); | |
} | |
public void registerFilter(MetaDataStorageFilter storageFilter) | |
{ | |
synchronized (this) | |
{ | |
if(!isFilterDenied(storageFilter) && !isFilterAlreadyRegistered(storageFilter)) | |
{ | |
this.metaDataStorageFilters.add(storageFilter); | |
logAddedFilter(storageFilter.getClass()); | |
} | |
} | |
} | |
private boolean isFilterDenied(MetaDataStorageFilter storageFilter) | |
{ | |
return this.deniedMetaDataFilters.contains(getStorageFilterClass(storageFilter)); | |
} | |
private boolean isFilterAlreadyRegistered(MetaDataStorageFilter storageFilter) | |
{ | |
for(MetaDataStorageFilter filter : this.metaDataStorageFilters) | |
{ | |
if(filter.getClass().equals(getStorageFilterClass(storageFilter))) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
public void deregisterFilter(Class<? extends MetaDataStorageFilter> filterClass) | |
{ | |
MetaDataStorageFilter storageFilter = ClassUtils.tryToInstantiateClass(filterClass); | |
synchronized (this) | |
{ | |
this.metaDataStorageFilters.remove(storageFilter); | |
} | |
logRemovedFilter(storageFilter.getClass()); | |
} | |
public void denyFilter(Class<? extends MetaDataStorageFilter> filterClass) | |
{ | |
synchronized (this) | |
{ | |
for(Class<? extends MetaDataStorageFilter> filterId : this.deniedMetaDataFilters) | |
{ | |
if(filterId.equals(filterClass)) | |
{ | |
return; | |
} | |
} | |
this.deniedMetaDataFilters.add(filterClass); | |
} | |
deregisterFilter(filterClass); | |
} | |
@ToDo(Priority.MEDIUM) | |
private void copyMetaData(PropertyInformation source, PropertyInformation target) | |
{ | |
MetaDataEntry newMetaDataEntry; | |
for(MetaDataEntry metaDataEntry : source.getMetaDataEntries()) | |
{ | |
newMetaDataEntry = new MetaDataEntry(); | |
newMetaDataEntry.setKey(metaDataEntry.getKey()); | |
newMetaDataEntry.setValue(metaDataEntry.getValue()); | |
target.addMetaDataEntry(newMetaDataEntry); | |
} | |
} | |
private void logAddedFilter(Class<? extends MetaDataStorageFilter> filterClass) | |
{ | |
this.logger.info(filterClass.getName() + " added"); | |
} | |
private void logRemovedFilter(Class<? extends MetaDataStorageFilter> filterClass) | |
{ | |
this.logger.info(filterClass.getName() + " removed"); | |
} | |
private Map<String, PropertyInformation> getMapForClass(Class target) | |
{ | |
String key = ProxyUtils.getClassName(target); | |
if(!this.cachedPropertyInformation.containsKey(key)) | |
{ | |
this.cachedPropertyInformation.put(key, | |
new NullValueAwareConcurrentHashMap<String, PropertyInformation>(new NullMarkerPropertyInformation())); | |
} | |
return this.cachedPropertyInformation.get(key); | |
} | |
private static class NullMarkerPropertyInformation implements PropertyInformation | |
{ | |
public boolean containsInformation(String key) | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public Object getInformation(String key) | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public <T> T getInformation(String key, Class<T> targetClass) | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public void setInformation(String key, Object value) | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public MetaDataEntry[] getMetaDataEntries() | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public void addMetaDataEntry(MetaDataEntry metaDataEntry) | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
public void resetMetaDataEntries() | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
@Override | |
public int hashCode() | |
{ | |
return getClass().hashCode(); | |
} | |
@Override | |
public boolean equals(Object target) | |
{ | |
return target != null && getClass().equals(target.getClass()); | |
} | |
} | |
private Class<? extends MetaDataStorageFilter> getStorageFilterClass(MetaDataStorageFilter storageFilter) | |
{ | |
return ProxyUtils.getUnproxiedClass(storageFilter.getClass(), MetaDataStorageFilter.class); | |
} | |
} |