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    }