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.wrap; 020 021import java.util.Iterator; 022import java.util.Map; 023 024import lucee.commons.lang.StringUtil; 025import lucee.runtime.PageContext; 026import lucee.runtime.dump.DumpData; 027import lucee.runtime.dump.DumpProperties; 028import lucee.runtime.dump.DumpUtil; 029import lucee.runtime.exp.ExpressionException; 030import lucee.runtime.exp.PageException; 031import lucee.runtime.op.Caster; 032import lucee.runtime.op.Duplicator; 033import lucee.runtime.type.Collection; 034import lucee.runtime.type.KeyImpl; 035import lucee.runtime.type.Struct; 036import lucee.runtime.type.dt.DateTime; 037import lucee.runtime.type.it.EntryIterator; 038import lucee.runtime.type.it.KeyIterator; 039import lucee.runtime.type.it.StringIterator; 040import lucee.runtime.type.it.ValueIterator; 041import lucee.runtime.type.util.StructSupport; 042 043/** 044 * 045 */ 046public class MapAsStruct extends StructSupport implements Struct { 047 048 Map map; 049 private boolean caseSensitive; 050 051 /** 052 * constructor of the class 053 * @param map 054 * @param caseSensitive 055 */ 056 private MapAsStruct(Map map, boolean caseSensitive) { 057 this.map=map; 058 this.caseSensitive=caseSensitive; 059 } 060 061 062 public static Struct toStruct(Map map) { 063 return toStruct(map,false); 064 } 065 066 public static Struct toStruct(Map map, boolean caseSensitive) { 067 if(map instanceof Struct) return ((Struct)map); 068 return new MapAsStruct(map,caseSensitive); 069 } 070 071 @Override 072 public int size() { 073 return map.size(); 074 } 075 076 @Override 077 public synchronized Collection.Key[] keys() { 078 int len=size(); 079 Collection.Key[] k=new Collection.Key[len]; 080 Iterator it = map.keySet().iterator(); 081 int count=0; 082 while(it.hasNext()) { 083 k[count++]=KeyImpl.init(StringUtil.toStringNative(it.next(),"")); 084 } 085 return k; 086 } 087 088 public static String getCaseSensitiveKey(Map map,String key) { 089 Iterator it = map.keySet().iterator(); 090 String strKey; 091 while(it.hasNext()) { 092 strKey=Caster.toString(it.next(),""); 093 if(strKey.equalsIgnoreCase(key)) return strKey; 094 } 095 return null; 096 } 097 098 @Override 099 public synchronized Object remove(Collection.Key key) throws ExpressionException { 100 Object obj= map.remove(key.getString()); 101 if(obj==null) { 102 if(map.containsKey(key.getString())) return null; 103 if(!caseSensitive){ 104 String csKey = getCaseSensitiveKey(map,key.getString()); 105 if(csKey!=null)obj= map.remove(csKey); 106 if(obj!=null)return obj; 107 } 108 throw new ExpressionException("can't remove key ["+key.getString()+"] from map, key doesn't exist"); 109 } 110 return obj; 111 } 112 113 @Override 114 public synchronized Object removeEL(Collection.Key key) { 115 Object obj= map.remove(key.getString()); 116 if(!caseSensitive && obj==null) { 117 String csKey = getCaseSensitiveKey(map,key.getString()); 118 if(csKey!=null)obj= map.remove(csKey); 119 } 120 return obj; 121 } 122 123 @Override 124 public synchronized void clear() { 125 map.clear(); 126 } 127 128 @Override 129 public synchronized Object get(Collection.Key key) throws ExpressionException { 130 Object o=map.get(key.getString()); 131 if(o==null) { 132 if(map.containsKey(key.getString())) return null; 133 if(!caseSensitive){ 134 String csKey = getCaseSensitiveKey(map,key.getString()); 135 if(csKey!=null)o= map.get(csKey); 136 if(o!=null || map.containsKey(csKey)) return o; 137 } 138 throw new ExpressionException("key "+key.getString()+" doesn't exist in "+Caster.toClassName(map)); 139 } 140 return o; 141 } 142 143 @Override 144 public synchronized Object get(Collection.Key key, Object defaultValue) { 145 Object obj=map.get(key.getString()); 146 if(obj==null) { 147 if(map.containsKey(key.getString())) return null; 148 if(!caseSensitive){ 149 String csKey = getCaseSensitiveKey(map,key.getString()); 150 if(csKey!=null)obj= map.get(csKey); 151 if(obj!=null || map.containsKey(csKey)) return obj; 152 } 153 return defaultValue; 154 } 155 return obj; 156 } 157 158 @Override 159 public synchronized Object set(Collection.Key key, Object value) throws PageException { 160 return map.put(key.getString(),value); 161 } 162 163 @Override 164 public synchronized Object setEL(Collection.Key key, Object value) { 165 return map.put(key.getString(),value); 166 } 167 168 @Override 169 public synchronized Iterator<Collection.Key> keyIterator() { 170 return new KeyIterator(keys()); 171 } 172 173 @Override 174 public Iterator<String> keysAsStringIterator() { 175 return new StringIterator(keys()); 176 } 177 178 @Override 179 public Iterator<Entry<Key, Object>> entryIterator() { 180 return new EntryIterator(this,keys()); 181 } 182 183 @Override 184 public Iterator<Object> valueIterator() { 185 return new ValueIterator(this,keys()); 186 } 187 188 189 190 @Override 191 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 192 return DumpUtil.toDumpData(map, pageContext,maxlevel,dp); 193 } 194 195 @Override 196 public synchronized Collection duplicate(boolean deepCopy) { 197 return new MapAsStruct(Duplicator.duplicateMap(map,deepCopy),caseSensitive); 198 } 199 200 201 202 @Override 203 public boolean containsKey(Collection.Key key) { 204 205 //return map.containsKey(key.getString()); 206 207 boolean contains = map.containsKey(key.getString()); 208 if(contains) return true; 209 if(!caseSensitive)return map.containsKey(getCaseSensitiveKey(map,key.getString())); 210 return false; 211 } 212 213 @Override 214 public String castToString() throws ExpressionException { 215 throw new ExpressionException("Can't cast Complex Object Type Struct ["+getClass().getName()+"] to String", 216 "Use Built-In-Function \"serialize(Struct):String\" to create a String from Struct"); 217 } 218 @Override 219 public String castToString(String defaultValue) { 220 return defaultValue; 221 } 222 223 224 @Override 225 public boolean castToBooleanValue() throws ExpressionException { 226 throw new ExpressionException("Can't cast Complex Object Type Struct ["+getClass().getName()+"] to a boolean value"); 227 } 228 229 @Override 230 public Boolean castToBoolean(Boolean defaultValue) { 231 return defaultValue; 232 } 233 234 235 @Override 236 public double castToDoubleValue() throws ExpressionException { 237 throw new ExpressionException("Can't cast Complex Object Type Struct ["+getClass().getName()+"] to a number value"); 238 } 239 240 @Override 241 public double castToDoubleValue(double defaultValue) { 242 return defaultValue; 243 } 244 245 246 @Override 247 public DateTime castToDateTime() throws ExpressionException { 248 throw new ExpressionException("Can't cast Complex Object Type Struct ["+getClass().getName()+"] to a Date"); 249 } 250 251 @Override 252 public DateTime castToDateTime(DateTime defaultValue) { 253 return defaultValue; 254 } 255 256 @Override 257 public int compareTo(boolean b) throws ExpressionException { 258 throw new ExpressionException("can't compare Complex Object Type Struct ["+getClass().getName()+"] with a boolean value"); 259 } 260 261 @Override 262 public int compareTo(DateTime dt) throws PageException { 263 throw new ExpressionException("can't compare Complex Object Type Struct ["+getClass().getName()+"] with a DateTime Object"); 264 } 265 266 @Override 267 public int compareTo(double d) throws PageException { 268 throw new ExpressionException("can't compare Complex Object Type Struct ["+getClass().getName()+"] with a numeric value"); 269 } 270 271 @Override 272 public int compareTo(String str) throws PageException { 273 throw new ExpressionException("can't compare Complex Object Type Struct ["+getClass().getName()+"] with a String"); 274 } 275 276 @Override 277 public boolean containsValue(Object value) { 278 return map.containsValue(value); 279 } 280 281 @Override 282 public java.util.Collection values() { 283 return map.values(); 284 } 285}