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 }