blob: a9fd128dfa267585cf99387238835cc322e44619 [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.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);
}
}