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.runtime.PageContext; 010 import railo.runtime.dump.DumpData; 011 import railo.runtime.dump.DumpProperties; 012 import railo.runtime.dump.DumpTable; 013 import railo.runtime.dump.DumpUtil; 014 import railo.runtime.dump.SimpleDumpData; 015 import railo.runtime.exp.ExpressionException; 016 import railo.runtime.exp.PageException; 017 import railo.runtime.op.Duplicator; 018 import railo.runtime.op.ThreadLocalDuplication; 019 import railo.runtime.type.dt.DateTime; 020 import railo.runtime.type.it.EntryIterator; 021 import railo.runtime.type.it.StringIterator; 022 import railo.runtime.type.util.StructSupport; 023 024 /** 025 * CFML 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<Collection.Key,Object> _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<Collection.Key,Object>(); 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<Collection.Key,Object>(); 054 else if(type==TYPE_WEAKED) _map=new java.util.WeakHashMap<Collection.Key,Object>(); 055 else if(type==TYPE_SYNC) _map=new HashTable(); 056 else _map=new HashMap<Collection.Key,Object>(); 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<Key> it = keyIterator(); 103 Collection.Key[] keys = new Collection.Key[size()]; 104 int count=0; 105 while(it.hasNext()) { 106 keys[count++]=it.next(); 107 } 108 return keys; 109 } 110 111 /** 112 * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key) 113 */ 114 public Object remove(Collection.Key key) throws PageException { 115 Object obj= _map.remove(key); 116 if(obj==null) throw new ExpressionException("can't remove key ["+key.getString()+"] from struct, key doesn't exist"); 117 return obj; 118 } 119 120 /** 121 * 122 * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key) 123 */ 124 public Object removeEL(Collection.Key key) { 125 return _map.remove(key); 126 } 127 128 /** 129 * @see railo.runtime.type.Collection#clear() 130 */ 131 public void clear() { 132 _map.clear(); 133 } 134 135 /** 136 * 137 * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int) 138 */ 139 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 140 Iterator it=_map.keySet().iterator(); 141 142 DumpTable table = new DumpTable("struct","#9999ff","#ccccff","#000000"); 143 table.setTitle("Struct"); 144 maxlevel--; 145 int maxkeys=dp.getMaxKeys(); 146 int index=0; 147 while(it.hasNext()) { 148 Object key=it.next(); 149 if(DumpUtil.keyValid(dp, maxlevel,key.toString())){ 150 if(maxkeys<=index++)break; 151 table.appendRow(1,new SimpleDumpData(key.toString()),DumpUtil.toDumpData(_map.get(key), pageContext,maxlevel,dp)); 152 } 153 } 154 return table; 155 } 156 157 /** 158 * throw exception for invalid key 159 * @param key Invalid key 160 * @return returns an invalid key Exception 161 */ 162 protected ExpressionException invalidKey(String key) { 163 return new ExpressionException("key ["+key+"] doesn't exist in struct"); 164 } 165 166 /** 167 * @see railo.runtime.type.Collection#duplicate(boolean) 168 */ 169 public Collection duplicate(boolean deepCopy) { 170 Struct sct=new StructImplKey(); 171 copy(this,sct,deepCopy); 172 return sct; 173 } 174 175 176 public static void copy(Struct src,Struct trg,boolean deepCopy) { 177 ThreadLocalDuplication.set(src, trg); 178 try { 179 Iterator<Entry<Key, Object>> it = src.entryIterator(); 180 Entry<Key, Object> e; 181 while(it.hasNext()) { 182 e = it.next(); 183 if(!deepCopy) trg.setEL(e.getKey(),e.getValue()); 184 else trg.setEL(e.getKey(),Duplicator.duplicate(e.getValue(),deepCopy)); 185 } 186 } 187 finally { 188 //ThreadLocalDuplication.remove(src); removed "remove" to catch sisters and brothers 189 } 190 } 191 192 @Override 193 public Iterator<Collection.Key> keyIterator() { 194 return _map.keySet().iterator(); 195 } 196 197 @Override 198 public Iterator<String> keysAsStringIterator() { 199 return new StringIterator(keys()); 200 } 201 202 @Override 203 public Iterator<Entry<Key, Object>> entryIterator() { 204 return new EntryIterator(this, keys()); 205 } 206 207 /** 208 * @see railo.runtime.type.Iteratorable#iterator() 209 */ 210 public Iterator valueIterator() { 211 return _map.values().iterator(); 212 } 213 214 /** 215 * @see railo.runtime.type.Collection#_contains(java.lang.String) 216 */ 217 public boolean containsKey(Collection.Key key) { 218 return _map.containsKey(key); 219 } 220 221 /** 222 * @see railo.runtime.op.Castable#castToString() 223 */ 224 public String castToString() throws ExpressionException { 225 throw new ExpressionException("Can't cast Complex Object Type Struct to String", 226 "Use Built-In-Function \"serialize(Struct):String\" to create a String from Struct"); 227 } 228 229 /** 230 * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String) 231 */ 232 public String castToString(String defaultValue) { 233 return defaultValue; 234 } 235 236 /** 237 * @see railo.runtime.op.Castable#castToBooleanValue() 238 */ 239 public boolean castToBooleanValue() throws ExpressionException { 240 throw new ExpressionException("can't cast Complex Object Type Struct to a boolean value"); 241 } 242 243 /** 244 * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean) 245 */ 246 public Boolean castToBoolean(Boolean defaultValue) { 247 return defaultValue; 248 } 249 250 251 /** 252 * @see railo.runtime.op.Castable#castToDoubleValue() 253 */ 254 public double castToDoubleValue() throws ExpressionException { 255 throw new ExpressionException("can't cast Complex Object Type Struct to a number value"); 256 } 257 258 /** 259 * @see railo.runtime.op.Castable#castToDoubleValue(double) 260 */ 261 public double castToDoubleValue(double defaultValue) { 262 return defaultValue; 263 } 264 265 266 /** 267 * @see railo.runtime.op.Castable#castToDateTime() 268 */ 269 public DateTime castToDateTime() throws ExpressionException { 270 throw new ExpressionException("can't cast Complex Object Type Struct to a Date"); 271 } 272 273 /** 274 * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime) 275 */ 276 public DateTime castToDateTime(DateTime defaultValue) { 277 return defaultValue; 278 } 279 280 /** 281 * @see railo.runtime.op.Castable#compare(boolean) 282 */ 283 public int compareTo(boolean b) throws ExpressionException { 284 throw new ExpressionException("can't compare Complex Object Type Struct with a boolean value"); 285 } 286 287 /** 288 * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime) 289 */ 290 public int compareTo(DateTime dt) throws PageException { 291 throw new ExpressionException("can't compare Complex Object Type Struct with a DateTime Object"); 292 } 293 294 /** 295 * @see railo.runtime.op.Castable#compareTo(double) 296 */ 297 public int compareTo(double d) throws PageException { 298 throw new ExpressionException("can't compare Complex Object Type Struct with a numeric value"); 299 } 300 301 /** 302 * @see railo.runtime.op.Castable#compareTo(java.lang.String) 303 */ 304 public int compareTo(String str) throws PageException { 305 throw new ExpressionException("can't compare Complex Object Type Struct with a String"); 306 } 307 308 public boolean containsValue(Object value) { 309 return _map.containsValue(value); 310 } 311 312 public java.util.Collection values() { 313 return _map.values(); 314 } 315 316 }