001    package railo.runtime.type.scope;
002    
003    import java.util.ArrayList;
004    import java.util.Iterator;
005    import java.util.List;
006    
007    import railo.runtime.PageContext;
008    import railo.runtime.PageContextImpl;
009    import railo.runtime.config.Config;
010    import railo.runtime.dump.DumpData;
011    import railo.runtime.dump.DumpProperties;
012    import railo.runtime.exp.ExpressionException;
013    import railo.runtime.exp.PageException;
014    import railo.runtime.type.Collection;
015    import railo.runtime.type.KeyImpl;
016    import railo.runtime.type.Query;
017    import railo.runtime.type.Scope;
018    import railo.runtime.type.Struct;
019    import railo.runtime.type.StructImpl;
020    import railo.runtime.type.dt.DateTime;
021    import railo.runtime.type.util.StructSupport;
022    import railo.runtime.util.QueryStack;
023    import railo.runtime.util.QueryStackImpl;
024    
025    /**
026     * Undefined Scope
027     */
028    public final class UndefinedImpl extends StructSupport implements Undefined {
029    
030            private static final Collection.Key QUERY = KeyImpl.intern("query");
031            private Collection[] scopes;
032            private QueryStackImpl qryStack=new QueryStackImpl();
033            private Scope variable;
034            private boolean allowImplicidQueryCall;
035            private boolean checkArguments;
036            
037    
038    
039            private boolean localAlways;
040            private short type;
041            private boolean isInit;
042            private Scope local;
043            private ArgumentPro argument;
044            private PageContextImpl pc;
045            
046            /**
047             * constructor of the class
048             * @param pageContextImpl 
049             * @param type type of the undefined scope (ServletConfigImpl.SCOPE_STRICT;ServletConfigImpl.SCOPE_SMALL;ServletConfigImpl.SCOPE_STANDART)
050             */
051            public UndefinedImpl(PageContextImpl pc, short type) {
052                    this.type=type;
053                    this.pc=pc;
054            }
055            
056            
057            /**
058         * @see railo.runtime.type.scope.Undefined#localScope()
059         */
060            public Scope localScope() {
061                    return local;
062            }
063            
064    
065            // FUTURE add to interface
066            public ArgumentPro argumentsScope() {
067                    // TODO Auto-generated method stub
068                    return argument;
069            }
070    
071            // FUTURE add to interface
072            public Variables variablesScope() {
073                    return (Variables) variable;
074            }
075    
076            /*
077         * @see railo.runtime.type.scope.Undefined#check Arguments(boolean)
078         * /
079            public boolean check Arguments(boolean b) {
080                    boolean old=this.check Arguments;
081                    this.check Arguments=b;
082                    return old;
083            }*/
084            
085            /**
086             * @see railo.runtime.type.scope.Undefined#setMode(int)
087             */
088            public int setMode(int mode) {
089                    int m=Undefined.MODE_NO_LOCAL_AND_ARGUMENTS;
090                    if(checkArguments) {
091                            if(localAlways)m=Undefined.MODE_LOCAL_OR_ARGUMENTS_ALWAYS;
092                            else m=Undefined.MODE_LOCAL_OR_ARGUMENTS_ONLY_WHEN_EXISTS;
093                    }
094                    
095                    checkArguments=mode!=Undefined.MODE_NO_LOCAL_AND_ARGUMENTS;
096                    localAlways=mode==Undefined.MODE_LOCAL_OR_ARGUMENTS_ALWAYS;
097                    return m;
098            }
099            
100            
101            /**
102         * @see railo.runtime.type.scope.Undefined#setFunctionScopes(railo.runtime.type.Scope, railo.runtime.type.Scope)
103         */
104            public void setFunctionScopes(Scope local, Scope argument) {// FUTURE setFunctionScopes(Local local,Argument argument)
105                    this.local=local;
106                    this.argument=(ArgumentPro) argument;
107            }
108    
109            /**
110         * @see railo.runtime.type.scope.Undefined#getCollectionStack()
111         */
112            public QueryStack getCollectionStack() {
113                    return getQueryStack();
114            }
115            
116            /**
117             * @see railo.runtime.type.scope.Undefined#getQueryStack()
118             */
119            public QueryStack getQueryStack() {
120                    return qryStack;
121            }
122            
123            /**
124         * @see railo.runtime.type.scope.Undefined#setCollectionStack(railo.runtime.util.QueryStack)
125         */
126            public void setCollectionStack(QueryStack collStack) {
127                    setQueryStack(collStack);
128            }
129            
130            /**
131             * @see railo.runtime.type.scope.Undefined#setQueryStack(railo.runtime.util.QueryStack)
132             */
133            public void setQueryStack(QueryStack qryStack) {
134                    this.qryStack=(QueryStackImpl) qryStack;
135            }
136            
137            /**
138         * @see railo.runtime.type.scope.Undefined#addCollection(railo.runtime.type.Query)
139         */
140            public void addCollection(Query coll) {
141                    addQuery(coll);
142            }
143    
144            /**
145             * @see railo.runtime.type.scope.Undefined#addQuery(railo.runtime.type.Query)
146             */
147            public void addQuery(Query qry) {
148                    if(allowImplicidQueryCall)
149                            qryStack.addQuery(qry);
150            }
151    
152            /**
153         * @see railo.runtime.type.scope.Undefined#removeCollection()
154         */
155            public void removeCollection() {
156                    removeQuery();
157            }
158    
159            /**
160             * @see railo.runtime.type.scope.Undefined#removeQuery()
161             */
162            public void removeQuery() {
163                    if(allowImplicidQueryCall)
164                            qryStack.removeQuery();
165            }
166    
167            /**
168             * @see railo.runtime.type.Collection#size()
169             */
170            public int size() {
171                    return variable.size();
172            }
173    
174            /**
175             * @see railo.runtime.type.Collection#keysAsString()
176             */
177            public String[] keysAsString() {
178                    return variable.keysAsString();
179            }
180    
181            /**
182             * @see railo.runtime.type.Collection#keys()
183             */
184            public Collection.Key[] keys() {
185                    return variable.keys();
186            }
187    
188            /**
189             * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key)
190             */
191            public Object remove(Collection.Key key) throws PageException {
192                    if(checkArguments && local.containsKey(key))
193                            return local.remove(key);
194                    return variable.remove(key);
195            }
196    
197            /**
198             *
199             * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key)
200             */
201            public Object removeEL(Collection.Key key) {
202                    if(checkArguments && local.containsKey(key))
203                            return local.removeEL(key);
204                    return variable.removeEL(key);
205            }
206    
207            /**
208             * @see railo.runtime.type.Collection#clear()
209             */
210            public void clear() {
211                    variable.clear();
212            }
213            
214            public Object get(Collection.Key key) throws PageException {
215                    
216                    Object rtn=null;
217                    if(checkArguments) {
218                        rtn=local.get(key,null);
219                        if(rtn!=null) return rtn;
220    
221                        rtn=argument.getFunctionArgument(key,null);
222                        if(rtn!=null) return rtn;
223                    }
224                    
225                    // get data from queries
226                    if(allowImplicidQueryCall && !qryStack.isEmpty()) {
227                            rtn=qryStack.getDataFromACollection(pc,key);
228                            if(rtn!=null) {
229                            return rtn;
230                        }
231                    }
232                    
233                    // variable
234                    rtn=variable.get(key,null);
235                    if(rtn!=null) {
236                            return rtn;
237                }
238                    
239                    // thread scopes
240                    if(pc.hasFamily()) {
241                            rtn = pc.getThreadScope(key,null);
242                            if(rtn!=null) return rtn;
243                    }
244                    
245                    // get a scope value
246                    for(int i=0;i<scopes.length;i++) {
247                        rtn=scopes[i].get(key,null);
248                            if(rtn!=null) {
249                                    return rtn;
250                            }
251                    }
252                    throw new ExpressionException("variable ["+key.getString()+"] doesn't exist");
253            }
254            
255            /**
256         * @see railo.runtime.type.scope.Undefined#getCollection(java.lang.String)
257         */
258            public Object getCollection(String key) throws ExpressionException {
259                    Object rtn=null;
260                    
261                    if(checkArguments) {
262                        rtn=local.get(key,null);
263                        if(rtn!=null) return rtn;
264                        rtn=argument.getFunctionArgument(key,null);
265                        if(rtn!=null) return rtn;
266                    }
267                                    
268                    // get data from queries
269                    if(allowImplicidQueryCall && !qryStack.isEmpty()) {
270                            rtn=qryStack.getColumnFromACollection(key);
271                            if(rtn!=null) return rtn;
272                    }
273                    
274                    // variable
275                    rtn=variable.get(key,null);
276                    if(rtn!=null) {
277                            return rtn;
278                    }
279                    
280                    // thread scopes
281                    if(pc.hasFamily()) {
282                            rtn = pc.getThreadScope(key,null);
283                            if(rtn!=null) return rtn;
284                    }
285                    
286                    // get a scope value
287                    for(int i=0;i<scopes.length;i++) {
288                            rtn=scopes[i].get(key,null);
289                            if(rtn!=null) {
290                                    return rtn;
291                            }
292                    }
293                    throw new ExpressionException("variable ["+key+"] doesn't exist");
294            }
295            
296            public Struct getScope(String key) {
297                    Object rtn=null;
298                    Struct sct=new StructImpl(Struct.TYPE_LINKED);
299                    
300                    if(checkArguments) {
301                        rtn=local.get(key,null);
302                        if(rtn!=null) sct.setEL(KeyImpl.LOCAL, rtn);
303                        rtn=argument.getFunctionArgument(key,null);
304                        if(rtn!=null) sct.setEL(KeyImpl.ARGUMENTS, rtn);
305                    }
306                                    
307                    // get data from queries
308                    if(allowImplicidQueryCall && !qryStack.isEmpty()) {
309                            rtn=qryStack.getColumnFromACollection(key);
310                            if(rtn!=null) sct.setEL(QUERY, rtn);
311                    }
312                    
313                    // variable
314                    rtn=variable.get(key,null);
315                    if(rtn!=null) {
316                            sct.setEL(KeyImpl.VARIABLES, rtn);
317                    }
318                    
319                    // thread scopes
320                    if(pc.hasFamily()) {
321                            rtn = pc.getThreadScope(key,null);
322                            if(rtn!=null) sct.setEL(KeyImpl.THREAD, rtn); 
323                    }
324                    
325                    // get a scope value
326                    for(int i=0;i<scopes.length;i++) {
327                            rtn=scopes[i].get(key,null);
328                            if(rtn!=null) {
329                                    sct.setEL(((Scope)scopes[i]).getTypeAsString(), rtn); 
330                            }
331                    }
332                    return sct;
333            }
334            
335            /**
336             * return a list of String with the scope names
337             * @param key
338             * @return
339             */
340            public List getScopeNames() {
341                    List scopeNames=new ArrayList();
342                    
343                    if(checkArguments) {
344                            scopeNames.add("local");
345                            scopeNames.add("arguments");
346                    }
347                    scopeNames.add("variables");
348                    
349                    // thread scopes
350                    if(pc.hasFamily()) {
351                            String[] names = pc.getThreadScopeNames();
352                            for(int i=0;i<names.length;i++)scopeNames.add(i,names[i]);
353                    }
354                    
355                    for(int i=0;i<scopes.length;i++) {
356                            
357                            scopeNames.add(((Scope)scopes[i]).getTypeAsString()); 
358                    }
359                    return scopeNames;
360                    
361                    
362                    
363            }
364    
365            public Object getCollection(Key key) throws PageException {
366                    Object rtn=null;
367                    
368                    if(checkArguments) {
369                        rtn=local.get(key,null);
370                        if(rtn!=null) return rtn;
371                        rtn=argument.getFunctionArgument(key,null);
372                        if(rtn!=null) return rtn;
373                    }
374                                    
375                    // get data from queries
376                    if(allowImplicidQueryCall && !qryStack.isEmpty()) {
377                            rtn=qryStack.getColumnFromACollection(key);
378                            if(rtn!=null) return rtn;
379                    }
380                    
381                    // variable
382                    rtn=variable.get(key,null);
383                    if(rtn!=null) {
384                            return rtn;
385                    }
386                    
387                    // thread scopes
388                    if(pc.hasFamily()) {
389                            rtn = pc.getThreadScope(key,null);
390                            if(rtn!=null) return rtn;
391                    }
392                    
393                    // get a scope value
394                    for(int i=0;i<scopes.length;i++) {
395                            rtn=scopes[i].get(key,null);
396                            if(rtn!=null) {
397                                    return rtn;
398                            }
399                    }
400                    throw new ExpressionException("variable ["+key.getString()+"] doesn't exist");
401            }
402    
403        public Object get(Collection.Key key, Object defaultValue) {
404                    Object rtn=null;
405            
406            if(checkArguments) {
407                rtn=local.get(key,null);
408                if(rtn!=null) return rtn;
409                rtn=argument.getFunctionArgument(key,null);
410                if(rtn!=null) return rtn;
411            }
412            
413            // get data from queries
414            if(allowImplicidQueryCall && !qryStack.isEmpty()) {
415                rtn=qryStack.getDataFromACollection(key);
416                if(rtn!=null) return rtn;
417            }
418            
419            // variable
420            rtn=variable.get(key,null);
421            if(rtn!=null) {
422                return rtn;
423            }
424                    
425                    // thread scopes
426                    if(pc.hasFamily()) {
427                            rtn = pc.getThreadScope(key,null);
428                            if(rtn!=null) return rtn;
429                    }
430            
431            // get a scope value
432            for(int i=0;i<scopes.length;i++) {
433                rtn=scopes[i].get(key,null);
434                if(rtn!=null) {
435                    return rtn;
436                }
437            }
438            return defaultValue;
439        }
440        
441        
442        /**
443         * @see railo.runtime.type.scope.Undefined#getCascading(java.lang.String)
444         */
445        public Object getCascading(String strKey) {
446            Object rtn=null;
447            Key key = KeyImpl.init(strKey);
448            // get a scope value
449            for(int i=0;i<scopes.length;i++) {
450                rtn=scopes[i].get(key,null);
451                if(rtn!=null) {
452                    return rtn;
453                }
454            }
455            return null;
456        }
457    
458    
459            /**
460             *
461             * @see railo.runtime.type.scope.Undefined#getCascading(railo.runtime.type.Collection.Key)
462             */
463            public Object getCascading(Collection.Key key) {
464            Object rtn=null;
465              
466            // get a scope value
467            for(int i=0;i<scopes.length;i++) {
468                rtn=scopes[i].get(key,null);
469                if(rtn!=null) {
470                    return rtn;
471                }
472            }
473            return null;
474            }
475    
476            /**
477             * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object)
478             */
479            public Object setEL(Collection.Key key, Object value) {
480                    if(checkArguments) {
481                if(localAlways || local.containsKey(key))     return local.setEL(key,value);
482                if(argument.containsFunctionArgumentKey(key))  return argument.setEL(key,value);
483            }
484                            
485                    return variable.setEL(key,value);
486            }
487    
488            /**
489             *
490             * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object)
491             */
492            public Object set(Collection.Key key, Object value) throws PageException {
493                    if(checkArguments) {
494                    if(localAlways || local.containsKey(key))     return local.set(key,value);
495                if(argument.containsFunctionArgumentKey(key))  return argument.set(key,value);
496                
497            }
498                    return variable.set(key,value);
499            }
500            
501            /**
502             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int)
503             */
504            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
505                    return variable.toDumpData(pageContext, maxlevel,dp);
506            }
507    
508            /**
509             * @see railo.runtime.type.Collection#keyIterator()
510             */
511            public Iterator keyIterator() {
512                    return variable.keyIterator();
513            }
514            
515            /**
516             * @see railo.runtime.type.Scope#isInitalized()
517             */
518            public boolean isInitalized() {
519                    return isInit;
520            }
521    
522            /**
523             * @see railo.runtime.type.Scope#initialize(railo.runtime.PageContext)
524             */
525            public void initialize(PageContext pc) {
526                    if(isInitalized()) return;
527                    isInit=true;
528                    variable=pc.variablesScope();
529            argument=(ArgumentPro) pc.argumentsScope();
530                    local=pc.localScope();
531                    allowImplicidQueryCall=pc.getConfig().allowImplicidQueryCall();
532            type=pc.getConfig().getScopeCascadingType();
533            
534                    // Strict
535                    if(type==Config.SCOPE_STRICT) {
536                            //print.ln("strict");
537                            scopes=new Collection[] {};
538                    }
539                    // small
540                    else if(type==Config.SCOPE_SMALL) {
541                            //print.ln("small");
542                            if(pc.getConfig().mergeFormAndURL()) {
543                                    scopes=new Collection[] {
544                                                    pc.formScope()
545                                            };
546                            }
547                            else {
548                                    scopes=new Collection[] {
549                                                    pc.urlScope(),
550                                                    pc.formScope()
551                                            };
552                            }
553                    }
554                    // standard
555                    else  {
556                            reinitialize((PageContextImpl) pc);
557                    }
558                    
559                    
560            }
561    
562            public void reinitialize(PageContextImpl pc) {
563                    if(type!=Config.SCOPE_STANDARD) return;
564                    Client cs = pc.clientScopeEL();
565    //              print.ln("standard");
566                    if(pc.getConfig().mergeFormAndURL()) {
567                scopes=new Collection[cs==null?3:4]; 
568                scopes[0]=pc.cgiScope();
569                scopes[1]=pc.formScope();
570                scopes[2]=pc.cookieScope();
571                if(cs!=null)scopes[3]=cs;
572                    }
573                    else {
574                scopes=new Collection[cs==null?4:5]; 
575                scopes[0]=pc.cgiScope();
576                scopes[1]=pc.urlScope();
577                scopes[2]=pc.formScope();
578                scopes[3]=pc.cookieScope();
579                if(cs!=null)scopes[4]=cs;
580                    }
581            }
582    
583    
584            /**
585             * @see railo.runtime.type.Scope#release()
586             */
587            public void release() {
588                    isInit=false;
589                    argument=null;
590                    local=null;
591                    variable=null;
592                    scopes=null;
593                    checkArguments=false;
594                    localAlways=false;
595                    if(allowImplicidQueryCall)qryStack.clear();
596                    
597                    
598                    //threads=null;
599                    //hasThreads=false;
600            }
601    
602            /**
603             * @see railo.runtime.type.Collection#duplicate(boolean)
604             */
605            public Collection duplicate(boolean deepCopy) {
606                    UndefinedImpl dupl = new UndefinedImpl(pc, type);
607                    dupl.allowImplicidQueryCall=allowImplicidQueryCall;
608                    dupl.checkArguments=checkArguments;
609                    dupl.argument=deepCopy?(ArgumentPro)argument.duplicate(deepCopy):argument;
610                    dupl.isInit=isInit;
611                    dupl.local=deepCopy?(Scope)local.duplicate(deepCopy):local;
612                    dupl.localAlways=localAlways;
613                    dupl.qryStack= (deepCopy?(QueryStackImpl)qryStack.duplicate(deepCopy):qryStack);
614                    
615                    dupl.variable=deepCopy?(Scope)variable.duplicate(deepCopy):variable;
616                    
617                    // scopes
618                    if(deepCopy) {
619                            dupl.scopes=new Collection[scopes.length];
620                            for(int i=0;i<scopes.length;i++) {
621                                    dupl.scopes[i]=scopes[i].duplicate(deepCopy);
622                            }
623                    }
624                    else dupl.scopes=scopes;
625                    
626                    return dupl;
627            }
628            
629    
630            /**
631             *
632             * @see railo.runtime.type.Collection#containsKey(railo.runtime.type.Collection.Key)
633             */
634            public boolean containsKey(Key key) {
635            return get(key,null)!=null;
636            }
637    
638        /**
639         * @see railo.runtime.op.Castable#castToString()
640         */
641        public String castToString() throws ExpressionException {
642            throw new ExpressionException("Can't cast Complex Object Type Struct to String",
643              "Use Build-In-Function \"serialize(Struct):String\" to create a String from Struct");
644        }
645        
646            /**
647             * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String)
648             */
649            public String castToString(String defaultValue) {
650                    return defaultValue;
651            }
652    
653        /**
654         * @see railo.runtime.op.Castable#castToBooleanValue()
655         */
656        public boolean castToBooleanValue() throws ExpressionException {
657            throw new ExpressionException("Can't cast Complex Object Type Struct to a boolean value");
658        }
659        
660        /**
661         * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean)
662         */
663        public Boolean castToBoolean(Boolean defaultValue) {
664            return defaultValue;
665        }
666    
667    
668        /**
669         * @see railo.runtime.op.Castable#castToDoubleValue()
670         */
671        public double castToDoubleValue() throws ExpressionException {
672            throw new ExpressionException("Can't cast Complex Object Type Struct to a number value");
673        }
674        
675        /**
676         * @see railo.runtime.op.Castable#castToDoubleValue(double)
677         */
678        public double castToDoubleValue(double defaultValue) {
679            return defaultValue;
680        }
681    
682    
683        /**
684         * @see railo.runtime.op.Castable#castToDateTime()
685         */
686        public DateTime castToDateTime() throws ExpressionException {
687            throw new ExpressionException("Can't cast Complex Object Type Struct to a Date");
688        }
689        
690        /**
691         * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime)
692         */
693        public DateTime castToDateTime(DateTime defaultValue) {
694            return defaultValue;
695        }
696    
697            /**
698             * @see railo.runtime.op.Castable#compare(boolean)
699             */
700            public int compareTo(boolean b) throws ExpressionException {
701                    throw new ExpressionException("can't compare Complex Object Type Struct with a boolean value");
702            }
703    
704            /**
705             * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime)
706             */
707            public int compareTo(DateTime dt) throws PageException {
708                    throw new ExpressionException("can't compare Complex Object Type Struct with a DateTime Object");
709            }
710    
711            /**
712             * @see railo.runtime.op.Castable#compareTo(double)
713             */
714            public int compareTo(double d) throws PageException {
715                    throw new ExpressionException("can't compare Complex Object Type Struct with a numeric value");
716            }
717    
718            /**
719             * @see railo.runtime.op.Castable#compareTo(java.lang.String)
720             */
721            public int compareTo(String str) throws PageException {
722                    throw new ExpressionException("can't compare Complex Object Type Struct with a String");
723            }
724    
725        /**
726         * @see railo.runtime.type.scope.Undefined#setVariableScope(railo.runtime.type.Scope)
727         */
728        public void setVariableScope(Scope scope) {
729            variable=scope;
730        }
731    
732        /**
733         * @see railo.runtime.type.Scope#getType()
734         */
735        public int getType() {
736            return SCOPE_UNDEFINED;
737        }
738    
739        /**
740         * @see railo.runtime.type.Scope#getTypeAsString()
741         */
742        public String getTypeAsString() {
743            return "undefined";
744        }
745    
746    
747            /**
748             * @return the allowImplicidQueryCall
749             */
750            public boolean isAllowImplicidQueryCall() {
751                    return allowImplicidQueryCall;
752            }
753    
754    
755            /**
756             * @param allowImplicidQueryCall the allowImplicidQueryCall to set
757             */
758            public boolean setAllowImplicidQueryCall(boolean allowImplicidQueryCall) {
759                    boolean old=this.allowImplicidQueryCall;
760                    this.allowImplicidQueryCall = allowImplicidQueryCall;
761                    return old;
762            }
763            
764            /**
765             * @return the checkArguments
766             */
767            public boolean getCheckArguments() {
768                    return checkArguments;
769            }
770    
771    
772    }