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