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