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