| package org.apache.commons.ognl; |
| |
| /* |
| * 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. |
| */ |
| |
| import org.apache.commons.ognl.internal.*; |
| import org.apache.commons.ognl.internal.entry.*; |
| |
| import java.beans.PropertyDescriptor; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.security.Permission; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Enumeration; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * This class takes care of all the internal caching for OGNL. |
| */ |
| public class OgnlCache { |
| |
| private final CacheFactory cacheFactory = new HashMapCacheFactory(); |
| |
| private final ClassCache<MethodAccessor> methodAccessors = cacheFactory.createClassCache(); |
| { |
| MethodAccessor methodAccessor = new ObjectMethodAccessor(); |
| setMethodAccessor( Object.class, methodAccessor ); |
| setMethodAccessor( byte[].class, methodAccessor ); |
| setMethodAccessor( short[].class, methodAccessor ); |
| setMethodAccessor( char[].class, methodAccessor ); |
| setMethodAccessor( int[].class, methodAccessor ); |
| setMethodAccessor( long[].class, methodAccessor ); |
| setMethodAccessor( float[].class, methodAccessor ); |
| setMethodAccessor( double[].class, methodAccessor ); |
| setMethodAccessor( Object[].class, methodAccessor ); |
| } |
| |
| private final ClassCache<PropertyAccessor> propertyAccessors = cacheFactory.createClassCache(); |
| { |
| PropertyAccessor propertyAccessor = new ArrayPropertyAccessor(); |
| setPropertyAccessor( Object.class, new ObjectPropertyAccessor() ); |
| setPropertyAccessor( byte[].class, propertyAccessor ); |
| setPropertyAccessor( short[].class, propertyAccessor ); |
| setPropertyAccessor( char[].class, propertyAccessor ); |
| setPropertyAccessor( int[].class, propertyAccessor ); |
| setPropertyAccessor( long[].class, propertyAccessor ); |
| setPropertyAccessor( float[].class, propertyAccessor ); |
| setPropertyAccessor( double[].class, propertyAccessor ); |
| setPropertyAccessor( Object[].class, propertyAccessor ); |
| setPropertyAccessor( List.class, new ListPropertyAccessor() ); |
| setPropertyAccessor( Map.class, new MapPropertyAccessor() ); |
| setPropertyAccessor( Set.class, new SetPropertyAccessor() ); |
| setPropertyAccessor( Iterator.class, new IteratorPropertyAccessor() ); |
| setPropertyAccessor( Enumeration.class, new EnumerationPropertyAccessor() ); |
| } |
| |
| private final ClassCache<ElementsAccessor> elementsAccessors = cacheFactory.createClassCache(); |
| { |
| ElementsAccessor elementsAccessor = new ArrayElementsAccessor(); |
| setElementsAccessor( Object.class, new ObjectElementsAccessor() ); |
| setElementsAccessor( byte[].class, elementsAccessor ); |
| setElementsAccessor( short[].class, elementsAccessor ); |
| setElementsAccessor( char[].class, elementsAccessor ); |
| setElementsAccessor( int[].class, elementsAccessor ); |
| setElementsAccessor( long[].class, elementsAccessor ); |
| setElementsAccessor( float[].class, elementsAccessor ); |
| setElementsAccessor( double[].class, elementsAccessor ); |
| setElementsAccessor( Object[].class, elementsAccessor ); |
| setElementsAccessor( Collection.class, new CollectionElementsAccessor() ); |
| setElementsAccessor( Map.class, new MapElementsAccessor() ); |
| setElementsAccessor( Iterator.class, new IteratorElementsAccessor() ); |
| setElementsAccessor( Enumeration.class, new EnumerationElementsAccessor() ); |
| setElementsAccessor( Number.class, new NumberElementsAccessor() ); |
| } |
| |
| private final ClassCache<NullHandler> nullHandlers = cacheFactory.createClassCache( ); |
| { |
| NullHandler nullHandler = new ObjectNullHandler(); |
| setNullHandler( Object.class, nullHandler ); |
| setNullHandler( byte[].class, nullHandler ); |
| setNullHandler( short[].class, nullHandler ); |
| setNullHandler( char[].class, nullHandler ); |
| setNullHandler( int[].class, nullHandler ); |
| setNullHandler( long[].class, nullHandler ); |
| setNullHandler( float[].class, nullHandler ); |
| setNullHandler( double[].class, nullHandler ); |
| setNullHandler( Object[].class, nullHandler ); |
| } |
| |
| final ClassCache<Map<String, PropertyDescriptor>> propertyDescriptorCache = |
| cacheFactory.createClassCache( new PropertyDescriptorCacheEntryFactory() ); |
| |
| private final ClassCache<List<Constructor<?>>> constructorCache = |
| cacheFactory.createClassCache(key -> Arrays.<Constructor<?>>asList( key.getConstructors() )); |
| |
| private final Cache<DeclaredMethodCacheEntry, Map<String, List<Method>>> _methodCache = |
| cacheFactory.createCache( new DeclaredMethodCacheEntryFactory() ); |
| |
| private final Cache<PermissionCacheEntry, Permission> _invokePermissionCache = |
| cacheFactory.createCache( new PermissionCacheEntryFactory() ); |
| |
| private final ClassCache<Map<String, Field>> _fieldCache = |
| cacheFactory.createClassCache( new FieldCacheEntryFactory() ); |
| |
| private final Cache<Method, Class<?>[]> _methodParameterTypesCache = |
| cacheFactory.createCache(Method::getParameterTypes); |
| |
| private final Cache<GenericMethodParameterTypeCacheEntry, Class<?>[]> _genericMethodParameterTypesCache = |
| cacheFactory.createCache( new GenericMethodParameterTypeFactory() ); |
| |
| private final Cache<Constructor<?>, Class<?>[]> _ctorParameterTypesCache = |
| cacheFactory.createCache(Constructor::getParameterTypes); |
| |
| private final Cache<Method, MethodAccessEntryValue> _methodAccessCache = |
| cacheFactory.createCache( new MethodAccessCacheEntryFactory( ) ); |
| |
| private final MethodPermCacheEntryFactory methodPermCacheEntryFactory = |
| new MethodPermCacheEntryFactory( System.getSecurityManager() ); |
| |
| private final Cache<Method, Boolean> _methodPermCache = cacheFactory.createCache( methodPermCacheEntryFactory ); |
| |
| public Class<?>[] getMethodParameterTypes( Method method ) throws CacheException { |
| return _methodParameterTypesCache.get( method ); |
| } |
| |
| public Class<?>[] getParameterTypes( Constructor<?> constructor ) throws CacheException { |
| return _ctorParameterTypesCache.get( constructor ); |
| } |
| |
| public List<Constructor<?>> getConstructor( Class<?> clazz ) throws CacheException { |
| return constructorCache.get( clazz ); |
| } |
| |
| public Map<String, Field> getField( Class<?> clazz ) throws CacheException { |
| return _fieldCache.get( clazz ); |
| } |
| |
| public Map<String, List<Method>> getMethod( DeclaredMethodCacheEntry declaredMethodCacheEntry ) throws CacheException { |
| return _methodCache.get( declaredMethodCacheEntry ); |
| } |
| |
| public Map<String, PropertyDescriptor> getPropertyDescriptor( Class<?> clazz ) throws CacheException { |
| return propertyDescriptorCache.get( clazz ); |
| } |
| |
| public Permission getInvokePermission( PermissionCacheEntry permissionCacheEntry ) throws CacheException { |
| return _invokePermissionCache.get( permissionCacheEntry ); |
| } |
| |
| public MethodAccessor getMethodAccessor( Class<?> clazz ) throws OgnlException |
| { |
| MethodAccessor methodAccessor = ClassCacheHandler.getHandler( clazz, methodAccessors ); |
| if ( methodAccessor != null ) |
| { |
| return methodAccessor; |
| } |
| throw new OgnlException( "No method accessor for " + clazz ); |
| } |
| |
| public void setMethodAccessor( Class<?> clazz, MethodAccessor accessor ) |
| { |
| methodAccessors.put( clazz, accessor ); |
| } |
| |
| public void setPropertyAccessor( Class<?> clazz, PropertyAccessor accessor ) |
| { |
| propertyAccessors.put( clazz, accessor ); |
| } |
| |
| public PropertyAccessor getPropertyAccessor( Class<?> clazz ) |
| throws OgnlException |
| { |
| PropertyAccessor propertyAccessor = ClassCacheHandler.getHandler( clazz, propertyAccessors ); |
| if ( propertyAccessor != null ) |
| { |
| return propertyAccessor; |
| } |
| throw new OgnlException( "No property accessor for class " + clazz ); |
| } |
| |
| /** |
| * Registers the specified {@link ClassCacheInspector} with all class reflection based internal caches. This may |
| * have a significant performance impact so be careful using this in production scenarios. |
| * |
| * @param inspector The inspector instance that will be registered with all internal cache instances. |
| */ |
| public void setClassCacheInspector( ClassCacheInspector inspector ) |
| { |
| propertyDescriptorCache.setClassInspector( inspector ); |
| constructorCache.setClassInspector( inspector ); |
| //TODO: methodCache and invokePC should allow to use classCacheInsecptor |
| // _methodCache.setClassInspector( inspector ); |
| // _invokePermissionCache.setClassInspector( inspector ); |
| _fieldCache.setClassInspector( inspector ); |
| } |
| |
| public Class<?>[] getGenericMethodParameterTypes( GenericMethodParameterTypeCacheEntry key ) |
| throws CacheException |
| { |
| return _genericMethodParameterTypesCache.get( key ); |
| } |
| |
| public boolean getMethodPerm( Method method ) throws CacheException |
| { |
| return _methodPermCache.get( method ); |
| } |
| |
| public MethodAccessEntryValue getMethodAccess( Method method ) throws CacheException |
| { |
| return _methodAccessCache.get( method ); |
| } |
| |
| public void clear() { |
| _methodParameterTypesCache.clear(); |
| _ctorParameterTypesCache.clear(); |
| propertyDescriptorCache.clear(); |
| constructorCache.clear(); |
| _methodCache.clear(); |
| _invokePermissionCache.clear(); |
| _fieldCache.clear(); |
| _methodAccessCache.clear(); |
| } |
| |
| public ElementsAccessor getElementsAccessor( Class<?> clazz ) throws OgnlException |
| { |
| ElementsAccessor answer = ClassCacheHandler.getHandler( clazz, elementsAccessors ); |
| if ( answer != null ) |
| { |
| return answer; |
| } |
| throw new OgnlException( "No elements accessor for class " + clazz ); |
| } |
| |
| public void setElementsAccessor( Class<?> clazz, ElementsAccessor accessor ) |
| { |
| elementsAccessors.put( clazz, accessor ); |
| } |
| |
| public NullHandler getNullHandler( Class<?> clazz ) throws OgnlException |
| { |
| NullHandler answer = ClassCacheHandler.getHandler( clazz, nullHandlers ); |
| if ( answer != null ) |
| { |
| return answer; |
| } |
| throw new OgnlException( "No null handler for class " + clazz ); |
| } |
| |
| public void setNullHandler( Class<?> clazz, NullHandler handler ) |
| { |
| nullHandlers.put( clazz, handler ); |
| } |
| |
| public void setSecurityManager( SecurityManager securityManager ) |
| { |
| methodPermCacheEntryFactory.setSecurityManager( securityManager ); |
| } |
| } |