001    /*
002     * $Id: Converter.java,v 1.30 2014/05/17 17:31:33 oboehm Exp $
003     *
004     * Copyright (c) 2008 by Oliver Boehm
005     *
006     * Licensed under the Apache License, Version 2.0 (the "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *   http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     *
018     * (c)reated 19.01.2009 by oliver (ob@oasd.de)
019     */
020    package patterntesting.runtime.util;
021    
022    import static patterntesting.runtime.NullConstants.NULL_DATE;
023    
024    import java.io.*;
025    import java.lang.reflect.Array;
026    import java.net.*;
027    import java.text.*;
028    import java.util.*;
029    
030    import org.apache.commons.io.IOUtils;
031    import org.apache.commons.lang.*;
032    import org.slf4j.*;
033    
034    /**
035     * The Class Converter to convert objects from one type to another type.
036     *
037     * @author <a href="boehm@javatux.de">oliver</a>
038     * @since 19.01.2009
039     * @version $Revision: 1.30 $
040     */
041    public final class Converter {
042    
043        private static final Logger log = LoggerFactory.getLogger(Converter.class);
044    
045        /** The different date patterns (date only) which are used by toDate(). */
046        private static final String[] datePatterns = { "dd-MMM-yyyy", "dd-MM-yyyy", "yyyy-MMM-dd",
047                "yyyy-MM-dd", "MMM-dd-yyyy", "dd MMM yyyy", "dd MM yyyy", "yyyy MMM dd", "yyyy MM dd",
048                "MMM dd yyyy", "dd.MMM.yyyy", "dd.MM.yyyy", "yyyy.MMM.dd", "MMM.dd.yyyy" };
049    
050        /** The differnt date patterns including the time. */
051        private static final String[] dateTimePatterns = getDateTimePatterns();
052    
053        /**
054         * To avoid that this class is instantiated.
055         */
056        private Converter() {}
057    
058        /**
059         * Gets the memory as string.
060         *
061         * @param mem the mem
062         *
063         * @return the memory as string
064         */
065        public static String getMemoryAsString(final long mem) {
066            if (mem < 1000) {
067                return mem + " bytes";
068            } else if (mem < 0x100000) {
069                return (mem + 512) / 1024 + " KB";
070            } else {
071                return (mem + 0x80000) / 0x100000 + " MB";
072            }
073        }
074    
075        /**
076         * Gets the time as string with the corresponding unit. Unit can be
077         * "ms" (for milliseconds) or "seconds".
078         *
079         * @param timeInMillis the time in millis
080         * @return the time as string
081         * @since 1.2.20
082         */
083        public static String getTimeAsString(final long timeInMillis) {
084            if (timeInMillis > 300000L) {
085                return ((timeInMillis + 30000L) / 60000L) + " minutes";
086            } else if (timeInMillis > 5000L) {
087                return ((timeInMillis + 500L) / 1000L) + " seconds";
088            }
089            return timeInMillis + " ms";
090        }
091    
092        /**
093         * Gets the time as string with the corresponding unit. Unit can be
094         * "ms" (for milliseconds) or "seconds".
095         *
096         * @param timeInMillis the time in millis
097         * @return the time as string
098         * @since 1.4.2
099         */
100        public static String getTimeAsString(final double timeInMillis) {
101            return getTimeAsString(timeInMillis, Locale.getDefault());
102        }
103    
104        /**
105         * Gets the time as string with the corresponding unit. Unit can be
106         * "ms" (for milliseconds) or "seconds".
107         *
108         * @param timeInMillis the time in millis
109         * @param locale the locale
110         * @return the time as string
111         * @since 1.4.2
112         */
113        public static String getTimeAsString(final double timeInMillis, final Locale locale) {
114            if (timeInMillis > 1.0) {
115                return getTimeAsString((long) timeInMillis);
116            }
117            Format nf = new DecimalFormat("#.###", new DecimalFormatSymbols(locale));
118            return nf.format(timeInMillis) + " ms";
119        }
120    
121        /**
122         * Converts a classname (e.g. "java.lang.String") into a resource
123         * ("/java/lang/String.class").).
124         *
125         * @param name e.g. "java.lang.String"
126         *
127         * @return e.g. "/java/lang/String.class"
128         */
129        public static String classToResource(final String name) {
130            if (name == null) {
131                return null;
132            }
133            return name.replaceAll("\\.", "/") + ".class";
134        }
135    
136        /**
137         * To resource.
138         *
139         * @param clazz the clazz
140         *
141         * @return the string
142         */
143        public static String toResource(final Class<?> clazz) {
144            return classToResource(clazz.getName());
145        }
146    
147        /**
148         * Converts a package name (e.g. "java.lang") into a resource
149         * ("/java/lang").).
150         *
151         * @param name e.g. "java.lang"
152         *
153         * @return e.g. "/java/lang"
154         */
155        public static String packageToResource(final String name) {
156            if (name == null) {
157                return null;
158            }
159            return name.replaceAll("\\.", "/");
160        }
161    
162        /**
163         * To resource.
164         *
165         * @param p the p
166         *
167         * @return the string
168         */
169        public static String toResource(final Package p) {
170            return packageToResource(p.getName());
171        }
172    
173        /**
174         * Converts a resource (e.g. "/java/lang/String.class") into its classname
175         * ("java.lang.String").
176         *
177         * @param name e.g. "/java/lang/String.class"
178         *
179         * @return e.g. "java.lang.String"
180         */
181        public static String resourceToClass(final String name) {
182            if (name == null) {
183                return null;
184            }
185            if (name.endsWith(".class")) {
186                int lastdot = name.lastIndexOf(".");
187                return name.substring(0, lastdot).replaceAll("[/\\\\]", "\\.");
188            } else {
189                return name;
190            }
191        }
192    
193        /**
194         * If a URL contains illegal characters for an URI (like blanks) this
195         * should be automatically converted (e.g. to "%20")
196         *
197         * @param url the URL to be converted
198         * @return the given URL as URI
199         */
200        public static URI toURI(final URL url) {
201            try {
202                            return url.toURI();
203                    } catch (URISyntaxException e) {
204                            return toURI(url.toExternalForm());
205                    }
206        }
207    
208        /**
209         * If a URL contains illegal characters for an URI (like blanks) this
210         * should be automatically converted (e.g. to "%20")
211         *
212         * @param uri the URL to be converted
213         * @return the given URL as URI
214         */
215        public static URI toURI(final String uri) {
216            try {
217                            return new URI(uri);
218                    } catch (URISyntaxException e) {
219                            String converted = uri.replaceAll(" ", "%20");
220                            try {
221                                    return new URI(converted);
222                            } catch (URISyntaxException e2) {
223                    throw new IllegalArgumentException(uri + " is not a valid URI",
224                            e2);
225                            }
226                    }
227        }
228    
229        /**
230         * Converts an URI into a file.
231         *
232         * @param uri e.g. URI("file:/tmp")
233         *
234         * @return e.g. File("/tmp")
235         */
236        public static File toFile(final URI uri) {
237            try {
238                    File file = new File(uri);
239                    try {
240                            return file.getCanonicalFile();
241                    } catch (IOException ioe) {
242                            return file;
243                    }
244            } catch (IllegalArgumentException iae) {
245                    if (uri.getScheme().equalsIgnoreCase("jar")) {
246                            try {
247                                    String fileScheme = uri.toString().substring(4);
248                                            return toFile(new URI(fileScheme));
249                                    } catch (URISyntaxException e) {
250                        throw new IllegalArgumentException("not a File: " + uri, e);
251                                    }
252                    }
253            }
254            String path = uri.getPath();
255            if (StringUtils.isEmpty(path)) {
256                path = StringUtils.substringAfterLast(uri.toString(), ":");
257            }
258            return new File(path);
259        }
260    
261        /**
262         * Converts an URI into a file.
263         *
264         * @param uri the uri as string
265         * @return the file
266         */
267        public static File toFile(final String uri) {
268            try {
269                return toFile(new URI(uri));
270            } catch (URISyntaxException e) {
271                return new File(uri);
272            }
273        }
274    
275        /**
276         * Converts an URI into a file and returns it as absolute pathname.
277         *
278         * @param uri e.g. URI("file:/tmp")
279         *
280         * @return e.g. "/tmp"
281         */
282        public static String toAbsolutePath(final URI uri) {
283            File file = toFile(uri);
284            return file.getAbsolutePath();
285        }
286    
287        /**
288         * Converts an object into its string representation.
289         * A null object is mapped to "" (empty string).
290         *
291         * @param obj the obj
292         *
293         * @return "" if the given object is null
294         */
295        public static String toString(final Object obj) {
296            if (obj == null) {
297                return "";
298            }
299            try {
300                if (obj instanceof Object[]) {
301                    return toString((Object[]) obj);
302                }
303                if (obj instanceof Enumeration<?>) {
304                    return toString((Enumeration<?>) obj);
305                }
306                return obj.toString();
307            } catch (RuntimeException e) {
308                log.debug("Returning empty string because of " + e);
309                return "";
310            }
311        }
312    
313        /**
314         * To string.
315         *
316         * @param enumeration the enumeration
317         * @return the string
318         */
319        public static String toString(final Enumeration<?> enumeration) {
320            if (!enumeration.hasMoreElements()) {
321                return "";
322            }
323            StringBuffer sbuf = new StringBuffer();
324            while(enumeration.hasMoreElements()) {
325                sbuf.append(" ," + enumeration.nextElement());
326            }
327            return sbuf.substring(2);
328        }
329    
330        /**
331         * Converts an object to its toString representation. If the resuulting
332         * string would be too long it will be abbreviated.
333         * <p>
334         * If the resulting toString representation looks like the default
335         * implementation of {@link Object#toString()} the package name will be
336         * removed from the result. For other toString results
337         * {@link StringUtils#abbreviate(String, int)} will be used to cut it if
338         * necessary.
339         * </p>
340         *
341         * @param obj the obj
342         *
343         * @return the string
344         */
345        public static String toShortString(final Object obj) {
346            if (obj == null) {
347                return "";
348            }
349            if (obj instanceof Object[]) {
350                return toShortString((Object[]) obj);
351            }
352            if (obj instanceof Class<?>) {
353                return ((Class<?>)obj).getSimpleName();
354            }
355            if (obj instanceof Number) {
356                return toShortString((Number) obj);
357            }
358            if (obj.getClass().isArray()) {
359                StringBuffer sbuf = new StringBuffer();
360                int n = Array.getLength(obj);
361                if (n == 0) {
362                    return "";
363                }
364                sbuf.append(Array.get(obj, 0));
365                for (int i = 1; i < n; i++) {
366                    sbuf.append(", ");
367                    if (i > 2) {
368                        sbuf.append("...");
369                        break;
370                    }
371                    sbuf.append(Array.get(obj, i));
372                }
373                return sbuf.toString();
374            }
375            String s = toString(obj);
376            if (s.startsWith(obj.getClass().getName())) {
377                int lengthPackagename = obj.getClass().getPackage().getName().length();
378                return s.substring(lengthPackagename + 1);
379            }
380            return StringUtils.abbreviate(s, 24);
381        }
382    
383        /**
384         * To short string.
385         *
386         * @param number the number
387         * @return the string
388         */
389        public static String toShortString(final Number number) {
390            NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
391            nf.setMaximumFractionDigits(5);
392            nf.setGroupingUsed(false);
393            return nf.format(number);
394        }
395    
396        /**
397         * Converts an object into a long representation as the normal toString
398         * method. E.g. maps are splitted into several lines.
399         *
400         * @param obj the obj
401         * @return the string
402         * @since 1.4
403         */
404        public static String toLongString(final Object obj) {
405            if (obj instanceof Map<?, ?>) {
406                return toLongString((Map<?, ?>) obj);
407            } else if (obj instanceof Object[]) {
408                return toLongString((Object[]) obj);
409            }
410            return toString(obj);
411        }
412    
413        /**
414         * An empty array or null is mapped to "" (empty string).
415         *
416         * @param array e.g. an int array {1, 2, 3}
417         *
418         * @return e.g. "[ 1, 2, 3 ]"
419         */
420        public static String toString(final Object[] array) {
421            if (ArrayUtils.isEmpty(array)) {
422                return "[]";
423            }
424            StringBuffer sbuf = new StringBuffer("[ ");
425            sbuf.append(toString(array[0]));
426            for (int i = 1; i < array.length; i++) {
427                sbuf.append(", ");
428                sbuf.append(toString(array[i]));
429            }
430            sbuf.append(" ]");
431            return sbuf.toString();
432        }
433    
434        /**
435         * To short string.
436         *
437         * @param array the array
438         *
439         * @return the string
440         */
441        public static String toShortString(final Object[] array) {
442            try {
443                StringBuffer sbuf = new StringBuffer(toShortString(array[0]));
444                for (int i = 1; i < array.length; i++) {
445                    if (i > 2) {
446                        sbuf.append(", ...");
447                        break;
448                    }
449                    sbuf.append(", ");
450                    sbuf.append(toShortString(array[i]));
451                }
452                return sbuf.toString();
453            } catch (RuntimeException e) {
454                return "";
455            }
456        }
457    
458        /**
459         * If you want to print the system properties as key-value pairs
460         * (e.g. "java.version=1.6.0_17...") you can use this method here.
461         *
462         * @since 1.4
463         * @param pairs e.g. the system properties
464         * @return "key=value" lines (separated by newlines)
465         */
466        @SuppressWarnings({ "unchecked", "rawtypes" })
467        public static String toLongString(final Map<?, ?> pairs) {
468            StringBuilder buf = new StringBuilder();
469            Set<?> keys = new TreeSet(pairs.keySet());
470            for (Iterator<?> iterator = keys.iterator(); iterator.hasNext();) {
471                Object key = iterator.next();
472                buf.append(key);
473                buf.append('=');
474                buf.append(pairs.get(key));
475                buf.append('\n');
476            }
477            return buf.toString();
478        }
479    
480        /**
481         * If you want to print each element of an array into a single line you
482         * can use this method here.
483         *
484         * @param array the array
485         * @return the string
486         * @since 1.4.2
487         */
488        public static String toLongString(final Object[] array) {
489            if (array instanceof StackTraceElement[]) {
490                return toLongString((StackTraceElement[]) array);
491            }
492            StringBuilder buf = new StringBuilder();
493            for (int i = 0; i < array.length; i++) {
494                buf.append('[');
495                buf.append(i);
496                buf.append("]\t");
497                buf.append(toString(array[i]));
498                buf.append('\n');
499            }
500            return buf.toString();
501        }
502    
503        /**
504         * This implementation prints the stacktrace in a similar way as the
505         * printStacktrace method of {@link Throwable} does it.
506         *
507         * @param stacktrace the array
508         * @return the string
509         * @since 1.4.2
510         */
511        public static String toLongString(final StackTraceElement[] stacktrace) {
512            StringBuilder buf = new StringBuilder();
513            for (int i = 0; i < stacktrace.length; i++) {
514                buf.append("\tat ");
515                buf.append(stacktrace[i]);
516                buf.append('\n');
517            }
518            return buf.toString();
519        }
520    
521        /**
522         * Each object inside the array is converted into its toString()
523         * representation.
524         *
525         * @param array e.g. an int array {1, 2, 3}
526         *
527         * @return e.g. {"1", "2", "3"}
528         *
529         * @since 27-Jul-2009
530         */
531        public static String[] toStringArray(final Object[] array) {
532            String[] strings = new String[array.length];
533            for (int i = 0; i < strings.length; i++) {
534                            try {
535                                    strings[i] = array[i].toString();
536                            } catch (NullPointerException npe) {
537                                    strings[i] = null;
538                            }
539                    }
540            return strings;
541        }
542    
543        /**
544         * Each object inside the Set is converted into its toString()
545         * representation.
546         *
547         * @param set the set
548         *
549         * @return the given Set as array
550         *
551         * @since 27-Jul-2009
552         */
553            public static String[] toStringArray(final Set<? extends Object> set) {
554                    Object[] objects = new Object[set.size()];
555                    objects = set.toArray(objects);
556                    return toStringArray(objects);
557            }
558    
559            /**
560             * Converts a date to string using the default locale.
561             *
562             * @param date a valid date
563             * @param pattern e.g. "dd-MMM-yyyy"
564             * @return e.g. "26-Nov-2009"
565             */
566            public static String toString(final Date date, final String pattern) {
567                DateFormat df = new SimpleDateFormat(pattern);
568                return df.format(date);
569            }
570    
571        /**
572         * Converts a date to string using the default locale.
573         *
574         * @param date a valid date
575         * @param pattern e.g. "dd-MMM-yyyy"
576         * @param locale e.g. new Locale("de")
577         * @return e.g. "30-Mai-2010" (with German locale)
578         */
579        public static String toString(final Date date, final String pattern,
580                final Locale locale) {
581            DateFormat df = new SimpleDateFormat(pattern, locale);
582            return df.format(date);
583        }
584    
585            /**
586             * Converts a string to a date by trying different date patterns.
587             * If the string can't be converted an IllegalArgumentException will
588             * be thrown.
589             *
590             * @param s e.g. "28-Nov-2009" or "Thu Nov 26 14:30:25 CET 2009"
591             * @return a valid date or NULL_DATE (if an empty string is given)
592             */
593            public static Date toDate(final String s) {
594                try {
595                    return toDate(s, false);
596            } catch (IllegalArgumentException iae) {
597                return toDate(s, true);
598            }
599            }
600    
601        /**
602         * Converts a string to a date by trying different date patterns.
603         * To speed up this method we look first if the string is long enough
604         * to hold a date <em>and</em> time value. If not only the datePatterns
605         * are probed. This speeds up this method about a factor of 5 (from about
606         * 10 ms to 2 ms on a MacBook Pro with 2 GHz).
607         *
608         * @param s e.g. "28-Nov-2009"
609         * @param lenient the lenient
610         * @return the date
611         */
612        private static Date toDate(final String s, final boolean lenient) {
613            if (StringUtils.isEmpty(s)) {
614                return NULL_DATE;
615            }
616            String[] patterns = dateTimePatterns;
617            if (s.length() < 12) {
618                patterns = datePatterns;
619            }
620            for (int i = 0; i < patterns.length; i++) {
621                try {
622                    return toDate(s, patterns[i], lenient);
623                } catch (IllegalArgumentException iae) {
624                    log.trace(iae.getMessage());
625                }
626            }
627            throw new IllegalArgumentException("can't convert \"" + s
628                    + "\" to date");
629        }
630    
631        /**
632         * Here we combine date and time patterns.
633         * If it takes too long, cache the result!
634         *
635         * @since 1.1
636         * @return combined date and time patterns
637         */
638        private static String[] getDateTimePatterns() {
639            String[] timePatterns = { "H:m", "h:m", "K:m", "k:m" };
640            List<String> patterns = new ArrayList<String>(datePatterns.length
641                    * (timePatterns.length + 1));
642            for (int i = 0; i < datePatterns.length; i++) {
643                for (int j = 0; j < timePatterns.length; j++) {
644                    patterns.add(datePatterns[i] + " " + timePatterns[j]);
645                }
646            }
647            patterns.addAll(Arrays.asList(datePatterns));
648            return patterns.toArray(new String[patterns.size()]);
649        }
650    
651            /**
652             * Converts a string to a date with the help of the given pattern.
653         * If the string can't be converted an IllegalArgumentException will
654         * be thrown.
655         *
656         * @param s e.g. "28-Nov-2009"
657             * @param pattern e.g. "dd-MMM-yyyy"
658         * @return a valid date or NULL_DATE (if an empty string is given)
659             */
660            public static Date toDate(final String s, final String pattern) {
661                return toDate(s, pattern, true);
662            }
663    
664        private static Date toDate(final String s, final String pattern,
665                final boolean lenient) {
666            DateFormat df = new SimpleDateFormat(pattern);
667            df.setLenient(lenient);
668            try {
669                return df.parse(s);
670            } catch (ParseException e1) {
671                if (log.isTraceEnabled()) {
672                    log.trace("trying to match " + s + " with locale \"en\"...");
673                }
674                df = new SimpleDateFormat(pattern, new Locale("en"));
675                df.setLenient(lenient);
676                try {
677                    return df.parse(s);
678                } catch (ParseException e2) {
679                    throw new IllegalArgumentException("\"" + s
680                            + "\" does not match pattern " + pattern, e2);
681                }
682            }
683        }
684    
685        /**
686         * Converts an Enumeration into a SortedSet.
687         *
688         * @since 1.0
689         * @param enumeration the Enumeration
690         * @return the SortedSet
691         */
692        public static SortedSet<?> toSortedSet(final Enumeration<?> enumeration) {
693            SortedSet<Object> set = new TreeSet<Object>();
694            while (enumeration.hasMoreElements()) {
695                Object element = enumeration.nextElement();
696                set.add(element);
697            }
698            return set;
699        }
700    
701        /**
702         * Serializes the given object and returns it as byte array.
703         *
704         * @param object the object to be serialized
705         * @return the object as byte array
706         * @throws NotSerializableException the not serializable exception
707         */
708        public static byte[] serialize(final Serializable object)
709                throws NotSerializableException {
710            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
711            try {
712                ObjectOutputStream oostream = new ObjectOutputStream(byteStream);
713                oostream.writeObject(object);
714                oostream.close();
715                byteStream.close();
716            } catch (NotSerializableException nse) {
717                throw nse;
718            } catch (IOException canthappen) {
719                throw new IllegalArgumentException(object + " can't be serialized", canthappen);
720            }
721            return byteStream.toByteArray();
722        }
723    
724        /**
725         * Deserializes the given byte array and returns it as object.
726         *
727         * @param bytes the byte array
728         * @return the deserialized object
729         * @throws ClassNotFoundException if byte array can't be deserialized
730         */
731        public static Serializable deserialize(final byte[] bytes)
732                throws ClassNotFoundException {
733            ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
734            try {
735                ObjectInputStream oistream = new ObjectInputStream(byteStream);
736                Object object = oistream.readObject();
737                IOUtils.closeQuietly(oistream);
738                return (Serializable) object;
739            } catch (IOException canthappen) {
740                throw new IllegalArgumentException(toShortString(bytes)
741                        + " can't be deserialized", canthappen);
742            }
743        }
744    
745    }