001 package railo.runtime.functions.system; 002 003 import java.io.File; 004 005 import railo.runtime.Mapping; 006 import railo.runtime.Page; 007 import railo.runtime.PageContext; 008 import railo.runtime.PageSourceImpl; 009 import railo.runtime.config.ConfigWebImpl; 010 import railo.runtime.exp.ExpressionException; 011 import railo.runtime.exp.PageException; 012 import railo.runtime.op.Caster; 013 import railo.runtime.op.Duplicator; 014 import railo.runtime.type.Collection; 015 import railo.runtime.type.FunctionValue; 016 import railo.runtime.type.KeyImpl; 017 import railo.runtime.type.Struct; 018 import railo.runtime.type.StructImpl; 019 import railo.runtime.type.UDF; 020 import railo.runtime.type.scope.Variables; 021 import railo.runtime.type.scope.VariablesImpl; 022 import railo.runtime.type.util.ArrayUtil; 023 import railo.runtime.type.util.KeyConstants; 024 025 public class CFFunction { 026 027 028 private static final Variables VAR = new VariablesImpl(); 029 //private static Map udfs=new ReferenceMap(); 030 031 public static Object call(PageContext pc , Object[] objArr) throws PageException { 032 if(objArr.length<3) 033 throw new ExpressionException("invalid call of a CFML Based built in function"); 034 035 // translate arguments 036 String filename=Caster.toString((((FunctionValue) objArr[0]).getValue())); 037 Collection.Key name=KeyImpl.toKey((((FunctionValue) objArr[1]).getValue())); 038 boolean isweb=Caster.toBooleanValue((((FunctionValue) objArr[2]).getValue())); 039 040 041 UDF udf=loadUDF(pc, filename, name, isweb); 042 Struct meta = udf.getMetaData(pc); 043 boolean caller=meta==null?false:Caster.toBooleanValue(meta.get(KeyConstants._caller,Boolean.FALSE),false); 044 045 Struct namedArguments=null; 046 Object[] arguments=null; 047 if(objArr.length<=3)arguments=ArrayUtil.OBJECT_EMPTY; 048 else if(objArr[3] instanceof FunctionValue){ 049 FunctionValue fv; 050 namedArguments=new StructImpl(); 051 if(caller)namedArguments.setEL(KeyConstants._caller, Duplicator.duplicate(pc.undefinedScope(),false)); 052 for(int i=3;i<objArr.length;i++){ 053 fv=toFunctionValue(name,objArr[i]); 054 namedArguments.set(fv.getName(), fv.getValue()); 055 } 056 } 057 else { 058 int offset=(caller?2:3); 059 arguments=new Object[objArr.length-offset]; 060 if(caller)arguments[0]=Duplicator.duplicate(pc.undefinedScope(),false); 061 for(int i=3;i<objArr.length;i++){ 062 arguments[i-offset]=toObject(name,objArr[i]); 063 } 064 } 065 066 067 // load UDF 068 069 070 // execute UDF 071 if(namedArguments==null){ 072 return udf.call(pc, arguments, false); 073 } 074 075 076 return udf.callWithNamedValues(pc, namedArguments, false); 077 } 078 079 public static synchronized UDF loadUDF(PageContext pc, String filename,Collection.Key name,boolean isweb) throws PageException { 080 ConfigWebImpl config = (ConfigWebImpl) pc.getConfig(); 081 String key=isweb?name.getString()+config.getId():name.getString(); 082 UDF udf=config.getFromFunctionCache(key); 083 if(udf!=null) return udf; 084 085 Mapping mapping=isweb?config.getFunctionMapping():config.getServerFunctionMapping(); 086 PageSourceImpl ps = (PageSourceImpl) mapping.getPageSource(filename); 087 Page p = ps.loadPage(pc); 088 089 090 // execute page 091 Variables old = pc.variablesScope(); 092 pc.setVariablesScope(VAR); 093 boolean wasSilent = pc.setSilent(); 094 try { 095 p.call(pc); 096 Object o= pc.variablesScope().get(name,null); 097 if(o instanceof UDF) { 098 udf= (UDF) o; 099 config.putToFunctionCache(key, udf); 100 return udf; 101 } 102 throw new ExpressionException("there is no Function defined with name ["+name+"] in template ["+mapping.getStrPhysical()+File.separator+filename+"]"); 103 } 104 catch (Throwable t) { 105 throw Caster.toPageException(t); 106 } 107 finally{ 108 pc.setVariablesScope(old); 109 if(!wasSilent)pc.unsetSilent(); 110 } 111 112 113 } 114 115 private static FunctionValue toFunctionValue(Collection.Key name,Object obj) throws ExpressionException { 116 if(obj instanceof FunctionValue) 117 return (FunctionValue) obj; 118 throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments"); 119 } 120 121 private static Object toObject(Collection.Key name,Object obj) throws ExpressionException { 122 if(obj instanceof FunctionValue) 123 throw new ExpressionException("invalid argument for function "+name+", you can not mix named and unnamed arguments"); 124 return obj; 125 } 126 }