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}