001    package railo.runtime.op;
002    
003    import java.io.Serializable;
004    import java.util.ArrayList;
005    import java.util.Date;
006    import java.util.HashMap;
007    import java.util.Iterator;
008    import java.util.List;
009    import java.util.ListIterator;
010    import java.util.Map;
011    
012    import railo.commons.lang.ClassException;
013    import railo.commons.lang.ClassUtil;
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.converter.JavaConverter;
016    import railo.runtime.exp.PageException;
017    import railo.runtime.type.Collection;
018    import railo.runtime.type.CollectionPlus;
019    import railo.runtime.type.Duplicable;
020    import railo.runtime.type.UDF;
021    
022    
023    /**
024     *
025     *
026     * To change the template for this generated type comment go to
027     * Window - Preferences - Java - Code Generation - Code and Comments
028     */
029    public final class Duplicator {
030    
031            /**
032             * primitive value duplication (do nothing, value type must not be duplicated)
033             * @param _boolean boolean value to duplicate
034             * @return duplicated value
035             */
036            public static boolean duplicate(boolean _boolean) {
037                    return _boolean;
038            }
039            
040            /**
041             * primitive value duplication (do nothing, value type must not be duplicated)
042             * @param _byte byte value to duplicate
043             * @return duplicated value
044             */
045            public static byte duplicate(byte _byte) {
046                    return _byte;
047            }
048            
049            /**
050             * primitive value duplication (do nothing, value type must not be duplicated)
051             * @param _short byte value to duplicate
052             * @return duplicated value
053             */
054            public static short duplicate(short _short) {
055                    return _short;
056            }
057            
058            /**
059             * primitive value duplication (do nothing, value type must not be duplicated)
060             * @param _int byte value to duplicate
061             * @return duplicated value
062             */
063            public static int duplicate(int _int) {
064                    return _int;
065            }
066            
067            /**
068             * primitive value duplication (do nothing, value type must not be duplicated)
069             * @param _long byte value to duplicate
070             * @return duplicated value
071             */
072            public static long duplicate(long _long) {
073                    return _long;
074            }
075            
076            /**
077             * primitive value duplication (do nothing, value type must not be duplicated)
078             * @param _double byte value to duplicate
079             * @return duplicated value
080             */
081            public static double duplicate(double _double) {
082                    return _double;
083            }
084            
085            /**
086             * reference type value duplication
087             * @param object object to duplicate
088             * @return duplicated value
089             */
090            
091            public static Object duplicate(Object object, boolean deepCopy) {
092                    if(object == null)                              return null;
093            if(object instanceof Number)    return object;
094            if(object instanceof String)    return object;
095            if(object instanceof Date)              return ((Date)object).clone();
096            if(object instanceof Boolean)   return object;
097                    
098                    
099                    
100                    Object copy = ThreadLocalDuplication.get(object);
101            if(copy!=null){
102                    return copy;
103            }
104            
105    
106            if(object instanceof CollectionPlus)return ((CollectionPlus)object).duplicate(deepCopy,ThreadLocalDuplication.getMap());
107            if(object instanceof Collection)return ((Collection)object).duplicate(deepCopy);
108            if(object instanceof Duplicable)return ((Duplicable)object).duplicate(deepCopy);
109            if(object instanceof UDF)               return ((UDF)object).duplicate();
110            if(object instanceof List)              return duplicateList((List)object,deepCopy);
111            if(object instanceof Map)               return duplicateMap((Map)object,deepCopy);
112                    if(object instanceof Serializable) {
113                            try {
114                                    String ser = JavaConverter.serialize((Serializable)object);
115                                    return JavaConverter.deserialize(ser);
116                                    
117                            } catch (Throwable t) {}
118                    }
119                    
120                
121                    return object;
122        }
123    
124        public static List duplicateList(List list, boolean deepCopy) {
125            List newList;
126            try {
127                    newList=(List) ClassUtil.loadInstance(list.getClass());
128                    } catch (ClassException e) {
129                            newList=new ArrayList();
130                    }
131            return duplicateList(list, newList, deepCopy);
132            }
133        
134        public static List duplicateList(List list,List newList, boolean deepCopy) {
135            ListIterator it = list.listIterator();  
136            while(it.hasNext()) {
137                    if(deepCopy)
138                            newList.add(Duplicator.duplicate(it.next(),deepCopy));
139                    else
140                            newList.add(it.next());
141            }
142                    return newList;
143            }
144    
145            /**
146         * duplicate a map
147         * @param map
148         * @param doKeysLower
149         * @return duplicated Map
150         * @throws PageException 
151         */
152        public static Map duplicateMap(Map map, boolean doKeysLower,boolean deepCopy) throws PageException{
153            if(doKeysLower) {
154                    Map newMap;
155                    try {
156                            newMap=(Map) ClassUtil.loadInstance(map.getClass());
157                    } catch (ClassException e) {
158                            newMap=new HashMap();
159                    }
160                    ThreadLocalDuplication.set(map,newMap);
161                Iterator it=map.keySet().iterator();
162                while(it.hasNext()) {
163                    Object key=it.next();
164                    if(deepCopy)newMap.put(StringUtil.toLowerCase(Caster.toString(key)),duplicate(map.get(key), deepCopy));
165                    else newMap.put(StringUtil.toLowerCase(Caster.toString(key)),map.get(key));
166                }
167                ThreadLocalDuplication.remove(map);
168                return newMap;
169            }
170            return duplicateMap(map,deepCopy);
171        }
172    
173        public static Map duplicateMap(Map map,boolean deepCopy){
174            Map other;
175            try {
176                            other=(Map) ClassUtil.loadInstance(map.getClass());
177                    } catch (ClassException e) {
178                            other=new HashMap();
179            }
180                    ThreadLocalDuplication.set(map,other);
181            duplicateMap(map,other, deepCopy);
182            ThreadLocalDuplication.remove(map);
183            return other;
184        }
185        
186        public static Map duplicateMap(Map map,Map newMap,boolean deepCopy){
187            
188            
189            Iterator it=map.keySet().iterator();
190            while(it.hasNext()) {
191                Object key=it.next();
192                if(deepCopy)newMap.put(key,duplicate(map.get(key),deepCopy));
193                else newMap.put(key,map.get(key));
194            }
195            return newMap;
196        }
197    }
198    
199