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