001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.reflection.storage;
020
021import java.lang.reflect.Method;
022import java.util.Map;
023import java.util.concurrent.ConcurrentHashMap;
024
025import lucee.runtime.type.Array;
026import lucee.runtime.type.ArrayImpl;
027import lucee.runtime.type.Collection;
028import lucee.runtime.type.Collection.Key;
029import lucee.runtime.type.KeyImpl;
030
031import org.apache.commons.collections.map.ReferenceMap;
032
033/**
034 * Method Storage Class
035 */
036public final class SoftMethodStorage {
037        private Map<Class,Map<Key,Array>> map=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT);
038        
039        /**
040         * returns a methods matching given criteria or null if method doesn't exist
041         * @param clazz clazz to get methods from
042         * @param methodName Name of the Method to get
043         * @param count wished count of arguments
044         * @return matching Methods as Array
045         */
046        public Method[] getMethods(Class clazz,Collection.Key methodName, int count) {
047                Map<Key,Array> methodsMap = map.get(clazz); 
048                if(methodsMap==null) 
049                        methodsMap=store(clazz);
050                
051                Array methods = methodsMap.get(methodName);
052                if(methods==null) return null;
053                
054                Object o = methods.get(count+1,null);
055                if(o==null) return null;
056                return (Method[]) o;
057        }
058
059
060        /**
061         * store a class with his methods
062         * @param clazz
063         * @return returns stored struct
064         */
065        private Map<Key,Array> store(Class clazz) {
066                Method[] methods=clazz.getMethods();
067                Map<Key,Array> methodsMap=new ConcurrentHashMap<Key, Array>();
068                for(int i=0;i<methods.length;i++) {
069                        storeMethod(methods[i],methodsMap);
070                        
071                }
072                map.put(clazz,methodsMap);
073                return methodsMap;
074        }
075
076        /**
077         * stores a single method
078         * @param method
079         * @param methodsMap
080         */
081        private synchronized void storeMethod(Method method, Map<Key,Array> methodsMap) {
082                Key methodName = KeyImpl.init(method.getName());
083
084                Array methodArgs=methodsMap.get(methodName);
085                if(methodArgs==null) {
086                        methodArgs=new ArrayImpl();
087                        methodsMap.put(methodName,methodArgs);
088                }
089                
090                storeArgs(method,methodArgs);
091                //Modifier.isStatic(method.getModifiers());
092        }
093
094        /**
095         * stores arguments of a method
096         * @param method
097         * @param methodArgs
098         */
099        private void storeArgs(Method method, Array methodArgs) {
100                
101                Class[] pmt = method.getParameterTypes();
102                Object o=methodArgs.get(pmt.length+1,null);
103                Method[] args;
104                if(o==null) {
105                        args=new Method[1];
106                        methodArgs.setEL(pmt.length+1,args);
107                }
108                else {
109                        Method[] ms = (Method[]) o;
110                        args = new Method[ms.length+1];
111                        for(int i=0;i<ms.length;i++) {
112                                args[i]=ms[i];
113                        }
114                        methodArgs.setEL(pmt.length+1,args);
115                }
116                args[args.length-1]=method;
117        }
118}