001 package railo.runtime.type; 002 003 import java.util.HashMap; 004 import java.util.Iterator; 005 import java.util.LinkedHashMap; 006 import java.util.Map; 007 008 import railo.commons.collections.HashTable; 009 import railo.commons.lang.StringUtil; 010 import railo.runtime.PageContext; 011 import railo.runtime.dump.DumpData; 012 import railo.runtime.dump.DumpProperties; 013 import railo.runtime.dump.DumpTable; 014 import railo.runtime.dump.DumpTablePro; 015 import railo.runtime.dump.DumpUtil; 016 import railo.runtime.dump.SimpleDumpData; 017 import railo.runtime.exp.ExpressionException; 018 import railo.runtime.exp.PageException; 019 import railo.runtime.op.Duplicator; 020 import railo.runtime.op.ThreadLocalDuplication; 021 import railo.runtime.type.dt.DateTime; 022 import railo.runtime.type.util.StructSupport; 023 024 /** 025 * cold fusion data type struct 026 */ 027 public final class StructImplKey extends StructSupport implements Struct { 028 029 public static final int TYPE_WEAKED=0; 030 public static final int TYPE_LINKED=1; 031 public static final int TYPE_SYNC=2; 032 public static final int TYPE_REGULAR=3; 033 034 private Map _map; 035 //private static int scount=0; 036 //private static int kcount=0; 037 038 /** 039 * default constructor 040 */ 041 public StructImplKey() { 042 _map=new HashMap(); 043 } 044 045 /** 046 * This implementation spares its clients from the unspecified, 047 * generally chaotic ordering provided by normally Struct , 048 * without incurring the increased cost associated with TreeMap. 049 * It can be used to produce a copy of a map that has the same order as the original 050 * @param doubleLinked 051 */ 052 public StructImplKey(int type) { 053 if(type==TYPE_LINKED) _map=new LinkedHashMap(); 054 else if(type==TYPE_WEAKED) _map=new java.util.WeakHashMap(); 055 else if(type==TYPE_SYNC) _map=new HashTable(); 056 else _map=new HashMap(); 057 } 058 059 /** 060 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object) 061 */ 062 public Object get(Collection.Key key, Object defaultValue) { 063 Object rtn=_map.get(key); 064 if(rtn!=null) return rtn; 065 return defaultValue; 066 } 067 068 /** 069 * 070 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key) 071 */ 072 public Object get(Collection.Key key) throws PageException {//print.out("k:"+(kcount++)); 073 Object rtn=_map.get(key); 074 if(rtn!=null) return rtn; 075 throw invalidKey(key.getString()); 076 } 077 078 /** 079 * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object) 080 */ 081 public Object set(Collection.Key key, Object value) throws PageException { 082 _map.put(key,value); 083 return value; 084 } 085 086 /** 087 * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object) 088 */ 089 public Object setEL(Collection.Key key, Object value) { 090 _map.put(key,value); 091 return value; 092 } 093 094 /** 095 * @see railo.runtime.type.Collection#size() 096 */ 097 public int size() { 098 return _map.size(); 099 } 100 101 public Collection.Key[] keys() {//print.out("keys"); 102 Iterator it = keyIterator(); 103 Collection.Key[] keys = new Collection.Key[size()]; 104 int count=0; 105 while(it.hasNext()) { 106 keys[count++]=KeyImpl.toKey(it.next(), null); 107 } 108 return keys; 109 } 110 111 /** 112 * @see railo.runtime.type.Collection#keysAsString() 113 */ 114 public String[] keysAsString() { 115 Iterator it = keyIterator(); 116 String[] keys = new String[size()]; 117 int count=0; 118 while(it.hasNext()) { 119 keys[count++]=StringUtil.toString(it.next(), null); 120 } 121 return keys; 122 } 123 124 /** 125 * @see railo.runtime.type.Collection#remove(java.lang.String) 126 */ 127 public Object remove(String key) throws PageException { 128 Object obj= _map.remove(StringUtil.toLowerCase(key)); 129 if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from struct, key doesn't exists"); 130 return obj; 131 } 132 133 /** 134 * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key) 135 */ 136 public Object remove(Collection.Key key) throws PageException { 137 Object obj= _map.remove(key); 138 if(obj==null) throw new ExpressionException("can't remove key ["+key.getString()+"] from struct, key doesn't exists"); 139 return obj; 140 } 141 142 /** 143 * 144 * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key) 145 */ 146 public Object removeEL(Collection.Key key) { 147 return _map.remove(key); 148 } 149 150 /** 151 * @see railo.runtime.type.Collection#clear() 152 */ 153 public void clear() { 154 _map.clear(); 155 } 156 157 /** 158 * 159 * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int) 160 */ 161 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 162 Iterator it=_map.keySet().iterator(); 163 164 DumpTable table = new DumpTablePro("struct","#9999ff","#ccccff","#000000"); 165 table.setTitle("Struct"); 166 maxlevel--; 167 int maxkeys=dp.getMaxKeys(); 168 int index=0; 169 while(it.hasNext()) { 170 Object key=it.next(); 171 if(DumpUtil.keyValid(dp, maxlevel,key.toString())){ 172 if(maxkeys<=index++)break; 173 table.appendRow(1,new SimpleDumpData(key.toString()),DumpUtil.toDumpData(_map.get(key), pageContext,maxlevel,dp)); 174 } 175 } 176 return table; 177 } 178 179 /** 180 * throw exception for invalid key 181 * @param key Invalid key 182 * @return returns a invalid key Exception 183 */ 184 protected ExpressionException invalidKey(String key) { 185 return new ExpressionException("key ["+key+"] doesn't exist in struct"); 186 } 187 188 /** 189 * @see railo.runtime.type.Collection#duplicate(boolean) 190 */ 191 public Collection duplicate(boolean deepCopy) { 192 Struct sct=new StructImplKey(); 193 copy(this,sct,deepCopy); 194 return sct; 195 } 196 197 198 public static void copy(Struct src,Struct trg,boolean deepCopy) { 199 ThreadLocalDuplication.set(src, trg); 200 try { 201 Collection.Key[] keys=src.keys(); 202 Collection.Key key; 203 for(int i=0;i<keys.length;i++) { 204 key=keys[i]; 205 if(!deepCopy) trg.setEL(key,src.get(key,null)); 206 else trg.setEL(key,Duplicator.duplicate(src.get(key,null),deepCopy)); 207 } 208 } 209 finally { 210 ThreadLocalDuplication.remove(src); 211 } 212 } 213 214 /** 215 * @see railo.runtime.type.Collection#keyIterator() 216 */ 217 public Iterator keyIterator() { 218 //return new ArrayIterator(map.keySet().toArray()); 219 return _map.keySet().iterator(); 220 } 221 222 /** 223 * @see railo.runtime.type.Iteratorable#iterator() 224 */ 225 public Iterator valueIterator() { 226 return values().iterator(); 227 } 228 229 /** 230 * @see railo.runtime.type.Collection#_contains(java.lang.String) 231 */ 232 public boolean containsKey(Collection.Key key) { 233 return _map.containsKey(key); 234 } 235 236 /** 237 * @see railo.runtime.op.Castable#castToString() 238 */ 239 public String castToString() throws ExpressionException { 240 throw new ExpressionException("Can't cast Complex Object Type Struct to String", 241 "Use Build-In-Function \"serialize(Struct):String\" to create a String from Struct"); 242 } 243 244 /** 245 * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String) 246 */ 247 public String castToString(String defaultValue) { 248 return defaultValue; 249 } 250 251 /** 252 * @see railo.runtime.op.Castable#castToBooleanValue() 253 */ 254 public boolean castToBooleanValue() throws ExpressionException { 255 throw new ExpressionException("can't cast Complex Object Type Struct to a boolean value"); 256 } 257 258 /** 259 * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean) 260 */ 261 public Boolean castToBoolean(Boolean defaultValue) { 262 return defaultValue; 263 } 264 265 266 /** 267 * @see railo.runtime.op.Castable#castToDoubleValue() 268 */ 269 public double castToDoubleValue() throws ExpressionException { 270 throw new ExpressionException("can't cast Complex Object Type Struct to a number value"); 271 } 272 273 /** 274 * @see railo.runtime.op.Castable#castToDoubleValue(double) 275 */ 276 public double castToDoubleValue(double defaultValue) { 277 return defaultValue; 278 } 279 280 281 /** 282 * @see railo.runtime.op.Castable#castToDateTime() 283 */ 284 public DateTime castToDateTime() throws ExpressionException { 285 throw new ExpressionException("can't cast Complex Object Type Struct to a Date"); 286 } 287 288 /** 289 * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime) 290 */ 291 public DateTime castToDateTime(DateTime defaultValue) { 292 return defaultValue; 293 } 294 295 /** 296 * @see railo.runtime.op.Castable#compare(boolean) 297 */ 298 public int compareTo(boolean b) throws ExpressionException { 299 throw new ExpressionException("can't compare Complex Object Type Struct with a boolean value"); 300 } 301 302 /** 303 * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime) 304 */ 305 public int compareTo(DateTime dt) throws PageException { 306 throw new ExpressionException("can't compare Complex Object Type Struct with a DateTime Object"); 307 } 308 309 /** 310 * @see railo.runtime.op.Castable#compareTo(double) 311 */ 312 public int compareTo(double d) throws PageException { 313 throw new ExpressionException("can't compare Complex Object Type Struct with a numeric value"); 314 } 315 316 /** 317 * @see railo.runtime.op.Castable#compareTo(java.lang.String) 318 */ 319 public int compareTo(String str) throws PageException { 320 throw new ExpressionException("can't compare Complex Object Type Struct with a String"); 321 } 322 323 public boolean containsValue(Object value) { 324 return _map.containsValue(value); 325 } 326 327 public java.util.Collection values() { 328 return _map.values(); 329 } 330 331 }