001    package railo.runtime.type.scope;
002    
003    import java.util.Iterator;
004    
005    import railo.runtime.PageContext;
006    import railo.runtime.config.NullSupportHelper;
007    import railo.runtime.dump.DumpData;
008    import railo.runtime.dump.DumpProperties;
009    import railo.runtime.dump.DumpTable;
010    import railo.runtime.engine.ThreadLocalPageContext;
011    import railo.runtime.exp.PageException;
012    import railo.runtime.op.Duplicator;
013    import railo.runtime.type.Collection;
014    import railo.runtime.type.Struct;
015    
016    public class Closure extends ScopeSupport implements Variables {
017            
018            private static final Object NULL = new Object();
019            private Argument arg;
020            private Local local;
021            private Variables var;
022            private boolean debug;
023            private Undefined und; 
024    
025            public Closure(PageContext pc,Argument arg, Local local,Variables var ){
026                    super("variables",SCOPE_VARIABLES,Struct.TYPE_REGULAR);
027                    arg.setBind(true);
028                    local.setBind(true);
029                    var.setBind(true);
030                    und = pc.undefinedScope();
031                    this.arg=arg;
032                    this.local=local;
033                    this.var=var;
034                    this.debug=pc.getConfig().debug();
035            }
036    
037            @Override
038            public boolean isInitalized() {
039                    return true;
040            }
041    
042            @Override
043            public void initialize(PageContext pc) {        
044            }
045    
046            @Override
047            public void release() {
048            }
049    
050            @Override
051            public void release(PageContext pc) {
052            }
053    
054            @Override
055            public int getType() {
056                    return SCOPE_VARIABLES;
057            }
058    
059            @Override
060            public String getTypeAsString() {
061                    return "variables";
062            }
063    
064            @Override
065            public int size() {
066                    return var.size();
067            }
068    
069            @Override
070            public Key[] keys() {
071                    return var.keys();
072            }
073    
074            @Override
075            public Object remove(Key key) throws PageException {
076                    if(local.containsKey(key))
077                            return local.remove(key);
078                    return var.remove(key);
079            }
080    
081            @Override
082            public Object removeEL(Key key) {
083                    if(local.containsKey(key))
084                            return local.removeEL(key);
085                    return var.removeEL(key);
086            }
087    
088            @Override
089            public void clear() {
090                    var.clear();
091            }
092    
093            @Override
094            public Object get(Key key) throws PageException {
095                    Object value = local.get(key,NullSupportHelper.NULL());
096                    if(value!=NullSupportHelper.NULL()) return value;
097                    value=arg.get(key,NullSupportHelper.NULL());
098                    if(value!=NullSupportHelper.NULL()) {
099                            if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
100                            return value;
101                    }
102                    
103                    value= var.get(key);
104                    if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
105                    return value;
106            }
107    
108            @Override
109            public Object get(Key key, Object defaultValue) {
110                    Object value = local.get(key,NullSupportHelper.NULL());
111                    if(value!=NullSupportHelper.NULL()) return value;
112                    value=arg.get(key,NullSupportHelper.NULL());
113                    if(value!=NullSupportHelper.NULL()) {
114                            if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
115                            return value;
116                    }
117                    value= var.get(key,NullSupportHelper.NULL());
118                    if(value!=NullSupportHelper.NULL()){
119                            if(debug) UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
120                            return value;
121                    }
122                    return defaultValue;
123            }
124    
125            @Override
126            public Object set(Key key, Object value) throws PageException {
127                    if(und.getLocalAlways() || local.containsKey(key))     return local.set(key,value);
128                if(arg.containsKey(key))  {
129                    if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
130                    return arg.set(key,value);
131                }
132                if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
133                    return var.set(key, value);
134            }
135    
136            @Override
137            public Object setEL(Key key, Object value) {
138                if(und.getLocalAlways() || local.containsKey(key))     return local.setEL(key,value);
139            if(arg.containsKey(key))  {
140                    if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),arg.getTypeAsString(), key);
141                    return arg.setEL(key,value);
142            }
143                    
144                    if(debug)UndefinedImpl.debugCascadedAccess(ThreadLocalPageContext.get(),var.getTypeAsString(), key);
145                    return var.setEL(key,value);
146            }
147    
148            @Override
149            public Collection duplicate(boolean deepCopy) {
150                    return new Closure(ThreadLocalPageContext.get(),(Argument)Duplicator.duplicate(arg,deepCopy), (Local)Duplicator.duplicate(local,deepCopy), (Variables)Duplicator.duplicate(var,deepCopy));
151            }
152    
153            @Override
154            public boolean containsKey(Key key) {
155                    return get(key,NULL)!=NULL;
156            }
157    
158            @Override
159            public Iterator<Collection.Key> keyIterator() {
160                    return var.keyIterator();
161            }
162        
163        @Override
164            public Iterator<String> keysAsStringIterator() {
165            return var.keysAsStringIterator();
166        }
167            
168            @Override
169            public Iterator<Entry<Key, Object>> entryIterator() {
170                    return var.entryIterator();
171            }
172            
173            @Override
174            public Iterator<Object> valueIterator() {
175                    return var.valueIterator();
176            }
177            
178            @Override
179            public void setBind(boolean bind) {}
180    
181            @Override
182            public boolean isBind() {
183                    return true;
184            }
185            
186            @Override
187            public DumpData toDumpData(PageContext pageContext, int maxlevel,
188                            DumpProperties properties) {
189                    
190                    DumpTable dt= (DumpTable) super.toDumpData(pageContext, maxlevel, properties);
191                    dt.setTitle("Closure Variable Scope");
192                    return dt;
193            }
194    
195    
196    }