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.type.scope; 020 021import java.util.ArrayList; 022import java.util.Comparator; 023import java.util.Iterator; 024import java.util.LinkedHashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.Set; 028 029import lucee.commons.lang.CFTypes; 030import lucee.runtime.PageContext; 031import lucee.runtime.config.NullSupportHelper; 032import lucee.runtime.dump.DumpData; 033import lucee.runtime.dump.DumpProperties; 034import lucee.runtime.dump.DumpTable; 035import lucee.runtime.dump.DumpUtil; 036import lucee.runtime.dump.SimpleDumpData; 037import lucee.runtime.exp.ExpressionException; 038import lucee.runtime.exp.PageException; 039import lucee.runtime.exp.PageRuntimeException; 040import lucee.runtime.op.Caster; 041import lucee.runtime.op.Decision; 042import lucee.runtime.type.Array; 043import lucee.runtime.type.ArrayImpl; 044import lucee.runtime.type.Collection; 045import lucee.runtime.type.KeyImpl; 046import lucee.runtime.type.Null; 047import lucee.runtime.type.Struct; 048import lucee.runtime.type.StructImpl; 049import lucee.runtime.type.UDFPlus; 050import lucee.runtime.type.util.CollectionUtil; 051import lucee.runtime.type.util.MemberUtil; 052import lucee.runtime.type.wrap.ArrayAsList; 053 054/** 055 * implementation of the argument scope 056 */ 057public final class ArgumentImpl extends ScopeSupport implements Argument { 058 059 private boolean bind; 060 private Set functionArgumentNames; 061 //private boolean supportFunctionArguments; 062 063 /** 064 * constructor of the class 065 */ 066 public ArgumentImpl() { 067 super("arguments",SCOPE_ARGUMENTS,Struct.TYPE_LINKED); 068 //this(true); 069 } 070 071 072 @Override 073 public void release() { 074 release(null); 075 } 076 077 @Override 078 public void release(PageContext pc) { 079 functionArgumentNames=null; 080 if(pc==null)super.release(); 081 else super.release(pc); 082 } 083 084 085 086 @Override 087 public void setBind(boolean bind) { 088 this.bind=bind; 089 } 090 091 @Override 092 public boolean isBind() { 093 return this.bind; 094 } 095 096 public Object getFunctionArgument(String key, Object defaultValue) { 097 return getFunctionArgument(KeyImpl.getInstance(key), defaultValue); 098 } 099 100 public Object getFunctionArgument(Collection.Key key, Object defaultValue) { 101 return super.get(key,defaultValue); 102 } 103 104 105 @Override 106 public boolean containsFunctionArgumentKey(Key key) { 107 return super.containsKey(key);//functionArgumentNames!=null && functionArgumentNames.contains(key); 108 } 109 110 111 112 @Override 113 public Object get(Collection.Key key, Object defaultValue) { 114 /*if(NullSupportHelper.full()) { 115 Object o=super.get(key,NullSupportHelper.NULL()); 116 if(o!=NullSupportHelper.NULL())return o; 117 118 o=get(Caster.toIntValue(key.getString(),-1),NullSupportHelper.NULL()); 119 if(o!=NullSupportHelper.NULL())return o; 120 return defaultValue; 121 }*/ 122 123 Object o=super.g(key,Null.NULL); 124 if(o!=Null.NULL)return o; 125 126 o=get(Caster.toIntValue(key.getString(),-1),Null.NULL); 127 if(o!=Null.NULL)return o; 128 return defaultValue; 129 } 130 131 132 133 @Override 134 public Object get(Collection.Key key) throws ExpressionException { 135 /*if(NullSupportHelper.full()) { 136 Object o=super.get(key,NullSupportHelper.NULL()); 137 if(o!=NullSupportHelper.NULL())return o; 138 139 o=get(Caster.toIntValue(key.getString(),-1),NullSupportHelper.NULL()); 140 if(o!=NullSupportHelper.NULL())return o; 141 throw new ExpressionException("key ["+key.getString()+"] doesn't exist in argument scope. existing keys are ["+ 142 lucee.runtime.type.List.arrayToList(CollectionUtil.keys(this),", ") 143 +"]"); 144 }*/ 145 146 // null is supported as returned value with argument scope 147 Object o=super.g(key,Null.NULL); 148 if(o!=Null.NULL)return o; 149 150 o=get(Caster.toIntValue(key.getString(),-1),Null.NULL); 151 if(o!=Null.NULL)return o; 152 153 throw new ExpressionException("key ["+key.getString()+"] doesn't exist in argument scope. existing keys are ["+ 154 lucee.runtime.type.util.ListUtil.arrayToList(CollectionUtil.keys(this),", ") 155 +"]"); 156 } 157 158 159 160 @Override 161 public Object get(int intKey, Object defaultValue) { 162 Iterator<Object> it = valueIterator(); //keyIterator();//getMap().keySet().iterator(); 163 int count=0; 164 Object o; 165 while(it.hasNext()) { 166 o=it.next(); 167 if((++count)==intKey) { 168 return o;//super.get(o.toString(),defaultValue); 169 } 170 } 171 return defaultValue; 172 } 173 174 /** 175 * return a value matching to key 176 * @param intKey 177 * @return value matching key 178 * @throws PageException 179 */ 180 public Object getE(int intKey) throws PageException { 181 Iterator it = valueIterator();//getMap().keySet().iterator(); 182 int count=0; 183 Object o; 184 while(it.hasNext()) { 185 o=it.next(); 186 if((++count)==intKey) { 187 return o;//super.get(o.toString()); 188 } 189 } 190 throw new ExpressionException("invalid index ["+intKey+"] for argument scope"); 191 } 192 193 @Override 194 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 195 DumpTable htmlBox = new DumpTable("struct","#9999ff","#ccccff","#000000"); 196 htmlBox.setTitle("Scope Arguments"); 197 if(size()>10 && dp.getMetainfo())htmlBox.setComment("Entries:"+size()); 198 199 maxlevel--; 200 //Map mapx=getMap(); 201 Iterator<Key> it = keyIterator();//mapx.keySet().iterator(); 202 int count=0; 203 Collection.Key key; 204 int maxkeys=dp.getMaxKeys(); 205 int index=0; 206 while(it.hasNext()) { 207 key=it.next();//it.next(); 208 209 if(DumpUtil.keyValid(dp, maxlevel,key)){ 210 if(maxkeys<=index++)break; 211 htmlBox.appendRow(3, 212 new SimpleDumpData(key.getString()), 213 new SimpleDumpData(++count), 214 DumpUtil.toDumpData(get(key,null), 215 pageContext,maxlevel,dp)); 216 } 217 } 218 return htmlBox; 219 } 220 221 222 @Override 223 public int getDimension() { 224 return 1; 225 } 226 227 @Override 228 public Object setEL(int intKey, Object value) { 229 int count=0; 230 231 if(intKey>size()) { 232 return setEL(Caster.toString(intKey),value); 233 } 234 //Iterator it = keyIterator(); 235 Key[] keys = keys(); 236 for(int i=0;i<keys.length;i++) { 237 if((++count)==intKey) { 238 return super.setEL(keys[i],value); 239 } 240 } 241 return value; 242 } 243 244 245 @Override 246 public Object setE(int intKey, Object value) throws PageException { 247 248 if(intKey>size()) { 249 return set(Caster.toString(intKey),value); 250 } 251 //Iterator it = keyIterator(); 252 Key[] keys = keys(); 253 for(int i=0;i<keys.length;i++) { 254 if((i+1)==intKey) { 255 return super.set(keys[i],value); 256 } 257 } 258 throw new ExpressionException("invalid index ["+intKey+"] for argument scope"); 259 } 260 261 262 @Override 263 public int[] intKeys() { 264 int[] ints=new int[size()]; 265 for(int i=0;i<ints.length;i++)ints[i]=i+1; 266 return ints; 267 } 268 269 270 @Override 271 public boolean insert(int index, Object value) throws ExpressionException { 272 return insert(index, ""+index, value); 273 } 274 275 @Override 276 public boolean insert(int index, String key, Object value) throws ExpressionException { 277 int len=size(); 278 if(index<1 || index>len) 279 throw new ExpressionException("invalid index to insert a value to argument scope",len==0?"can't insert in a empty argument scope":"valid index goes from 1 to "+(len-1)); 280 281 // remove all upper 282 LinkedHashMap lhm = new LinkedHashMap(); 283 Collection.Key[] keys=keys(); 284 285 Collection.Key k; 286 for(int i=1;i<=keys.length;i++) { 287 if(i<index)continue; 288 k=keys[i-1]; 289 lhm.put(k.getString(),get(k,null)); 290 removeEL(k); 291 } 292 293 // set new value 294 setEL(key,value); 295 296 // reset upper values 297 Iterator it = lhm.entrySet().iterator(); 298 Map.Entry entry; 299 while(it.hasNext()) { 300 entry=(Entry) it.next(); 301 setEL(KeyImpl.toKey(entry.getKey()),entry.getValue()); 302 } 303 return true; 304 } 305 306 307 @Override 308 public Object append(Object o) throws PageException { 309 return set(Caster.toString(size()+1),o); 310 } 311 312 @Override 313 public Object appendEL(Object o) { 314 try { 315 return append(o); 316 } catch (PageException e) { 317 return null; 318 } 319 } 320 321 322 @Override 323 public Object prepend(Object o) throws PageException { 324 for(int i=size();i>0;i--) { 325 setE(i+1,getE(i)); 326 } 327 setE(1,o); 328 return o; 329 } 330 331 332 @Override 333 public void resize(int to) throws PageException { 334 for(int i=size(); i<to; i++) { 335 append(null); 336 } 337 //throw new ExpressionException("can't resize this array"); 338 } 339 340 341 342 @Override 343 public void sort(String sortType, String sortOrder) throws ExpressionException { 344 // TODO Impl. 345 throw new ExpressionException("can't sort ["+sortType+"-"+sortOrder+"] Argument Scope","not Implemnted Yet"); 346 } 347 348 public void sort(Comparator com) { 349 // TODO Impl. 350 throw new PageRuntimeException("can't sort Argument Scope","not Implemnted Yet"); 351 } 352 353 @Override 354 public Object[] toArray() { 355 Iterator it = keyIterator();//getMap().keySet().iterator(); 356 Object[] arr=new Object[size()]; 357 int count=0; 358 359 while(it.hasNext()) { 360 arr[count++]=it.next(); 361 } 362 return arr; 363 } 364 365 public Object setArgument(Object obj) throws PageException { 366 if(obj==this) return obj; 367 368 369 if(Decision.isStruct(obj)) { 370 clear(); // TODO bessere impl. anstelle vererbung wrao auf struct 371 Struct sct=Caster.toStruct(obj); 372 Iterator<Key> it = sct.keyIterator(); 373 Key key; 374 while(it.hasNext()) { 375 key=it.next(); 376 setEL(key, sct.get(key,null)); 377 } 378 return obj; 379 } 380 throw new ExpressionException("can not overwrite arguments scope"); 381 } 382 383 384 public ArrayList toArrayList() { 385 ArrayList list = new ArrayList(); 386 Object[] arr = toArray(); 387 for(int i=0;i<arr.length;i++) { 388 list.add(arr[i]); 389 } 390 return list; 391 } 392 393 @Override 394 public Object removeE(int intKey) throws PageException { 395 Key[] keys = keys(); 396 for(int i=0;i<keys.length;i++) { 397 if((i+1)==intKey) { 398 return super.remove(keys[i]); 399 } 400 } 401 throw new ExpressionException("can't remove argument number ["+intKey+"], argument doesn't exist"); 402 } 403 404 @Override 405 public Object removeEL(int intKey) { 406 Key[] keys = keys(); 407 for(int i=0;i<keys.length;i++) { 408 if((i+1)==intKey) { 409 return super.removeEL (keys[i]); 410 } 411 } 412 return null; 413 } 414 415 @Override 416 public boolean containsKey(Collection.Key key) { 417 if(NullSupportHelper.full()) return super.containsKey(key); 418 419 return super.g(key,null)!=null; 420 // return get(key,NullSupportHelper.NULL())!=NullSupportHelper.NULL() && super.containsKey(key); 421 } 422 /* 423 public boolean containsKey(Collection.Key key) { 424 return get(key,null)!=null && super.containsKey(key); 425 }*/ 426 427 @Override 428 public boolean containsKey(int key) { 429 return key>0 && key<=size(); 430 } 431 432 @Override 433 public List toList() { 434 return ArrayAsList.toList(this); 435 } 436 437 438 @Override 439 public Collection duplicate(boolean deepCopy) { 440 ArgumentImpl trg=new ArgumentImpl(); 441 trg.bind=false; 442 trg.functionArgumentNames=functionArgumentNames; 443 //trg.supportFunctionArguments=supportFunctionArguments; 444 copy(this,trg,deepCopy); 445 return trg; 446 } 447 448 public void setFunctionArgumentNames(Set functionArgumentNames) {// future add to interface 449 this.functionArgumentNames=functionArgumentNames; 450 } 451/* 452 public void setNamedArguments(boolean namedArguments) { 453 this.namedArguments=namedArguments; 454 } 455 public boolean isNamedArguments() { 456 return namedArguments; 457 } 458*/ 459 460 /** 461 * converts a argument scope to a regular struct 462 * @param arg argument scope to convert 463 * @return resulting struct 464 */ 465 public static Struct toStruct(Argument arg) { 466 Struct trg=new StructImpl(); 467 StructImpl.copy(arg, trg, false); 468 return trg; 469 } 470 471 /** 472 * converts a argument scope to a regular array 473 * @param arg argument scope to convert 474 * @return resulting array 475 */ 476 public static Array toArray(Argument arg) { 477 ArrayImpl trg=new ArrayImpl(); 478 int[] keys = arg.intKeys(); 479 for(int i=0;i<keys.length;i++){ 480 trg.setEL(keys[i], 481 arg.get(keys[i],null)); 482 } 483 return trg; 484 } 485 486 @Override 487 public Object get(PageContext pc, Key key, Object defaultValue) { 488 return get(key, defaultValue); 489 } 490 491 @Override 492 public Object get(PageContext pc, Key key) throws PageException { 493 return get(key); 494 } 495 496 @Override 497 public Object set(PageContext pc, Key propertyName, Object value) throws PageException { 498 return set(propertyName, value); 499 } 500 501 @Override 502 public Object setEL(PageContext pc, Key propertyName, Object value) { 503 return setEL(propertyName, value); 504 } 505 506 @Override 507 public Object call(PageContext pc, Key methodName, Object[] args) throws PageException { 508 Object obj = get(methodName,null); 509 if(obj instanceof UDFPlus) { 510 return ((UDFPlus)obj).call(pc,methodName,args,false); 511 } 512 return MemberUtil.call(pc, this, methodName, args, CFTypes.TYPE_STRUCT, "struct"); 513 //return MemberUtil.call(pc, this, methodName, args, CFTypes.TYPE_ARRAY, "array"); 514 } 515 516 @Override 517 public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException { 518 Object obj = get(methodName,null); 519 if(obj instanceof UDFPlus) { 520 return ((UDFPlus)obj).callWithNamedValues(pc,methodName,args,false); 521 } 522 return MemberUtil.callWithNamedValues(pc,this,methodName,args, CFTypes.TYPE_STRUCT, "struct"); 523 //return MemberUtil.callWithNamedValues(pc,this,methodName,args, CFTypes.TYPE_ARRAY, "array"); 524 } 525}