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.dump.DumpTable;
013    import railo.runtime.dump.DumpUtil;
014    import railo.runtime.dump.SimpleDumpData;
015    import railo.runtime.exp.ExpressionException;
016    import railo.runtime.exp.PageException;
017    import railo.runtime.op.Duplicator;
018    import railo.runtime.op.ThreadLocalDuplication;
019    import railo.runtime.type.dt.DateTime;
020    import railo.runtime.type.it.EntryIterator;
021    import railo.runtime.type.it.StringIterator;
022    import railo.runtime.type.util.StructSupport;
023    
024    /**
025     * CFML 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<Collection.Key,Object> _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<Collection.Key,Object>();
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<Collection.Key,Object>();
054            else if(type==TYPE_WEAKED)      _map=new java.util.WeakHashMap<Collection.Key,Object>();
055            else if(type==TYPE_SYNC)        _map=new HashTable();
056            else                                            _map=new HashMap<Collection.Key,Object>();
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<Key> it = keyIterator();
103                    Collection.Key[] keys = new Collection.Key[size()];
104                    int count=0;
105                    while(it.hasNext()) {
106                            keys[count++]=it.next();
107                    }
108                    return keys;
109            }
110    
111            /**
112             * @see railo.runtime.type.Collection#remove(railo.runtime.type.Collection.Key)
113             */
114            public Object remove(Collection.Key key) throws PageException {
115                    Object obj= _map.remove(key);
116                    if(obj==null) throw new ExpressionException("can't remove key ["+key.getString()+"] from struct, key doesn't exist");
117                    return obj;
118            }
119            
120            /**
121             *
122             * @see railo.runtime.type.Collection#removeEL(railo.runtime.type.Collection.Key)
123             */
124            public Object removeEL(Collection.Key key) {
125                    return _map.remove(key);
126            }
127            
128            /**
129             * @see railo.runtime.type.Collection#clear()
130             */
131            public void clear() {
132                    _map.clear();
133            }
134             
135            /**
136             *
137             * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int)
138             */
139            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
140                Iterator it=_map.keySet().iterator();
141                    
142                    DumpTable table = new DumpTable("struct","#9999ff","#ccccff","#000000");
143                    table.setTitle("Struct");
144                    maxlevel--;
145                    int maxkeys=dp.getMaxKeys();
146                    int index=0;
147                    while(it.hasNext()) {
148                            Object key=it.next();
149                            if(DumpUtil.keyValid(dp, maxlevel,key.toString())){
150                                    if(maxkeys<=index++)break;
151                                    table.appendRow(1,new SimpleDumpData(key.toString()),DumpUtil.toDumpData(_map.get(key), pageContext,maxlevel,dp));
152                            }
153                    }
154                    return table;
155            }
156    
157            /**
158             * throw exception for invalid key
159             * @param key Invalid key
160             * @return returns an invalid key Exception
161             */
162            protected ExpressionException invalidKey(String key) {
163                    return new ExpressionException("key ["+key+"] doesn't exist in struct");
164            }
165    
166            /**
167             * @see railo.runtime.type.Collection#duplicate(boolean)
168             */
169            public Collection duplicate(boolean deepCopy) {
170                    Struct sct=new StructImplKey();
171                    copy(this,sct,deepCopy);
172                    return sct;
173            }
174            
175            
176            public static void copy(Struct src,Struct trg,boolean deepCopy) {
177                    ThreadLocalDuplication.set(src, trg);
178                    try {
179                            Iterator<Entry<Key, Object>> it = src.entryIterator();
180                            Entry<Key, Object> e;
181                            while(it.hasNext()) {
182                                    e = it.next();
183                                    if(!deepCopy) trg.setEL(e.getKey(),e.getValue());
184                                    else trg.setEL(e.getKey(),Duplicator.duplicate(e.getValue(),deepCopy));
185                            }
186                    }
187                    finally {
188                            //ThreadLocalDuplication.remove(src); removed "remove" to catch sisters and brothers
189                    }
190            }
191    
192            @Override
193            public Iterator<Collection.Key> keyIterator() {
194                    return _map.keySet().iterator();
195            }
196        
197            @Override
198            public Iterator<String> keysAsStringIterator() {
199            return new StringIterator(keys());
200        }
201            
202            @Override
203            public Iterator<Entry<Key, Object>> entryIterator() {
204                    return new EntryIterator(this, keys());
205            }
206            
207            /**
208             * @see railo.runtime.type.Iteratorable#iterator()
209             */
210            public Iterator valueIterator() {
211                    return _map.values().iterator();
212            }
213    
214        /**
215         * @see railo.runtime.type.Collection#_contains(java.lang.String)
216         */
217        public boolean containsKey(Collection.Key key) {
218            return _map.containsKey(key);
219        }
220    
221        /**
222         * @see railo.runtime.op.Castable#castToString()
223         */
224        public String castToString() throws ExpressionException {
225            throw new ExpressionException("Can't cast Complex Object Type Struct to String",
226              "Use Built-In-Function \"serialize(Struct):String\" to create a String from Struct");
227        }
228    
229            /**
230             * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String)
231             */
232            public String castToString(String defaultValue) {
233                    return defaultValue;
234            }
235    
236        /**
237         * @see railo.runtime.op.Castable#castToBooleanValue()
238         */
239        public boolean castToBooleanValue() throws ExpressionException {
240            throw new ExpressionException("can't cast Complex Object Type Struct to a boolean value");
241        }
242        
243        /**
244         * @see railo.runtime.op.Castable#castToBoolean(java.lang.Boolean)
245         */
246        public Boolean castToBoolean(Boolean defaultValue) {
247            return defaultValue;
248        }
249    
250    
251        /**
252         * @see railo.runtime.op.Castable#castToDoubleValue()
253         */
254        public double castToDoubleValue() throws ExpressionException {
255            throw new ExpressionException("can't cast Complex Object Type Struct to a number value");
256        }
257        
258        /**
259         * @see railo.runtime.op.Castable#castToDoubleValue(double)
260         */
261        public double castToDoubleValue(double defaultValue) {
262            return defaultValue;
263        }
264    
265    
266        /**
267         * @see railo.runtime.op.Castable#castToDateTime()
268         */
269        public DateTime castToDateTime() throws ExpressionException {
270            throw new ExpressionException("can't cast Complex Object Type Struct to a Date");
271        }
272        
273        /**
274         * @see railo.runtime.op.Castable#castToDateTime(railo.runtime.type.dt.DateTime)
275         */
276        public DateTime castToDateTime(DateTime defaultValue) {
277            return defaultValue;
278        }
279    
280            /**
281             * @see railo.runtime.op.Castable#compare(boolean)
282             */
283            public int compareTo(boolean b) throws ExpressionException {
284                    throw new ExpressionException("can't compare Complex Object Type Struct with a boolean value");
285            }
286    
287            /**
288             * @see railo.runtime.op.Castable#compareTo(railo.runtime.type.dt.DateTime)
289             */
290            public int compareTo(DateTime dt) throws PageException {
291                    throw new ExpressionException("can't compare Complex Object Type Struct with a DateTime Object");
292            }
293    
294            /**
295             * @see railo.runtime.op.Castable#compareTo(double)
296             */
297            public int compareTo(double d) throws PageException {
298                    throw new ExpressionException("can't compare Complex Object Type Struct with a numeric value");
299            }
300    
301            /**
302             * @see railo.runtime.op.Castable#compareTo(java.lang.String)
303             */
304            public int compareTo(String str) throws PageException {
305                    throw new ExpressionException("can't compare Complex Object Type Struct with a String");
306            }
307        
308            public boolean containsValue(Object value) {
309                    return _map.containsValue(value);
310            }
311    
312            public java.util.Collection values() {
313                    return _map.values();
314            }
315    
316    }