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.type.util; 020 021import java.util.ArrayList; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026 027import lucee.commons.lang.StringUtil; 028import lucee.runtime.PageContext; 029import lucee.runtime.config.ConfigWebImpl; 030import lucee.runtime.exp.ExpressionException; 031import lucee.runtime.exp.PageException; 032import lucee.runtime.interpreter.ref.Ref; 033import lucee.runtime.interpreter.ref.cast.Casting; 034import lucee.runtime.interpreter.ref.func.BIFCall; 035import lucee.runtime.interpreter.ref.literal.LFunctionValue; 036import lucee.runtime.interpreter.ref.literal.LString; 037import lucee.runtime.reflection.Reflector; 038import lucee.runtime.type.Collection; 039import lucee.runtime.type.Collection.Key; 040import lucee.runtime.type.KeyImpl; 041import lucee.runtime.type.Struct; 042import lucee.transformer.library.function.FunctionLib; 043import lucee.transformer.library.function.FunctionLibFunction; 044import lucee.transformer.library.function.FunctionLibFunctionArg; 045 046public class MemberUtil { 047 048 private static final Object DEFAULT_VALUE = new Object(); 049 private static Map<Short,Map<Collection.Key,FunctionLibFunction>> matches=new HashMap<Short, Map<Collection.Key,FunctionLibFunction>>(); 050 051 public static Map<Collection.Key,FunctionLibFunction> getMembers(PageContext pc, short type) { 052 053 Map<Key, FunctionLibFunction> match = matches.get(type); 054 if(match!=null) return match; 055 056 FunctionLib[] flds = ((ConfigWebImpl)pc.getConfig()).getFLDs(); 057 Iterator<FunctionLibFunction> it; 058 FunctionLibFunction f; 059 match=new HashMap<Collection.Key,FunctionLibFunction>(); 060 String[] names; 061 for(int i=0;i<flds.length;i++){ 062 it = flds[i].getFunctions().values().iterator(); 063 while(it.hasNext()){ 064 f = it.next(); 065 names = f.getMemberNames(); 066 if(!ArrayUtil.isEmpty(names) && f.getMemberType()==type && f.getArgType()==FunctionLibFunction.ARG_FIX) { 067 for(int y=0;y<names.length;y++) 068 069 match.put(KeyImpl.getInstance(names[y]),f); 070 } 071 } 072 } 073 matches.put(type, match); 074 return match; 075 } 076 077 public static Object call(PageContext pc, Object coll,Collection.Key methodName, Object[] args, short type, String strType) throws PageException { 078 Map<Key, FunctionLibFunction> members = getMembers(pc, type); 079 FunctionLibFunction member=members.get(methodName); 080 081 if(member!=null){ 082 List<FunctionLibFunctionArg> _args = member.getArg(); 083 FunctionLibFunctionArg arg; 084 if(args.length<_args.size()){ 085 ArrayList<Ref> refs=new ArrayList<Ref>(); 086 087 int pos = member.getMemberPosition(); 088 FunctionLibFunctionArg flfa; 089 Iterator<FunctionLibFunctionArg> it = _args.iterator(); 090 int glbIndex=0,argIndex=-1; 091 while(it.hasNext()){ 092 glbIndex++; 093 flfa = it.next(); 094 if(glbIndex==pos) { 095 refs.add(new Casting(strType,type,coll)); 096 } 097 else if(args.length>++argIndex) { // careful, argIndex is only incremented when condition above is false 098 refs.add(new Casting(flfa.getTypeAsString(),flfa.getType(),args[argIndex])); 099 } 100 } 101 return new BIFCall(coll, member, refs.toArray(new Ref[refs.size()])).getValue(pc); 102 } 103 104 } 105 if(pc.getConfig().getSecurityManager().getAccess(lucee.runtime.security.SecurityManager.TYPE_DIRECT_JAVA_ACCESS)==lucee.runtime.security.SecurityManager.VALUE_YES) { 106 return Reflector.callMethod(coll,methodName,args); 107 //Object res = Reflector.callMethod(coll,methodName,args,DEFAULT_VALUE); 108 //if(res!=DEFAULT_VALUE) return res; 109 } 110 throw new ExpressionException("No matching function member ["+methodName+"] found, available function members are ["+lucee.runtime.type.util.ListUtil.sort(CollectionUtil.getKeyList(members.keySet().iterator(), ","),"textnocase","asc",",")+"]"); 111 } 112 113 public static Object callWithNamedValues(PageContext pc,Object coll, Collection.Key methodName, Struct args,short type, String strType) throws PageException { 114 Map<Key, FunctionLibFunction> members = getMembers(pc, type); 115 FunctionLibFunction member=members.get(methodName); 116 117 if(member!=null){ 118 List<FunctionLibFunctionArg> _args = member.getArg(); 119 FunctionLibFunctionArg arg; 120 if(args.size()<_args.size()){ 121 Object val; 122 ArrayList<Ref> refs=new ArrayList<Ref>(); 123 arg=_args.get(0); 124 refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),coll))); 125 for(int y=1;y<_args.size();y++){ 126 arg = _args.get(y); 127 128 // match by name 129 val = args.get(arg.getName(),null); 130 131 //match by alias 132 if(val==null) { 133 String alias=arg.getAlias(); 134 if(!StringUtil.isEmpty(alias,true)) { 135 String[] aliases = lucee.runtime.type.util.ListUtil.trimItems(lucee.runtime.type.util.ListUtil.listToStringArray(alias,',')); 136 for(int x=0;x<aliases.length;x++){ 137 val = args.get(aliases[x],null); 138 if(val!=null) break; 139 } 140 } 141 } 142 143 if(val==null) { 144 if(arg.getRequired()) { 145 String[] names = member.getMemberNames(); 146 String n=ArrayUtil.isEmpty(names)?"":names[0]; 147 throw new ExpressionException("missing required argument ["+arg.getName()+"] for member function call ["+n+"]"); 148 } 149 } 150 else{ 151 refs.add(new Casting(arg.getTypeAsString(),arg.getType(),new LFunctionValue(new LString(arg.getName()),val))); 152 //refs.add(new LFunctionValue(new LString(arg.getName()),new Casting(pc,arg.getTypeAsString(),arg.getType(),val))); 153 } 154 155 } 156 return new BIFCall(coll,member, refs.toArray(new Ref[refs.size()])).getValue(pc); 157 } 158 159 } 160 throw new ExpressionException("No matching function member ["+methodName+"] for call with named arguments found, available function members are ["+lucee.runtime.type.util.ListUtil.sort(CollectionUtil.getKeyList(members.keySet().iterator(), ","),"textnocase","asc",",")+"]"); 161 } 162 163}