/** * * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see <http://www.gnu.org/licenses/>. * **/ /** * Implements the CFML Function getfunctiondescription */ package lucee.runtime.functions.other; import java.util.ArrayList; import lucee.commons.lang.CFTypes; import lucee.commons.lang.ExceptionUtil; import lucee.commons.lang.StringUtil; import lucee.runtime.PageContext; import lucee.runtime.config.ConfigImpl; import lucee.runtime.config.ConfigWebUtil; import lucee.runtime.exp.ExpressionException; import lucee.runtime.exp.FunctionException; import lucee.runtime.exp.PageException; import lucee.runtime.ext.function.Function; import lucee.runtime.functions.system.CFFunction; import lucee.runtime.op.Caster; import lucee.runtime.type.Array; import lucee.runtime.type.ArrayImpl; import lucee.runtime.type.Collection; import lucee.runtime.type.Collection.Key; import lucee.runtime.type.FunctionArgument; import lucee.runtime.type.KeyImpl; import lucee.runtime.type.Struct; import lucee.runtime.type.StructImpl; import lucee.runtime.type.UDF; import lucee.runtime.type.util.ArrayUtil; import lucee.runtime.type.util.KeyConstants; import lucee.transformer.library.function.FunctionLib; import lucee.transformer.library.function.FunctionLibFunction; import lucee.transformer.library.function.FunctionLibFunctionArg; import lucee.transformer.library.tag.TagLibFactory; public final class GetFunctionData implements Function { private static final Collection.Key SOURCE = KeyConstants._source; private static final Collection.Key RETURN_TYPE = KeyImpl.intern("returnType"); private static final Collection.Key ARGUMENT_TYPE = KeyImpl.intern("argumentType"); private static final Collection.Key ARG_MIN = KeyImpl.intern("argMin"); private static final Collection.Key ARG_MAX = KeyImpl.intern("argMax"); static final Collection.Key INTRODUCED = KeyImpl.intern("introduced"); public static Struct call(PageContext pc , String strFunctionName) throws PageException { return _call(pc, strFunctionName, pc.getCurrentTemplateDialect()); } public static Struct call(PageContext pc , String strFunctionName, String strDialect) throws PageException { int dialect=ConfigWebUtil.toDialect(strDialect,-1); if(dialect==-1) throw new FunctionException(pc, "GetFunctionData", 2, "dialect", "value ["+strDialect+"] is invalid, valid values are [cfml,lucee]"); return _call(pc, strFunctionName, dialect); } private static Struct _call(PageContext pc , String strFunctionName, int dialect) throws PageException { FunctionLib[] flds; flds = ((ConfigImpl)pc.getConfig()).getFLDs(dialect); FunctionLibFunction function=null; for(int i=0;i<flds.length;i++) { function = flds[i].getFunction(strFunctionName.toLowerCase()); if(function!=null)break; } if(function == null) throw new ExpressionException("function ["+strFunctionName+"] is not a built in function"); // CFML Based Function Class clazz=null; try{ clazz=function.getFunctionClassDefinition().getClazz(); } catch(Throwable t) {ExceptionUtil.rethrowIfNecessary(t);} if(clazz==lucee.runtime.functions.system.CFFunction.class){ return cfmlBasedFunction(pc,function); } return javaBasedFunction(function); } private static Struct javaBasedFunction(FunctionLibFunction function) throws PageException { Struct sct=new StructImpl(); sct.set(KeyConstants._name,function.getName()); sct.set(KeyConstants._status,TagLibFactory.toStatus(function.getStatus())); if(function.getIntroduced()!=null)sct.set(INTRODUCED,function.getIntroduced().toString()); //else if(inside.equals("introduced")) att.setIntroduced(value); sct.set(KeyConstants._description,StringUtil.emptyIfNull(function.getDescription())); if(!ArrayUtil.isEmpty(function.getKeywords()))sct.set("keywords",Caster.toArray(function.getKeywords())); sct.set(RETURN_TYPE,StringUtil.emptyIfNull(function.getReturnTypeAsString())); sct.set(ARGUMENT_TYPE,StringUtil.emptyIfNull(function.getArgTypeAsString())); sct.set(ARG_MIN,Caster.toDouble(function.getArgMin())); sct.set(ARG_MAX,Caster.toDouble(function.getArgMax())); sct.set(KeyConstants._type,"java"); String[] names = function.getMemberNames(); if(!ArrayUtil.isEmpty(names) && function.getMemberType()!=CFTypes.TYPE_UNKNOW) { StructImpl mem = new StructImpl(); sct.set(KeyConstants._member, mem); mem.set(KeyConstants._name,names[0]); mem.set(KeyConstants._chaining,Caster.toBoolean(function.getMemberChaining())); mem.set(KeyConstants._type, function.getMemberTypeAsString()); mem.set("position", Caster.toDouble(function.getMemberPosition())); } Array _args=new ArrayImpl(); sct.set(KeyConstants._arguments,_args); if(function.getArgType()!=FunctionLibFunction.ARG_DYNAMIC){ ArrayList<FunctionLibFunctionArg> args = function.getArg(); for(int i=0;i<args.size();i++) { FunctionLibFunctionArg arg=args.get(i); Struct _arg=new StructImpl(); _arg.set(KeyConstants._required,arg.getRequired()?Boolean.TRUE:Boolean.FALSE); _arg.set(KeyConstants._type,StringUtil.emptyIfNull(arg.getTypeAsString())); _arg.set(KeyConstants._name,StringUtil.emptyIfNull(arg.getName())); _arg.set(KeyConstants._status,TagLibFactory.toStatus(arg.getStatus())); if(arg.getIntroduced()!=null)_arg.set(INTRODUCED,arg.getIntroduced().toString()); _arg.set("defaultValue",arg.getDefaultValue()); _arg.set(KeyConstants._description,StringUtil.toStringEmptyIfNull(arg.getDescription())); _args.append(_arg); } } return sct; } private static Struct cfmlBasedFunction(PageContext pc, FunctionLibFunction function) throws PageException { Struct sct=new StructImpl(); ArrayList<FunctionLibFunctionArg> args = function.getArg(); String filename = Caster.toString(args.get(0).getDefaultValue()); Key name = KeyImpl.toKey(args.get(1).getDefaultValue()); boolean isWeb = Caster.toBooleanValue(args.get(2).getDefaultValue()); UDF udf = CFFunction.loadUDF(pc, filename, name, isWeb); sct.set(KeyConstants._name,function.getName()); sct.set(ARGUMENT_TYPE,"fixed"); sct.set(KeyConstants._description,StringUtil.emptyIfNull(udf.getHint())); sct.set(RETURN_TYPE,StringUtil.emptyIfNull(udf.getReturnTypeAsString())); sct.set(KeyConstants._type,"cfml"); sct.set(SOURCE,udf.getSource()); sct.set(KeyConstants._status,"implemeted"); FunctionArgument[] fas = udf.getFunctionArguments(); Array _args=new ArrayImpl(); sct.set(KeyConstants._arguments,_args); int min=0,max=0; for(int i=0;i<fas.length;i++) { FunctionArgument fa=fas[i]; Struct meta = fa.getMetaData(); Struct _arg=new StructImpl(); if(fa.isRequired()) min++; max++; _arg.set(KeyConstants._required,fa.isRequired()?Boolean.TRUE:Boolean.FALSE); _arg.set(KeyConstants._type,StringUtil.emptyIfNull(fa.getTypeAsString())); _arg.set(KeyConstants._name,StringUtil.emptyIfNull(fa.getName())); _arg.set(KeyConstants._description,StringUtil.emptyIfNull(fa.getHint())); String status; if(meta==null)status="implemeted"; else status=TagLibFactory.toStatus(TagLibFactory.toStatus(Caster.toString(meta.get(KeyConstants._status,"implemeted")))); _arg.set(KeyConstants._status,status); _args.append(_arg); } sct.set(ARG_MIN,Caster.toDouble(min)); sct.set(ARG_MAX,Caster.toDouble(max)); return sct; } }