View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.ognl.internal.*;
23  import org.apache.commons.ognl.internal.entry.*;
24  
25  import java.beans.PropertyDescriptor;
26  import java.lang.reflect.Constructor;
27  import java.lang.reflect.Field;
28  import java.lang.reflect.Method;
29  import java.security.Permission;
30  import java.util.Arrays;
31  import java.util.Collection;
32  import java.util.Enumeration;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Set;
37  
38  /**
39   * This class takes care of all the internal caching for OGNL.
40   */
41  public class OgnlCache {
42  
43      private final CacheFactory cacheFactory = new HashMapCacheFactory();
44  
45      private final ClassCache<MethodAccessor> methodAccessors = cacheFactory.createClassCache();
46      {
47          MethodAccessor methodAccessor = new ObjectMethodAccessor();
48          setMethodAccessor( Object.class, methodAccessor );
49          setMethodAccessor( byte[].class, methodAccessor );
50          setMethodAccessor( short[].class, methodAccessor );
51          setMethodAccessor( char[].class, methodAccessor );
52          setMethodAccessor( int[].class, methodAccessor );
53          setMethodAccessor( long[].class, methodAccessor );
54          setMethodAccessor( float[].class, methodAccessor );
55          setMethodAccessor( double[].class, methodAccessor );
56          setMethodAccessor( Object[].class, methodAccessor );
57      }
58  
59      private final ClassCache<PropertyAccessor> propertyAccessors = cacheFactory.createClassCache();
60      {
61          PropertyAccessor propertyAccessor = new ArrayPropertyAccessor();
62          setPropertyAccessor( Object.class, new ObjectPropertyAccessor() );
63          setPropertyAccessor( byte[].class, propertyAccessor );
64          setPropertyAccessor( short[].class, propertyAccessor );
65          setPropertyAccessor( char[].class, propertyAccessor );
66          setPropertyAccessor( int[].class, propertyAccessor );
67          setPropertyAccessor( long[].class, propertyAccessor );
68          setPropertyAccessor( float[].class, propertyAccessor );
69          setPropertyAccessor( double[].class, propertyAccessor );
70          setPropertyAccessor( Object[].class, propertyAccessor );
71          setPropertyAccessor( List.class, new ListPropertyAccessor() );
72          setPropertyAccessor( Map.class, new MapPropertyAccessor() );
73          setPropertyAccessor( Set.class, new SetPropertyAccessor() );
74          setPropertyAccessor( Iterator.class, new IteratorPropertyAccessor() );
75          setPropertyAccessor( Enumeration.class, new EnumerationPropertyAccessor() );
76      }
77  
78      private final ClassCache<ElementsAccessor> elementsAccessors = cacheFactory.createClassCache();
79      {
80          ElementsAccessor elementsAccessor = new ArrayElementsAccessor();
81          setElementsAccessor( Object.class, new ObjectElementsAccessor() );
82          setElementsAccessor( byte[].class, elementsAccessor );
83          setElementsAccessor( short[].class, elementsAccessor );
84          setElementsAccessor( char[].class, elementsAccessor );
85          setElementsAccessor( int[].class, elementsAccessor );
86          setElementsAccessor( long[].class, elementsAccessor );
87          setElementsAccessor( float[].class, elementsAccessor );
88          setElementsAccessor( double[].class, elementsAccessor );
89          setElementsAccessor( Object[].class, elementsAccessor );
90          setElementsAccessor( Collection.class, new CollectionElementsAccessor() );
91          setElementsAccessor( Map.class, new MapElementsAccessor() );
92          setElementsAccessor( Iterator.class, new IteratorElementsAccessor() );
93          setElementsAccessor( Enumeration.class, new EnumerationElementsAccessor() );
94          setElementsAccessor( Number.class, new NumberElementsAccessor() );
95      }
96  
97      private final ClassCache<NullHandler> nullHandlers = cacheFactory.createClassCache( );
98      {
99          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 }