package railo.runtime.type.scope; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import railo.commons.lang.CFTypes; import railo.runtime.PageContext; import railo.runtime.config.NullSupportHelper; import railo.runtime.dump.DumpData; import railo.runtime.dump.DumpProperties; import railo.runtime.dump.DumpTable; import railo.runtime.dump.DumpUtil; import railo.runtime.dump.SimpleDumpData; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.type.Array; import railo.runtime.type.ArrayImpl; import railo.runtime.type.Collection; import railo.runtime.type.KeyImpl; import railo.runtime.type.Null; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.UDFPlus; import railo.runtime.type.util.CollectionUtil; import railo.runtime.type.util.MemberUtil; import railo.runtime.type.wrap.ArrayAsList; /** * implementation of the argument scope */ public final class ArgumentImpl extends ScopeSupport implements Argument { private boolean bind; private Set functionArgumentNames; //private boolean supportFunctionArguments; /** * constructor of the class */ public ArgumentImpl() { super("arguments",SCOPE_ARGUMENTS,Struct.TYPE_LINKED); //this(true); } @Override public void release() { release(null); } @Override public void release(PageContext pc) { functionArgumentNames=null; if(pc==null)super.release(); else super.release(pc); } @Override public void setBind(boolean bind) { this.bind=bind; } @Override public boolean isBind() { return this.bind; } public Object getFunctionArgument(String key, Object defaultValue) { return getFunctionArgument(KeyImpl.getInstance(key), defaultValue); } public Object getFunctionArgument(Collection.Key key, Object defaultValue) { return super.get(key,defaultValue); } @Override public boolean containsFunctionArgumentKey(Key key) { return super.containsKey(key);//functionArgumentNames!=null && functionArgumentNames.contains(key); } @Override public Object get(Collection.Key key, Object defaultValue) { /*if(NullSupportHelper.full()) { Object o=super.get(key,NullSupportHelper.NULL()); if(o!=NullSupportHelper.NULL())return o; o=get(Caster.toIntValue(key.getString(),-1),NullSupportHelper.NULL()); if(o!=NullSupportHelper.NULL())return o; return defaultValue; }*/ Object o=super.g(key,Null.NULL); if(o!=Null.NULL)return o; o=get(Caster.toIntValue(key.getString(),-1),Null.NULL); if(o!=Null.NULL)return o; return defaultValue; } @Override public Object get(Collection.Key key) throws ExpressionException { /*if(NullSupportHelper.full()) { Object o=super.get(key,NullSupportHelper.NULL()); if(o!=NullSupportHelper.NULL())return o; o=get(Caster.toIntValue(key.getString(),-1),NullSupportHelper.NULL()); if(o!=NullSupportHelper.NULL())return o; throw new ExpressionException("key ["+key.getString()+"] doesn't exist in argument scope. existing keys are ["+ railo.runtime.type.List.arrayToList(CollectionUtil.keys(this),", ") +"]"); }*/ // null is supported as returned value with argument scope Object o=super.g(key,Null.NULL); if(o!=Null.NULL)return o; o=get(Caster.toIntValue(key.getString(),-1),Null.NULL); if(o!=Null.NULL)return o; throw new ExpressionException("key ["+key.getString()+"] doesn't exist in argument scope. existing keys are ["+ railo.runtime.type.util.ListUtil.arrayToList(CollectionUtil.keys(this),", ") +"]"); } @Override public Object get(int intKey, Object defaultValue) { Iterator<Object> it = valueIterator(); //keyIterator();//getMap().keySet().iterator(); int count=0; Object o; while(it.hasNext()) { o=it.next(); if((++count)==intKey) { return o;//super.get(o.toString(),defaultValue); } } return defaultValue; } /** * return a value matching to key * @param intKey * @return value matching key * @throws PageException */ public Object getE(int intKey) throws PageException { Iterator it = valueIterator();//getMap().keySet().iterator(); int count=0; Object o; while(it.hasNext()) { o=it.next(); if((++count)==intKey) { return o;//super.get(o.toString()); } } throw new ExpressionException("invalid index ["+intKey+"] for argument scope"); } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { DumpTable htmlBox = new DumpTable("struct","#9999ff","#ccccff","#000000"); htmlBox.setTitle("Scope Arguments"); if(size()>10 && dp.getMetainfo())htmlBox.setComment("Entries:"+size()); maxlevel--; //Map mapx=getMap(); Iterator<Key> it = keyIterator();//mapx.keySet().iterator(); int count=0; Collection.Key key; int maxkeys=dp.getMaxKeys(); int index=0; while(it.hasNext()) { key=it.next();//it.next(); if(DumpUtil.keyValid(dp, maxlevel,key)){ if(maxkeys<=index++)break; htmlBox.appendRow(3, new SimpleDumpData(key.getString()), new SimpleDumpData(++count), DumpUtil.toDumpData(get(key,null), pageContext,maxlevel,dp)); } } return htmlBox; } @Override public int getDimension() { return 1; } @Override public Object setEL(int intKey, Object value) { int count=0; if(intKey>size()) { return setEL(Caster.toString(intKey),value); } //Iterator it = keyIterator(); Key[] keys = keys(); for(int i=0;i<keys.length;i++) { if((++count)==intKey) { return super.setEL(keys[i],value); } } return value; } @Override public Object setE(int intKey, Object value) throws PageException { if(intKey>size()) { return set(Caster.toString(intKey),value); } //Iterator it = keyIterator(); Key[] keys = keys(); for(int i=0;i<keys.length;i++) { if((i+1)==intKey) { return super.set(keys[i],value); } } throw new ExpressionException("invalid index ["+intKey+"] for argument scope"); } @Override public int[] intKeys() { int[] ints=new int[size()]; for(int i=0;i<ints.length;i++)ints[i]=i+1; return ints; } @Override public boolean insert(int index, Object value) throws ExpressionException { return insert(index, ""+index, value); } @Override public boolean insert(int index, String key, Object value) throws ExpressionException { int len=size(); if(index<1 || index>len) 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)); // remove all upper LinkedHashMap lhm = new LinkedHashMap(); Collection.Key[] keys=keys(); Collection.Key k; for(int i=1;i<=keys.length;i++) { if(i<index)continue; k=keys[i-1]; lhm.put(k.getString(),get(k,null)); removeEL(k); } // set new value setEL(key,value); // reset upper values Iterator it = lhm.entrySet().iterator(); Map.Entry entry; while(it.hasNext()) { entry=(Entry) it.next(); setEL(KeyImpl.toKey(entry.getKey()),entry.getValue()); } return true; } @Override public Object append(Object o) throws PageException { return set(Caster.toString(size()+1),o); } @Override public Object appendEL(Object o) { try { return append(o); } catch (PageException e) { return null; } } @Override public Object prepend(Object o) throws PageException { for(int i=size();i>0;i--) { setE(i+1,getE(i)); } setE(1,o); return o; } @Override public void resize(int to) throws PageException { for(int i=size(); i<to; i++) { append(null); } //throw new ExpressionException("can't resize this array"); } @Override public void sort(String sortType, String sortOrder) throws ExpressionException { // TODO Impl. throw new ExpressionException("can't sort ["+sortType+"-"+sortOrder+"] Argument Scope","not Implemnted Yet"); } public void sort(Comparator com) throws ExpressionException { // TODO Impl. throw new ExpressionException("can't sort Argument Scope","not Implemnted Yet"); } @Override public Object[] toArray() { Iterator it = keyIterator();//getMap().keySet().iterator(); Object[] arr=new Object[size()]; int count=0; while(it.hasNext()) { arr[count++]=it.next(); } return arr; } public Object setArgument(Object obj) throws PageException { if(obj==this) return obj; if(Decision.isStruct(obj)) { clear(); // TODO bessere impl. anstelle vererbung wrao auf struct Struct sct=Caster.toStruct(obj); Iterator<Key> it = sct.keyIterator(); Key key; while(it.hasNext()) { key=it.next(); setEL(key, sct.get(key,null)); } return obj; } throw new ExpressionException("can not overwrite arguments scope"); } public ArrayList toArrayList() { ArrayList list = new ArrayList(); Object[] arr = toArray(); for(int i=0;i<arr.length;i++) { list.add(arr[i]); } return list; } @Override public Object removeE(int intKey) throws PageException { Key[] keys = keys(); for(int i=0;i<keys.length;i++) { if((i+1)==intKey) { return super.remove(keys[i]); } } throw new ExpressionException("can't remove argument number ["+intKey+"], argument doesn't exist"); } @Override public Object removeEL(int intKey) { Key[] keys = keys(); for(int i=0;i<keys.length;i++) { if((i+1)==intKey) { return super.removeEL (keys[i]); } } return null; } @Override public boolean containsKey(Collection.Key key) { if(NullSupportHelper.full()) return super.containsKey(key); return super.g(key,null)!=null; // return get(key,NullSupportHelper.NULL())!=NullSupportHelper.NULL() && super.containsKey(key); } /* public boolean containsKey(Collection.Key key) { return get(key,null)!=null && super.containsKey(key); }*/ @Override public boolean containsKey(int key) { return key>0 && key<=size(); } @Override public List toList() { return ArrayAsList.toList(this); } @Override public Collection duplicate(boolean deepCopy) { ArgumentImpl trg=new ArgumentImpl(); trg.bind=false; trg.functionArgumentNames=functionArgumentNames; //trg.supportFunctionArguments=supportFunctionArguments; copy(this,trg,deepCopy); return trg; } public void setFunctionArgumentNames(Set functionArgumentNames) {// future add to interface this.functionArgumentNames=functionArgumentNames; } /* public void setNamedArguments(boolean namedArguments) { this.namedArguments=namedArguments; } public boolean isNamedArguments() { return namedArguments; } */ /** * converts a argument scope to a regular struct * @param arg argument scope to convert * @return resulting struct */ public static Struct toStruct(Argument arg) { Struct trg=new StructImpl(); StructImpl.copy(arg, trg, false); return trg; } /** * converts a argument scope to a regular array * @param arg argument scope to convert * @return resulting array */ public static Array toArray(Argument arg) { ArrayImpl trg=new ArrayImpl(); int[] keys = arg.intKeys(); for(int i=0;i<keys.length;i++){ trg.setEL(keys[i], arg.get(keys[i],null)); } return trg; } @Override public Object get(PageContext pc, Key key, Object defaultValue) { return get(key, defaultValue); } @Override public Object get(PageContext pc, Key key) throws PageException { return get(key); } @Override public Object set(PageContext pc, Key propertyName, Object value) throws PageException { return set(propertyName, value); } @Override public Object setEL(PageContext pc, Key propertyName, Object value) { return setEL(propertyName, value); } @Override public Object call(PageContext pc, Key methodName, Object[] args) throws PageException { Object obj = get(methodName,null); if(obj instanceof UDFPlus) { return ((UDFPlus)obj).call(pc,methodName,args,false); } return MemberUtil.call(pc, this, methodName, args, CFTypes.TYPE_ARRAY, "array"); } @Override public Object callWithNamedValues(PageContext pc, Key methodName, Struct args) throws PageException { Object obj = get(methodName,null); if(obj instanceof UDFPlus) { return ((UDFPlus)obj).callWithNamedValues(pc,methodName,args,false); } return MemberUtil.callWithNamedValues(pc,this,methodName,args, CFTypes.TYPE_ARRAY, "array"); } }