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 **/
019/**
020 * Implements the CFML Function getfunctiondescription
021 */
022package lucee.runtime.functions.other;
023
024import java.util.ArrayList;
025
026import lucee.commons.lang.CFTypes;
027import lucee.commons.lang.ExceptionUtil;
028import lucee.commons.lang.StringUtil;
029import lucee.runtime.PageContext;
030import lucee.runtime.config.ConfigImpl;
031import lucee.runtime.exp.ExpressionException;
032import lucee.runtime.exp.PageException;
033import lucee.runtime.ext.function.Function;
034import lucee.runtime.functions.system.CFFunction;
035import lucee.runtime.op.Caster;
036import lucee.runtime.type.Array;
037import lucee.runtime.type.ArrayImpl;
038import lucee.runtime.type.Collection;
039import lucee.runtime.type.Collection.Key;
040import lucee.runtime.type.FunctionArgument;
041import lucee.runtime.type.KeyImpl;
042import lucee.runtime.type.Struct;
043import lucee.runtime.type.StructImpl;
044import lucee.runtime.type.UDF;
045import lucee.runtime.type.util.ArrayUtil;
046import lucee.runtime.type.util.KeyConstants;
047import lucee.transformer.library.function.FunctionLib;
048import lucee.transformer.library.function.FunctionLibFunction;
049import lucee.transformer.library.function.FunctionLibFunctionArg;
050import lucee.transformer.library.tag.TagLibFactory;
051
052public final class GetFunctionData implements Function {
053        private static final Collection.Key SOURCE = KeyConstants._source;
054        private static final Collection.Key RETURN_TYPE = KeyImpl.intern("returnType");
055        private static final Collection.Key ARGUMENT_TYPE = KeyImpl.intern("argumentType");
056        private static final Collection.Key ARG_MIN = KeyImpl.intern("argMin");
057        private static final Collection.Key ARG_MAX = KeyImpl.intern("argMax");
058        
059        public static Struct call(PageContext pc , String strFunctionName) throws PageException {
060                FunctionLib[] flds;
061                flds = ((ConfigImpl)pc.getConfig()).getFLDs();
062
063                
064                FunctionLibFunction function=null;
065                for(int i=0;i<flds.length;i++) {
066                        function = flds[i].getFunction(strFunctionName.toLowerCase());
067                        if(function!=null)break;
068                }
069                if(function == null) throw new ExpressionException("function ["+strFunctionName+"] is not a built in function");
070
071        //sct.set("returnTypeClass",_class(function.getCazz()));
072        //sct.set("class",__class(function.getCazz()));
073        
074                
075                
076                // CFML Based Function
077                Class clazz=null;
078                try{
079                        clazz=function.getClazz();
080                }
081                catch(Throwable t){
082                        ExceptionUtil.rethrowIfNecessary(t);
083                }
084                if(clazz==lucee.runtime.functions.system.CFFunction.class){
085                        return cfmlBasedFunction(pc,function);
086                }
087                return javaBasedFunction(function);
088                
089                
090                
091        }
092
093        private static Struct javaBasedFunction(FunctionLibFunction function) throws PageException {
094                Struct sct=new StructImpl();
095                sct.set(KeyConstants._name,function.getName());
096        sct.set(KeyConstants._status,TagLibFactory.toStatus(function.getStatus()));
097        sct.set(KeyConstants._description,StringUtil.emptyIfNull(function.getDescription()));
098        if(!ArrayUtil.isEmpty(function.getKeywords()))sct.set("keywords",Caster.toArray(function.getKeywords()));
099         
100                
101                sct.set(RETURN_TYPE,StringUtil.emptyIfNull(function.getReturnTypeAsString()));
102        sct.set(ARGUMENT_TYPE,StringUtil.emptyIfNull(function.getArgTypeAsString()));
103        sct.set(ARG_MIN,Caster.toDouble(function.getArgMin()));
104        sct.set(ARG_MAX,Caster.toDouble(function.getArgMax()));
105        sct.set(KeyConstants._type,"java");
106                String[] names = function.getMemberNames();
107        if(!ArrayUtil.isEmpty(names) && function.getMemberType()!=CFTypes.TYPE_UNKNOW) {
108                StructImpl mem = new StructImpl();
109                sct.set(KeyConstants._member, mem);
110                mem.set(KeyConstants._name,names[0]);
111                mem.set(KeyConstants._chaining,Caster.toBoolean(function.getMemberChaining()));
112            mem.set(KeyConstants._type, function.getMemberTypeAsString());
113            mem.set("position", Caster.toDouble(function.getMemberPosition()));
114        }
115                
116                Array _args=new ArrayImpl();
117                sct.set(KeyConstants._arguments,_args);
118                if(function.getArgType()!=FunctionLibFunction.ARG_DYNAMIC){
119                        ArrayList<FunctionLibFunctionArg> args = function.getArg();
120                        for(int i=0;i<args.size();i++) {
121                                FunctionLibFunctionArg arg=args.get(i);
122                                Struct _arg=new StructImpl();
123                                _arg.set(KeyConstants._required,arg.getRequired()?Boolean.TRUE:Boolean.FALSE);
124                                _arg.set(KeyConstants._type,StringUtil.emptyIfNull(arg.getTypeAsString()));
125                                _arg.set(KeyConstants._name,StringUtil.emptyIfNull(arg.getName()));
126                                _arg.set(KeyConstants._status,TagLibFactory.toStatus(arg.getStatus()));
127                                _arg.set("defaultValue",arg.getDefaultValue());
128                                _arg.set(KeyConstants._description,StringUtil.toStringEmptyIfNull(arg.getDescription()));
129                                
130                                
131                                _args.append(_arg);
132                        }
133                }
134                return sct;
135        }
136
137        private static Struct cfmlBasedFunction(PageContext pc, FunctionLibFunction function) throws PageException {
138                Struct sct=new StructImpl();
139                ArrayList<FunctionLibFunctionArg> args = function.getArg();
140                
141                String filename = Caster.toString(args.get(0).getDefaultValue());
142                Key name = KeyImpl.toKey(args.get(1).getDefaultValue());
143                boolean isWeb = Caster.toBooleanValue(args.get(2).getDefaultValue());
144                UDF udf = CFFunction.loadUDF(pc, filename, name, isWeb);
145                
146                sct.set(KeyConstants._name,function.getName());
147        sct.set(ARGUMENT_TYPE,"fixed");
148        sct.set(KeyConstants._description,StringUtil.emptyIfNull(udf.getHint()));
149        sct.set(RETURN_TYPE,StringUtil.emptyIfNull(udf.getReturnTypeAsString()));
150        sct.set(KeyConstants._type,"cfml");
151        sct.set(SOURCE,udf.getPageSource().getDisplayPath());
152                sct.set(KeyConstants._status,"implemeted");
153                
154                
155        FunctionArgument[] fas = udf.getFunctionArguments();
156        Array _args=new ArrayImpl();
157                sct.set(KeyConstants._arguments,_args);
158        int min=0,max=0;
159                for(int i=0;i<fas.length;i++) {
160                FunctionArgument fa=fas[i];
161                Struct meta = fa.getMetaData();
162                
163                        Struct _arg=new StructImpl();
164                        if(fa.isRequired()) min++;
165                        max++;
166                        _arg.set(KeyConstants._required,fa.isRequired()?Boolean.TRUE:Boolean.FALSE);
167                        _arg.set(KeyConstants._type,StringUtil.emptyIfNull(fa.getTypeAsString()));
168                        _arg.set(KeyConstants._name,StringUtil.emptyIfNull(fa.getName()));
169                        _arg.set(KeyConstants._description,StringUtil.emptyIfNull(fa.getHint()));
170                        
171                        String status;
172                        if(meta==null)status="implemeted";
173                        else status=TagLibFactory.toStatus(TagLibFactory.toStatus(Caster.toString(meta.get(KeyConstants._status,"implemeted"))));
174                        
175                        _arg.set(KeyConstants._status,status);
176                        
177                        _args.append(_arg);
178                }
179        sct.set(ARG_MIN,Caster.toDouble(min));
180        sct.set(ARG_MAX,Caster.toDouble(max));
181        
182        
183                return sct;
184        }
185}