001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.util;
029
030import java.io.ByteArrayInputStream;
031import java.io.ByteArrayOutputStream;
032import java.io.IOException;
033import java.io.ObjectInputStream;
034import java.io.ObjectOutputStream;
035import java.util.Date;
036import java.util.Hashtable;
037import java.util.Iterator;
038import java.util.Map;
039import java.util.Map.Entry;
040
041import org.apache.commons.codec.binary.Base64;
042
043/**
044 *
045 * Utilities to handle basic data types.<p>
046 *
047 * @since 6.5.6
048 */
049public final class CmsDataTypeUtil {
050
051    /**
052     * Hides the public constructor.<p>
053     */
054    private CmsDataTypeUtil() {
055
056        // noop
057    }
058
059    /**
060     * Returns the deserialized (if needed) object.<p>
061     *
062     * @param data the data to deserialize
063     * @param type the data type
064     *
065     * @return the deserialized object
066     *
067     * @throws IOException if the inputstream fails
068     * @throws ClassNotFoundException if the serialized object fails
069     */
070    public static Object dataDeserialize(byte[] data, String type) throws IOException, ClassNotFoundException {
071
072        // check the type of the stored data
073        Class<?> clazz = Class.forName(type);
074
075        if (isParseable(clazz)) {
076            // this is parseable data
077            return parse(new String(data), clazz);
078        }
079
080        // this is a serialized object
081        ByteArrayInputStream bin = new ByteArrayInputStream(data);
082        ObjectInputStream oin = new ObjectInputStream(bin);
083        return oin.readObject();
084    }
085
086    /**
087     * Returns a ready to export string representation of the given object.<p>
088     *
089     * For not parseable objects, base64 encoded string with the serialized object is generated.<p>
090     *
091     * @param data the object to export
092     *
093     * @return the string representation
094     *
095     * @throws IOException  if something goes wrong
096     */
097    public static String dataExport(Object data) throws IOException {
098
099        if (CmsDataTypeUtil.isParseable(data.getClass())) {
100            return CmsDataTypeUtil.format(data);
101        }
102        ByteArrayOutputStream bout = new ByteArrayOutputStream();
103        ObjectOutputStream oout = new ObjectOutputStream(bout);
104        oout.writeObject(data);
105        oout.close();
106        return new String(Base64.encodeBase64(bout.toByteArray()));
107    }
108
109    /**
110     * Returns the import data object.<p>
111     *
112     * @param value the exported value
113     * @param type the expected data type
114     *
115     * @return the import data object
116     *
117     * @throws ClassNotFoundException if something goes wrong
118     * @throws IOException if something goes wrong
119     */
120    public static Object dataImport(String value, String type) throws ClassNotFoundException, IOException {
121
122        Class<?> clazz = Class.forName(type);
123        if (CmsDataTypeUtil.isParseable(clazz)) {
124            return CmsDataTypeUtil.parse(value, clazz);
125        }
126        byte[] data = Base64.decodeBase64(value.getBytes());
127        return dataDeserialize(data, type);
128    }
129
130    /**
131     * Serialize the given data.<p>
132     *
133     * @param data the data to serialize
134     *
135     * @return byte[] the serailized data
136     *
137     * @throws IOException if something goes wrong
138     */
139    public static byte[] dataSerialize(Object data) throws IOException {
140
141        if (isParseable(data.getClass())) {
142            return format(data).getBytes();
143        }
144
145        // serialize the data
146        ByteArrayOutputStream bout = new ByteArrayOutputStream();
147        ObjectOutputStream oout = new ObjectOutputStream(bout);
148        Object obj = data;
149        if (data instanceof Map) {
150            Hashtable<Object, Object> ht = new Hashtable<Object, Object>();
151            @SuppressWarnings("unchecked")
152            Iterator<Entry<Object, Object>> it = ((Map<Object, Object>)data).entrySet().iterator();
153            while (it.hasNext()) {
154                Entry<Object, Object> entry = it.next();
155                if ((entry.getKey() != null) && (entry.getValue() != null)) {
156                    ht.put(entry.getKey(), entry.getValue());
157                }
158            }
159            obj = ht;
160        }
161        oout.writeObject(obj);
162        oout.close();
163        return bout.toByteArray();
164    }
165
166    /**
167     * Formats the given data into a string value.<p>
168     *
169     * @param data the data to format
170     *
171     * @return a string representation of the given data
172     */
173    public static String format(boolean data) {
174
175        return String.valueOf(data);
176    }
177
178    /**
179     * Formats the given data into a string value.<p>
180     *
181     * @param data the data to format
182     *
183     * @return a string representation of the given data
184     */
185    public static String format(byte data) {
186
187        return new Byte(data).toString();
188    }
189
190    /**
191     * Formats the given data into a string value.<p>
192     *
193     * @param data the data to format
194     *
195     * @return a string representation of the given data
196     */
197    public static String format(char data) {
198
199        return new Character(data).toString();
200    }
201
202    /**
203     * Formats the given data into a string value.<p>
204     *
205     * @param data the data to format
206     *
207     * @return a string representation of the given data
208     */
209    public static String format(Date data) {
210
211        return new Long(data.getTime()).toString();
212    }
213
214    /**
215     * Formats the given data into a string value.<p>
216     *
217     * @param data the data to format
218     *
219     * @return a string representation of the given data
220     */
221    public static String format(double data) {
222
223        return new Double(data).toString();
224    }
225
226    /**
227     * Formats the given data into a string value.<p>
228     *
229     * @param data the data to format
230     *
231     * @return a string representation of the given data
232     */
233    public static String format(float data) {
234
235        return new Float(data).toString();
236    }
237
238    /**
239     * Formats the given data into a string value.<p>
240     *
241     * @param data the data to format
242     *
243     * @return a string representation of the given data
244     */
245    public static String format(int data) {
246
247        return new Integer(data).toString();
248    }
249
250    /**
251     * Formats the given data into a string value.<p>
252     *
253     * @param data the data to format
254     *
255     * @return a string representation of the given data
256     */
257    public static String format(long data) {
258
259        return new Long(data).toString();
260    }
261
262    /**
263     * Formats the given data into a string value depending on the data type.<p>
264     *
265     * @param data the data to format
266     *
267     * @return a string representation of the given data
268     */
269    public static String format(Object data) {
270
271        if (data == null) {
272            return null;
273        }
274        Class<?> clazz = data.getClass();
275        if (clazz.equals(Date.class)) {
276            return format(((Date)data).getTime());
277        }
278        return data.toString();
279    }
280
281    /**
282     * Formats the given data into a string value.<p>
283     *
284     * @param data the data to format
285     *
286     * @return a string representation of the given data
287     */
288    public static String format(short data) {
289
290        return new Short(data).toString();
291    }
292
293    /**
294     * Checks if the given class is representable as a string.<p>
295     *
296     * @param clazz the type to test
297     *
298     * @return if the given class is representable as a string
299     */
300    public static boolean isParseable(Class<?> clazz) {
301
302        boolean parseable = false;
303        parseable = parseable || (clazz.equals(byte.class));
304        parseable = parseable || (clazz.equals(Byte.class));
305        parseable = parseable || (clazz.equals(short.class));
306        parseable = parseable || (clazz.equals(Short.class));
307        parseable = parseable || (clazz.equals(int.class));
308        parseable = parseable || (clazz.equals(Integer.class));
309        parseable = parseable || (clazz.equals(long.class));
310        parseable = parseable || (clazz.equals(Long.class));
311        parseable = parseable || (clazz.equals(float.class));
312        parseable = parseable || (clazz.equals(Float.class));
313        parseable = parseable || (clazz.equals(double.class));
314        parseable = parseable || (clazz.equals(Double.class));
315        parseable = parseable || (clazz.equals(boolean.class));
316        parseable = parseable || (clazz.equals(Boolean.class));
317        parseable = parseable || (clazz.equals(char.class));
318        parseable = parseable || (clazz.equals(Character.class));
319        parseable = parseable || (clazz.equals(String.class));
320        parseable = parseable || (clazz.equals(Date.class));
321        parseable = parseable || (clazz.equals(CmsUUID.class));
322        return parseable;
323    }
324
325    /**
326     * Converts Number to int.<p>
327     *
328     * @param n the number object
329     *
330     * @return Number.inValue(), 0 - if the parameter is null
331     */
332    public static int numberToInt(Number n) {
333
334        return (n == null ? 0 : n.intValue());
335    }
336
337    /**
338     * Returns an object of the given type (or a wrapper for base types)
339     * with the value of the given data.<p>
340     *
341     * @param data the data to parse
342     * @param clazz the data type
343     *
344     * @return the value of the given data
345     */
346    public static Object parse(String data, Class<?> clazz) {
347
348        if (data == null) {
349            return null;
350        }
351        if (clazz.equals(byte.class) || clazz.equals(Byte.class)) {
352            return parseByte(data);
353        }
354        if (clazz.equals(short.class) || clazz.equals(Short.class)) {
355            return parseShort(data);
356        }
357        if (clazz.equals(long.class) || clazz.equals(Long.class)) {
358            return parseLong(data);
359        }
360        if (clazz.equals(int.class) || clazz.equals(Integer.class)) {
361            return parseInt(data);
362        }
363        if (clazz.equals(float.class) || clazz.equals(Float.class)) {
364            return parseFloat(data);
365        }
366        if (clazz.equals(double.class) || clazz.equals(Double.class)) {
367            return parseDouble(data);
368        }
369        if (clazz.equals(boolean.class) || clazz.equals(Boolean.class)) {
370            return parseBoolean(data);
371        }
372        if (clazz.equals(char.class) || clazz.equals(Character.class)) {
373            return parseChar(data);
374        }
375        if (clazz.equals(CmsUUID.class)) {
376            return parseUUID(data);
377        }
378        if (clazz.equals(Date.class)) {
379            return parseDate(data);
380        }
381        return data;
382    }
383
384    /**
385     * Parses the given data as a boolean.<p>
386     *
387     * @param data the data to parse
388     *
389     * @return the converted data value
390     */
391    public static Boolean parseBoolean(String data) {
392
393        return Boolean.valueOf(data);
394    }
395
396    /**
397     * Parses the given data as a byte.<p>
398     *
399     * @param data the data to parse
400     *
401     * @return the converted data value
402     */
403    public static Byte parseByte(String data) {
404
405        return new Byte(data);
406    }
407
408    /**
409     * Parses the given data as a char.<p>
410     *
411     * @param data the data to parse
412     *
413     * @return the converted data value
414     */
415    public static Character parseChar(String data) {
416
417        return new Character(data.charAt(0));
418    }
419
420    /**
421     * Parses the given data as a date.<p>
422     *
423     * @param data the data to parse
424     *
425     * @return the converted data value
426     */
427    public static Date parseDate(String data) {
428
429        return new Date(parseLong(data).longValue());
430    }
431
432    /**
433     * Parses the given data as a double.<p>
434     *
435     * @param data the data to parse
436     *
437     * @return the converted data value
438     */
439    public static Double parseDouble(String data) {
440
441        return new Double(data);
442    }
443
444    /**
445     * Parses the given data as a float.<p>
446     *
447     * @param data the data to parse
448     *
449     * @return the converted data value
450     */
451    public static Float parseFloat(String data) {
452
453        return new Float(data);
454    }
455
456    /**
457     * Parses the given data as an integer.<p>
458     *
459     * @param data the data to parse
460     *
461     * @return the converted data value
462     */
463    public static Integer parseInt(String data) {
464
465        return new Integer(data);
466    }
467
468    /**
469     * Parses the given data as a long.<p>
470     *
471     * @param data the data to parse
472     *
473     * @return the converted data value
474     */
475    public static Long parseLong(String data) {
476
477        return new Long(data);
478    }
479
480    /**
481     * Parses the given data as a short.<p>
482     *
483     * @param data the data to parse
484     *
485     * @return the converted data value
486     */
487    public static Short parseShort(String data) {
488
489        return new Short(data);
490    }
491
492    /**
493     * Parses the given data as an uuid.<p>
494     *
495     * @param data the data to parse
496     *
497     * @return the converted data value
498     */
499    public static CmsUUID parseUUID(String data) {
500
501        return new CmsUUID(data);
502    }
503}