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