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