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