001    package railo.runtime;
002    
003    import java.io.Externalizable;
004    import java.io.IOException;
005    import java.io.ObjectInput;
006    import java.io.ObjectOutput;
007    import java.lang.ref.SoftReference;
008    import java.util.ArrayList;
009    import java.util.Date;
010    import java.util.HashMap;
011    import java.util.HashSet;
012    import java.util.Iterator;
013    import java.util.LinkedHashMap;
014    import java.util.Map;
015    import java.util.Set;
016    
017    import javax.servlet.http.Cookie;
018    
019    import railo.commons.io.DevNullOutputStream;
020    import railo.commons.lang.CFTypes;
021    import railo.commons.lang.ExceptionUtil;
022    import railo.commons.lang.Pair;
023    import railo.commons.lang.SizeOf;
024    import railo.commons.lang.StringUtil;
025    import railo.commons.lang.types.RefBoolean;
026    import railo.commons.lang.types.RefBooleanImpl;
027    import railo.runtime.component.ComponentLoader;
028    import railo.runtime.component.DataMember;
029    import railo.runtime.component.InterfaceCollection;
030    import railo.runtime.component.Member;
031    import railo.runtime.component.Property;
032    import railo.runtime.config.ConfigImpl;
033    import railo.runtime.config.ConfigWeb;
034    import railo.runtime.config.ConfigWebImpl;
035    import railo.runtime.converter.ScriptConverter;
036    import railo.runtime.debug.DebugEntry;
037    import railo.runtime.dump.DumpData;
038    import railo.runtime.dump.DumpProperties;
039    import railo.runtime.dump.DumpTable;
040    import railo.runtime.dump.DumpTablePro;
041    import railo.runtime.dump.DumpUtil;
042    import railo.runtime.dump.SimpleDumpData;
043    import railo.runtime.engine.ThreadLocalPageContext;
044    import railo.runtime.exp.ApplicationException;
045    import railo.runtime.exp.DeprecatedException;
046    import railo.runtime.exp.ExpressionException;
047    import railo.runtime.exp.PageException;
048    import railo.runtime.exp.PageRuntimeException;
049    import railo.runtime.interpreter.CFMLExpressionInterpreter;
050    import railo.runtime.op.Caster;
051    import railo.runtime.op.Duplicator;
052    import railo.runtime.op.Operator;
053    import railo.runtime.op.ThreadLocalDuplication;
054    import railo.runtime.op.date.DateCaster;
055    import railo.runtime.thread.ThreadUtil;
056    import railo.runtime.type.ArrayImpl;
057    import railo.runtime.type.Collection;
058    import railo.runtime.type.FunctionArgument;
059    import railo.runtime.type.KeyImpl;
060    import railo.runtime.type.List;
061    import railo.runtime.type.Sizeable;
062    import railo.runtime.type.Struct;
063    import railo.runtime.type.StructImpl;
064    import railo.runtime.type.UDF;
065    import railo.runtime.type.UDFGSProperty;
066    import railo.runtime.type.UDFImpl;
067    import railo.runtime.type.UDFProperties;
068    import railo.runtime.type.cfc.ComponentAccess;
069    import railo.runtime.type.comparator.ArrayOfStructComparator;
070    import railo.runtime.type.dt.DateTime;
071    import railo.runtime.type.scope.Argument;
072    import railo.runtime.type.scope.ArgumentImpl;
073    import railo.runtime.type.scope.ArgumentIntKey;
074    import railo.runtime.type.scope.Variables;
075    import railo.runtime.type.util.ArrayUtil;
076    import railo.runtime.type.util.ComponentUtil;
077    import railo.runtime.type.util.PropertyFactory;
078    import railo.runtime.type.util.StructSupport;
079    import railo.runtime.type.util.StructUtil;
080    import railo.runtime.util.ArrayIterator;
081    
082    /**
083     * %**%
084     * MUST add handling for new attributes (style, namespace, serviceportname, porttypename, wsdlfile, bindingname, and output)
085     */ 
086    public final class ComponentImpl extends StructSupport implements Externalizable,ComponentAccess,coldfusion.runtime.TemplateProxy,Sizeable {
087    
088    
089            private ComponentProperties properties;
090            private Map<Key,Member> _data;
091        private Map<Key,UDF> _udfs;
092    
093            ComponentImpl top=this;
094        ComponentImpl base;
095        //private ComponentPage componentPage;
096        private PageSource pageSource;
097        private ComponentScope scope;
098        
099        // for all the same
100        private int dataMemberDefaultAccess;
101            private boolean triggerDataMember;
102            
103            // state control of component
104            boolean isInit=false;
105    
106            private InterfaceCollection interfaceCollection;
107    
108            private boolean useShadow;
109            boolean afterConstructor;
110            private Map<Key,UDF> constructorUDFs;
111    
112            private static final Key TO_DATETIME = KeyImpl.intern("_toDateTime");
113            private static final Key TO_NUMERIC = KeyImpl.intern("_toNumeric");
114            private static final Key TO_BOOLEAN = KeyImpl.intern("_toBoolean");
115            private static final Key TO_STRING = KeyImpl.intern("_toString");
116    
117            private static final Key ON_MISSING_METHOD = KeyImpl.intern("onmissingmethod");
118    
119            protected static final Key EXTENDS = KeyImpl.intern("extends");
120            protected static final Key IMPLEMENTS = KeyImpl.intern("implements");
121            protected static final Key FUNCTIONS = KeyImpl.intern("functions");
122            protected static final Key FULLNAME = KeyImpl.intern("fullname");
123            protected static final Key SKELETON = KeyImpl.intern("skeleton");
124            protected static final Key PROPERTIES = KeyImpl.intern("properties");
125            private static final Key MAPPED_SUPER_CLASS = KeyImpl.intern("mappedSuperClass");
126            private static final Key PERSISTENT = KeyImpl.intern("persistent");
127            private static final Key ACCESSORS = KeyImpl.intern("accessors");
128            private static final Key SYNCRONIZED = KeyImpl.intern("synchronized");
129            protected static final Key DISPLAY_NAME = KeyImpl.intern("displayname");
130            
131            public long sizeOf() {
132                    return 
133                            SizeOf.size(properties)+
134                            SizeOf.size(_data)+
135                            SizeOf.size(scope)+
136                            SizeOf.size(dataMemberDefaultAccess)+
137                            SizeOf.size(triggerDataMember)+
138                            SizeOf.size(false)+
139                            SizeOf.size(interfaceCollection)+
140                            SizeOf.size(useShadow)+
141                            SizeOf.size(afterConstructor)+
142                            SizeOf.size(base);
143            }
144            
145        /**
146         * Constructor of the Component, USED ONLY FOR DESERIALIZE
147         */
148             public ComponentImpl() {
149             }
150            
151        /**
152         * Constructor of the class
153         * @param componentPage
154         * @param output
155         * @param _synchronized
156         * @param extend
157         * @param implement
158         * @param hint
159         * @param dspName
160         * @param callPath
161         * @param realPath
162         * @param style
163         * @param meta
164         * @throws ApplicationException
165         */
166    
167        public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized, 
168                    String extend, String implement, String hint, String dspName,String callPath, boolean realPath, 
169                    String style,StructImpl meta) throws ApplicationException {
170            this(componentPage,output,_synchronized, 
171                            extend, implement, hint, dspName,callPath, realPath, style,false, false,meta);
172        }
173        
174        public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized, 
175                    String extend, String implement, String hint, String dspName,String callPath, boolean realPath, 
176                    String style,boolean persistent,StructImpl meta) throws ApplicationException {
177            this(componentPage,output,_synchronized, 
178                            extend, implement, hint, dspName,callPath, realPath, style,persistent, false,meta);
179        }
180             
181        public ComponentImpl(ComponentPage componentPage,Boolean output,boolean _synchronized, 
182                    String extend, String implement, String hint, String dspName,String callPath, boolean realPath, 
183                    String style,boolean persistent,boolean accessors,StructImpl meta) throws ApplicationException {
184            this.properties=new ComponentProperties(dspName,extend.trim(),implement,hint,output,callPath,realPath,_synchronized,null,persistent,accessors,meta);
185            //this.componentPage=componentPage instanceof ComponentPageProxy?componentPage:PageProxy.toProxy(componentPage);
186            this.pageSource=componentPage.getPageSource();
187            
188            if(!StringUtil.isEmpty(style) && !"rpc".equals(style))
189                    throw new ApplicationException("style ["+style+"] is not supported, only the following styles are supported [rpc]");
190        }
191        
192    
193        /**
194         * @see railo.runtime.type.Collection#duplicate(boolean)
195         
196        public synchronized Collection duplicatex(boolean deepCopy) {
197            ComponentImpl c=new ClonedComponent(this,deepCopy);
198            return c;
199        }*/
200    
201        public Collection duplicate(boolean deepCopy) {
202            ComponentImpl top= _duplicate(deepCopy,true);
203            setTop(top,top);
204            
205                    
206                    return top;
207        }
208            
209        
210        
211        
212        private ComponentImpl _duplicate( boolean deepCopy, boolean isTop) {
213            ComponentImpl trg=new ComponentImpl();
214            ThreadLocalDuplication.set(this, trg);
215            try{
216                            // attributes
217                    trg.pageSource=pageSource;
218                    trg.triggerDataMember=triggerDataMember;
219                    trg.useShadow=useShadow;
220                    trg.afterConstructor=afterConstructor;
221                    trg.dataMemberDefaultAccess=dataMemberDefaultAccess;
222                            trg.properties=properties.duplicate();
223                            trg.isInit=isInit;
224                            trg.interfaceCollection=interfaceCollection;
225                    
226                            boolean useShadow=scope instanceof ComponentScopeShadow;
227                            if(!useShadow)trg.scope=new ComponentScopeThis(trg);
228                            
229                    if(base!=null){
230                                    trg.base=base._duplicate(deepCopy,false);
231                                    
232                                    trg._data=trg.base._data;
233                                    trg._udfs=duplicateUTFMap(this,trg, _udfs,new HashMap<Key,UDF>(trg.base._udfs));
234    
235                            if(useShadow) trg.scope=new ComponentScopeShadow(trg,(ComponentScopeShadow)trg.base.scope,false);
236                            }
237                    else {
238                            // clone data member, ignore udfs for the moment
239                            trg._data=duplicateDataMember(trg, _data, new HashMap(), deepCopy);
240                            trg._udfs=duplicateUTFMap(this,trg, _udfs,new HashMap<Key, UDF>());
241                            
242                            if(useShadow) {
243                                    ComponentScopeShadow css = (ComponentScopeShadow)scope;
244                                    trg.scope=new ComponentScopeShadow(trg,duplicateDataMember(trg,css.getShadow(),new HashMap(),deepCopy));
245                            }
246                    }
247                    
248                    // at the moment this makes no sense, becuae this map is no more used after constructor has runned and for a clone the constructo is not executed, but perhaps this is used in future
249                    if(constructorUDFs!=null){
250                            trg.constructorUDFs=new HashMap<Collection.Key, UDF>();
251                            addUDFS(trg, constructorUDFs, trg.constructorUDFs);
252                    }
253                            
254                            
255                    if(isTop) {
256                            setTop(trg,trg);
257                            
258                            addUDFS(trg,_data,trg._data);
259                            if(useShadow){
260                                    addUDFS(trg,((ComponentScopeShadow)scope).getShadow(),((ComponentScopeShadow)trg.scope).getShadow());
261                            }
262                    }
263                    
264                    
265                    
266                    
267            }
268            finally {
269                    ThreadLocalDuplication.remove(this);
270            }
271            
272                    return trg;
273            }
274        
275        
276        private static void addUDFS(ComponentImpl trgComp, Map src, Map trg) {
277                    Iterator it = src.entrySet().iterator();
278                    Map.Entry entry;
279                    Object key,value;
280                    UDF udf;
281                    ComponentImpl comp,owner;
282                    boolean done;
283            while(it.hasNext()){
284                    entry=(Entry) it.next();
285                    key=entry.getKey();
286                    value=entry.getValue();
287                    if(value instanceof UDF) {
288                            udf=(UDF) value;
289                            done=false;
290                            // get udf from _udf
291                            owner = (ComponentImpl)udf.getOwnerComponent();
292                            if(owner!=null) {
293                                    comp=trgComp;
294                                    do{
295                                            if(owner.pageSource==comp.pageSource)
296                                                    break;
297                                    }
298                                    while((comp=comp.base)!=null);
299                                    if(comp!=null) {
300                                            value=comp._udfs.get(key);
301                                            trg.put(key, value);
302                                            done=true;
303                                    }
304                            }
305                            // udf with no owner
306                            if(!done) 
307                                    trg.put(key, udf.duplicate());
308                            
309                            //print.o(owner.pageSource.getComponentName()+":"+udf.getFunctionName());
310                    }
311            }
312            }
313    
314        /**
315         * duplicate the datamember in the map, ignores the udfs
316         * @param c
317         * @param map
318         * @param newMap
319         * @param deepCopy
320         * @return
321         */
322        public static Map duplicateDataMember(ComponentImpl c,Map map,Map newMap,boolean deepCopy){
323            Iterator it=map.entrySet().iterator();
324            Map.Entry entry;
325            Object value;
326            while(it.hasNext()) {
327                entry=(Entry) it.next();
328                    value=entry.getValue();
329                
330                if(!(value instanceof UDF)) {
331                    if(deepCopy) value=Duplicator.duplicate(value,deepCopy);
332                    newMap.put(entry.getKey(),value);
333                }
334            }
335            return newMap;
336        }
337        
338        public static Map<Key, UDF> duplicateUTFMap(ComponentImpl src,ComponentImpl trg,Map<Key,UDF> srcMap, Map<Key, UDF> trgMap){
339            Iterator<Entry<Key, UDF>> it = srcMap.entrySet().iterator();
340            Map.Entry<Key, UDF> entry;
341            UDF udf;
342            while(it.hasNext()) {
343                entry=it.next();
344                udf=entry.getValue();
345                    
346                if(udf.getOwnerComponent()==src) {
347                            udf=((UDFImpl)entry.getValue()).duplicate(trg);
348                            trgMap.put(entry.getKey(),udf); 
349                }
350                    
351            }
352            return trgMap;
353        }
354        
355    
356            /**
357         * initalize the Component
358         * @param pageContext
359         * @param componentPage
360         * @throws PageException
361         */    
362        public void init(PageContext pageContext, ComponentPage componentPage) throws PageException {
363            //this.componentPage=componentPage;
364            this.pageSource=componentPage.getPageSource();
365    
366            // extends
367                if(!StringUtil.isEmpty(properties.extend)) {
368                            base= ComponentLoader.loadComponent(pageContext,properties.extend,Boolean.TRUE,null);
369                    }
370                else { 
371                    Page p=((ConfigWebImpl)pageContext.getConfig()).getBaseComponentPage(pageContext);
372                    if(!componentPage.getPageSource().equals(p.getPageSource())) {
373                    base=ComponentLoader.loadComponent(pageContext,p,p.getPageSource(),"Component",false);
374                    } 
375                }
376            
377                if(base!=null){
378                    this.dataMemberDefaultAccess=base.dataMemberDefaultAccess;
379                    this.triggerDataMember=base.triggerDataMember;
380                    _data=base._data;
381                    _udfs=new HashMap<Key,UDF>(base._udfs);
382                    setTop(this,base);
383                }
384                else {
385                    this.dataMemberDefaultAccess=pageContext.getConfig().getComponentDataMemberDefaultAccess();
386                    this.triggerDataMember=pageContext.getConfig().getTriggerComponentDataMember();
387                        _udfs=new HashMap<Key,UDF>();
388                        _data=new HashMap<Key,Member>();
389                }
390                
391                // implements
392                if(!StringUtil.isEmpty(properties.implement)) {
393                    interfaceCollection=new InterfaceCollection((PageContextImpl)pageContext,properties.implement);
394                }
395                
396                // scope
397                if(useShadow=pageContext.getConfig().useComponentShadow()) {
398                    if(base==null) scope=new ComponentScopeShadow(this,new HashMap<Key,Object>());
399                        else scope=new ComponentScopeShadow(this,(ComponentScopeShadow)base.scope,false);
400                }
401                else {
402                    scope=new ComponentScopeThis(this);
403                }
404                initProperties();
405            }
406        
407        public void checkInterface(PageContext pc, ComponentPage componentPage) throws PageException {
408            if(interfaceCollection==null || interfaceCollection.lastUpdate()<=componentPage.lastCheck()) return;
409            
410                Iterator it = interfaceCollection.getUdfs().entrySet().iterator();
411                Map.Entry entry;
412                UDFImpl iUdf,cUdf;
413                FunctionArgument[] iFA,cFA;
414            while(it.hasNext()){
415                    
416                    entry=(Entry) it.next();
417                    iUdf=(UDFImpl) entry.getValue();
418                    cUdf=(UDFImpl) _udfs.get(entry.getKey());
419                    
420                    // UDF does not exist
421                    if(cUdf==null ) {
422                            throw new ExpressionException(
423                                             "component ["+componentPage.getPageSource().getDisplayPath()+
424                                             "] does not implement the function ["+iUdf.toString().toLowerCase()+"] of the interface ["+
425                                             iUdf.getPageSource().getDisplayPath()+"]");
426                                            
427                    }
428                    
429                    iFA=iUdf.getFunctionArguments();
430                    cFA=cUdf.getFunctionArguments();
431        // access
432                    if(cUdf.getAccess()>Component.ACCESS_PUBLIC){
433                            throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
434                                    "access ["+ComponentUtil.toStringAccess(cUdf.getAccess())+"] has to be at least [public]");
435                    }
436                    
437        // return type
438                    if(iUdf.getReturnType()!=cUdf.getReturnType()){
439                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
440                                            "return type ["+cUdf.getReturnTypeAsString()+"] does not match interface function return type ["+iUdf.getReturnTypeAsString()+"]");
441                            }
442                            // none base types
443                            if(iUdf.getReturnType()==CFTypes.TYPE_UNKNOW && !iUdf.getReturnTypeAsString().equalsIgnoreCase(cUdf.getReturnTypeAsString())) {
444                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
445                                            "return type ["+cUdf.getReturnTypeAsString()+"] does not match interface function return type ["+iUdf.getReturnTypeAsString()+"]");
446                            }
447            // output
448                    if(iUdf.getOutput()!=cUdf.getOutput()){
449                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
450                                            "output does not match interface function output definition");
451                            }
452                            
453        // arguments
454                    if(iFA.length!=cFA.length) {
455                            throw new ExpressionException( _getErrorMessage(cUdf,iUdf),"not the same argument count");
456                            }
457                    
458                    for(int i=0;i<iFA.length;i++) {
459                            // type
460                            if(iFA[i].getType()!=cFA[i].getType()){
461                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
462                                            "argument type ["+cFA[i].getTypeAsString()+"] does not match interface function argument type ["+iFA[i].getTypeAsString()+"]");
463                            }
464                            // none base types
465                            if(iFA[i].getType()==CFTypes.TYPE_UNKNOW && !iFA[i].getTypeAsString().equalsIgnoreCase(cFA[i].getTypeAsString())) {
466                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
467                                                    "argument type ["+cFA[i].getTypeAsString()+"] does not match interface function argument type ["+iFA[i].getTypeAsString()+"]");
468                            }
469                            // name
470                            if(!iFA[i].getName().equalsIgnoreCase(cFA[i].getName())){
471                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
472                                            "argument name ["+cFA[i].getName()+"] does not match interface function argument name ["+iFA[i].getName()+"]");
473                            }
474                            // required
475                            if(iFA[i].isRequired()!=cFA[i].isRequired()){
476                                    throw new ExpressionException( _getErrorMessage(cUdf,iUdf),
477                                            "argument ["+cFA[i].getName()+"] should "+(iFA[i].isRequired()?"":"not ")+"be required");
478                            }
479                    }
480            }
481                componentPage.ckecked();
482        }
483    
484            private String _getErrorMessage(UDFImpl cUdf,UDFImpl iUdf) {
485                    return "function ["+cUdf.toString().toLowerCase()+"] of component " +
486                             "["+pageSource.getDisplayPath()+"]" +
487                             " does not match the function declarition ["+iUdf.toString().toLowerCase()+"] of the interface " +
488                             "["+iUdf.getPageSource().getDisplayPath()+"]";
489            }
490    
491    
492            private static void setTop(ComponentImpl top,ComponentImpl trg) {
493                    while(trg!=null){
494                            trg.top=top;
495                            trg=trg.base;
496                    }
497            }
498    
499        Object _call(PageContext pc, Collection.Key key, Struct namedArgs, Object[] args,boolean superAccess) throws PageException {
500            Member member=getMember(pc,key,false, superAccess);
501            if(member instanceof UDF) {
502                    return _call(pc,(UDF)member,namedArgs,args);
503            }
504            return onMissingMethod(pc, -1, member, key.getString(), args, namedArgs, superAccess);
505        }
506    
507        Object _call(PageContext pc, int access, Collection.Key key, Struct namedArgs, Object[] args,boolean superAccess) throws PageException {
508            Member member=getMember(access,key,false,superAccess);
509            if(member instanceof UDF) {
510                return _call(pc,(UDF)member,namedArgs,args);
511            }
512            return onMissingMethod(pc, access, member, key.getString(), args, namedArgs, superAccess);
513        }
514        
515        public Object onMissingMethod(PageContext pc, int access,Member member,String name,Object _args[],Struct _namedArgs, boolean superAccess) throws PageException {
516            Member ommm = access==-1?
517                            getMember(pc,ON_MISSING_METHOD,false, superAccess):
518                            getMember(access,ON_MISSING_METHOD,false, superAccess);
519            if(ommm instanceof UDF) {
520                    Argument args=new ArgumentImpl();
521                    if(_args!=null) {
522                            for(int i=0;i<_args.length;i++) {
523                                    args.setEL(ArgumentIntKey.init(i+1), _args[i]);
524                            }
525                    }
526                    else if(_namedArgs!=null) {
527                            UDFImpl.argumentCollection(_namedArgs, new FunctionArgument[]{});
528                            Key[] keys = _namedArgs.keys();
529                            for(int i=0;i<keys.length;i++) {
530                                    args.setEL(keys[i],_namedArgs.get(keys[i],null));
531                            }
532                    }
533                    
534                    //Struct newArgs=new StructImpl(StructImpl.TYPE_SYNC);
535                    //newArgs.setEL(MISSING_METHOD_NAME, name);
536                    //newArgs.setEL(MISSING_METHOD_ARGS, args); 
537                    Object[] newArgs=new Object[]{name,args};
538                    
539                    return _call(pc,(UDF)ommm,null,newArgs);
540            }
541            if(member==null)throw ComponentUtil.notFunction(this, KeyImpl.init(name), null,access);
542            throw ComponentUtil.notFunction(this, KeyImpl.init(name), member.getValue(),access);
543        }
544            
545            Object _call(PageContext pc, UDF udf, Struct namedArgs, Object[] args) throws PageException {
546                            
547                    Object rtn=null;
548                    Variables parent=null;
549            
550                    // INFO duplicate code is for faster execution -> less contions
551                    
552                    
553                    // debug yes
554                    if(pc.getConfig().debug()) {
555                        DebugEntry debugEntry=pc.getDebugger().getEntry(pc,pageSource,udf.getFunctionName());//new DebugEntry(src,udf.getFunctionName());
556                            int currTime=pc.getExecutionTime();
557                            long time=System.currentTimeMillis();
558                            
559                            // sync yes
560                            if(top.properties._synchronized){
561                                    synchronized (this) {
562                                            try {
563                                                    parent=beforeCall(pc);// FUTURE add to interface
564                                                    if(args!=null)rtn=udf.call(pc,args,true);
565                                                    else rtn=udf.callWithNamedValues(pc,namedArgs,true);
566                                            }               
567                                            finally {
568                                                    pc.setVariablesScope(parent);
569                                                    int diff= ((int)(System.currentTimeMillis()-time)-(pc.getExecutionTime()-currTime));
570                                                    pc.setExecutionTime(pc.getExecutionTime()+diff);
571                                                    debugEntry.updateExeTime(diff); 
572                                            }       
573                                    }
574                            }
575    
576                            // sync no
577                            else {
578                                    try {
579                                            parent=beforeCall(pc);// FUTURE add to interface
580                                            if(args!=null)rtn=udf.call(pc,args,true);
581                                            else rtn=udf.callWithNamedValues(pc,namedArgs,true);
582                                    }               
583                                    finally {
584                                            pc.setVariablesScope(parent);
585                                            int diff= ((int)(System.currentTimeMillis()-time)-(pc.getExecutionTime()-currTime));
586                                            pc.setExecutionTime(pc.getExecutionTime()+diff);
587                                            debugEntry.updateExeTime(diff); 
588                                    }       
589                            }
590                            
591                            
592                    }
593                    
594                    // debug no
595                    else {
596                            
597                            // sync yes
598                            if(top.properties._synchronized){
599                                    synchronized (this) {
600                                        try {
601                                    parent=beforeCall(pc); // FUTURE add to interface
602                                    if(args!=null)rtn=udf.call(pc,args,true);
603                                                    else rtn=udf.callWithNamedValues(pc,namedArgs,true);
604                                            }               
605                                            finally {
606                                                    pc.setVariablesScope(parent);
607                                            }
608                                    }
609                            }
610                            
611                            // sync no
612                            else {
613                                try {
614                            parent=beforeCall(pc); // FUTURE add to interface
615                            if(args!=null)rtn=udf.call(pc,args,true);
616                                            else rtn=udf.callWithNamedValues(pc,namedArgs,true);
617                                    }               
618                                    finally {
619                                            pc.setVariablesScope(parent);
620                                    }
621                            }
622                    }
623                    return rtn;
624            }
625    
626            /*private void openLock(int id) {
627                    // check log
628                    if(top.properties._synchronized) {
629                            if(top.threadUsingLock!=0 && top.threadUsingLock!=id){
630                                    try {
631                                            top.threadsWaiting++;
632                                            synchronized(this) {
633                                            wait();
634                                            top.threadsWaiting--;
635                                    }
636                                    } catch (InterruptedException e) {
637                                            
638                                    }
639                            }
640                            else top.threadUsingLock=id;
641                    }
642            }
643    
644            private void closeLock() {
645                    top.threadUsingLock=0;
646                    if(top.threadsWaiting==0)return;
647                    synchronized(this) {
648                    notify();
649            }
650            }*/
651            
652            
653            /**
654         * will be called before executing method or constructor
655         * @param pc
656         * @return the old scope map
657         */
658            public Variables beforeCall(PageContext pc) {
659            Variables parent=pc.variablesScope();
660            pc.setVariablesScope(scope);
661            return parent;
662        }
663            
664            /**
665         * will be called after invoking constructor, only invoked by constructor (component body execution)
666             * @param pc
667             * @param parent
668             */
669        public void afterConstructor(PageContext pc, Variables parent) {
670            pc.setVariablesScope(parent);
671            this.afterConstructor=true;
672            
673            if(constructorUDFs!=null){
674                    Iterator<Entry<Key, UDF>> it = constructorUDFs.entrySet().iterator();
675                    Map.Entry<Key, UDF> entry;
676                    Key key;
677                    UDFImpl udf;
678                    while(it.hasNext()){
679                            entry=it.next();
680                            key=entry.getKey();
681                            udf=(UDFImpl) entry.getValue();
682                            registerUDF(key, udf,false,true);
683                    }
684            }
685            
686            }
687        
688        /**
689         * this function may be called by generated code inside a ra file
690         * @deprecated replaced with <code>afterConstructor(PageContext pc, Variables parent)</code>
691         * @param pc
692         * @param parent
693         */
694        public void afterCall(PageContext pc, Variables parent) {
695            afterConstructor(pc, parent);
696            }
697            
698        /**
699         * sets the callpath
700         * @param callPath
701         * /
702        public void setCallPath(String callPath) {
703                    properties.callPath=callPath;
704            }*/
705    
706            /**
707         * rerturn the size
708             * @param access
709             * @return size
710             */
711        public int size(int access) {
712                return keys(access).length;
713            }
714    
715        /**
716         * list of keys
717         * @param c 
718         * @param access
719         * @param doBase 
720         * @return key set
721         */
722            public Set<Key> keySet(int access) {
723            HashSet<Key> set=new HashSet<Key>();
724            Map.Entry<Key, Member> entry;    
725            Iterator<Entry<Key, Member>> it = _data.entrySet().iterator();
726            while(it.hasNext()) {
727                entry=it.next();
728                if(entry.getValue().getAccess()<=access)set.add(entry.getKey());
729            }
730            return set;
731        }
732        
733        /*protected Set<Key> udfKeySet(int access) {
734            Set<Key> set=new HashSet<Key>();
735            Member m;
736            Map.Entry<Key, UDF> entry;
737            Iterator<Entry<Key, UDF>> it = _udfs.entrySet().iterator();
738            while(it.hasNext()) {
739                entry= it.next();
740                m=entry.getValue();
741                if(m.getAccess()<=access)set.add(entry.getKey());
742            }
743            return set;
744        }*/
745        
746        
747        protected java.util.List<Member> getMembers(int access) {
748            java.util.List<Member> members=new ArrayList<Member>();
749            Member e;
750            Iterator<Entry<Key, Member>> it = _data.entrySet().iterator();
751            while(it.hasNext()) {
752                    e=it.next().getValue();
753                if(e.getAccess()<=access)members.add(e);
754            }
755            return members;
756        }
757        
758        
759    
760        /**
761         * return iterator for keys
762         * @param access
763         * @return iterator of the keys
764         */
765        public Iterator iterator(int access) {
766            return new ArrayIterator(keysAsString(access));
767        }
768        
769        /**
770         * @param access 
771         * @return keys inside Component
772         */
773        public Collection.Key[] keys(int access) {
774            Set<Key> set = keySet(access);
775            return set.toArray(new Collection.Key[set.size()]);
776        }
777    
778        /**
779         * @param access
780         * @return
781         */
782        public String[] keysAsString(int access) {
783            Collection.Key[] keys = keys(access);
784            String[] strKeys = new String[keys.length];
785            for(int i=0;i<keys.length;i++) {
786                    strKeys[i]=keys[i].getString();
787            }
788            return strKeys;
789        }
790            
791            /**
792             * clear all member
793             */
794            public void clear() {
795                    _data.clear();
796                    _udfs.clear();
797            }
798            
799    
800    
801        public Member getMember(int access,Collection.Key key, boolean dataMember,boolean superAccess) {
802            // check super
803            if(dataMember && access==ACCESS_PRIVATE && key.equalsIgnoreCase(KeyImpl.SUPER)) {
804                    return SuperComponent.superMember((ComponentImpl)ComponentUtil.getActiveComponent((PageContextImpl)ThreadLocalPageContext.get(),this)._base());
805                //return SuperComponent . superMember(base);
806            }
807            if(superAccess) {
808                    return (Member) _udfs.get(key);
809            }
810            // check data
811            Member member=(Member)_data.get(key);
812            if(member!=null) {
813                if(member.getAccess()<=access)return member;
814                return null;
815            }
816            return null;
817        }
818    
819    
820            /**
821         * get entry matching key
822         * @param access 
823         * @param keyLowerCase key lower case (case sensitive)
824         * @param doBase do check also base component
825         * @param dataMember do also check if key super
826         * @return matching entry if exists otherwise null
827         */
828        protected Member getMember(PageContext pc, Collection.Key key, boolean dataMember,boolean superAccess) {
829            // check super
830            if(dataMember && isPrivate(pc) && key.equalsIgnoreCase(KeyImpl.SUPER)) {
831                    return SuperComponent.superMember((ComponentImpl)ComponentUtil.getActiveComponent((PageContextImpl)pc,this)._base());
832            }
833            if(superAccess) 
834                    return (Member) _udfs.get(key);
835            
836            // check data
837            Member member=(Member)_data.get(key);
838            if(isAccessible(pc,member)) return member;
839            return null;
840        }
841        
842        private boolean isAccessible(PageContext pc, Member member) {
843            // TODO geschwindigkeit 
844            if(member!=null) {
845                    int access=member.getAccess();
846                    if(access<=ACCESS_PUBLIC) return true;
847                    else if(access==ACCESS_PRIVATE && isPrivate(pc)) return true;
848                    else if(access==ACCESS_PACKAGE && isPackage(pc)) return true;
849                    /*switch(member.getAccess()) {
850                    case ACCESS_REMOTE: return true;
851                    case ACCESS_PUBLIC: return true;
852                    case ACCESS_PRIVATE:
853                        if(isPrivate(pc)) return true;
854                    break;
855                    case ACCESS_PACKAGE:
856                        if(isPackage(pc)) return true;
857                    break;
858                }*/
859            }
860            return false;
861            }
862    
863        /**
864         * @param pc
865         * @return returns if is private
866         */
867        private boolean isPrivate(PageContext pc) {
868            if(pc==null) return true;
869            Component ac = pc.getActiveComponent();
870            return (ac!=null && (ac==this || 
871                    ((ComponentImpl)ac).top.pageSource.equals(top.pageSource))) ;
872        }
873        /**
874         * @param pc
875         * @return returns if is package
876         */
877        private boolean isPackage(PageContext pc) {
878            Component ac = pc.getActiveComponent();
879            if(ac!=null) {
880                if(ac==this) return true;
881                ComponentImpl aci = ((ComponentImpl)ac);
882                if(aci.top.pageSource.equals(top.pageSource))return true;
883                
884                int index;
885                String other=aci.top.getAbsName();
886                index=other.lastIndexOf('.');
887                if(index==-1)other="";
888                else other=other.substring(0,index);
889                
890                String my=top.getAbsName();
891                index=my.lastIndexOf('.');
892                if(index==-1)my="";
893                else my=my.substring(0,index);
894                
895                return my.equalsIgnoreCase(other);
896            }
897            return false;
898        }
899        
900            /**
901             * return the access of a member
902             * @param key
903             * @return returns the access (Component.ACCESS_REMOTE, ACCESS_PUBLIC, ACCESS_PACKAGE,Component.ACCESS_PRIVATE)
904             */
905            private int getAccess(Collection.Key key){
906            Member member=getMember(ACCESS_PRIVATE,key,false,false);
907            if(member==null) return Component.ACCESS_PRIVATE;
908            return member.getAccess();
909            }
910        
911        /** 
912         * returns current access to this component
913         * @param pc
914         * @return access
915         */
916        private int getAccess(PageContext pc) {
917            if(pc==null) return ACCESS_PUBLIC;
918            
919            if(isPrivate(pc)) return ACCESS_PRIVATE;
920            if(isPackage(pc)) return ACCESS_PACKAGE;
921            return ACCESS_PUBLIC;
922        }
923            
924        /**
925             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int)
926             */
927            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
928                    return toDumpData(pageContext,maxlevel,dp,getAccess(pageContext));
929        }
930        
931    
932        /**
933         * to html output print only with access less than given access
934         * @param pageContext
935         * @param access
936         * @return html output
937         */
938        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, int access) {
939                DumpTable table = new DumpTablePro("component","#99cc99","#ccffcc","#000000");
940            table.setTitle("Component "+getCallPath()+""+(" "+StringUtil.escapeHTML(top.properties.dspName)));
941            table.setComment("Only the functions and data members that are accessible from your location are displayed");
942            if(top.properties.extend.length()>0)table.appendRow(1,new SimpleDumpData("Extends"),new SimpleDumpData(top.properties.extend));
943            if(top.properties.hint.trim().length()>0)table.appendRow(1,new SimpleDumpData("Hint"),new SimpleDumpData(top.properties.hint));
944            
945            DumpTable content = _toDumpData(top,pageContext,maxlevel,dp,access);
946            if(!content.isEmpty())table.appendRow(1,new SimpleDumpData(""),content);
947            return table;
948        }
949        
950            static DumpTable _toDumpData(ComponentImpl ci,PageContext pc, int maxlevel, DumpProperties dp,int access) {
951                    maxlevel--;
952                    ComponentWrap cw=new ComponentWrap(Component.ACCESS_PRIVATE, ci);
953                    Collection.Key[] keys= cw.keys();
954                    
955                    
956                    
957                    DumpTable[] accesses=new DumpTable[4];
958                    accesses[Component.ACCESS_PRIVATE] = new DumpTable("#ff6633","#ff9966","#000000");
959                    accesses[Component.ACCESS_PRIVATE].setTitle("private");
960                    accesses[Component.ACCESS_PRIVATE].setWidth("100%");
961                    //accesses[Component.ACCESS_PRIVATE].setRow(1,"100%");
962                    accesses[Component.ACCESS_PACKAGE] = new DumpTable("#ff9966","#ffcc99","#000000");
963                    accesses[Component.ACCESS_PACKAGE].setTitle("package");
964                    accesses[Component.ACCESS_PACKAGE].setWidth("100%");
965                    accesses[Component.ACCESS_PUBLIC] = new DumpTable("#ffcc99","#ffffcc","#000000");
966                    accesses[Component.ACCESS_PUBLIC].setTitle("public");
967                    accesses[Component.ACCESS_PUBLIC].setWidth("100%");
968                    accesses[Component.ACCESS_REMOTE] = new DumpTable("#ccffcc","#ffffff","#000000");
969                    accesses[Component.ACCESS_REMOTE].setTitle("remote");
970                    accesses[Component.ACCESS_REMOTE].setWidth("100%");
971                    
972                    Collection.Key key;
973                    for(int i=0;i<keys.length;i++) {
974                            key=keys[i];
975                            int a=ci.getAccess(key);
976                            DumpTable box=accesses[a];
977                            Object o=cw.get(key,null);
978                            if(o==ci)o="[this]";
979                            if(DumpUtil.keyValid(dp,maxlevel, key))
980                                    box.appendRow(1,new SimpleDumpData(key.getString()),DumpUtil.toDumpData(o,pc,maxlevel,dp));
981                    }
982                    
983                    
984                    DumpTable table=new DumpTable("#ffffff","#cccccc","#000000");
985                    
986                    // properties
987                    if(ci.top.properties.persistent || ci.top.properties.accessors){
988                            Property[] properties=ci.getProperties(false);
989                            DumpTable prop = new DumpTable("#99cc99","#ccffcc","#000000");
990    
991                            prop.setTitle("Properties");
992                            prop.setWidth("100%");
993                            Property p;
994                            Object child;
995                            for(int i=0;i<properties.length;i++) {
996                                    p=properties[i];
997                                    child = ci.scope.get(KeyImpl.init(p.getName()),null);
998                                    DumpData dd;
999                                    if(child instanceof Component) {
1000                                            DumpTable t = new DumpTablePro("component","#99cc99","#ffffff","#000000");
1001                                            t.appendRow(1,new SimpleDumpData("Component"),new SimpleDumpData(((Component)child).getCallName()));
1002                                            dd=t;
1003                                            
1004                                    }
1005                                    else 
1006                                            dd=DumpUtil.toDumpData(child, pc, maxlevel-1, dp);
1007                                    
1008                                    
1009                                    
1010                                    prop.appendRow(1, new SimpleDumpData(p.getName()),dd);
1011                            }
1012                            
1013                            if(access>=ACCESS_PUBLIC && !prop.isEmpty()) {
1014                                    table.appendRow(0,prop);
1015                            }
1016                    }
1017                    
1018    
1019                    
1020    
1021                    if(!accesses[ACCESS_REMOTE].isEmpty()) {
1022                            table.appendRow(0,accesses[Component.ACCESS_REMOTE]);
1023                    }
1024                    if(!accesses[ACCESS_PUBLIC].isEmpty()) {
1025                            table.appendRow(0,accesses[Component.ACCESS_PUBLIC]);
1026                    }
1027                    if(!accesses[ACCESS_PACKAGE].isEmpty()) {
1028                            table.appendRow(0,accesses[Component.ACCESS_PACKAGE]);
1029                    }
1030                    if(!accesses[ACCESS_PRIVATE].isEmpty()) {
1031                            table.appendRow(0,accesses[Component.ACCESS_PRIVATE]);
1032                    }
1033                    return table;
1034            }
1035            
1036            /**
1037             * @return return call path
1038             */
1039            protected String getCallPath() {
1040                    if(StringUtil.isEmpty(top.properties.callPath)) return getName();
1041                    try {
1042                return "("+List.arrayToList(List.listToArrayTrim(top.properties.callPath.replace('/','.').replace('\\','.'),"."),".")+")";
1043            } catch (PageException e) {
1044                return top.properties.callPath;
1045            }
1046            }
1047    
1048        /**
1049         * @see railo.runtime.Component#getDisplayName()
1050         */
1051        public String getDisplayName() {
1052                    return top.properties.dspName;
1053            }
1054            
1055        /**
1056         * @see railo.runtime.Component#getExtends()
1057         */
1058        public String getExtends() {
1059                    return top.properties.extend;
1060            }
1061        public String getBaseAbsName() {
1062                    return top.base.pageSource.getComponentName();
1063            }
1064        
1065        public boolean isBasePeristent() {
1066                    return top.base!=null && top.base.properties.persistent;
1067            }
1068            
1069            
1070        /**
1071         * @see railo.runtime.Component#getHint()
1072         */
1073        public String getHint() {
1074                    return top.properties.hint;
1075            }
1076        
1077        // FUTURE add to interface
1078        public String getWSDLFile() {
1079                    return top.properties.getWsdlFile();
1080            }
1081    
1082        /**
1083         * @see railo.runtime.Component#getName()
1084         */
1085        public String getName() {
1086                if(top.properties.callPath==null) return "";
1087                return List.last(top.properties.callPath,"./",true);
1088            }
1089        public String _getName() { // MUST nicht so toll
1090                if(properties.callPath==null) return "";
1091                return List.last(properties.callPath,"./",true);
1092            }
1093        public PageSource _getPageSource() {
1094            return pageSource;
1095            }
1096            
1097        /**
1098         * @see railo.runtime.Component#getCallName()
1099         */
1100        public String getCallName() {
1101                return top.properties.callPath;
1102            }
1103        
1104        /**
1105         * @see railo.runtime.Component#getAbsName()
1106         */
1107        public String getAbsName() {
1108            return top.pageSource.getComponentName();
1109            }
1110        
1111    
1112        /**
1113         * @see railo.runtime.Component#getOutput()
1114         */
1115        public boolean getOutput() {
1116            if(top.properties.output==null) return true;
1117            return top.properties.output.booleanValue();
1118        }
1119    
1120        /**
1121         * @see railo.runtime.Component#instanceOf(java.lang.String)
1122         */
1123        public boolean instanceOf(String type) {
1124            
1125            ComponentImpl c=top;
1126            do {
1127                    if(type.equalsIgnoreCase(c.properties.callPath)) return true;
1128                if(type.equalsIgnoreCase(c.pageSource.getComponentName())) return true;
1129                if(type.equalsIgnoreCase(c._getName())) return true;       
1130                
1131                    // check interfaces
1132                    if(c.interfaceCollection!=null){
1133                            InterfaceImpl[] interfaces = c.interfaceCollection.getInterfaces();
1134                            if(interfaces!=null)for(int i=0;i<interfaces.length;i++){
1135                                    if(interfaces[i].instanceOf(type))return true;
1136                            }
1137                    }
1138                    c=c.base;
1139            }
1140            while(c!=null);
1141            if(StringUtil.endsWithIgnoreCase(type, "component")){
1142                    if(type.equalsIgnoreCase("component"))                                                  return true;
1143                    if(type.equalsIgnoreCase("web-inf.cftags.component"))                   return true;
1144                    //if(type.equalsIgnoreCase("web-inf.railo.context.component"))  return true;
1145                    
1146            }
1147            return false;
1148        }
1149        
1150        public boolean equalTo(String type) {
1151            ComponentImpl c=top;
1152            
1153            if(type.equalsIgnoreCase(c.properties.callPath)) return true;
1154            if(type.equalsIgnoreCase(c.pageSource.getComponentName())) return true;
1155            if(type.equalsIgnoreCase(c._getName())) return true;       
1156                
1157                    // check interfaces
1158                    if(c.interfaceCollection!=null){
1159                    InterfaceImpl[] interfaces = c.interfaceCollection.getInterfaces();
1160                    if(interfaces!=null)for(int i=0;i<interfaces.length;i++){
1161                            if(interfaces[i].instanceOf(type))return true;
1162                    }
1163                    }
1164                    
1165            if(StringUtil.endsWithIgnoreCase(type, "component")){
1166                    if(type.equalsIgnoreCase("component"))                                                  return true;
1167                    if(type.equalsIgnoreCase("web-inf.cftags.component"))                   return true;
1168            }
1169            return false;
1170        }
1171        
1172    
1173        /**
1174         * @see railo.runtime.Component#isValidAccess(int)
1175         */
1176        public boolean isValidAccess(int access) {
1177                    return !(access <0 || access>ACCESS_COUNT);
1178            }
1179            
1180        /**
1181         * @return returns the ComponentPage of the Component
1182         * @deprecated use instead getPageSource()
1183         */
1184        public Page getPage() {
1185            throw new PageRuntimeException(new DeprecatedException("method getPage():Page is no longer suppoted, use instead getPageSource():PageSource"));
1186            //return properties.page;
1187        }
1188        
1189        
1190        
1191        // FUTURE add to interface
1192        public PageSource getPageSource() {
1193            return top.pageSource;
1194        }
1195        
1196    
1197        /**
1198         * @see railo.runtime.op.Castable#castToString()
1199         */
1200        public String castToString() throws PageException {
1201            return castToString(false);
1202        }
1203        
1204            /**
1205             * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String)
1206             */
1207            public String castToString(String defaultValue) {
1208                    return castToString(false,defaultValue);
1209            }
1210        
1211        String castToString(boolean superAccess) throws PageException {
1212            // magic function
1213            PageContext pc = ThreadLocalPageContext.get();
1214                    if(pc!=null) {
1215                            Member member = getMember(pc,TO_STRING,true,superAccess);
1216                            //Object o = get(pc,"_toString",null);
1217                            if(member instanceof UDF) {
1218                                    UDF udf = (UDF)member;
1219                                    if(udf.getReturnType()==CFTypes.TYPE_STRING && udf.getFunctionArguments().length==0) {
1220                                            return Caster.toString(_call(pc, udf, null, new Object[0]));
1221                                    }
1222                            }
1223                    }
1224                    
1225                    
1226                    throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to String"),"Add a User-Defined-Function to Component with the following pattern [_toString():String] to cast it to a String or use Build-In-Function \"serialize(Component):String\" to convert it to a serialized String");
1227            
1228        }
1229        
1230        
1231        
1232        
1233        String castToString(boolean superAccess,String defaultValue) {
1234            // magic function
1235            PageContext pc = ThreadLocalPageContext.get();
1236                    if(pc!=null) {
1237                            Member member = getMember(pc,TO_STRING,true,superAccess);
1238                            //Object o = get(pc,"_toString",null);
1239                            if(member instanceof UDF) {
1240                                    UDF udf = (UDF)member;
1241                                    if(udf.getReturnType()==CFTypes.TYPE_STRING && udf.getFunctionArguments().length==0) {
1242                                            try {
1243                                                    return Caster.toString(_call(pc, udf, null, new Object[0]),defaultValue);
1244                                            } catch (PageException e) {
1245                                                    return defaultValue;
1246                                            }
1247                                    }
1248                            }
1249                    }
1250                    return defaultValue;
1251        }
1252    
1253        /**
1254         * @see railo.runtime.op.Castable#castToBooleanValue()
1255         */
1256        public boolean castToBooleanValue() throws PageException {
1257            return castToBooleanValue(false);
1258        }
1259        
1260        /**
1261         * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean)
1262         */
1263        public Boolean castToBoolean(Boolean defaultValue) {
1264            return castToBoolean(false, defaultValue);
1265        }
1266    
1267        boolean castToBooleanValue(boolean superAccess) throws PageException {
1268            // magic function
1269            PageContext pc = ThreadLocalPageContext.get();
1270                    if(pc!=null) {
1271                            Member member = getMember(pc,TO_BOOLEAN,true,superAccess);
1272                            //Object o = get(pc,"_toBoolean",null);
1273                            if(member instanceof UDF) {
1274                                    UDF udf = (UDF)member;
1275                                    if(udf.getReturnType()==CFTypes.TYPE_BOOLEAN && udf.getFunctionArguments().length==0) {
1276                                            return Caster.toBooleanValue(_call(pc, udf, null, new Object[0]));
1277                                    }
1278                            }
1279                    }
1280            
1281            throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a boolean value"),
1282                    "Add a User-Defined-Function to Component with the following pattern [_toBoolean():boolean] to cast it to a boolean value");
1283        }
1284        
1285        Boolean castToBoolean(boolean superAccess,Boolean defaultValue) {
1286            // magic function
1287            PageContext pc = ThreadLocalPageContext.get();
1288                    if(pc!=null) {
1289                            Member member = getMember(pc,TO_BOOLEAN,true,superAccess);
1290                            //Object o = get(pc,"_toBoolean",null);
1291                            if(member instanceof UDF) {
1292                                    UDF udf = (UDF)member;
1293                                    if(udf.getReturnType()==CFTypes.TYPE_BOOLEAN && udf.getFunctionArguments().length==0) {
1294                                            try {
1295                                                    return Caster.toBoolean(_call(pc, udf, null, new Object[0]),defaultValue);
1296                                            } catch (PageException e) {
1297                                                    return defaultValue;
1298                                            }
1299                                    }
1300                            }
1301                    }
1302            return defaultValue;
1303        }
1304    
1305        /**
1306         * @see railo.runtime.op.Castable#castToDoubleValue()
1307         */
1308        public double castToDoubleValue() throws PageException {
1309            return castToDoubleValue(false);
1310        }
1311        
1312        /**
1313         * @see railo.runtime.op.Castable#castToDoubleValue(double)
1314         */
1315        public double castToDoubleValue(double defaultValue) {
1316            return castToDoubleValue(false, defaultValue);
1317        }
1318        
1319        
1320        double castToDoubleValue(boolean superAccess) throws PageException {
1321            // magic function
1322            PageContext pc = ThreadLocalPageContext.get();
1323                    if(pc!=null) {
1324                            Member member = getMember(pc,TO_NUMERIC,true,superAccess);
1325                            //Object o = get(pc,"_toNumeric",null);
1326                            if(member instanceof UDF) {
1327                                    UDF udf = (UDF)member;
1328                                    if(udf.getReturnType()==CFTypes.TYPE_NUMERIC && udf.getFunctionArguments().length==0) {
1329                                            return Caster.toDoubleValue(_call(pc, udf, null, new Object[0]));
1330                                    }
1331                            }
1332                    }
1333        
1334            throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a numeric value"),
1335                    "Add a User-Defined-Function to Component with the following pattern [_toNumeric():numeric] to cast it to a numeric value");
1336        }
1337        double castToDoubleValue(boolean superAccess,double defaultValue) {
1338            // magic function
1339            PageContext pc = ThreadLocalPageContext.get();
1340                    if(pc!=null) {
1341                            Member member = getMember(pc,TO_NUMERIC,true,superAccess);
1342                            //Object o = get(pc,"_toNumeric",null);
1343                            if(member instanceof UDF) {
1344                                    UDF udf = (UDF)member;
1345                                    if(udf.getReturnType()==CFTypes.TYPE_NUMERIC && udf.getFunctionArguments().length==0) {
1346                                            try {
1347                                                    return Caster.toDoubleValue(_call(pc, udf, null, new Object[0]),defaultValue);
1348                                            } catch (PageException e) {
1349                                                    return defaultValue;
1350                                            }
1351                                    }
1352                            }
1353                    }
1354                    return defaultValue;
1355        }
1356    
1357        /**
1358         * @see railo.runtime.op.Castable#castToDateTime()
1359         */
1360        public DateTime castToDateTime() throws PageException {
1361            return castToDateTime(false);
1362        }
1363        
1364        /**
1365         * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime)
1366         */
1367        public DateTime castToDateTime(DateTime defaultValue) {
1368            return castToDateTime(false, defaultValue);
1369        }
1370    
1371        DateTime castToDateTime(boolean superAccess) throws PageException {
1372            // magic function
1373            PageContext pc = ThreadLocalPageContext.get();
1374                    if(pc!=null) {
1375                            Member member = getMember(pc,TO_DATETIME,true,superAccess);
1376                            //Object o = get(pc,"_toDateTime",null);
1377                            if(member instanceof UDF) {
1378                                    UDF udf = (UDF)member;
1379                                    if(udf.getReturnType()==CFTypes.TYPE_DATETIME && udf.getFunctionArguments().length==0) {
1380                                            return Caster.toDate(_call(pc, udf, null, new Object[0]),pc.getTimeZone());
1381                                    }
1382                            }
1383                    }
1384        
1385                    throw ExceptionUtil.addHint(new ExpressionException("Can't cast Component ["+getName()+"] to a date"),
1386                    "Add a User-Defined-Function to Component with the following pattern [_toDateTime():datetime] to cast it to a date");
1387        }
1388        DateTime castToDateTime(boolean superAccess,DateTime defaultValue) {
1389            // magic function
1390            PageContext pc = ThreadLocalPageContext.get();
1391                    if(pc!=null) {
1392                            Member member = getMember(pc,TO_DATETIME,true,superAccess);
1393                            //Object o = get(pc,"_toDateTime",null);
1394                            if(member instanceof UDF) {
1395                                    UDF udf = (UDF)member;
1396                                    if(udf.getReturnType()==CFTypes.TYPE_DATETIME && udf.getFunctionArguments().length==0) {
1397                                            
1398                                            try {
1399                                                    return DateCaster.toDateAdvanced(_call(pc, udf, null, new Object[0]),true,pc.getTimeZone(),defaultValue);
1400                                            } catch (PageException e) {
1401                                                    return defaultValue;
1402                                            }
1403                                            
1404                                    }
1405                            }
1406                    }
1407                    return defaultValue;
1408        }
1409    
1410        /**
1411         * @see railo.runtime.Component#getMetaData(railo.runtime.PageContext)
1412         */
1413        public synchronized Struct getMetaData(PageContext pc) throws PageException {
1414            return getMetaData(ACCESS_PRIVATE,pc,top);
1415        }
1416        
1417    
1418        public synchronized Object getMetaStructItem(Collection.Key name) {
1419            if(top.properties.meta!=null) {
1420                    return top.properties.meta.get(name,null);
1421            }
1422            return null;
1423        }
1424    
1425        protected static Struct getMetaData(int access,PageContext pc, ComponentImpl comp) throws PageException {
1426            
1427            // Cache
1428            PagePlus page = (PagePlus) ((PageSourceImpl)comp.pageSource).getPage();
1429            if(page==null) page = (PagePlus) comp.pageSource.loadPage(pc.getConfig());
1430            if(page.metaData!=null && page.metaData.get()!=null) {
1431                    return page.metaData.get();
1432            }
1433            
1434            StructImpl sct=new StructImpl();
1435            
1436            // fill udfs
1437            metaUDFs(pc, comp, sct,access);
1438            
1439            // meta
1440            if(comp.properties.meta!=null) 
1441                    StructUtil.copy(comp.properties.meta, sct, true);
1442                
1443            String hint=comp.properties.hint;
1444            String displayname=comp.properties.dspName;
1445            if(!StringUtil.isEmpty(hint))sct.set(KeyImpl.HINT,hint);
1446            if(!StringUtil.isEmpty(displayname))sct.set(DISPLAY_NAME,displayname);
1447            
1448            sct.set(PERSISTENT,comp.properties.persistent);
1449            sct.set(ACCESSORS,comp.properties.accessors);
1450            sct.set(SYNCRONIZED,comp.properties._synchronized);
1451            if(comp.properties.output!=null)
1452            sct.set(KeyImpl.OUTPUT,comp.properties.output);
1453                
1454            // extends
1455            Struct ex=null;
1456            if(comp.base!=null) ex=getMetaData(access,pc,comp.base);
1457            if(ex!=null)sct.set(EXTENDS,ex);
1458            
1459            // implements
1460            InterfaceCollection ic = comp.interfaceCollection;
1461            if(ic!=null){
1462                    Set<String> set = List.listToSet(comp.properties.implement, ",",true);
1463                InterfaceImpl[] interfaces = comp.interfaceCollection.getInterfaces();
1464                if(!ArrayUtil.isEmpty(interfaces)){
1465                        Struct imp=new StructImpl();
1466                    for(int i=0;i<interfaces.length;i++){
1467                            if(!set.contains(interfaces[i].getCallPath())) continue;
1468                            //print.e("-"+interfaces[i].getCallPath());
1469                            imp.setEL(KeyImpl.init(interfaces[i].getCallPath()), interfaces[i].getMetaData(pc));
1470                        }
1471                        sct.set(IMPLEMENTS,imp);
1472                }
1473            }
1474             
1475            // PageSource
1476            PageSource ps = comp.pageSource;
1477            sct.set(FULLNAME,ps.getComponentName());
1478            sct.set(KeyImpl.NAME,ps.getComponentName());
1479            sct.set(KeyImpl.PATH,ps.getDisplayPath());
1480            sct.set(KeyImpl.TYPE,"component");
1481            Class skeleton = comp.getJavaAccessClass(new RefBooleanImpl(false),((ConfigImpl)pc.getConfig()).getExecutionLogEnabled(),false,false);
1482            if(skeleton !=null)sct.set(SKELETON, skeleton);
1483            
1484            // Properties
1485            if(comp.properties.properties!=null) {
1486                    ArrayImpl parr = new ArrayImpl();
1487                    Property p;
1488                    Iterator<Entry<String, Property>> pit = comp.properties.properties.entrySet().iterator();
1489                    while(pit.hasNext()){
1490                            p=pit.next().getValue();
1491                            parr.add(p.getMetaData());
1492                    }
1493                    parr.sort(new ArrayOfStructComparator(KeyImpl.NAME));
1494                    sct.set(PROPERTIES,parr);
1495            }
1496            page.metaData=new SoftReference<Struct>(sct);
1497            return page.metaData.get();
1498        }    
1499    
1500        private static void metaUDFs(PageContext pc,ComponentImpl comp,Struct sct, int access) throws PageException {
1501            ArrayImpl arr=new ArrayImpl();
1502            //Collection.Key name;
1503            
1504            PagePlus page = (PagePlus) ((PageSourceImpl)comp._getPageSource()).getPage();
1505            if(page!=null && page.udfs!=null){
1506                    for(int i=0;i<page.udfs.length;i++){
1507                            if(page.udfs[i].getAccess()>access) continue;
1508                            arr.add(ComponentUtil.getMetaData(pc,page.udfs[i]));
1509                    }
1510            }
1511            
1512            // property functions
1513            Iterator<Entry<Key, UDF>> it = comp._udfs.entrySet().iterator();
1514            Entry<Key, UDF> entry;
1515                    UDF udf;
1516                    while(it.hasNext()) {
1517                    entry= it.next();
1518                    udf=entry.getValue();
1519                if(udf.getAccess()>access || !(udf instanceof UDFGSProperty)) continue;
1520                            if(comp.base!=null) {
1521                            if(udf==comp.base.getMember(access,entry.getKey(),true,true))
1522                                    continue;
1523                    }
1524                    arr.append(udf.getMetaData(pc));
1525                
1526            }
1527            if(arr.size()!=0)sct.set(FUNCTIONS,arr);
1528            }
1529        
1530        
1531        
1532    
1533            /**
1534         * @see railo.runtime.type.Objects#isInitalized()
1535         */
1536        public boolean isInitalized() {
1537            return isInit;
1538        }
1539        
1540        public void setInitalized(boolean isInit) {
1541            this.isInit=isInit;;
1542        }
1543        
1544            
1545        /**
1546         * sets a value to the current Component, dont to base Component
1547         * @param key
1548         * @param value
1549         * @return value set
1550         */
1551        private synchronized Object _set(Collection.Key key, Object value) {
1552            //print.out("set:"+key);
1553            if(value instanceof UDFImpl) {
1554                    UDFImpl udf = (UDFImpl)((UDF)value).duplicate();
1555                    //udf.isComponentMember(true);///+++
1556                    udf.setOwnerComponent(this);
1557                    if(udf.getAccess()>Component.ACCESS_PUBLIC)
1558                            udf.setAccess(Component.ACCESS_PUBLIC);
1559                    _data.put(key,udf);
1560                    _udfs.put(key,udf);
1561                    
1562            }
1563            else {
1564                    _data.put(key,new DataMember(dataMemberDefaultAccess,value));
1565            }
1566            return value;
1567        }
1568    
1569        
1570    
1571        public void reg(Collection.Key key, UDFImpl udf) {
1572            registerUDF(key, udf,useShadow,false);
1573        }
1574        public void reg(String key, UDFImpl udf) {
1575            registerUDF(KeyImpl.init(key), udf,useShadow,false);
1576        }
1577    
1578        public void registerUDF(String key, UDF udf) {
1579            registerUDF(KeyImpl.init(key), (UDFImpl) udf,useShadow,false);
1580        }
1581        public void registerUDF(String key, UDFProperties prop) {
1582            registerUDF(KeyImpl.init(key), new UDFImpl(prop),useShadow,false);
1583        }
1584    
1585        public void registerUDF(Collection.Key key, UDF udf) {
1586            registerUDF(key, (UDFImpl) udf,useShadow,false);
1587        }
1588        public void registerUDF(Collection.Key key, UDFProperties prop) {
1589            registerUDF(key, new UDFImpl(prop),useShadow,false);
1590        }
1591        
1592        // FUTURE deprecated injected is not used
1593        public void registerUDF(Collection.Key key, UDFImpl udf,boolean useShadow,boolean injected) {
1594            udf.setOwnerComponent(this);//+++
1595            _udfs.put(key,udf);
1596            _data.put(key,udf);
1597            if(useShadow)scope.setEL(key, udf);
1598        }
1599        
1600            /**
1601             *
1602             * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key)
1603             */
1604            public Object remove(Key key) throws PageException {
1605            return _data.remove(key);
1606            }
1607    
1608        public Object removeEL(Collection.Key key) {
1609            // MUST access muss beruecksichtigt werden
1610            return _data.remove(key);
1611        }
1612    
1613        /**
1614         * @see railo.runtime.type.Objects#set(railo.runtime.PageContext, java.lang.String, java.lang.Object)
1615         */
1616        public Object set(PageContext pc, String name, Object value) throws PageException {
1617            return set(pc, KeyImpl.init(name), value);
1618        }
1619    
1620        /**
1621         * @see railo.runtime.type.Objects#set(railo.runtime.PageContext, railo.runtime.type.Collection.Key, java.lang.Object)
1622         */
1623        public Object set(PageContext pc, Collection.Key key, Object value) throws PageException {
1624            if(triggerDataMember && isInit) {
1625                    if(pc==null)pc=ThreadLocalPageContext.get();
1626                    
1627                    if(!isPrivate(pc)) {
1628                            return callSetter(pc, key, value);
1629                    }
1630            }
1631            return _set(key,value);
1632        }
1633    
1634            /**
1635             * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object)
1636             */
1637            public Object set(Collection.Key key, Object value) throws PageException {
1638            return set(null,key,value);
1639            }
1640    
1641        /**
1642         * @see railo.runtime.type.Objects#setEL(railo.runtime.PageContext, java.lang.String, java.lang.Object)
1643         */
1644        public Object setEL(PageContext pc, String name, Object value) {
1645            try {return set(pc, name, value);} 
1646            catch (PageException e) {return null;}
1647        }
1648        
1649        /**
1650         * @see railo.runtime.type.Objects#setEL(railo.runtime.PageContext, railo.runtime.type.Collection.Key, java.lang.Object)
1651         */
1652        public Object setEL(PageContext pc, Collection.Key name, Object value) {
1653            try {return set(pc, name, value);} 
1654            catch (PageException e) {return null;}
1655        }
1656    
1657            /**
1658             * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object)
1659             */
1660            public Object setEL(Key key, Object value) {
1661            return setEL(null, key, value);
1662            }
1663        
1664    
1665        /**
1666         * @see railo.runtime.type.ContextCollection#get(railo.runtime.PageContext, java.lang.String)
1667         */
1668        public Object get(PageContext pc, String name) throws PageException {
1669            return get(pc, KeyImpl.init(name));
1670        }
1671        
1672        public Object get(PageContext pc, Collection.Key key) throws PageException {
1673            Member member=getMember(pc,key,true,false);
1674            if(member!=null) return member.getValue();
1675            
1676            // trigger
1677            if(triggerDataMember && !isPrivate(pc)) {
1678                    return callGetter(pc,key);
1679            }
1680            throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]","enable [trigger data member] in admininistrator to also invoke getters and setters");
1681            //throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+name+"]");
1682        }
1683    
1684        private Object callGetter(PageContext pc,Collection.Key key) throws PageException {
1685            Member member=getMember(pc,KeyImpl.getInstance("get"+key.getLowerString()),false,false);
1686            if(member instanceof UDF) {
1687                UDF udf = (UDF)member;
1688                if(udf.getFunctionArguments().length==0 && udf.getReturnType()!=CFTypes.TYPE_VOID) {
1689                    return _call(pc,udf,null,ArrayUtil.OBJECT_EMPTY);
1690                }
1691            } 
1692            throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]");
1693            }
1694        
1695        private Object callGetter(PageContext pc,Collection.Key key, Object defaultValue) {
1696            Member member=getMember(pc,KeyImpl.getInstance("get"+key.getLowerString()),false,false);
1697            if(member instanceof UDF) {
1698                UDF udf = (UDF)member;
1699                if(udf.getFunctionArguments().length==0 && udf.getReturnType()!=CFTypes.TYPE_VOID) {
1700                    try {
1701                                            return _call(pc,udf,null,ArrayUtil.OBJECT_EMPTY);
1702                                    } catch (PageException e) {
1703                                            return defaultValue;
1704                                    }
1705                }
1706            } 
1707            return defaultValue;
1708            }
1709        
1710        private Object callSetter(PageContext pc,Collection.Key key, Object value) throws PageException {
1711            Member member=getMember(pc,KeyImpl.getInstance("set"+key.getLowerString()),false,false);
1712            if(member instanceof UDF) {
1713                    UDF udf = (UDF)member;
1714                    if(udf.getFunctionArguments().length==1 && (udf.getReturnType()==CFTypes.TYPE_VOID) || udf.getReturnType()==CFTypes.TYPE_ANY   ) {// TDOO support int return type
1715                    return _call(pc,udf,null,new Object[]{value});
1716                }    
1717            }
1718            return _set(key,value);
1719            }
1720        
1721    
1722            /**
1723         * return element that has at least given access or null
1724         * @param access
1725         * @param name
1726         * @return matching value
1727         * @throws PageException
1728         */
1729        public Object get(int access, String name) throws PageException {
1730            return get(access, KeyImpl.init(name));
1731        }
1732        
1733        public Object get(int access, Collection.Key key) throws PageException {
1734            Member member=getMember(access,key,true,false);
1735            if(member!=null) return member.getValue();
1736            
1737            // Trigger
1738            if(triggerDataMember && !isPrivate(ThreadLocalPageContext.get())) {
1739                    return callGetter(ThreadLocalPageContext.get(),key);
1740            }
1741            throw new ExpressionException("Component ["+getCallName()+"] has no accessible Member with name ["+key+"]");
1742        }
1743    
1744        /**
1745         * @see railo.runtime.type.ContextCollection#get(railo.runtime.PageContext, java.lang.String, java.lang.Object)
1746         */
1747        public Object get(PageContext pc, String name, Object defaultValue) {
1748            return get(pc, KeyImpl.init(name), defaultValue);
1749        }
1750    
1751        /**
1752         * @see railo.runtime.type.Objects#get(railo.runtime.PageContext, railo.runtime.type.Collection.Key, java.lang.Object)
1753         */
1754        public Object get(PageContext pc, Collection.Key key, Object defaultValue) {
1755            Member member=getMember(pc,key,true,false);
1756            if(member!=null) return member.getValue();
1757            
1758            // trigger
1759            if(triggerDataMember && !isPrivate(pc)) {
1760                    return callGetter(pc,key,defaultValue);
1761            }
1762            return defaultValue;
1763        }
1764        
1765        /**
1766         * return element that has at least given access or null
1767         * @param access
1768         * @param name
1769         * @return matching value
1770         */
1771        protected Object get(int access, String name, Object defaultValue) {
1772            return get(access, KeyImpl.init(name), defaultValue);
1773        }
1774    
1775        /**
1776         * @param access
1777         * @param key
1778         * @param defaultValue
1779         * @return
1780         */
1781        public Object get(int access, Collection.Key key, Object defaultValue) { 
1782            Member member=getMember(access,key,true,false);
1783            if(member!=null) return member.getValue();
1784            
1785            // trigger
1786            if(triggerDataMember && !isPrivate(ThreadLocalPageContext.get())) {
1787                    return callGetter(ThreadLocalPageContext.get(),key,defaultValue);
1788            }
1789            return defaultValue;
1790        }
1791        
1792            /**
1793             * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key)
1794             */
1795            public Object get(Collection.Key key) throws PageException {
1796            return get(ThreadLocalPageContext.get(),key);
1797            }
1798    
1799            /**
1800             *
1801             * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object)
1802             */
1803            public Object get(Collection.Key key, Object defaultValue) {
1804            return get(ThreadLocalPageContext.get(),key,defaultValue);
1805            }
1806    
1807        /**
1808         * @see railo.runtime.Component#call(railo.runtime.PageContext, java.lang.String, java.lang.Object[])
1809         */
1810        public Object call(PageContext pc, String name, Object[] args) throws PageException {
1811            return _call(pc,KeyImpl.init(name),null,args,false);
1812        }
1813    
1814            public Object call(PageContext pc, Collection.Key name, Object[] args) throws PageException {
1815                    return _call(pc,name,null,args,false);
1816            }
1817        
1818        protected Object call(PageContext pc, int access, String name, Object[] args) throws PageException {
1819            return _call(pc,access,KeyImpl.init(name),null,args,false);
1820        }
1821        
1822        public Object call(PageContext pc, int access, Collection.Key name, Object[] args) throws PageException {
1823            return _call(pc,access,name,null,args,false);
1824        }
1825    
1826        /**
1827         * @see railo.runtime.Component#callWithNamedValues(railo.runtime.PageContext, java.lang.String, railo.runtime.type.Struct)
1828         */
1829        public Object callWithNamedValues(PageContext pc, String name, Struct args) throws PageException {
1830            return _call(pc,KeyImpl.init(name),args,null,false);
1831        }
1832    
1833        public Object callWithNamedValues(PageContext pc, Collection.Key methodName, Struct args) throws PageException {
1834                    return _call(pc,methodName,args,null,false);
1835            }
1836        
1837        protected Object callWithNamedValues(PageContext pc, int access, String name, Struct args) throws PageException {
1838            return _call(pc,access,KeyImpl.init(name),args,null,false);
1839        }
1840        
1841        public Object callWithNamedValues(PageContext pc, int access, Collection.Key name, Struct args) throws PageException {
1842            return _call(pc,access,name,args,null,false);
1843        }
1844    
1845        public boolean contains(PageContext pc,String name) {
1846            return get(getAccess(pc),name,null)!=null;
1847        }
1848    
1849            /**
1850             * @param pc
1851             * @param key
1852             * @return
1853             */
1854            public boolean contains(PageContext pc,Key key) {
1855                    return get(getAccess(pc),key,null)!=null;
1856            }
1857            
1858            /**
1859             * @see railo.runtime.type.Collection#containsKey(railo.runtime.type.Collection.Key)
1860             */
1861            public boolean containsKey(Key key) {
1862                    return contains(ThreadLocalPageContext.get(),key);
1863            }
1864        
1865        public boolean contains(int access,String name) {
1866            return get(access,name,null)!=null;
1867       }
1868        
1869        public boolean contains(int access,Key name) {
1870            return get(access,name,null)!=null;
1871        }
1872    
1873        /**
1874         * @see railo.runtime.type.Collection#keyIterator()
1875         */
1876        public Iterator keyIterator() {
1877            return iterator(getAccess(ThreadLocalPageContext.get()));
1878        }
1879        
1880        /**
1881         * @see railo.runtime.type.Collection#keysAsString()
1882         */
1883        public String[] keysAsString() {
1884            return keysAsString(getAccess(ThreadLocalPageContext.get()));
1885       }
1886    
1887        public Collection.Key[] keys() {
1888            return keys(getAccess(ThreadLocalPageContext.get()));
1889        }
1890    
1891        /**
1892         * @see railo.runtime.type.Collection#size()
1893         */
1894        public int size() {
1895            return size(getAccess(ThreadLocalPageContext.get()));
1896        }
1897    
1898        
1899        /**
1900         * @param isNew because we can return only one value we give a editable boolean in to 
1901         * become tzhe info if the class is new or not
1902         * @return
1903         * @throws PageException
1904         */
1905        public Class getJavaAccessClass(RefBoolean isNew) throws PageException {
1906            return getJavaAccessClass(isNew, false,true,true);
1907        }
1908    
1909        public Class getJavaAccessClass(RefBoolean isNew,boolean writeLog, boolean takeTop, boolean create) throws PageException {
1910            isNew.setValue(false);
1911            ComponentProperties props =(takeTop)?top.properties:properties;
1912            if(props.javaAccessClass==null) {
1913                    props.javaAccessClass=ComponentUtil.getComponentJavaAccess(this,isNew,create,writeLog);
1914                    }
1915            return props.javaAccessClass;
1916        }
1917        
1918        public boolean isPersistent() {
1919            return top.properties.persistent;
1920        }
1921        
1922        public boolean isAccessors() {
1923            return top.properties.accessors;
1924        }
1925    
1926            public void setProperty(Property property) throws PageException {
1927                    top.properties.properties.put(StringUtil.toLowerCase(property.getName()),property);
1928                    if(top.properties.persistent || top.properties.accessors){
1929                            if(property.getDefault()!=null)scope.setEL(KeyImpl.init(property.getName()), property.getDefault());
1930                            PropertyFactory.createPropertyUDFs(this,property);
1931                    }
1932            }
1933    
1934            
1935    
1936            private void initProperties() throws PageException {
1937                    top.properties.properties=new LinkedHashMap<String,Property>();
1938                    
1939                    // MappedSuperClass  
1940                    if(isPersistent() && !isBasePeristent() && top.base!=null && top.base.properties.properties!=null && top.base.properties.meta!=null) {
1941                            boolean msc = Caster.toBooleanValue(top.base.properties.meta.get(MAPPED_SUPER_CLASS,Boolean.FALSE),false);
1942                            if(msc){
1943                                    Property p;
1944                                    Iterator<Entry<String, Property>> it = top.base.properties.properties.entrySet().iterator();
1945                                    while(it.hasNext())     {
1946                                            p = it.next().getValue();
1947                                            if(p.isPeristent()) {
1948                                                    
1949                                                    setProperty(p);
1950                                            }
1951                                    }
1952                            }
1953                    }
1954            }
1955    
1956            // FUTURE add to interface and then search for #321 and change this as well
1957            public Property[] getProperties(boolean onlyPeristent) {
1958                    if(top.properties.properties==null) return new Property[0];
1959                    
1960                    
1961                    // for faster execution we have this
1962                    if(!onlyPeristent) {
1963                            int index=0;
1964                            Iterator<Entry<String, Property>> it = top.properties.properties.entrySet().iterator();
1965                            Property[] props=new Property[top.properties.properties.size()];
1966                            while(it.hasNext())     {
1967                                    props[index++]=it.next().getValue();
1968                            }
1969                    }
1970                    
1971                    
1972                    // collect with filter
1973                    Property p;
1974                    java.util.List<Property> props=new ArrayList<Property>();
1975                    Iterator<Entry<String, Property>> it = top.properties.properties.entrySet().iterator();
1976                    while(it.hasNext())     {
1977                            p = it.next().getValue();
1978                            if(p.isPeristent()) {
1979                                    props.add(p);
1980                            }
1981                    }
1982                    
1983                    return props.toArray(new Property[props.size()]);
1984            }
1985    
1986            public ComponentScope getComponentScope() {
1987                    return scope;
1988            }
1989    
1990    
1991            /**
1992             * @see railo.runtime.op.Castable#compare(boolean)
1993             */
1994            public int compareTo(boolean b) throws PageException {
1995                    return Operator.compare(castToBooleanValue(), b);
1996            }
1997    
1998            /**
1999             * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime)
2000             */
2001            public int compareTo(DateTime dt) throws PageException {
2002                    return Operator.compare((Date)castToDateTime(), (Date)dt);
2003            }
2004    
2005            /**
2006             * @see railo.runtime.op.Castable#compareTo(double)
2007             */
2008            public int compareTo(double d) throws PageException {
2009                    return Operator.compare(castToDoubleValue(), d);
2010            }
2011    
2012            /**
2013             * @see railo.runtime.op.Castable#compareTo(java.lang.String)
2014             */
2015            public int compareTo(String str) throws PageException {
2016                    return Operator.compare(castToString(), str);
2017            }
2018    
2019            public void addConstructorUDF(Key key, UDF value) {
2020                    if(constructorUDFs==null)
2021                            constructorUDFs=new HashMap<Key,UDF>();
2022                    constructorUDFs.put(key, (UDF) value);
2023            }
2024    
2025    // MUST more native impl
2026            public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException {
2027                    boolean pcCreated=false;
2028                    PageContext pc = ThreadLocalPageContext.get();
2029                    // MUST this is just a workaround
2030                    if(pc==null){
2031                            pcCreated=true;
2032                            ConfigWeb config = (ConfigWeb) ThreadLocalPageContext.getConfig();
2033                            Pair[] parr = new Pair[0];
2034                            pc=ThreadUtil.createPageContext(config, DevNullOutputStream.DEV_NULL_OUTPUT_STREAM, "localhost", "/","", new Cookie[0], parr, parr, new StructImpl());
2035                    }
2036                    
2037                    try {
2038                            // MUST do serialisation more like the cloning way
2039                            ComponentImpl other=(ComponentImpl) new CFMLExpressionInterpreter().interpret(pc,in.readUTF());
2040                            
2041                            
2042                            this._data=other._data;
2043                            this._udfs=other._udfs;
2044                            setOwner(_udfs);
2045                            setOwner(_data);
2046                            this.afterConstructor=other.afterConstructor;
2047                            this.base=other.base;
2048                            //this.componentPage=other.componentPage;
2049                            this.pageSource=other.pageSource;
2050                            this.constructorUDFs=other.constructorUDFs;
2051                            this.dataMemberDefaultAccess=other.dataMemberDefaultAccess;
2052                            this.interfaceCollection=other.interfaceCollection;
2053                            this.isInit=other.isInit;
2054                            this.properties=other.properties;
2055                            this.scope=other.scope;
2056                            this.top=this;
2057                            this.triggerDataMember=other.triggerDataMember;
2058                            this.useShadow=other.useShadow;
2059                            
2060                            
2061                    } catch (PageException e) {
2062                            throw new IOException(e.getMessage());
2063                    }
2064                    finally {
2065                            if(pcCreated)ThreadLocalPageContext.release();
2066                    }
2067            }
2068    
2069            private void  setOwner(Map<Key,? extends Member> data) {
2070                    Member m;
2071                    Iterator<? extends Member> it = data.values().iterator();
2072                    while(it.hasNext()){
2073                            m=it.next();
2074                            if(m instanceof UDFImpl) {
2075                                    ((UDFImpl)m).setOwnerComponent(this);
2076                            }
2077                    }
2078            }
2079    
2080            public void writeExternal(ObjectOutput out) throws IOException {
2081            try {
2082                    out.writeUTF(new ScriptConverter().serialize(this));
2083                    } 
2084                    catch (Throwable t) {
2085                            //print.printST(t);
2086                    }
2087                    
2088            }
2089    
2090            /**
2091             * @see railo.runtime.type.cfc.ComponentAccess#_base()
2092             */
2093            public ComponentAccess _base() {
2094                    return base;
2095            }               
2096    }