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 }