001    package railo.runtime.type.util;
002    
003    import java.util.ArrayList;
004    import java.util.HashMap;
005    import java.util.Iterator;
006    import java.util.List;
007    import java.util.Map;
008    
009    import railo.commons.lang.StringUtil;
010    import railo.runtime.PageContext;
011    import railo.runtime.config.ConfigWebImpl;
012    import railo.runtime.exp.ExpressionException;
013    import railo.runtime.exp.PageException;
014    import railo.runtime.interpreter.ref.Ref;
015    import railo.runtime.interpreter.ref.cast.Casting;
016    import railo.runtime.interpreter.ref.func.BIFCall;
017    import railo.runtime.interpreter.ref.literal.LFunctionValue;
018    import railo.runtime.interpreter.ref.literal.LString;
019    import railo.runtime.reflection.Reflector;
020    import railo.runtime.type.Collection;
021    import railo.runtime.type.Collection.Key;
022    import railo.runtime.type.KeyImpl;
023    import railo.runtime.type.Struct;
024    import railo.transformer.library.function.FunctionLib;
025    import railo.transformer.library.function.FunctionLibFunction;
026    import railo.transformer.library.function.FunctionLibFunctionArg;
027    
028    public class MemberUtil {
029            
030            private static final Object DEFAULT_VALUE = new Object();
031            private static Map<Short,Map<Collection.Key,FunctionLibFunction>> matches=new HashMap<Short, Map<Collection.Key,FunctionLibFunction>>();
032            
033            public static Map<Collection.Key,FunctionLibFunction> getMembers(PageContext pc, short type) {
034                    
035                    Map<Key, FunctionLibFunction> match = matches.get(type);
036                    if(match!=null) return match;
037                    
038                    FunctionLib[] flds = ((ConfigWebImpl)pc.getConfig()).getFLDs();
039                    Iterator<FunctionLibFunction> it;
040                    FunctionLibFunction f;
041                    match=new HashMap<Collection.Key,FunctionLibFunction>();
042                    for(int i=0;i<flds.length;i++){
043                             it = flds[i].getFunctions().values().iterator();
044                             while(it.hasNext()){
045                                     f = it.next();
046                                     if(f.getMemberName()!=null && f.getMemberType()==type && f.getArgType()==FunctionLibFunction.ARG_FIX) {
047                                             match.put(KeyImpl.getInstance(f.getMemberName()),f);
048                                     }
049                             }
050                    }
051                    matches.put(type, match);
052                    return match;
053            }
054            
055            public static Object call(PageContext pc, Object coll,Collection.Key methodName, Object[] args, short type, String strType) throws PageException {
056                    Map<Key, FunctionLibFunction> members = getMembers(pc, type);
057                    FunctionLibFunction member=members.get(methodName); 
058                    
059                    if(member!=null){
060                            List<FunctionLibFunctionArg> _args = member.getArg();
061                            FunctionLibFunctionArg arg;
062                            if(args.length<_args.size()){
063                                    ArrayList<Ref> refs=new ArrayList<Ref>();
064                                    refs.add(new Casting(strType,type,coll));
065                                    for(int y=0;y<args.length;y++){
066                                            arg = _args.get(y+1);
067                                            refs.add(new Casting(arg.getTypeAsString(),arg.getType(),args[y]));
068                                    }
069                                    return new BIFCall(coll, member, refs.toArray(new Ref[refs.size()])).getValue(pc);
070                            }
071                            
072                    }
073                    if(pc.getConfig().getSecurityManager().getAccess(railo.runtime.security.SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==railo.runtime.security.SecurityManager.VALUE_YES) {
074                            return Reflector.callMethod(coll,methodName,args);
075                            //Object res = Reflector.callMethod(coll,methodName,args,DEFAULT_VALUE);
076                    //if(res!=DEFAULT_VALUE) return res;
077                } 
078                    throw new ExpressionException("No matching function member ["+methodName+"] found, available function members are ["+railo.runtime.type.util.ListUtil.sort(CollectionUtil.getKeyList(members.keySet().iterator(), ","),"textnocase","asc",",")+"]");
079            }
080    
081            public static Object callWithNamedValues(PageContext pc,Object coll, Collection.Key methodName, Struct args,short type, String strType) throws PageException {
082                    Map<Key, FunctionLibFunction> members = getMembers(pc, type);
083                    FunctionLibFunction member=members.get(methodName); 
084                    
085                    if(member!=null){
086                            List<FunctionLibFunctionArg> _args = member.getArg();
087                            FunctionLibFunctionArg arg;
088                            if(args.size()<_args.size()){
089                                    Object val;
090                                    ArrayList<Ref> refs=new ArrayList<Ref>();
091                                    arg=_args.get(0);
092                                    refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),coll)));
093                                    for(int y=1;y<_args.size();y++){
094                                            arg = _args.get(y);
095                                            
096                                            // match by name
097                                            val = args.get(arg.getName(),null);
098                                            
099                                            //match by alias
100                                            if(val==null) {
101                                                    String alias=arg.getAlias();
102                                                    if(!StringUtil.isEmpty(alias,true)) {
103                                                            String[] aliases = railo.runtime.type.util.ListUtil.trimItems(railo.runtime.type.util.ListUtil.listToStringArray(alias,','));
104                                                            for(int x=0;x<aliases.length;x++){
105                                                                    val = args.get(aliases[x],null);
106                                                                    if(val!=null) break;
107                                                            }
108                                                    }
109                                            }
110                                            
111                                            if(val==null) {
112                                                    if(arg.getRequired()) {
113                                                            throw new ExpressionException("missing required argument ["+arg.getName()+"] for member function call ["+member.getMemberName()+"]");
114                                                    }
115                                            }
116                                            else{
117                                                    refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),val)));
118                                                    //refs.add(new LFunctionValue(new LString(arg.getName()),new Casting(pc,arg.getTypeAsString(),arg.getType(),val)));
119                                            }
120                                            
121                                    }
122                                    return new BIFCall(coll,member, refs.toArray(new Ref[refs.size()])).getValue(pc);
123                            }
124                            
125                    }
126                    throw new ExpressionException("No matching function member ["+methodName+"] for call with named arguments found, available function members are ["+railo.runtime.type.util.ListUtil.sort(CollectionUtil.getKeyList(members.keySet().iterator(), ","),"textnocase","asc",",")+"]");
127            }
128            
129    }