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