001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.runtime.op;
020
021import java.io.Serializable;
022import java.util.ArrayList;
023import java.util.Date;
024import java.util.HashMap;
025import java.util.Iterator;
026import java.util.List;
027import java.util.ListIterator;
028import java.util.Map;
029
030import lucee.commons.lang.ClassException;
031import lucee.commons.lang.ClassUtil;
032import lucee.commons.lang.ExceptionUtil;
033import lucee.commons.lang.StringUtil;
034import lucee.commons.lang.types.RefBoolean;
035import lucee.commons.lang.types.RefBooleanImpl;
036import lucee.runtime.converter.JavaConverter;
037import lucee.runtime.exp.PageException;
038import lucee.runtime.type.Collection;
039import lucee.runtime.type.Duplicable;
040import lucee.runtime.type.UDF;
041
042
043/**
044 *
045 *
046 * To change the template for this generated type comment go to
047 * Window - Preferences - Java - Code Generation - Code and Comments
048 */
049public final class Duplicator {
050
051        /**
052         * primitive value duplication (do nothing, value type must not be duplicated)
053         * @param _boolean boolean value to duplicate
054         * @return duplicated value
055         */
056        public static boolean duplicate(boolean _boolean) {
057                return _boolean;
058        }
059        
060        /**
061         * primitive value duplication (do nothing, value type must not be duplicated)
062         * @param _byte byte value to duplicate
063         * @return duplicated value
064         */
065        public static byte duplicate(byte _byte) {
066                return _byte;
067        }
068        
069        /**
070         * primitive value duplication (do nothing, value type must not be duplicated)
071         * @param _short byte value to duplicate
072         * @return duplicated value
073         */
074        public static short duplicate(short _short) {
075                return _short;
076        }
077        
078        /**
079         * primitive value duplication (do nothing, value type must not be duplicated)
080         * @param _int byte value to duplicate
081         * @return duplicated value
082         */
083        public static int duplicate(int _int) {
084                return _int;
085        }
086        
087        /**
088         * primitive value duplication (do nothing, value type must not be duplicated)
089         * @param _long byte value to duplicate
090         * @return duplicated value
091         */
092        public static long duplicate(long _long) {
093                return _long;
094        }
095        
096        /**
097         * primitive value duplication (do nothing, value type must not be duplicated)
098         * @param _double byte value to duplicate
099         * @return duplicated value
100         */
101        public static double duplicate(double _double) {
102                return _double;
103        }
104        
105        /**
106         * reference type value duplication
107         * @param object object to duplicate
108         * @return duplicated value
109         */
110        
111        public static Object duplicate(Object object, boolean deepCopy) {
112                if(object == null)                              return null;
113        if(object instanceof Number)    return object;
114        if(object instanceof String)    return object;
115        if(object instanceof Date)              return ((Date)object).clone();
116        if(object instanceof Boolean)   return object;
117                
118        RefBoolean before=new RefBooleanImpl();
119                try{
120                        Object copy = ThreadLocalDuplication.get(object,before);
121                        if(copy!=null){
122                        return copy;
123                }
124                
125        
126                //if(object instanceof CollectionPlus)return ((CollectionPlus)object).duplicate(deepCopy,ThreadLocalDuplication.getMap());
127                if(object instanceof Collection)return ((Collection)object).duplicate(deepCopy);
128                if(object instanceof Duplicable)return ((Duplicable)object).duplicate(deepCopy);
129                if(object instanceof UDF)               return ((UDF)object).duplicate();
130                if(object instanceof List)              return duplicateList((List)object,deepCopy);
131                if(object instanceof Map)               return duplicateMap((Map)object,deepCopy);
132                        if(object instanceof Serializable) {
133                                try {
134                                        String ser = JavaConverter.serialize((Serializable)object);
135                                        return JavaConverter.deserialize(ser);
136                                        
137                                } catch (Throwable t) {
138                                        ExceptionUtil.rethrowIfNecessary(t);
139                                }
140                        }
141        }  
142        finally {
143                if(!before.toBooleanValue())ThreadLocalDuplication.reset();
144        }
145            
146                return object;
147    }
148
149    public static List duplicateList(List list, boolean deepCopy) {
150        List newList;
151        try {
152                newList=(List) ClassUtil.loadInstance(list.getClass());
153                } catch (ClassException e) {
154                        newList=new ArrayList();
155                }
156        return duplicateList(list, newList, deepCopy);
157        }
158    
159    public static List duplicateList(List list,List newList, boolean deepCopy) {
160        ListIterator it = list.listIterator();  
161        while(it.hasNext()) {
162                if(deepCopy)
163                        newList.add(Duplicator.duplicate(it.next(),deepCopy));
164                else
165                        newList.add(it.next());
166        }
167                return newList;
168        }
169
170        /**
171     * duplicate a map
172     * @param map
173     * @param doKeysLower
174     * @return duplicated Map
175     * @throws PageException 
176     */
177    public static Map duplicateMap(Map map, boolean doKeysLower,boolean deepCopy) throws PageException{
178        if(doKeysLower) {
179                Map newMap;
180                try {
181                        newMap=(Map) ClassUtil.loadInstance(map.getClass());
182                } catch (ClassException e) {
183                        newMap=new HashMap();
184                }
185                boolean inside=ThreadLocalDuplication.set(map,newMap);
186            try{
187                Iterator it=map.keySet().iterator();
188            while(it.hasNext()) {
189                Object key=it.next();
190                if(deepCopy)newMap.put(StringUtil.toLowerCase(Caster.toString(key)),duplicate(map.get(key), deepCopy));
191                else newMap.put(StringUtil.toLowerCase(Caster.toString(key)),map.get(key));
192            }
193            }
194            finally {
195                if(!inside)ThreadLocalDuplication.reset();
196            }
197            return newMap;
198        }
199        return duplicateMap(map,deepCopy);
200    }
201
202    public static Map duplicateMap(Map map,boolean deepCopy){
203        Map other;
204        try {
205                        other=(Map) ClassUtil.loadInstance(map.getClass());
206                } catch (ClassException e) {
207                        other=new HashMap();
208        }
209                boolean inside=ThreadLocalDuplication.set(map,other);
210                try{
211        duplicateMap(map,other, deepCopy);
212                }
213                finally {
214                        if(!inside)ThreadLocalDuplication.reset();
215                }
216        //
217        return other;
218    }
219    
220    public static Map duplicateMap(Map map,Map newMap,boolean deepCopy){
221        
222        
223        Iterator it=map.keySet().iterator();
224        while(it.hasNext()) {
225            Object key=it.next();
226            if(deepCopy)newMap.put(key,duplicate(map.get(key),deepCopy));
227            else newMap.put(key,map.get(key));
228        }
229        return newMap;
230    }
231}
232
233