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.Iterator; 022import java.util.Set; 023 024import lucee.commons.collection.HashMapPro; 025import lucee.commons.collection.LinkedHashMapPro; 026import lucee.commons.collection.MapFactory; 027import lucee.commons.collection.MapPro; 028import lucee.commons.collection.MapProWrapper; 029import lucee.commons.collection.SyncMap; 030import lucee.commons.collection.WeakHashMapPro; 031import lucee.commons.lang.ExceptionUtil; 032import lucee.commons.lang.SerializableObject; 033import lucee.runtime.config.NullSupportHelper; 034import lucee.runtime.exp.ExpressionException; 035import lucee.runtime.exp.PageException; 036import lucee.runtime.op.Duplicator; 037import lucee.runtime.op.ThreadLocalDuplication; 038import lucee.runtime.type.it.StringIterator; 039import lucee.runtime.type.util.StructSupport; 040import lucee.runtime.type.util.StructUtil; 041 042import org.apache.commons.collections.map.ReferenceMap; 043 044/** 045 * CFML data type struct 046 */ 047public class StructImpl extends StructSupport { 048 private static final long serialVersionUID = 1421746759512286393L; 049 050 public static final int TYPE_UNDEFINED = -1;// FUTURE add to interface Struct 051 052 private MapPro<Collection.Key,Object> map; 053 054 /** 055 * default constructor 056 */ 057 public StructImpl() { 058 this(StructImpl.TYPE_UNDEFINED,HashMapPro.DEFAULT_INITIAL_CAPACITY);//asx 059 } 060 061 /** 062 * This implementation spares its clients from the unspecified, 063 * generally chaotic ordering provided by normally Struct , 064 * without incurring the increased cost associated with TreeMap. 065 * It can be used to produce a copy of a map that has the same order as the original 066 * @param type 067 */ 068 public StructImpl(int type) { 069 this(type,HashMapPro.DEFAULT_INITIAL_CAPACITY); 070 } 071 072 /** 073 * This implementation spares its clients from the unspecified, 074 * generally chaotic ordering provided by normally Struct , 075 * without incurring the increased cost associated with TreeMap. 076 * It can be used to produce a copy of a map that has the same order as the original 077 * @param type 078 * @param initialCapacity initial capacity - MUST be a power of two. 079 */ 080 public StructImpl(int type, int initialCapacity) { 081 if(type==TYPE_WEAKED) map=new SyncMap<Collection.Key, Object>(new WeakHashMapPro<Collection.Key,Object>(initialCapacity)); 082 else if(type==TYPE_SOFT) map=new SyncMap<Collection.Key, Object>(new MapProWrapper<Collection.Key, Object>(new ReferenceMap(ReferenceMap.HARD,ReferenceMap.SOFT,initialCapacity,0.75f),new SerializableObject())); 083 else if(type==TYPE_LINKED) map=new SyncMap<Collection.Key, Object>(new LinkedHashMapPro<Collection.Key,Object>(initialCapacity)); 084 else map=MapFactory.getConcurrentMap(initialCapacity); 085 } 086 087 088 089 090 public int getType(){ 091 return StructUtil.getType(map); 092 } 093 094 095 096 097 098 @Override 099 public Object get(Collection.Key key, Object defaultValue) { 100 if(NullSupportHelper.full())return map.g(key, defaultValue); 101 102 Object rtn=map.get(key); 103 if(rtn!=null) return rtn; 104 return defaultValue; 105 } 106 107 108 public Object g(Collection.Key key, Object defaultValue) { 109 return map.g(key, defaultValue); 110 } 111 public Object g(Collection.Key key) throws PageException { 112 return map.g(key); 113 } 114 115 @Override 116 public Object get(Collection.Key key) throws PageException { 117 if(NullSupportHelper.full()) return map.g(key); 118 119 Object rtn=map.get(key); 120 if(rtn!=null) return rtn; 121 throw StructSupport.invalidKey(null,this,key); 122 } 123 124 @Override 125 public Object set(Collection.Key key, Object value) throws PageException { 126 map.put(key,value); 127 return value; 128 } 129 130 @Override 131 public Object setEL(Collection.Key key, Object value) { 132 map.put(key,value); 133 return value; 134 } 135 136 @Override 137 public int size() { 138 return map.size(); 139 } 140 141 public Collection.Key[] keys() { 142 try { 143 return map.keySet().toArray(new Key[map.size()]); 144 } 145 catch(Throwable t) { 146 ExceptionUtil.rethrowIfNecessary(t); 147 MapPro<Key, Object> old = map; 148 try{ 149 map = new lucee.commons.collection.SyncMap(map); 150 Set<Key> set = map.keySet(); 151 Collection.Key[] keys = new Collection.Key[size()]; 152 synchronized(map){ 153 Iterator<Key> it = set.iterator(); 154 int count=0; 155 while(it.hasNext() && keys.length>count) { 156 keys[count++]=KeyImpl.toKey(it.next(), null); 157 } 158 return keys; 159 } 160 } 161 finally { 162 map=old; 163 } 164 } 165 } 166 167 @Override 168 public Object remove(Collection.Key key) throws PageException { 169 if(NullSupportHelper.full())return map.r(key); 170 Object obj= map.remove(key); 171 if(obj==null) throw new ExpressionException("can't remove key ["+key+"] from struct, key doesn't exist"); 172 return obj; 173 } 174 175 @Override 176 public Object removeEL(Collection.Key key) { 177 return map.remove(key); 178 } 179 180 public Object remove(Collection.Key key, Object defaultValue) { 181 if(NullSupportHelper.full())return map.r(key,defaultValue); 182 Object obj= map.remove(key); 183 if(obj==null) return defaultValue; 184 return obj; 185 } 186 187 188 @Override 189 public void clear() { 190 map.clear(); 191 } 192 193 194 @Override 195 public Collection duplicate(boolean deepCopy) { 196 Struct sct=new StructImpl(getType()); 197 copy(this,sct,deepCopy); 198 return sct; 199 } 200 201 public static void copy(Struct src,Struct trg,boolean deepCopy) { 202 boolean inside=ThreadLocalDuplication.set(src,trg); 203 try{ 204 Iterator<Entry<Key, Object>> it = src.entryIterator(); 205 Entry<Key, Object> e; 206 while(it.hasNext()) { 207 e = it.next(); 208 if(!deepCopy) trg.setEL(e.getKey(),e.getValue()); 209 else trg.setEL(e.getKey(),Duplicator.duplicate(e.getValue(),deepCopy)); 210 } 211 } 212 finally { 213 if(!inside)ThreadLocalDuplication.reset(); 214 } 215 } 216 217 218 219 @Override 220 public Iterator<Collection.Key> keyIterator() { 221 return map.keySet().iterator(); 222 } 223 224 @Override 225 public Iterator<String> keysAsStringIterator() { 226 return new StringIterator(keys()); 227 } 228 229 230 public Iterator<Entry<Key, Object>> entryIterator() { 231 return this.map.entrySet().iterator(); 232 } 233 234 @Override 235 public Iterator<Object> valueIterator() { 236 return map.values().iterator(); 237 } 238 239 @Override 240 public boolean containsKey(Collection.Key key) { 241 return map.containsKey(key); 242 } 243 244 @Override 245 public boolean containsValue(Object value) { 246 return map.containsValue(value); 247 } 248 249 @Override 250 public java.util.Collection<Object> values() { 251 return map.values(); 252 } 253 254 @Override 255 public int hashCode() { 256 return map.hashCode(); 257 } 258 259 @Override 260 public boolean equals(Object obj) { 261 return map.equals(obj); 262 } 263}