001 package org.apache.commons.ognl; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import org.apache.commons.ognl.internal.*; 023 import org.apache.commons.ognl.internal.entry.*; 024 025 import java.beans.PropertyDescriptor; 026 import java.lang.reflect.Constructor; 027 import java.lang.reflect.Field; 028 import java.lang.reflect.Method; 029 import java.security.Permission; 030 import java.util.Arrays; 031 import java.util.Collection; 032 import java.util.Enumeration; 033 import java.util.Iterator; 034 import java.util.List; 035 import java.util.Map; 036 import java.util.Set; 037 038 /** 039 * This class takes care of all the internal caching for OGNL. 040 */ 041 public class OgnlCache { 042 043 private final CacheFactory cacheFactory = new HashMapCacheFactory(); 044 045 private final ClassCache<MethodAccessor> methodAccessors = cacheFactory.createClassCache(); 046 { 047 MethodAccessor methodAccessor = new ObjectMethodAccessor(); 048 setMethodAccessor( Object.class, methodAccessor ); 049 setMethodAccessor( byte[].class, methodAccessor ); 050 setMethodAccessor( short[].class, methodAccessor ); 051 setMethodAccessor( char[].class, methodAccessor ); 052 setMethodAccessor( int[].class, methodAccessor ); 053 setMethodAccessor( long[].class, methodAccessor ); 054 setMethodAccessor( float[].class, methodAccessor ); 055 setMethodAccessor( double[].class, methodAccessor ); 056 setMethodAccessor( Object[].class, methodAccessor ); 057 } 058 059 private final ClassCache<PropertyAccessor> propertyAccessors = cacheFactory.createClassCache(); 060 { 061 PropertyAccessor propertyAccessor = new ArrayPropertyAccessor(); 062 setPropertyAccessor( Object.class, new ObjectPropertyAccessor() ); 063 setPropertyAccessor( byte[].class, propertyAccessor ); 064 setPropertyAccessor( short[].class, propertyAccessor ); 065 setPropertyAccessor( char[].class, propertyAccessor ); 066 setPropertyAccessor( int[].class, propertyAccessor ); 067 setPropertyAccessor( long[].class, propertyAccessor ); 068 setPropertyAccessor( float[].class, propertyAccessor ); 069 setPropertyAccessor( double[].class, propertyAccessor ); 070 setPropertyAccessor( Object[].class, propertyAccessor ); 071 setPropertyAccessor( List.class, new ListPropertyAccessor() ); 072 setPropertyAccessor( Map.class, new MapPropertyAccessor() ); 073 setPropertyAccessor( Set.class, new SetPropertyAccessor() ); 074 setPropertyAccessor( Iterator.class, new IteratorPropertyAccessor() ); 075 setPropertyAccessor( Enumeration.class, new EnumerationPropertyAccessor() ); 076 } 077 078 private final ClassCache<ElementsAccessor> elementsAccessors = cacheFactory.createClassCache(); 079 { 080 ElementsAccessor elementsAccessor = new ArrayElementsAccessor(); 081 setElementsAccessor( Object.class, new ObjectElementsAccessor() ); 082 setElementsAccessor( byte[].class, elementsAccessor ); 083 setElementsAccessor( short[].class, elementsAccessor ); 084 setElementsAccessor( char[].class, elementsAccessor ); 085 setElementsAccessor( int[].class, elementsAccessor ); 086 setElementsAccessor( long[].class, elementsAccessor ); 087 setElementsAccessor( float[].class, elementsAccessor ); 088 setElementsAccessor( double[].class, elementsAccessor ); 089 setElementsAccessor( Object[].class, elementsAccessor ); 090 setElementsAccessor( Collection.class, new CollectionElementsAccessor() ); 091 setElementsAccessor( Map.class, new MapElementsAccessor() ); 092 setElementsAccessor( Iterator.class, new IteratorElementsAccessor() ); 093 setElementsAccessor( Enumeration.class, new EnumerationElementsAccessor() ); 094 setElementsAccessor( Number.class, new NumberElementsAccessor() ); 095 } 096 097 private final ClassCache<NullHandler> nullHandlers = cacheFactory.createClassCache( ); 098 { 099 NullHandler nullHandler = new ObjectNullHandler(); 100 setNullHandler( Object.class, nullHandler ); 101 setNullHandler( byte[].class, nullHandler ); 102 setNullHandler( short[].class, nullHandler ); 103 setNullHandler( char[].class, nullHandler ); 104 setNullHandler( int[].class, nullHandler ); 105 setNullHandler( long[].class, nullHandler ); 106 setNullHandler( float[].class, nullHandler ); 107 setNullHandler( double[].class, nullHandler ); 108 setNullHandler( Object[].class, nullHandler ); 109 } 110 111 final ClassCache<Map<String, PropertyDescriptor>> propertyDescriptorCache = 112 cacheFactory.createClassCache( new PropertyDescriptorCacheEntryFactory() ); 113 114 private final ClassCache<List<Constructor<?>>> constructorCache = 115 cacheFactory.createClassCache( new ClassCacheEntryFactory<List<Constructor<?>>>() 116 { 117 public List<Constructor<?>> create( Class<?> key ) 118 throws CacheException 119 { 120 return Arrays.<Constructor<?>>asList( key.getConstructors() ); 121 } 122 } ); 123 124 private final Cache<DeclaredMethodCacheEntry, Map<String, List<Method>>> _methodCache = 125 cacheFactory.createCache( new DeclaredMethodCacheEntryFactory() ); 126 127 private final Cache<PermissionCacheEntry, Permission> _invokePermissionCache = 128 cacheFactory.createCache( new PermissionCacheEntryFactory() ); 129 130 private final ClassCache<Map<String, Field>> _fieldCache = 131 cacheFactory.createClassCache( new FieldCacheEntryFactory() ); 132 133 private final Cache<Method, Class<?>[]> _methodParameterTypesCache = 134 cacheFactory.createCache( new CacheEntryFactory<Method, Class<?>[]>() 135 { 136 public Class<?>[] create( Method key ) 137 throws CacheException 138 { 139 return key.getParameterTypes( ); 140 } 141 } ); 142 143 private final Cache<GenericMethodParameterTypeCacheEntry, Class<?>[]> _genericMethodParameterTypesCache = 144 cacheFactory.createCache( new GenericMethodParameterTypeFactory() ); 145 146 private final Cache<Constructor<?>, Class<?>[]> _ctorParameterTypesCache = 147 cacheFactory.createCache( new CacheEntryFactory<Constructor<?>, Class<?>[]>() 148 { 149 public Class<?>[] create( Constructor<?> key ) throws CacheException 150 { 151 return key.getParameterTypes( ); 152 } 153 } ); 154 155 private final Cache<Method, MethodAccessEntryValue> _methodAccessCache = 156 cacheFactory.createCache( new MethodAccessCacheEntryFactory( ) ); 157 158 private final MethodPermCacheEntryFactory methodPermCacheEntryFactory = 159 new MethodPermCacheEntryFactory( System.getSecurityManager() ); 160 161 private final Cache<Method, Boolean> _methodPermCache = cacheFactory.createCache( methodPermCacheEntryFactory ); 162 163 public Class<?>[] getMethodParameterTypes( Method method ) throws CacheException { 164 return _methodParameterTypesCache.get( method ); 165 } 166 167 public Class<?>[] getParameterTypes( Constructor<?> constructor ) throws CacheException { 168 return _ctorParameterTypesCache.get( constructor ); 169 } 170 171 public List<Constructor<?>> getConstructor( Class<?> clazz ) throws CacheException { 172 return constructorCache.get( clazz ); 173 } 174 175 public Map<String, Field> getField( Class<?> clazz ) throws CacheException { 176 return _fieldCache.get( clazz ); 177 } 178 179 public Map<String, List<Method>> getMethod( DeclaredMethodCacheEntry declaredMethodCacheEntry ) throws CacheException { 180 return _methodCache.get( declaredMethodCacheEntry ); 181 } 182 183 public Map<String, PropertyDescriptor> getPropertyDescriptor( Class<?> clazz ) throws CacheException { 184 return propertyDescriptorCache.get( clazz ); 185 } 186 187 public Permission getInvokePermission( PermissionCacheEntry permissionCacheEntry ) throws CacheException { 188 return _invokePermissionCache.get( permissionCacheEntry ); 189 } 190 191 public MethodAccessor getMethodAccessor( Class<?> clazz ) throws OgnlException 192 { 193 MethodAccessor methodAccessor = ClassCacheHandler.getHandler( clazz, methodAccessors ); 194 if ( methodAccessor != null ) 195 { 196 return methodAccessor; 197 } 198 throw new OgnlException( "No method accessor for " + clazz ); 199 } 200 201 public void setMethodAccessor( Class<?> clazz, MethodAccessor accessor ) 202 { 203 methodAccessors.put( clazz, accessor ); 204 } 205 206 public void setPropertyAccessor( Class<?> clazz, PropertyAccessor accessor ) 207 { 208 propertyAccessors.put( clazz, accessor ); 209 } 210 211 public PropertyAccessor getPropertyAccessor( Class<?> clazz ) 212 throws OgnlException 213 { 214 PropertyAccessor propertyAccessor = ClassCacheHandler.getHandler( clazz, propertyAccessors ); 215 if ( propertyAccessor != null ) 216 { 217 return propertyAccessor; 218 } 219 throw new OgnlException( "No property accessor for class " + clazz ); 220 } 221 222 /** 223 * Registers the specified {@link ClassCacheInspector} with all class reflection based internal caches. This may 224 * have a significant performance impact so be careful using this in production scenarios. 225 * 226 * @param inspector The inspector instance that will be registered with all internal cache instances. 227 */ 228 public void setClassCacheInspector( ClassCacheInspector inspector ) 229 { 230 propertyDescriptorCache.setClassInspector( inspector ); 231 constructorCache.setClassInspector( inspector ); 232 //TODO: methodCache and invokePC should allow to use classCacheInsecptor 233 // _methodCache.setClassInspector( inspector ); 234 // _invokePermissionCache.setClassInspector( inspector ); 235 _fieldCache.setClassInspector( inspector ); 236 } 237 238 public Class<?>[] getGenericMethodParameterTypes( GenericMethodParameterTypeCacheEntry key ) 239 throws CacheException 240 { 241 return _genericMethodParameterTypesCache.get( key ); 242 } 243 244 public boolean getMethodPerm( Method method ) throws CacheException 245 { 246 return _methodPermCache.get( method ); 247 } 248 249 public MethodAccessEntryValue getMethodAccess( Method method ) throws CacheException 250 { 251 return _methodAccessCache.get( method ); 252 } 253 254 public void clear() { 255 _methodParameterTypesCache.clear(); 256 _ctorParameterTypesCache.clear(); 257 propertyDescriptorCache.clear(); 258 constructorCache.clear(); 259 _methodCache.clear(); 260 _invokePermissionCache.clear(); 261 _fieldCache.clear(); 262 _methodAccessCache.clear(); 263 } 264 265 public ElementsAccessor getElementsAccessor( Class<?> clazz ) throws OgnlException 266 { 267 ElementsAccessor answer = ClassCacheHandler.getHandler( clazz, elementsAccessors ); 268 if ( answer != null ) 269 { 270 return answer; 271 } 272 throw new OgnlException( "No elements accessor for class " + clazz ); 273 } 274 275 public void setElementsAccessor( Class<?> clazz, ElementsAccessor accessor ) 276 { 277 elementsAccessors.put( clazz, accessor ); 278 } 279 280 public NullHandler getNullHandler( Class<?> clazz ) throws OgnlException 281 { 282 NullHandler answer = ClassCacheHandler.getHandler( clazz, nullHandlers ); 283 if ( answer != null ) 284 { 285 return answer; 286 } 287 throw new OgnlException( "No null handler for class " + clazz ); 288 } 289 290 public void setNullHandler( Class<?> clazz, NullHandler handler ) 291 { 292 nullHandlers.put( clazz, handler ); 293 } 294 295 public void setSecurityManager( SecurityManager securityManager ) 296 { 297 methodPermCacheEntryFactory.setSecurityManager( securityManager ); 298 } 299 }