001    package railo.runtime.type;
002    
003    import java.io.Externalizable;
004    import java.io.IOException;
005    import java.io.ObjectInput;
006    import java.io.ObjectOutput;
007    import java.util.Iterator;
008    import java.util.Map;
009    import java.util.Map.Entry;
010    
011    import javax.servlet.jsp.tagext.BodyContent;
012    
013    import railo.commons.lang.CFTypes;
014    import railo.commons.lang.SizeOf;
015    import railo.commons.lang.StringUtil;
016    import railo.runtime.Component;
017    import railo.runtime.ComponentImpl;
018    import railo.runtime.Page;
019    import railo.runtime.PageContext;
020    import railo.runtime.PageContextImpl;
021    import railo.runtime.PageSource;
022    import railo.runtime.component.MemberSupport;
023    import railo.runtime.dump.DumpData;
024    import railo.runtime.dump.DumpProperties;
025    import railo.runtime.dump.DumpRow;
026    import railo.runtime.dump.DumpTable;
027    import railo.runtime.dump.DumpTablePro;
028    import railo.runtime.dump.SimpleDumpData;
029    import railo.runtime.exp.DeprecatedException;
030    import railo.runtime.exp.ExpressionException;
031    import railo.runtime.exp.PageException;
032    import railo.runtime.exp.PageRuntimeException;
033    import railo.runtime.exp.UDFCasterException;
034    import railo.runtime.listener.ApplicationContextPro;
035    import railo.runtime.op.Caster;
036    import railo.runtime.op.Decision;
037    import railo.runtime.op.Duplicator;
038    import railo.runtime.type.Collection.Key;
039    import railo.runtime.type.scope.Argument;
040    import railo.runtime.type.scope.ArgumentIntKey;
041    import railo.runtime.type.scope.ArgumentPro;
042    import railo.runtime.type.scope.LocalImpl;
043    import railo.runtime.type.scope.Undefined;
044    import railo.runtime.type.util.ComponentUtil;
045    import railo.runtime.writer.BodyContentUtil;
046    
047    /**
048     * defines a abstract class for a User defined Functions
049     */
050    public class UDFImpl extends MemberSupport implements UDF,Sizeable,Externalizable {
051            
052            private static final FunctionArgument[] EMPTY = new FunctionArgument[0];
053            
054            
055            
056            private ComponentImpl ownerComponent;
057            private UDFProperties properties;
058        
059    
060            /**
061             * @see railo.runtime.engine.Sizeable#sizeOf()
062             */
063            public long sizeOf() {
064                    return SizeOf.size(properties);
065            }
066        
067            
068            /**
069             * Constructor of the class
070             * @param page
071             * @param arguments
072             * @param index
073             * @param functionName
074             * @param strReturnType
075             * @param strReturnFormat
076             * @param output
077             * @param async
078             * @param strAccess
079             * @param displayName
080             * @param description
081             * @param hint
082             * @param secureJson
083             * @param verifyClient
084             * @param meta
085             * @throws ExpressionException
086             * @deprecated use instead <code>UDFImpl(UDFProperties properties)</code>
087             */
088            public UDFImpl(
089                    Page page,
090                    FunctionArgument[] arguments,
091                            int index,
092                    String functionName, 
093                    String strReturnType, 
094                    String strReturnFormat, 
095                    boolean output, 
096                    boolean async, 
097                    String strAccess, 
098                    String displayName, 
099                    String description, 
100                    String hint, 
101                    Boolean secureJson,
102                    Boolean verifyClient,
103                    StructImpl meta) throws ExpressionException {
104                    super(ComponentUtil.toIntAccess(strAccess));
105                    properties=new UDFProperties(page,
106                            arguments,
107                                    index,
108                            functionName, 
109                            strReturnType, 
110                            strReturnFormat, 
111                            output, 
112                             async, 
113                             getAccess(), 
114                             displayName, 
115                             description, 
116                             hint, 
117                             secureJson,
118                             verifyClient,
119                             meta);
120                    
121            }
122        
123            /**
124             * Constructor of the class
125             * @param page
126             * @param arguments
127             * @param index
128             * @param functionName
129             * @param returnType
130             * @param strReturnFormat
131             * @param output
132             * @param async
133             * @param strAccess
134             * @param displayName
135             * @param description
136             * @param hint
137             * @param secureJson
138             * @param verifyClient
139             * @param meta
140             * @throws ExpressionException
141             * @deprecated use instead <code>UDFImpl(UDFProperties properties)</code>
142             */
143            public UDFImpl(
144                    Page page,
145                    FunctionArgument[] arguments,
146                            int index,
147                    String functionName, 
148                    short returnType, 
149                    String strReturnFormat, 
150                    boolean output, 
151                    boolean async, 
152                    String strAccess, 
153                    String displayName, 
154                    String description, 
155                    String hint, 
156                    Boolean secureJson,
157                    Boolean verifyClient,
158                    StructImpl meta) throws ExpressionException {
159                    super(ComponentUtil.toIntAccess(strAccess));
160                    properties=new UDFProperties(
161                            page,
162                            arguments,
163                                    index,
164                            functionName, 
165                            returnType, 
166                            strReturnFormat, 
167                            output, 
168                            async, 
169                            getAccess(), 
170                            displayName, 
171                            description, 
172                            hint, 
173                            secureJson,
174                            verifyClient,
175                            meta);
176                    //ownerComponent=null;
177            }
178            
179            /**
180             * DO NOT USE THIS CONSTRUCTOR!
181             * this constructor is only for deserialize process
182             */
183            public UDFImpl(){
184                    super(0);
185            }
186            
187            public UDFImpl(UDFProperties properties) {
188                    super(properties.getAccess());
189                    this.properties=properties;
190            }
191    
192            public UDF duplicate(ComponentImpl c) {
193                    UDFImpl udf = new UDFImpl(properties);
194                    udf.ownerComponent=c;
195                    udf.setAccess(getAccess());
196                    return udf;
197            }
198            
199            public UDF duplicate(boolean deepCopy) {
200                    return duplicate(ownerComponent);
201            }
202            
203            public UDF duplicate() {
204                    return duplicate(ownerComponent);
205            }
206    
207            /**
208         * @throws Throwable 
209             * @see railo.runtime.type.UDF#implementation(railo.runtime.PageContext)
210         */
211            public Object implementation(PageContext pageContext) throws Throwable {
212                    
213                    
214                    
215                    return ComponentUtil.getPage(pageContext, properties.pageSource).udfCall(pageContext,this,properties.index);
216            }
217    
218            private final Object castToAndClone(PageContext pc,FunctionArgument arg,Object value, int index) throws PageException {
219                    //if(value instanceof Array)print.out(count++);
220                    if(Decision.isCastableTo(arg.getType(),arg.getTypeAsString(),value)) 
221                            return arg.isPassByReference()?value:Duplicator.duplicate(value,false);
222                    throw new UDFCasterException(this,arg,value,index);
223                    //REALCAST return Caster.castTo(pc,arg.getType(),arg.getTypeAsString(),value);
224            }
225            private final Object castTo(FunctionArgument arg,Object value, int index) throws PageException {
226                    if(Decision.isCastableTo(arg.getType(),arg.getTypeAsString(),value)) return value;
227                    throw new UDFCasterException(this,arg,value,index);
228            }
229            
230            private void defineArguments(PageContext pc,FunctionArgument[] funcArgs, Object[] args,ArgumentPro newArgs) throws PageException {
231                    // define argument scope
232                    for(int i=0;i<funcArgs.length;i++) {
233                            // argument defined
234                            if(args.length>i) {
235                                    newArgs.setEL(funcArgs[i].getName(),castToAndClone(pc,funcArgs[i], args[i],i+1));
236                            }
237                            // argument not defined
238                            else {
239                                    Object d=getDefaultValue(pc,i);
240                                    if(d==null) { 
241                                            if(funcArgs[i].isRequired()) {
242                                                    throw new ExpressionException("The parameter "+funcArgs[i].getName()+" to function "+getFunctionName()+" is required but was not passed in.");
243                                            }
244                                            newArgs.setEL(funcArgs[i].getName(),ArgumentPro.NULL);
245                                    }
246                                    else {
247                                            newArgs.setEL(funcArgs[i].getName(),castTo(funcArgs[i],d,i+1));
248                                    }
249                            }
250                    }
251                    for(int i=funcArgs.length;i<args.length;i++) {
252                            newArgs.setEL(ArgumentIntKey.init(i+1),args[i]);
253                    }
254            }
255    
256            
257        private void defineArguments(PageContext pageContext, FunctionArgument[] funcArgs, Struct values, ArgumentPro newArgs) throws PageException {
258            // argumentCollection
259            argumentCollection(values,funcArgs);
260            //print.out(values.size());
261            Object value;
262            Collection.Key name;
263                    
264            for(int i=0;i<funcArgs.length;i++) {
265                            // argument defined
266                            name=funcArgs[i].getName();
267                            value=values.removeEL(name); 
268                            if(value!=null) {
269                                    newArgs.set(name,castToAndClone(pageContext,funcArgs[i], value,i+1));
270                                    continue;
271                            }
272                            else {
273                                    value=values.removeEL(ArgumentIntKey.init(i+1)); 
274                                    if(value!=null) {
275                                            newArgs.set(name,castToAndClone(pageContext,funcArgs[i], value,i+1));
276                                            continue;
277                                    }
278                            }
279                            
280                            // default argument or exception
281                            Object defaultValue=getDefaultValue(pageContext,i);//funcArgs[i].getDefaultValue();
282                            if(defaultValue==null) { 
283                                    if(funcArgs[i].isRequired()) {
284                                            throw new ExpressionException("The parameter "+funcArgs[i].getName()+" to function "+getFunctionName()+" is required but was not passed in.");
285                                    }
286                                    newArgs.set(name,ArgumentPro.NULL);
287                            }
288                            else newArgs.set(name,castTo(funcArgs[i],defaultValue,i+1));    
289                    }
290                    
291                    
292                    Collection.Key[] arr=values.keys();
293                    for(int i=0;i<arr.length;i++) {
294                            newArgs.set(arr[i],values.get(arr[i],null));
295                    }
296            }
297        
298    
299            public static void argumentCollection(Struct values) {
300                    argumentCollection(values,EMPTY);
301            }
302    
303            public static void argumentCollection(Struct values, FunctionArgument[] funcArgs) {
304                    Object value=values.removeEL(KeyImpl.ARGUMENT_COLLECTION);
305                    if(value !=null) {
306                            value=Caster.unwrap(value,value);
307                            
308                            if(value instanceof Argument) {
309                                    Argument argColl=(Argument) value;
310                                Collection.Key[] keys = argColl.keys();
311                                for(int i=0;i<keys.length;i++) {
312                                    if(funcArgs.length>i && keys[i] instanceof ArgumentIntKey) {
313                                    if(!values.containsKey(funcArgs[i].getName()))
314                                            values.setEL(funcArgs[i].getName(),argColl.get(keys[i],ArgumentPro.NULL));
315                                    else 
316                                            values.setEL(keys[i],argColl.get(keys[i],ArgumentPro.NULL));
317                                    }
318                            else if(!values.containsKey(keys[i])){
319                                    values.setEL(keys[i],argColl.get(keys[i],ArgumentPro.NULL));
320                            }
321                        }
322                        }
323                            else if(value instanceof Collection) {
324                            Collection argColl=(Collection) value;
325                                Collection.Key[] keys = argColl.keys();
326                                for(int i=0;i<keys.length;i++) {
327                                    if(!values.containsKey(keys[i])){
328                                    values.setEL(keys[i],argColl.get(keys[i],ArgumentPro.NULL));
329                            }
330                        }
331                        }
332                            else if(value instanceof Map) {
333                                    Map map=(Map) value;
334                                Iterator it = map.entrySet().iterator();
335                                Map.Entry entry;
336                                Key key;
337                                while(it.hasNext()) {
338                                    entry=(Entry) it.next();
339                                    key = toKey(entry.getKey());
340                                    if(!values.containsKey(key)){
341                                    values.setEL(key,entry.getValue());
342                            }
343                        }
344                        }
345                            else if(value instanceof java.util.List) {
346                                    java.util.List list=(java.util.List) value;
347                                Iterator it = list.iterator();
348                                Object v;
349                                int index=0;
350                                Key k;
351                                while(it.hasNext()) {
352                                    v= it.next();
353                                    k=ArgumentIntKey.init(++index);
354                                    if(!values.containsKey(k)){
355                                    values.setEL(k,v);
356                            }
357                        }
358                        }
359                        else {
360                            values.setEL(KeyImpl.ARGUMENT_COLLECTION,value);
361                        }
362                    } 
363            }
364            
365            public static Collection.Key toKey(Object obj) {
366                    if(obj==null) return null;
367                    if(obj instanceof Collection.Key) return (Collection.Key) obj;
368                    String str = Caster.toString(obj,null);
369                    if(str==null) return KeyImpl.init(obj.toString());
370                    return KeyImpl.init(str);
371            }
372    
373            /**
374         * @see railo.runtime.type.UDF#callWithNamedValues(railo.runtime.PageContext, railo.runtime.type.Struct, boolean)
375         */
376        public Object callWithNamedValues(PageContext pc, Struct values,boolean doIncludePath) throws PageException {
377            return _call(pc, null, values, doIncludePath);
378        }
379    
380            /**
381         * @see railo.runtime.type.UDF#call(railo.runtime.PageContext, java.lang.Object[], boolean)
382         */
383        public Object call(PageContext pc, Object[] args, boolean doIncludePath) throws PageException {
384            return _call(pc, args,null, doIncludePath);
385        }
386       // private static int count=0;
387        private Object _call(PageContext pc, Object[] args, Struct values,boolean doIncludePath) throws PageException {
388            //print.out(count++);
389            PageContextImpl pci=(PageContextImpl) pc;
390            ArgumentPro newArgs=(ArgumentPro) pci.getScopeFactory().getArgumentInstance();// FUTURE
391            newArgs.setFunctionArgumentNames(properties.argumentsSet);
392            LocalImpl newLocal=pci.getScopeFactory().getLocalInstance();
393            
394                    Undefined       undefined=pc.undefinedScope();
395                    Argument        oldArgs=pc.argumentsScope();
396            Scope           oldLocal=pc.localScope();
397            
398                    pci.setFunctionScopes(newLocal,newArgs);
399                    int oldCheckArgs=undefined.setMode(((ApplicationContextPro)pc.getApplicationContext()).getLocalMode());
400                    PageSource psInc=null;
401                    try {
402                            PageSource ps = getPageSource();
403                            if(doIncludePath)psInc = ps;
404                            //if(!ps.getDisplayPath().endsWith("Dump.cfc"))print.e(getPageSource().getDisplayPath());
405                            if(doIncludePath && getOwnerComponent()!=null) {
406                                    //if(!ps.getDisplayPath().endsWith("Dump.cfc"))print.ds(ps.getDisplayPath());
407                                    psInc=ComponentUtil.getPageSource(getOwnerComponent());
408                                    if(psInc==pci.getCurrentTemplatePageSource()) {
409                                            psInc=null;
410                                    }
411                                    
412                            }
413                            
414                            
415                            
416                            
417                            pci.addPageSource(ps,psInc);
418    //////////////////////////////////////////
419                            BodyContent bc =  (getOutput()?null:pci.pushBody());
420                        //boolean isC=ownerComponent!=null;
421                        
422                        UDF parent=null;
423                        if(ownerComponent!=null) {
424                                parent=pci.getActiveUDF();
425                                pci.setActiveUDF(this);
426                        }
427                        Object returnValue = null;
428                        
429                        try {
430                            
431                            if(args!=null)  defineArguments(pc,getFunctionArguments(),args,newArgs);
432                                    else                    defineArguments(pc,getFunctionArguments(),values,newArgs);
433                            
434                                    returnValue=implementation(pci);
435                                    if(ownerComponent!=null)pci.setActiveUDF(parent);
436                            }
437                    catch(Throwable t) {
438                            if(ownerComponent!=null)pci.setActiveUDF(parent);
439                            BodyContentUtil.flushAndPop(pc,bc);
440                            throw Caster.toPageException(t);
441                    }
442                    BodyContentUtil.clearAndPop(pc,bc);
443                    //pc.popBody();
444                            
445                    
446                    
447                    
448                    if(properties.returnType==CFTypes.TYPE_ANY) return returnValue;
449                    else if(Decision.isCastableTo(properties.strReturnType,returnValue,false)) return returnValue;
450                    else throw new UDFCasterException(this,properties.strReturnType,returnValue);
451                            //REALCAST return Caster.castTo(pageContext,returnType,returnValue,false);
452    //////////////////////////////////////////
453                            
454                    }
455                    finally {
456                            pc.removeLastPageSource(psInc!=null);
457                pci.setFunctionScopes(oldLocal,oldArgs);
458                        undefined.setMode(oldCheckArgs);
459                pci.getScopeFactory().recycle(newArgs);
460                pci.getScopeFactory().recycle(newLocal);
461                    }
462            }
463    
464        /**
465             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int)
466             */
467    
468            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
469                    return toDumpData(pageContext, maxlevel, dp,this);
470            }
471            public static DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp,UDF udf) {
472            
473                    if(!dp.getShowUDFs())
474                            return new SimpleDumpData("<UDF>");
475                    
476                    // arguments
477                    FunctionArgument[] args = udf.getFunctionArguments();
478            
479            DumpTable atts = new DumpTablePro("udf","#9999cc","#ccccff","#000000");
480            
481                    atts.appendRow(new DumpRow(63,new DumpData[]{new SimpleDumpData("label"),new SimpleDumpData("name"),new SimpleDumpData("required"),new SimpleDumpData("type"),new SimpleDumpData("default"),new SimpleDumpData("hint")}));
482                    for(int i=0;i<args.length;i++) {
483                            FunctionArgument arg=args[i];
484                            DumpData def;
485                            try {
486                                    Object oa=null;
487                    try {
488                        oa = udf.getDefaultValue(pageContext,i);
489                    } catch (PageException e1) {
490                    }
491                    if(oa==null)oa="null";
492                                    def=new SimpleDumpData(Caster.toString(oa));
493                            } catch (PageException e) {
494                                    def=new SimpleDumpData("");
495                            }
496                            atts.appendRow(new DumpRow(0,new DumpData[]{
497                                            new SimpleDumpData(arg.getDisplayName()),
498                                            new SimpleDumpData(arg.getName().getString()),
499                                            new SimpleDumpData(arg.isRequired()),
500                                            new SimpleDumpData(arg.getTypeAsString()),
501                                            def,
502                                            new SimpleDumpData(arg.getHint())}));
503                            //atts.setRow(0,arg.getHint());
504                            
505                    }
506                    
507                    DumpTable func = new DumpTable("#9999cc","#ccccff","#000000");
508                    String f="Function ";
509                    try {
510                            f=StringUtil.ucFirst(ComponentUtil.toStringAccess(udf.getAccess()).toLowerCase())+" "+f;
511                    } 
512                    catch (ExpressionException e) {}
513                    func.setTitle(f+udf.getFunctionName());
514                    if(udf instanceof UDFImpl)func.setComment("source:"+((UDFImpl)udf).getPageSource().getDisplayPath());
515                    
516                    
517                    if(!StringUtil.isEmpty(udf.getDescription()))func.setComment(udf.getDescription());
518                    
519                    
520                    
521                    func.appendRow(1,new SimpleDumpData("arguments"),atts);
522                    func.appendRow(1,new SimpleDumpData("return type"),new SimpleDumpData(udf.getReturnTypeAsString()));
523                    
524                    boolean hasLabel=!StringUtil.isEmpty(udf.getDisplayName());//displayName!=null && !displayName.equals("");
525                    boolean hasHint=!StringUtil.isEmpty(udf.getHint());//hint!=null && !hint.equals("");
526                    
527                    if(hasLabel || hasHint) {
528                            DumpTable box = new DumpTable("#ffffff","#cccccc","#000000");
529                            box.setTitle(hasLabel?udf.getDisplayName():udf.getFunctionName());
530                            if(hasHint)box.appendRow(0,new SimpleDumpData(udf.getHint()));
531                            box.appendRow(0,func);
532                            return box;
533                    }
534                    
535                    return func;
536            }
537            /**
538         * @see railo.runtime.type.UDF#getDisplayName()
539         */
540            public String getDisplayName() {
541                    return properties.displayName;
542            }
543            /**
544         * @see railo.runtime.type.UDF#getHint()
545         */
546            public String getHint() {
547                    return properties.hint;
548            }
549        /**
550         * @see railo.runtime.type.UDF#getPage()
551         * @deprecated use instead getPageSource()
552         */
553        public Page getPage() {
554            throw new PageRuntimeException(new DeprecatedException("method getPage():Page is no longer suppoted, use instead getPageSource():PageSource"));
555            //return properties.page;
556        }
557        
558        // FUTURE add to interface
559        public PageSource getPageSource() {
560            return properties.pageSource;
561        }
562    
563            public Struct getMeta() {
564                    return properties.meta;
565            }
566            
567            public Struct getMetaData(PageContext pc) throws PageException {
568                    return ComponentUtil.getMetaData(pc, properties);
569                    //return getMetaData(pc, this);
570            }
571            
572            /*public static Struct getMetaData(PageContext pc,UDFImpl udf) throws PageException {
573                    StructImpl func=new StructImpl();
574            
575                    // TODO func.set("roles", value);
576            // TODO func.set("userMetadata", value); neo unterst゚tzt irgendwelche a
577            // meta data
578            Struct meta = udf.getMeta();
579            if(meta!=null) StructUtil.copy(meta, func, true);
580            
581                    
582                    func.set(KeyImpl.ACCESS,ComponentUtil.toStringAccess(udf.getAccess()));
583            String hint=udf.getHint();
584            if(!StringUtil.isEmpty(hint))func.set(KeyImpl.HINT,hint);
585            String displayname=udf.getDisplayName();
586            if(!StringUtil.isEmpty(displayname))func.set(KeyImpl.DISPLAY_NAME,displayname);
587            func.set(KeyImpl.NAME,udf.getFunctionName());
588            func.set(KeyImpl.OUTPUT,Caster.toBoolean(udf.getOutput()));
589            func.set(KeyImpl.RETURN_TYPE, udf.getReturnTypeAsString());
590            func.set(KeyImpl.DESCRIPTION, udf.getDescription());
591            
592            func.set(KeyImpl.OWNER, udf.getPageSource().getDisplayPath());
593            
594                       
595                int format = udf.getReturnFormat();
596            if(format==UDF.RETURN_FORMAT_WDDX)                      func.set(KeyImpl.RETURN_FORMAT, "wddx");
597            else if(format==UDF.RETURN_FORMAT_PLAIN)        func.set(KeyImpl.RETURN_FORMAT, "plain");
598            else if(format==UDF.RETURN_FORMAT_JSON) func.set(KeyImpl.RETURN_FORMAT, "json");
599            else if(format==UDF.RETURN_FORMAT_SERIALIZE)func.set(KeyImpl.RETURN_FORMAT, "serialize");
600            
601            
602            FunctionArgument[] args =  udf.getFunctionArguments();
603            Array params=new ArrayImpl();
604            //Object defaultValue;
605            Struct m;
606            //Object defaultValue;
607            for(int y=0;y<args.length;y++) {
608                StructImpl param=new StructImpl();
609                param.set(KeyImpl.NAME,args[y].getName().getString());
610                param.set(KeyImpl.REQUIRED,Caster.toBoolean(args[y].isRequired()));
611                param.set(KeyImpl.TYPE,args[y].getTypeAsString());
612                displayname=args[y].getDisplayName();
613                if(!StringUtil.isEmpty(displayname)) param.set(KeyImpl.DISPLAY_NAME,displayname);
614                
615                int defType = args[y].getDefaultType();
616                if(defType==FunctionArgument.DEFAULT_TYPE_RUNTIME_EXPRESSION){
617                    param.set(KeyImpl.DEFAULT, "[runtime expression]");
618                }
619                else if(defType==FunctionArgument.DEFAULT_TYPE_LITERAL){
620                    param.set(KeyImpl.DEFAULT, udf.getDefaultValue(pc,y));
621                }
622                
623                hint=args[y].getHint();
624                if(!StringUtil.isEmpty(hint))param.set(KeyImpl.HINT,hint);
625                // TODO func.set("userMetadata", value); neo unterst゚tzt irgendwelche attr, die dann hier ausgebenen werden blレdsinn
626                
627                // meta data
628                m=args[y].getMetaData();
629                if(m!=null) StructUtil.copy(m, param, true);
630                    
631                params.append(param);
632            }
633            func.set(KeyImpl.PARAMETERS,params);
634                    return func;
635            }*/
636    
637            public Object getValue() {
638                    return this;
639            }
640    
641    
642            /**
643             * @param componentImpl the componentImpl to set
644             * @param injected 
645             */
646            public void setOwnerComponent(ComponentImpl component) {
647                    //print.err("setOwnerComponent("+this.hashCode()+"-"+component.hashCode()+"):"+component.getPage().getPageSource().getDisplayPath());
648                    this.ownerComponent = component;
649            }
650            
651            /**
652             * @see railo.runtime.type.UDF#getOwnerComponent()
653            // FUTURE deprecated
654             */
655            public Component getOwnerComponent() {
656                    return ownerComponent;//+++
657            }
658            
659    
660            public String toString() {
661                    StringBuffer sb=new StringBuffer(properties.functionName);
662                    sb.append("(");
663                    int optCount=0;
664                    for(int i=0;i<properties.arguments.length;i++) {
665                            if(i>0)sb.append(", ");
666                            if(!properties.arguments[i].isRequired()){
667                                    sb.append("[");
668                                    optCount++;
669                            }
670                            sb.append(properties.arguments[i].getTypeAsString());
671                            sb.append(" ");
672                            sb.append(properties.arguments[i].getName());
673                    }
674                    for(int i=0;i<optCount;i++){
675                            sb.append("]");
676                    }
677                    sb.append(")");
678                    return sb.toString();
679            }
680    
681            /**
682             * @see railo.runtime.type.UDF#getSecureJson()
683             */
684            public Boolean getSecureJson() {
685                    return properties.secureJson;
686            }
687    
688            /**
689             * @see railo.runtime.type.UDF#getVerifyClient()
690             */
691            public Boolean getVerifyClient() {
692                    return properties.verifyClient;
693            }
694            
695            /*public boolean isInjected() {
696                    return injected;
697            }*/
698    
699            public Object clone() {
700                    return duplicate();
701            }
702    
703    
704            
705            /**
706         * @see railo.runtime.type.UDF#getFunctionArguments()
707         */
708        public FunctionArgument[] getFunctionArguments() {
709            return properties.arguments;
710        }
711            
712            /**
713         * @see railo.runtime.type.UDF#getDefaultValue(railo.runtime.PageContext, int)
714         */
715        public Object getDefaultValue(PageContext pc,int index) throws PageException {
716            return ComponentUtil.getPage(pc,properties.pageSource).udfDefaultValue(pc,properties.index,index);
717        }
718        // public abstract Object getDefaultValue(PageContext pc,int index) throws PageException;
719    
720            /**
721         * @see railo.runtime.type.UDF#getFunctionName()
722         */
723            public String getFunctionName() {
724                    return properties.functionName;
725            }
726    
727            /**
728         * @see railo.runtime.type.UDF#getOutput()
729         */
730            public boolean getOutput() {
731                    return properties.output;
732            }
733    
734            /**
735         * @see railo.runtime.type.UDF#getReturnType()
736         */
737            public int getReturnType() {
738                    return properties.returnType;
739            }
740            
741            /**
742             * @see railo.runtime.type.UDF#getReturnTypeAsString()
743             */
744            public String getReturnTypeAsString() {
745                    return properties.strReturnType;
746            }
747            
748            /**
749             * @see railo.runtime.type.UDF#getDescription()
750             */
751            public String getDescription() {
752                    return properties.description;
753            }
754            
755            /**
756             * @see railo.runtime.type.UDF#getReturnFormat()
757             */
758            public int getReturnFormat() {
759                    return properties.returnFormat;
760            }
761            
762            public final String getReturnFormatAsString() {
763                    return properties.strReturnFormat;
764            }
765            
766            
767            public static int toReturnFormat(String returnFormat) throws ExpressionException {
768                    if(StringUtil.isEmpty(returnFormat,true))
769                            return UDF.RETURN_FORMAT_WDDX;
770                            
771                            
772                    returnFormat=returnFormat.trim().toLowerCase();
773                    if("wddx".equals(returnFormat))                         return UDF.RETURN_FORMAT_WDDX;
774                    else if("json".equals(returnFormat))            return UDF.RETURN_FORMAT_JSON;
775                    else if("plain".equals(returnFormat))           return UDF.RETURN_FORMAT_PLAIN;
776                    else if("text".equals(returnFormat))            return UDF.RETURN_FORMAT_PLAIN;
777                    else if("serialize".equals(returnFormat))       return UDF.RETURN_FORMAT_SERIALIZE;
778                    else throw new ExpressionException("invalid returnFormat definition ["+returnFormat+"], valid values are [wddx,plain,json,serialize]");
779            }
780    
781            public static String toReturnFormat(int returnFormat) throws ExpressionException {
782                    if(RETURN_FORMAT_WDDX==returnFormat)            return "wddx";
783                    else if(RETURN_FORMAT_JSON==returnFormat)       return "json";
784                    else if(RETURN_FORMAT_PLAIN==returnFormat)      return "plain";
785                    else if(RETURN_FORMAT_SERIALIZE==returnFormat)  return "serialize";
786                    else throw new ExpressionException("invalid returnFormat definition, valid values are [wddx,plain,json,serialize]");
787            }
788            
789            
790            // FUTURE move to interface
791            public static String toReturnFormat(int returnFormat,String defaultValue) {
792                    if(RETURN_FORMAT_WDDX==returnFormat)            return "wddx";
793                    else if(RETURN_FORMAT_JSON==returnFormat)       return "json";
794                    else if(RETURN_FORMAT_PLAIN==returnFormat)      return "plain";
795                    else if(RETURN_FORMAT_SERIALIZE==returnFormat)  return "serialize";
796                    else return defaultValue;
797            }
798    
799            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
800                    // access
801                    setAccess(in.readInt());
802                    
803                    // properties
804                    properties=(UDFProperties) in.readObject();
805            }
806    
807    
808            public void writeExternal(ObjectOutput out) throws IOException {
809                    // access
810                    out.writeInt(getAccess());
811                    
812                    // properties
813                    out.writeObject(properties);
814                    
815                    
816            }
817    
818            
819    }
820