001 package railo.runtime.type; 002 003 import java.util.Collections; 004 import java.util.HashMap; 005 import java.util.Iterator; 006 import java.util.LinkedHashMap; 007 import java.util.Map; 008 import java.util.Set; 009 010 import org.apache.commons.collections.map.ReferenceMap; 011 012 import railo.commons.collections.HashTable; 013 import railo.runtime.exp.ExpressionException; 014 import railo.runtime.exp.PageException; 015 import railo.runtime.op.Caster; 016 import railo.runtime.op.Duplicator; 017 import railo.runtime.op.ThreadLocalDuplication; 018 import railo.runtime.type.it.KeyIterator; 019 import railo.runtime.type.util.StructSupport; 020 021 /** 022 * cold fusion data type struct 023 */ 024 public class StructImpl extends StructSupport { 025 private static final long serialVersionUID = 1421746759512286393L; 026 027 public static final int TYPE_SOFT=4;//FUTURE move to Struct interface 028 029 private Map<Collection.Key,Object> map; 030 031 /** 032 * default constructor 033 */ 034 public StructImpl() { 035 this(TYPE_REGULAR);//asx 036 } 037 038 /** 039 * This implementation spares its clients from the unspecified, 040 * generally chaotic ordering provided by normally Struct , 041 * without incurring the increased cost associated with TreeMap. 042 * It can be used to produce a copy of a map that has the same order as the original 043 * @param doubleLinked 044 */ 045 public StructImpl(int type) { 046 if(type==TYPE_LINKED) map=new LinkedHashMap<Collection.Key,Object>(); 047 else if(type==TYPE_WEAKED) map=new java.util.WeakHashMap<Collection.Key,Object>(); 048 else if(type==TYPE_SOFT) map=new ReferenceMap(); 049 else if(type==TYPE_SYNC) map=Collections.synchronizedMap(new HashMap<Collection.Key,Object>()); 050 else map=new HashMap<Collection.Key,Object>(); 051 } 052 053 private int getType(){ 054 if(map instanceof LinkedHashMap) return TYPE_LINKED; 055 if(map instanceof java.util.WeakHashMap) return TYPE_WEAKED; 056 if(map instanceof ReferenceMap) return TYPE_SOFT; 057 if(map instanceof HashTable) return TYPE_SYNC; 058 return TYPE_REGULAR; 059 } 060 061 062 /** 063 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key, java.lang.Object) 064 */ 065 public Object get(Collection.Key key, Object defaultValue) { 066 Object rtn=map.get(key); 067 if(rtn!=null) return rtn; 068 return defaultValue; 069 } 070 071 /** 072 * 073 * @see railo.runtime.type.Collection#get(railo.runtime.type.Collection.Key) 074 */ 075 public Object get(Collection.Key key) throws PageException {//print.out("k:"+(kcount++)); 076 Object rtn=map.get(key); 077 if(rtn!=null) return rtn; 078 throw invalidKey(key); 079 } 080 081 /** 082 * @see railo.runtime.type.Collection#set(railo.runtime.type.Collection.Key, java.lang.Object) 083 */ 084 public Object set(Collection.Key key, Object value) throws PageException { 085 map.put(key,value); 086 return value; 087 } 088 089 /** 090 * @see railo.runtime.type.Collection#setEL(railo.runtime.type.Collection.Key, java.lang.Object) 091 */ 092 public Object setEL(Collection.Key key, Object value) { 093 map.put(key,value); 094 return value; 095 } 096 097 /** 098 * @see railo.runtime.type.Collection#size() 099 */ 100 public int size() { 101 return map.size(); 102 } 103 104 public Collection.Key[] keys() { 105 try { 106 //Collection.Key[] keys = new Collection.Key[size()]; 107 return map.keySet().toArray(new Key[map.size()]); 108 /*Iterator<Key> it = map.keySet().iterator(); 109 int count=0; 110 while(it.hasNext() && keys.length>count) { 111 keys[count++]=KeyImpl.toKey(it.next(), null); 112 } 113 return keys;*/ 114 } 115 catch(Throwable t) { 116 Map<Key, Object> old = map; 117 try{ 118 map=Collections.synchronizedMap(map); 119 Set<Key> set = map.keySet(); 120 Collection.Key[] keys = new Collection.Key[size()]; 121 synchronized(map){ 122 Iterator<Key> it = set.iterator(); 123 int count=0; 124 while(it.hasNext() && keys.length>count) { 125 keys[count++]=KeyImpl.toKey(it.next(), null); 126 } 127 return keys; 128 } 129 } 130 finally { 131 map=old; 132 } 133 } 134 } 135 136 137 /** 138 * @see railo.runtime.type.Collection#keysAsString() 139 */ 140 public String[] keysAsString() { 141 try { 142 //if(true)throw new RuntimeException(""); 143 String[] keys = new String[size()]; 144 Iterator<Key> it = map.keySet().iterator(); 145 int count=0; 146 while(it.hasNext() && keys.length>count) { 147 keys[count++]=Caster.toString(it.next(), ""); 148 } 149 return keys; 150 } 151 catch(Throwable t) { 152 Map<Key, Object> old = map; 153 try{ 154 map=Collections.synchronizedMap(map); 155 Object[] arr = map.keySet().toArray(); 156 String[] keys = new String[arr.length]; 157 for(int i=0;i<arr.length;i++){ 158 keys[i]=Caster.toString(arr[i], ""); 159 } 160 return keys; 161 } 162 finally { 163 map=old; 164 } 165 } 166 } 167 168 /** 169 * @see railo.runtime.type.Collection#remove(java.lang.String) 170 */ 171 public Object remove(String key) throws PageException { 172 Object obj= map.remove(KeyImpl.init(key)); 173 if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from struct, key doesn't exists"); 174 return obj; 175 } 176 177 /** 178 * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key) 179 */ 180 public Object remove(Collection.Key key) throws PageException { 181 Object obj= map.remove(key); 182 if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from struct, key doesn't exists"); 183 return obj; 184 } 185 186 /** 187 * 188 * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key) 189 */ 190 public Object removeEL(Collection.Key key) { 191 return map.remove(key); 192 } 193 194 /** 195 * @see railo.runtime.type.Collection#clear() 196 */ 197 public void clear() { 198 map.clear(); 199 } 200 201 202 /** 203 * @see railo.runtime.type.Collection#duplicate(boolean) 204 */ 205 public Collection duplicate(boolean deepCopy) { 206 Struct sct=new StructImpl(getType()); 207 copy(this,sct,deepCopy); 208 return sct; 209 } 210 211 public static void copy(Struct src,Struct trg,boolean deepCopy) { 212 ThreadLocalDuplication.set(src,trg); 213 try{ 214 Key[] keys = src.keys(); 215 Key key; 216 for(int i=0;i<keys.length;i++) { 217 key=keys[i]; 218 if(!deepCopy) trg.setEL(key,src.get(key,null)); 219 else trg.setEL(key,Duplicator.duplicate(src.get(key,null),deepCopy)); 220 } 221 } 222 finally { 223 ThreadLocalDuplication.remove(src); 224 } 225 } 226 227 228 229 /** 230 * @see railo.runtime.type.Collection#keyIterator() 231 */ 232 public Iterator keyIterator() { 233 return new KeyIterator(keys()); 234 } 235 236 /** 237 * @see railo.runtime.type.Iteratorable#iterator() 238 */ 239 public Iterator valueIterator() { 240 return values().iterator(); 241 } 242 243 /** 244 * @see railo.runtime.type.Collection#_contains(java.lang.String) 245 */ 246 public boolean containsKey(Collection.Key key) { 247 return map.containsKey(key); 248 } 249 250 /** 251 * @see java.util.Map#containsValue(java.lang.Object) 252 */ 253 public boolean containsValue(Object value) { 254 return map.containsValue(value); 255 } 256 257 /** 258 * @see java.util.Map#values() 259 */ 260 public java.util.Collection values() { 261 return map.values(); 262 } 263 264 /** 265 * @return the map 266 */ 267 protected Map<Collection.Key,Object> getMap() { 268 return map; 269 } 270 }