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