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.util.Iterator;
022
023import lucee.commons.collection.MapFactory;
024import lucee.commons.collection.MapPro;
025import lucee.commons.lang.CFTypes;
026import lucee.runtime.component.Member;
027import lucee.runtime.config.NullSupportHelper;
028import lucee.runtime.dump.DumpData;
029import lucee.runtime.dump.DumpProperties;
030import lucee.runtime.engine.ThreadLocalPageContext;
031import lucee.runtime.exp.ExpressionException;
032import lucee.runtime.exp.PageException;
033import lucee.runtime.op.Duplicator;
034import lucee.runtime.type.Collection;
035import lucee.runtime.type.Struct;
036import lucee.runtime.type.StructImpl;
037import lucee.runtime.type.UDF;
038import lucee.runtime.type.UDFPlus;
039import lucee.runtime.type.dt.DateTime;
040import lucee.runtime.type.it.EntryIterator;
041import lucee.runtime.type.it.KeyIterator;
042import lucee.runtime.type.it.StringIterator;
043import lucee.runtime.type.it.ValueIterator;
044import lucee.runtime.type.util.ComponentProUtil;
045import lucee.runtime.type.util.ComponentUtil;
046import lucee.runtime.type.util.KeyConstants;
047import lucee.runtime.type.util.MemberUtil;
048import lucee.runtime.type.util.StructSupport;
049import lucee.runtime.type.util.StructUtil;
050
051public class ComponentScopeShadow extends StructSupport implements ComponentScope {
052
053        private static final long serialVersionUID = 4930100230796574243L;
054
055        private final ComponentImpl component;
056        private static final int access=Component.ACCESS_PRIVATE;
057        private final MapPro<Key,Object> shadow;
058
059
060        /**
061         * Constructor of the class
062         * @param component
063         * @param shadow
064         */
065        public ComponentScopeShadow(ComponentImpl component, MapPro shadow) {
066        this.component=component;
067        this.shadow=shadow;
068        
069        }
070        
071        /**
072         * Constructor of the class
073         * @param component
074         * @param shadow
075         */
076        public ComponentScopeShadow(ComponentImpl component, ComponentScopeShadow scope,boolean cloneShadow) {
077        this.component=component;
078        this.shadow=cloneShadow?(MapPro)Duplicator.duplicateMap(scope.shadow,MapFactory.getConcurrentMap(), false):scope.shadow;
079        }
080
081
082        @Override
083        public Component getComponent() {
084                return component.top;
085        }
086
087    @Override
088    public int getType() {
089        return SCOPE_VARIABLES;
090    }
091
092    @Override
093    public String getTypeAsString() {
094        return "variables";
095    }
096
097        @Override
098        public void initialize(PageContext pc) {}
099
100        @Override
101        public boolean isInitalized() {
102        return component.isInitalized();
103        }
104
105
106    @Override
107    public void release() {}
108    
109    @Override
110    public void release(PageContext pc) {}
111
112
113        @Override
114        public void clear() {
115                shadow.clear();
116        }
117
118        @Override
119        public boolean containsKey(Collection.Key key) {
120                return get(key,null)!=null;
121        }
122
123        @Override
124        public Object get(Key key) throws PageException {
125                Object o = get(key,NullSupportHelper.NULL());
126                if(o!=NullSupportHelper.NULL()) return o;
127        throw new ExpressionException("Component ["+component.getCallName()+"] has no accessible Member with name ["+key+"]");
128        }
129        
130        @Override
131        public Object get(Key key, Object defaultValue) {
132                if(key.equalsIgnoreCase(KeyConstants._SUPER)) {
133                        Component ac = ComponentUtil.getActiveComponent(ThreadLocalPageContext.get(),component);
134                        return SuperComponent.superInstance((ComponentImpl) ComponentProUtil.getBaseComponent(ac));
135                }
136                if(key.equalsIgnoreCase(KeyConstants._THIS)) return component.top;
137                
138                if(NullSupportHelper.full())return shadow.g(key,defaultValue); 
139                
140                Object o=shadow.get(key);
141                if(o!=null) return o;
142                return defaultValue;
143                
144        }
145
146        @Override
147        public Iterator<Collection.Key> keyIterator() {
148                return new KeyIterator(keys());
149        }
150    
151        @Override
152        public Iterator<String> keysAsStringIterator() {
153        return new StringIterator(keys());
154    }
155
156        @Override
157        public Iterator<Entry<Key, Object>> entryIterator() {
158                return new EntryIterator(this, keys());
159        }
160
161        @Override
162        public Iterator<Object> valueIterator() {
163                return new ValueIterator(this,keys());
164        }
165
166        @Override
167        public Collection.Key[] keys() {
168                Collection.Key[] keys=new Collection.Key[shadow.size()+1];
169                Iterator<Key> it = shadow.keySet().iterator();
170                int index=0;
171                while(it.hasNext()) {
172                        keys[index++]=it.next();
173                }
174                keys[index]=KeyConstants._THIS;
175                return keys;
176        }
177
178        @Override
179        public Object remove(Collection.Key key) throws PageException {
180                if(key.equalsIgnoreCase(KeyConstants._this) || key.equalsIgnoreCase(KeyConstants._super))
181                        throw new ExpressionException("key ["+key.getString()+"] is part of the component and can't be removed");
182                if(NullSupportHelper.full())return shadow.r(key);
183                
184                Object o=shadow.remove(key);
185                if(o!=null) return o;
186                throw new ExpressionException("can't remove key ["+key.getString()+"] from struct, key doesn't exist");
187        }
188
189
190
191        public Object removeEL(Key key) {
192                if(key.equalsIgnoreCase(KeyConstants._this) || key.equalsIgnoreCase(KeyConstants._super))return null;
193                return shadow.remove(key);
194        }
195
196        @Override
197        public Object set(Collection.Key key, Object value) {
198                if(key.equalsIgnoreCase(KeyConstants._this) || key.equalsIgnoreCase(KeyConstants._super)) return value;
199                
200                if(!component.afterConstructor && value instanceof UDF) {
201                        component.addConstructorUDF(key,(UDF)value);
202                }
203                shadow.put(key, value);
204                return value;
205        }
206
207        @Override
208        public Object setEL(Collection.Key key, Object value) {
209                return set(key, value);
210        }
211
212        @Override
213        public int size() {
214                return keys().length;
215        }
216
217        @Override
218        public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
219                return StructUtil.toDumpTable(this, "Variable Scope (of Component)", pageContext, maxlevel, dp);
220        }
221
222        @Override
223        public boolean castToBooleanValue() throws PageException {
224        throw new ExpressionException("Can't cast Complex Object Type to a boolean value");
225        }
226    
227    @Override
228    public Boolean castToBoolean(Boolean defaultValue) {
229        return defaultValue;
230    }
231
232        @Override
233        public DateTime castToDateTime() throws PageException {
234        throw new ExpressionException("Can't cast Complex Object Type to a Date Object");
235        }
236    
237    @Override
238    public DateTime castToDateTime(DateTime defaultValue) {
239        return defaultValue;
240    }
241
242        @Override
243        public double castToDoubleValue() throws PageException {
244        throw new ExpressionException("Can't cast Complex Object Type to a numeric value");
245        }
246    
247    @Override
248    public double castToDoubleValue(double defaultValue) {
249        return defaultValue;
250    }
251
252        @Override
253        public String castToString() throws PageException {
254        throw new ExpressionException("Can't cast Complex Object Type to a String");
255        }
256        
257        @Override
258        public String castToString(String defaultValue) {
259                return defaultValue;
260        }
261
262        @Override
263        public int compareTo(boolean b) throws PageException {
264                throw new ExpressionException("can't compare Complex Object with a boolean value");
265        }
266
267        @Override
268        public int compareTo(DateTime dt) throws PageException {
269                throw new ExpressionException("can't compare Complex Object with a DateTime Object");
270        }
271
272        @Override
273        public int compareTo(double d) throws PageException {
274                throw new ExpressionException("can't compare Complex Object with a numeric value");
275        }
276
277        @Override
278        public int compareTo(String str) throws PageException {
279                throw new ExpressionException("can't compare Complex Object with a String");
280        }
281
282        /*public Object call(PageContext pc, String key, Object[] arguments) throws PageException {
283                return call(pc, KeyImpl.init(key), arguments);
284        }*/
285
286        public Object call(PageContext pc, Collection.Key key, Object[] arguments) throws PageException {
287                // first check variables
288                Object o=shadow.get(key);
289                if(o instanceof UDFPlus) {
290                        return ((UDFPlus)o).call(pc,key, arguments, false);
291                }
292                
293                // then check in component
294                Member m = component.getMember(access, key, false,false);
295                if(m!=null) {
296                        if(m instanceof UDFPlus) return ((UDFPlus)m).call(pc,key, arguments, false);
297                }
298                return MemberUtil.call(pc, this, key, arguments, CFTypes.TYPE_STRUCT, "struct");
299                //throw ComponentUtil.notFunction(component, key, m!=null?m.getValue():null,access);
300        }
301
302        /*public Object callWithNamedValues(PageContext pc, String key,Struct args) throws PageException {
303                return callWithNamedValues(pc, KeyImpl.init(key), args);
304        }*/
305
306        public Object callWithNamedValues(PageContext pc, Key key, Struct args) throws PageException {
307                // first check variables
308                Object o=shadow.get(key);
309                if(o instanceof UDFPlus) {
310                        return ((UDFPlus)o).callWithNamedValues(pc,key, args, false);
311                }
312                
313                Member m = component.getMember(access, key, false,false);
314                if(m!=null) {
315                        if(m instanceof UDFPlus) return ((UDFPlus)m).callWithNamedValues(pc,key, args, false);
316                        return MemberUtil.callWithNamedValues(pc, this, key, args, CFTypes.TYPE_STRUCT, "struct");
317                        //throw ComponentUtil.notFunction(component, key, m.getValue(),access);
318                }
319                return MemberUtil.callWithNamedValues(pc, this, key, args, CFTypes.TYPE_STRUCT, "struct");
320                //throw ComponentUtil.notFunction(component, key, null,access);
321        }
322    
323        @Override
324        public Collection duplicate(boolean deepCopy) {
325                StructImpl sct = new StructImpl();
326                StructImpl.copy(this, sct, deepCopy);
327                return sct;
328//               MUST muss deepCopy checken
329        //return new ComponentScopeShadow(component,shadow);//new ComponentScopeThis(component.cloneComponentImpl());
330    }
331        
332
333        /*public Object get(PageContext pc, String key, Object defaultValue) {
334                return get(key, defaultValue);
335        }*/
336
337        @Override
338        public Object get(PageContext pc, Key key, Object defaultValue) {
339                return get(key, defaultValue);
340        }
341
342        @Override
343        public Object set(PageContext pc, Collection.Key propertyName, Object value) throws PageException {
344                return set(propertyName, value);
345        }
346
347        /*public Object setEL(PageContext pc, String propertyName, Object value) {
348                return setEL(propertyName, value);
349        }*/
350
351        @Override
352        public Object setEL(PageContext pc, Collection.Key propertyName, Object value) {
353                return set(propertyName, value);
354        }
355
356        /*public Object get(PageContext pc, String key) throws PageException {
357                return get(key);
358        }*/
359
360        @Override
361        public Object get(PageContext pc, Collection.Key key) throws PageException {
362                return get(key);
363        }
364
365        public MapPro<Key,Object> getShadow() {
366                return shadow;
367        }
368
369        @Override
370        public void setBind(boolean bind) {}
371
372        @Override
373        public boolean isBind() {
374                return true;
375        }
376}