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.transformer.library.function;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.Iterator;
024
025import lucee.commons.lang.CFTypes;
026import lucee.commons.lang.ClassException;
027import lucee.commons.lang.ClassUtil;
028import lucee.commons.lang.ExceptionUtil;
029import lucee.commons.lang.Md5;
030import lucee.commons.lang.StringUtil;
031import lucee.runtime.exp.PageRuntimeException;
032import lucee.runtime.exp.TemplateException;
033import lucee.runtime.functions.BIF;
034import lucee.runtime.functions.BIFProxy;
035import lucee.runtime.reflection.Reflector;
036import lucee.runtime.type.util.ListUtil;
037import lucee.transformer.bytecode.BytecodeException;
038import lucee.transformer.cfml.evaluator.FunctionEvaluator;
039import lucee.transformer.library.tag.TagLib;
040
041
042
043/**
044 * Eine FunctionLibFunction repraesentiert eine einzelne Funktion innerhalb einer FLD.
045 */
046public final class FunctionLibFunction {
047        
048        /**
049         * Dynamischer Argument Typ
050         */
051        public static final int ARG_DYNAMIC = 0;
052        /**
053         * statischer Argument Typ
054         */
055        public static final int ARG_FIX = 1;
056
057         
058        private FunctionLib functionLib;
059        private String name;
060        private ArrayList<FunctionLibFunctionArg> argument=new ArrayList<FunctionLibFunctionArg>();
061        
062        private int argMin=0;
063        private int argMax=-1;
064        private int argType=ARG_FIX;
065        
066
067        private String strReturnType;
068
069        private String cls="";
070        private Class clazz;
071        private String description;
072        private boolean hasDefaultValues;
073        private FunctionEvaluator eval;
074        private String tteClass;        
075        private short status=TagLib.STATUS_IMPLEMENTED;
076        private String[] memberNames;
077        private int memberPosition=1;
078        private short memberType=CFTypes.TYPE_UNKNOW;
079        private boolean memberChaining;
080        private BIF bif;
081        private String[] keywords;
082
083        
084        /**
085         * Geschuetzer Konstruktor ohne Argumente.
086         */
087        public FunctionLibFunction() {
088        }
089        public FunctionLibFunction(FunctionLib functionLib) {
090                        this.functionLib=functionLib;
091        }
092        
093        /**
094         * Gibt den Namen der Funktion zurueck.
095         * @return name Name der Funktion.
096         */
097        public String getName() {
098                return name;
099        }
100        
101        /**
102        * Gibt alle Argumente einer Funktion als ArrayList zurueck.
103        * @return Argumente der Funktion.
104        */
105   public ArrayList<FunctionLibFunctionArg> getArg() {
106           return argument;
107   }
108
109        /**
110         * Gibt zurueck wieviele Argumente eine Funktion minimal haben muss.
111         * @return Minimale Anzahl Argumente der Funktion.
112         */
113        public int getArgMin() {
114                return argMin;
115        }
116        
117        /**
118         * Gibt zurueck wieviele Argumente eine Funktion minimal haben muss.
119         * @return Maximale Anzahl Argumente der Funktion.
120         */
121        public int getArgMax() {
122                return argMax;
123        }
124        
125        /**
126         * @return the status (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
127         */
128        public short getStatus() {
129                return status;
130        }
131
132
133        /**
134         * @param status the status to set (TagLib.,TagLib.STATUS_IMPLEMENTED,TagLib.STATUS_DEPRECATED,TagLib.STATUS_UNIMPLEMENTED)
135         */
136        public void setStatus(short status) {
137                this.status = status;
138        }
139        
140        
141        /**
142         * Gibt die argument art zurueck.
143         * @return argument art
144         */
145        public int getArgType() {
146                return argType;
147        }
148        
149        /**
150         * Gibt die argument art als String zurueck.
151         * @return argument art
152         */
153        public String getArgTypeAsString() {
154                if(argType==ARG_DYNAMIC) return "dynamic";
155                return "fixed";
156        }
157
158        /**
159         * Gibt zurueck von welchem Typ der Rueckgabewert dieser Funktion sein muss (query, string, struct, number usw.).
160         * @return Typ des Rueckgabewert.
161         */
162        public String getReturnTypeAsString() {
163                return strReturnType;
164        }
165
166        /**
167         * Gibt die Klassendefinition als Zeichenkette zurueck, welche diese Funktion implementiert.
168         * @return Klassendefinition als Zeichenkette.
169         */
170        public String getCls() {
171                return cls;
172        }
173
174        /**
175         * Gibt die Klasse zurueck, welche diese Funktion implementiert.
176         * @return Klasse der Function.
177         * @throws ClassException 
178         */
179        public Class getClazz() throws TemplateException {
180                if(clazz==null) {
181                        try {
182                                clazz=ClassUtil.loadClass(cls);
183                        }
184                        catch (ClassException e) {
185                                throw new BytecodeException(e, null);
186                        }
187                }
188                
189                return clazz;
190        }
191        
192        public Class getClazz(Class defaultValue) {
193                if(clazz==null) {
194                        clazz=ClassUtil.loadClass(cls,defaultValue);
195                }
196                
197                return clazz;
198        }
199
200        /**
201         * Gibt die Beschreibung der Funktion zurueck.
202         * @return String
203         */
204        public String getDescription() {
205                return description;
206        }
207
208        /**
209         * Gibt die FunctionLib zurueck, zu der die Funktion gehoert.
210         * @return Zugehoerige FunctionLib.
211         */
212        public FunctionLib getFunctionLib() {
213                return functionLib;
214        }
215
216        /**
217         * Setzt den Namen der Funktion.
218         * @param name Name der Funktion.
219         */
220        public void setName(String name) {
221                this.name = name.toLowerCase();
222        }       
223
224        /**
225         * Fuegt der Funktion ein Argument hinzu.
226         * @param arg Argument zur Funktion.
227         */
228        public void addArg(FunctionLibFunctionArg arg) {
229                arg.setFunction(this);
230                argument.add(arg); 
231                if(arg.getDefaultValue()!=null)
232                        hasDefaultValues=true;
233        }
234
235        /**
236         * Fuegt der Funktion ein Argument hinzu, alias fuer addArg.
237         * @param arg Argument zur Funktion.
238         */
239        public void setArg(FunctionLibFunctionArg arg) {
240                addArg(arg);
241        }
242
243
244        /**
245         * Setzt wieviele Argumente eine Funktion minimal haben muss.
246         * @param argMin Minimale Anzahl Argumente der Funktion.
247         */
248        public void setArgMin(int argMin) {
249                this.argMin = argMin;
250        }
251        
252        /**
253         * Setzt wieviele Argumente eine Funktion minimal haben muss.
254         * @param argMax Maximale Anzahl Argumente der Funktion.
255         */
256        public void setArgMax(int argMax) {
257                this.argMax = argMax;
258        }
259
260        /**
261         * Setzt den Rueckgabewert der Funktion (query,array,string usw.)
262         * @param value
263         */
264        public void setReturn(String value) {
265                strReturnType=value;
266        }
267
268        /**
269         * Setzt die Klassendefinition als Zeichenkette, welche diese Funktion implementiert.
270         * @param value Klassendefinition als Zeichenkette.
271         */
272        public void setCls(String value) {
273                cls+=value;
274                
275        }
276
277        /**
278         * Setzt die Beschreibung der Funktion.
279         * @param description Beschreibung der Funktion.
280         */
281        public void setDescription(String description) {
282                this.description = description;
283        }
284
285        /**
286         * Setzt die zugehoerige FunctionLib.
287         * @param functionLib Zugehoerige FunctionLib.
288         */
289        public void setFunctionLib(FunctionLib functionLib) {
290                this.functionLib=functionLib;
291        }
292
293        /**
294         * sets the argument type of the function
295         * @param argType
296         */
297        public void setArgType(int argType) {
298                this.argType=argType;
299        }
300        
301
302        public String getHash() {
303                StringBuffer sb=new StringBuffer();
304                sb.append(this.getArgMax());
305                sb.append(this.getArgMin());
306                sb.append(this.getArgType());
307                sb.append(this.getArgTypeAsString());
308                sb.append(this.getCls());
309                sb.append(this.getName());
310                sb.append(this.getReturnTypeAsString());
311                
312                Iterator it = this.getArg().iterator();
313                FunctionLibFunctionArg arg;
314                while(it.hasNext()){
315                        arg=(FunctionLibFunctionArg) it.next();
316                        sb.append(arg.getHash());
317                }
318                
319                try {
320                        return Md5.getDigestAsString(sb.toString());
321                } catch (IOException e) {
322                        return "";
323                }
324        }
325        public boolean hasDefaultValues() {
326                return hasDefaultValues;
327        }
328
329        public boolean hasTteClass() {
330                return tteClass !=null && tteClass.length()>0;
331        }
332        
333        public FunctionEvaluator getEvaluator() throws TemplateException {
334                if(!hasTteClass()) return null;
335                if(eval!=null) return eval;
336                try {
337                        eval = (FunctionEvaluator) ClassUtil.loadInstance(tteClass);
338                } 
339                catch (ClassException e) {
340                        throw new TemplateException(e.getMessage());
341                } 
342                return eval;
343        }
344        public void setTteClass(String tteClass) {
345                this.tteClass=tteClass;
346        }
347        public void setMemberName(String memberNames) {
348                if(StringUtil.isEmpty(memberNames,true)) return;
349                this.memberNames=ListUtil.trimItems(ListUtil.listToStringArray(memberNames, ','));      
350        }
351        public String[] getMemberNames() {
352                return memberNames;
353        }
354        
355
356        public void setKeywords(String keywords) {
357                this.keywords=ListUtil.trimItems(ListUtil.listToStringArray(keywords, ','));    
358        }
359        public String[] getKeywords() {
360                return keywords;
361        }
362        
363        public void setMemberPosition(int pos) {
364                this.memberPosition=pos;        
365        }
366        public int getMemberPosition() {
367                return memberPosition;
368        }
369        
370        public void setMemberChaining(boolean memberChaining) {
371                this.memberChaining=memberChaining;     
372        }
373        public boolean getMemberChaining() {
374                return memberChaining;
375        }
376        
377        public short getMemberType() {
378                if(memberNames!=null && memberType==CFTypes.TYPE_UNKNOW){
379                        ArrayList<FunctionLibFunctionArg> args = getArg();
380                        if(args.size()>=1){
381                                memberType=CFTypes.toShortStrict(args.get(getMemberPosition()-1).getTypeAsString(),CFTypes.TYPE_UNKNOW);
382                        }
383                }
384                return memberType;
385        }
386        public String getMemberTypeAsString() {
387                return CFTypes.toString(getMemberType(),"any");
388        }
389        public BIF getBIF() {
390                if(bif!=null) return bif;
391                
392                Class clazz=null;
393                try {
394                        clazz = getClazz();
395                }
396                catch (TemplateException e) {
397                        throw new PageRuntimeException(e);
398                }
399        
400                if(Reflector.isInstaneOf(clazz, BIF.class)) {
401                        try {
402                                bif=(BIF)clazz.newInstance();
403                        }
404                        catch (Throwable t) {
405                                ExceptionUtil.rethrowIfNecessary(t);
406                                throw new RuntimeException(t);
407                        }
408                }
409                else {
410                        return new BIFProxy(clazz);
411                }
412                return bif;
413        }
414}