All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ow2.bonita.util.Misc Maven / Gradle / Ivy

/**
 * Copyright (C) 2007  Bull S. A. S.
 * Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation
 * version 2.1 of the License.
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA  02110-1301, USA.
 **/
package org.ow2.bonita.util;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.TypeVariable;
import java.net.URL;
import java.security.Permission;
import java.security.Permissions;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Date;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MalformedObjectNameException;
import javax.management.ReflectionException;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.xml.sax.InputSource;

/**
 * @author Marc Blachon, Guillaume Porcher, Charles Souillard, Miguel Valdes,
 *         Pierre Vigneras
 */
public abstract class Misc {

  // public interface Cloner {
  // T newClone(T t);
  // }
  //
  // public interface Factory {
  // T newInstance(Object... objects);
  // }

  private static final Logger LOG = Logger.getLogger(Misc.class.getName());
  private static Object formatterLock = new Object();

  private Misc() {
  }

  /**
   * A RANDOM instance. Prevent creation of many instances.
   */
  public static final Random RANDOM = new Random();
  /**
   * The line separator as defined by the property line.separator.
   */
  public static final String LINE_SEPARATOR = System.getProperty("line.separator");
  /**
   * The file that represents the temporary directory. Usually, it is /tmp on
   * Unix platform and C:/TMP on MS Windows.
   */
  public static final File TMP_DIR = new File(System.getProperty("java.io.tmpdir"));
  // Time formatter
  private static final DateFormat DELAY_FORMATTER = new SimpleDateFormat("HH:mm:ss.SSS");

  static {
    Misc.DELAY_FORMATTER.setTimeZone(TimeZone.getTimeZone("GMT"));
  }
  /**
   * Number of milleseconds in a given day
   */
  public static final long DAY = 1000 * 60 * 60 * 24; // one day

  private static final AtomicLong SEQUENCE_NUMBER = new AtomicLong(0);

  /**
   * Generate a unique identifier prefixed by the given String.
   * 
   * @param prefix the prefix String
   * @return an UUID String prefixed by prefix
   * @see UUID
   */
  public static String getUniqueId(final String prefix) {
    return prefix + java.util.UUID.randomUUID();
  }

  /**
   * Generates a human readable id prefixed by the given String.
   * 
   * The generated identifier is unique only for the duration of the existence
   * of this class.
   * 
   * @param prefix the string prefiy
   * @return a human readable id prefixed by prefix.
   */
  public static String getHumanReadableId(final String prefix) {
    return prefix + Misc.getHumanReadableId();
  }

  /**
   * Generates a human readable id as a long.
   * 
   * The generated identifier is unique only for the duration of the existence
   * of this class.
   * 
   * @return a unique id as a long.
   */
  public static long getHumanReadableId() {
    return Misc.SEQUENCE_NUMBER.getAndIncrement();
  }

  /**
   * Returns a random number between min and max value
   * 
   * @param min a positive integer
   * @param max a positive integer
   * @return a random number between min and max value
   * @throws IllegalArgumentException if min >= max
   */
  public static int random(final int min, final int max) {
    if (min >= max) {
      throw new IllegalArgumentException("Pre-condition failed: min(" + min + ") < max(" + max + ")");
    }
    final int n = max - min;
    if (n < 0) {
      throw new IllegalArgumentException("Overflow due to big parameters (min: " + min + ", max: " + max + "), sorry!");
    }
    return Misc.RANDOM.nextInt(max - min) + min;
  }

  /**
   * Generate a RANDOM String of the given size.
   * 
   * @param size the size of the generated string
   * @return the RANDOM String
   */
  public static String getRandomString(final int size) {
    final char[] s = new char[size];
    int c = 'A';
    int r1 = 0;
    for (int i = 0; i < size; i++) {
      r1 = (int) (Math.random() * 3);
      switch (r1) {
      case 0:
        c = '0' + (int) (Math.random() * 10);
        break;
      case 1:
        c = 'a' + (int) (Math.random() * 26);
        break;
      case 2:
        c = 'A' + (int) (Math.random() * 26);
        break;
      }
      s[i] = (char) c;
    }
    return new String(s);
  }

  /**
   * 

* Format a delay. *

* *

* This method returns a human readable string for delay such as the one used * in benchmarks. * * This method is thread safe. *

* * @param delay a long value * @return a String value */ public static final String formatDelay(final long delay) { // Don't use Math.abs() here !! // Math.abs(Long.MIN_VALUE) returns Long.MIN_VALUE ! if (delay == Long.MAX_VALUE) { return "INFINITY"; } if (delay == Long.MIN_VALUE) { return "-INFINITY"; } if (Math.abs(delay) >= Misc.DAY) { final long days = delay / Misc.DAY; return days + " day" + ((days > 1) ? "s" : ""); } // Formatter are not thread safe. See Sun Bugs #6231579 and Sun Bug // #6178997. synchronized (Misc.formatterLock) { return (delay < 0) ? "-" + Misc.DELAY_FORMATTER.format(new Date(-delay)) : Misc.DELAY_FORMATTER.format(new Date(delay)); } } /** *

* Equivalent to {@link #formatDelay(long)}. *

* * @param delay a double value * @return a String value */ public static final String formatDelay(final double delay) { return Misc.formatDelay((long) delay); } /** *

* Return the list of Class objects representing every types a * given class implements. *

* * @param type a Class value * @return a Set value */ public static Set> findAllTypes(final Class< ? > type) { final Set> superTypes = Misc.findAllSuperTypes(type); final Set> result = new HashSet>(superTypes); for (final Class< ? > i : superTypes) { result.addAll(Misc.findAllInterfaces(i)); } result.addAll(Misc.findAllInterfaces(type)); return result; } /** * Return the generic name of a given class. * * For example, given java.util.Map.class, it returns string * java.util.Map * * @param clazz the class * @return the generic name of a given class. */ public static String getGenericFullName(final Class< ? > clazz) { final StringBuilder sb = new StringBuilder(clazz.getCanonicalName()); final TypeVariable< ? >[] types = clazz.getTypeParameters(); // This algorithm is weak! It only works for basic type. It will not work // for type such as: Type< A > or Type ... // Please fix it! // TODO: Fix. if (types.length != 0) { sb.append('<'); for (final TypeVariable< ? > type : types) { sb.append(type.getName()); sb.append(','); } sb.replace(sb.length() - 1, sb.length(), ">"); } return new String(sb); } /** *

* Return the list of Class objects representing all super type a * given class implements. *

* * @param type a Class value * @return a Set value */ public static Set> findAllSuperTypes(final Class< ? > type) { final Set> classes = new HashSet>(); for (Class< ? > c = type; c != null; c = c.getSuperclass()) { classes.add(c); } return classes; } /** *

* Return the list of Class objects representing all interfaces a * given class implements. *

* * @param type a Class value * @return a List value */ public static Set> findAllInterfaces(final Class< ? > type) { final Set> classes = new HashSet>(); final Class< ? >[] interfaces = type.getInterfaces(); for (final Class< ? > i : interfaces) { classes.add(i); classes.addAll(Misc.findAllInterfaces(i)); } final Class< ? > superClass = type.getSuperclass(); if (superClass != null) { classes.addAll(Misc.findAllInterfaces(superClass)); } return classes; } /** *

* Return the Class[] array representing the types a given method * take as parameters. *

* * @param subClasses the classes which are to be subclasses of parameters * @param classToTest the class which declares the given method * @param methodName the method name * * @return the formal parameters class array * @throws NoSuchMethodException if a method cannot be found. */ @SuppressWarnings("unchecked") public static Class< ? >[] findMethodClassArgs(final Class< ? >[] subClasses, final Class< ? > classToTest, final String methodName) throws NoSuchMethodException { final Set>[] classesList = new Set[subClasses.length]; for (int i = 0; i < classesList.length; i++) { classesList[i] = Misc.findAllTypes(subClasses[i]); } final Method[] methods = classToTest.getDeclaredMethods(); for (int i = methods.length - 1; i >= 0; i--) { // Same method name? if (!methods[i].getName().equals(methodName)) { continue; } // Same number of arguments? final Class< ? >[] formal = methods[i].getParameterTypes(); if (formal.length != subClasses.length) { continue; } if (Misc.checkFormal(formal, classesList)) { return formal; } } throw new NoSuchMethodException("Can't find formal " + " parameters for specified " + "arguments: " + "subClasses: " + Misc.componentsToString(subClasses, false) + ", classToTest: " + classToTest + ", methodName: " + methodName); } /** *

* Return the Class[] array representing the types a constructor * take as parameters. *

* * @param subClasses the classes which are to be subclasses of parameters * @param classToTest the class which declares the constructor * * @return the formal parameters class array * @throws NoSuchMethodException if a constructor cannot be found */ @SuppressWarnings("unchecked") public static Class< ? >[] findConstructorClassArgs(final Class< ? >[] subClasses, final Class< ? > classToTest) throws NoSuchMethodException { final Set>[] classesList = new Set[subClasses.length]; for (int i = 0; i < classesList.length; i++) { classesList[i] = Misc.findAllTypes(subClasses[i]); } final Constructor< ? >[] constructors = classToTest.getDeclaredConstructors(); for (int i = constructors.length - 1; i >= 0; i--) { // Same number of arguments? final Class< ? >[] formal = constructors[i].getParameterTypes(); if (formal.length != subClasses.length) { continue; } if (Misc.checkFormal(formal, classesList)) { return formal; } } throw new NoSuchMethodException("Can't find formal " + "parameters for specified " + "arguments: " + "subClasses: " + Misc.componentsToString(subClasses, false) + ", classToTest: " + classToTest); } private static boolean checkFormal(final Class< ? >[] formal, final Set>[] types) { for (int i = 0; i < formal.length; i++) { final Iterator> iterator = types[i].iterator(); boolean found = false; while (iterator.hasNext()) { final Class< ? > type = iterator.next(); if (type.equals(formal[i])) { found = true; break; } } if (!found) { return false; } } return true; } /** *

* Return an "identity string" for a given object. *

* *

* The string returned is: *

    *
  • "null" if o == null *
  • Otherwize, * o.getClass().getName() + "#" + System.identityHashCode(o) *
*

* * @param o the object to return the identity string of * @return the identity string as defined above */ public static String identityToString(final Object o) { if (o == null) { return "null"; } return o.getClass().getName() + "#" + System.identityHashCode(o); } /** *

* Smart toString() implementation of arrays. *

* * @param args the array to return a smart string of. * @return the smart string of the given array. */ public static String componentsToString(final Object[] args, final boolean deepToString) { if (args == null) { return "null"; } Class< ? > componentType = args.getClass().getComponentType(); final StringBuilder string = new StringBuilder(componentType.getName()); string.append("["); final int length = args.length; if (length != 0) { final int max = length - 1; for (int i = 0; i < max; i++) { if (args[i] == null) { string.append("null"); } else if (args[i].getClass().isArray()) { componentType = args[i].getClass().getComponentType(); if (componentType.isPrimitive()) { string.append(Misc.primitiveComponentsToString(args[i])); } else { string.append(Misc.componentsToString((Object[]) args[i], deepToString)); } } else { string.append(deepToString ? Misc.deepToString(args[i]) : args[i].toString()); } string.append("; "); } if (args[max] == null) { string.append("null"); } else if (args[max].getClass().isArray()) { componentType = args[max].getClass().getComponentType(); if (componentType.isPrimitive()) { string.append(Misc.primitiveComponentsToString(args[max])); } else { string.append(Misc.componentsToString((Object[]) args[max], deepToString)); } } else { string.append(deepToString ? Misc.deepToString(args[max]) : args[max].toString()); } } string.append("]"); return new String(string); } /** *

* Smart toString() implementation of an array of primitive types. *

* * @param array the array to return a smart string of. * @return the smart string of the given array. */ public static String primitiveComponentsToString(final Object array) { if (array == null) { return "null"; } final Class< ? > c = array.getClass(); if (!c.isArray() || !c.getComponentType().isPrimitive()) { throw new IllegalArgumentException("array must be an " + "array of primitive" + " component"); } final StringBuilder string = new StringBuilder(c.getComponentType().getName()); string.append("["); final int length = Array.getLength(array); if (length != 0) { final int max = length - 1; for (int i = 0; i < max; i++) { string.append(Array.get(array, i)); string.append("; "); } string.append(Array.get(array, max)); } string.append("]"); return new String(string); } /** * Equivalent to {@link #getAllContentFrom(InputStream) getAllContentFrom(new * FileInputStream(file))}; * * @param file the file to read * @return the whole content of the file in a single String. * @throws IOException If an I/O exception occured */ public static byte[] getAllContentFrom(final File file) throws IOException { InputStream in = null; try { in = new FileInputStream(file); return Misc.getAllContentFrom(in); } finally { Misc.close(in); } } /** * Equivalent to {@link #getAllContentFrom(InputStream) * getAllContentFrom(source.getByteStream(source))}; * * @param file the file to read * @return the whole content of the file in a single String. * @throws IOException If an I/O exception occured */ public static byte[] getAllContentFrom(final InputSource source) throws IOException { InputStream in = null; try { in = source.getByteStream(); return Misc.getAllContentFrom(in); } finally { Misc.close(in); } } /** * Return the whole underlying stream content into a single String. * * Warning: the whole content of stream will be kept in memory!! Use with * care! * * @param in the stream to read * @return the whole content of the stream in a single String. * @throws IOException if an I/O exception occured */ public static byte[] getAllContentFrom(final URL url) throws IOException { final InputStream in = url.openStream(); return Misc.getAllContentFrom(in); } /** * Return the whole underlying stream content into a single String. * * Warning: the whole content of stream will be kept in memory!! Use with * care! * * @param in the stream to read * @return the whole content of the stream in a single String. * @throws IOException if an I/O exception occured */ public static byte[] getAllContentFrom(final InputStream in) throws IOException { final BufferedInputStream bis = new BufferedInputStream(in); final ByteArrayOutputStream result = new ByteArrayOutputStream(); int c; while ((c = bis.read()) != -1) { result.write(c); } return result.toByteArray(); } /** * Equivalent to {@link #reflectClose(closeable)} */ public static Exception close(final Closeable closeable) { return Misc.reflectClose(closeable); } /** * Equivalent to {@link #reflectClose(encoder) */ public static Exception close(final XMLEncoder encoder) { return Misc.reflectClose(encoder); } /** * Equivalent to {@link #reflectClose(decoder) */ public static Exception close(final XMLDecoder decoder) { return Misc.reflectClose(decoder); } /** * Invoke the close() method on the given object. * * This method uses the reflection API to find a close() method with no * arguments. Any exception thrown (including NoSuchMethodException) will be * both logged using {@link #LOG} and returned. If the parameter is null, * nothing is done and null is returned. * * @param o the object to call the close() method on. * @return the exception thrown if any, null otherwise. */ public static Exception reflectClose(final Object o) { if (o == null) { return null; } try { final Method m = o.getClass().getMethod("close", new Class[0]); m.invoke(o, new Object[0]); } catch (final Exception e) { final StringBuilder sb = new StringBuilder("Exception thrown during close() on: "); sb.append(o.toString()); sb.append(Misc.LINE_SEPARATOR); sb.append("Exception message is: "); sb.append(e.getMessage()); sb.append(Misc.LINE_SEPARATOR); sb.append(Misc.getStackTraceFrom(e)); Misc.LOG.warning(sb.toString()); return e; } return null; } /** * @param permissions * @return */ public static int getPermissionsSize(final Permissions permissions) { int size = 0; final Enumeration p = permissions.elements(); while (p.hasMoreElements()) { size++; } return size; } /** * Return a proxy implementing all the interfaces specified that forward * method invocations to the specified MBean. * * @param * @param mbeanInterface the interface the proxy should implement (the MBean * should obviously also implement that interface). * @param jmxServiceUrl the JMX service URL * @param jmxObjectName the name the MBean has been registered to * @return a proxy implementing the specified interface and that forward * method invocations to the specified MBean. * * @throws IOException for any IO problem * @throws MalformedObjectNameException for any JMX Naming problem * @throws MBeanException for any MBean problem * @throws ReflectionException for any problem related to reflection */ @SuppressWarnings("unchecked") public static T getMBeanProxy(final Class mbeanInterface, final String jmxServiceUrl, final String jmxObjectName) throws IOException, MalformedObjectNameException, InstanceNotFoundException, MBeanException, ReflectionException { return (T) Proxy.newProxyInstance(Misc.class.getClassLoader(), new Class[] { mbeanInterface }, new MBeanInvocationHandler(jmxServiceUrl, jmxObjectName)); } /** * Return a proxy that forward void-method invocations to * each object specified in the list elements. * * The invocation order follows the given list order. * * @param the interface type of the returned proxy and of each elements. * @param elements the elements to forward method invocations to * @return the forwarding chaining proxy * @see Chainer * @see InvocationHandler * @see Proxy */ @SuppressWarnings("unchecked") public static T getChainOf(final List elements) { Misc.checkArgsNotNull(elements); final Chainer chain = new Chainer(); final Set> classes = new HashSet>(); final Set> initial = Misc.findAllInterfaces(elements.get(0).getClass()); classes.addAll(initial); for (final T element : elements) { chain.add(element); // We can't find the generic type T at runtime. // But this is required by Proxy.newProxyInstance(). // So, we find the common interfaces implemented by all elements. final Set> interfaces = Misc.findAllInterfaces(element.getClass()); classes.retainAll(interfaces); } if (classes.size() == 0) { throw new IllegalArgumentException("Can't find a common interface between classes of elements: " + elements); } return (T) Proxy.newProxyInstance(Misc.class.getClassLoader(), classes.toArray(new Class[classes.size()]), chain); } /** * Return a proxy that log method invocations through the provided logger. * * @param the target object type * @param target the target object method invocations should be forwarded to * @param logger the logger to use for logging * @return a proxy that log method invocations through the provided logger. * @see LoggingInvocationHandler * @see InvocationHandler * @see Proxy */ @SuppressWarnings("unchecked") public static T getLoggerProxyFor(final T target, final Logger logger) { final Set> classes = Misc.findAllInterfaces(target.getClass()); return (T) Proxy.newProxyInstance(Misc.class.getClassLoader(), classes.toArray(new Class[classes.size()]), new LoggingInvocationHandler(target, logger)); } /** * Represents null value returned by {@link Misc#findNull(Object...)}. * * @see Misc#findNull(Object...) * @author Pierre Vigneras * @date Feb 7, 2008 */ public static class NullCheckResult { private final int size; private final BitSet bitSet; NullCheckResult(final BitSet bitSet, final int size) { this.bitSet = bitSet; this.size = size; } /** * Returns true if some parameters given to {@link Misc#findNull(Object...)} * were null. * * @return true if some parameters given to {@link Misc#findNull(Object...)} * were null. * @see Misc#findNull(Object...) */ public boolean hasNull() { return this.bitSet.cardinality() != 0; } /** * Returns the number of parameters given to * {@link Misc#findNull(Object...)} * * @return the number of parameters given to * {@link Misc#findNull(Object...)} * @see Misc#findNull(Object...) */ public int getSize() { return this.size; } /** * Returns true if the i th parameter given to * {@link Misc#findNull(Object...)} was null. * * @param i the rank of the parameter given to * {@link Misc#findNull(Object...)}. * @return true if the i th parameter given to * {@link Misc#findNull(Object...)} was null. */ public boolean isNull(final int i) { return this.bitSet.get(i); } } /** * Find null parameters in the given list. * * This method returns a {@link NullCheckResult}. * * * @param params the parameters to check * @return a {@link NullCheckResult} representing null parameters. * @see NullCheckResult */ public static NullCheckResult findNull(final Object... params) { if (params == null) { final BitSet bitSet = new BitSet(1); bitSet.set(0); return new NullCheckResult(bitSet, 1); } final BitSet bitSet = new BitSet(params.length); for (int i = 0; i < params.length; i++) { if (params[i] == null) { bitSet.set(i, true); } else { bitSet.set(i, false); } } return new NullCheckResult(bitSet, params.length); } /** * Check that the given parameters are not null. * * This method should only be used to check that some parameters given to a * given method are not null. The exception message tries its best to produce * a helpful message by scanning the stack trace. * * @param params the parameters to check * @throws an IllegalArgumentException if at least one of the parameters is * null */ public static void checkArgsNotNull(final Object... params) { Misc.checkArgsNotNull(1, params); } /** * Check that the given parameters are not null. * * This method should only be used to check that some parameters given to a * given method are not null. The exception message tries its best to produce * a helpful message by scanning the stack trace. * * @param offset the offset to use in the stack trace to produce error message * @param params the parameters to check * @throws an IllegalArgumentException if at least one of the parameters is * null */ public static void checkArgsNotNull(final int offset, final Object... params) { final NullCheckResult result = Misc.findNull(params); if (result.hasNull()) { // Guess the signature of the caller final StackTraceElement callerSTE = Misc.getCaller(offset + 1); final String className = callerSTE.getClassName(); final String methodName = callerSTE.getMethodName(); final StringBuilder sb = new StringBuilder("Some parameters are null in " + className + "." + methodName + "(): "); for (int i = 0; i < result.getSize(); i++) { if (result.isNull(i)) { sb.append("null"); } else { sb.append(params[i].getClass().getName()); } if (i < result.getSize() - 1) { sb.append(", "); } } throw new IllegalArgumentException(sb.toString()); } } /** * Return the StackTraceElement at the given offset from this method * invocation. * * @param offset * @return a StackTraceElement */ public static StackTraceElement getCaller(final int offset) { final StackTraceElement[] stes = Thread.currentThread().getStackTrace(); StackTraceElement callerSTE = null; for (int i = 0; i < stes.length - offset - 1; i++) { if (stes[i].getClassName().equals(Misc.class.getName()) && stes[i].getMethodName().equals("getCaller")) { callerSTE = stes[i + 1 + offset]; break; } } Misc.badStateIfNull(callerSTE, "Ouch! Can't get the stack trace back to the caller of this method!"); return callerSTE; } /** * Return strings mapped to null values in a given @{link * {@link NullCheckResult}. . * * If the returned @{link List} of String is called l then, it * verifies: l.contains(names[i]) if and only if * nullCheckResult.isNull(i) returns true. * * Note that the number of String names given should be of the same size that * the one used to get the given {@link NullCheckResult} using * {@link #findNull(Object...)}. An {@link IllegalArgumentException} is thrown * otherwise. * * @param nullCheckResult the result as returned by * {@link #findNull(Object...)} * @param names the strings that should be mapped to null values * @return a List of string mapped to the given {@link NullCheckResult}. * @throws IllegalArgumentException if the number of given names is different * that {@link NullCheckResult#size()} * * @see #findNull(Object...) * @see NullCheckResult */ public static List getStringFrom(final NullCheckResult nullCheckResult, final String... names) { final int n = names.length; if (nullCheckResult.getSize() != n) { throw new IllegalArgumentException("Number of string names is different " + "from the arguments used to get the nullCheckResult: " + n + " != " + nullCheckResult.getSize()); } final List list = new ArrayList(); if (!nullCheckResult.hasNull()) { return list; } for (int i = 0; i < n; i++) { if (nullCheckResult.isNull(i)) { list.add(names[i]); } } return list; } /** * This method throw an IllegalStateException if the given parameter is null * * @param valueToCheck the value to check * @param msg the message for the thrown exception * * @see IllegalStateException */ public static void badStateIfNull(final Object valueToCheck, final String msg) { Misc.badStateIfTrue(valueToCheck == null, msg); } /** * This method throw an IllegalStateException if the given parameter is not * null * * @param valueToCheck the value to check * @param msg the message for the thrown exception * * @see IllegalStateException */ public static void badStateIfNotNull(final Object valueToCheck, final String msg) { Misc.badStateIfTrue(valueToCheck != null, msg); } /** * This method throw an IllegalStateException if the given parameter is true * * @param valueToCheck the value to check * @param msg the message for the thrown exception * * @see IllegalStateException */ public static void badStateIfTrue(final boolean valueToCheck, final String msg) { if (valueToCheck) { throw new IllegalStateException(msg); } } /** * This method throw an IllegalStateException if the given parameter is false * * @param valueToCheck the value to check * @param msg the message for the thrown exception * * @see IllegalStateException */ public static void badStateIfFalse(final boolean valueToCheck, final String msg) { Misc.badStateIfTrue(!valueToCheck, msg); } /** * This method throw an IllegalStateException if the given parameters are * equals (using {@link Object#equals(Object)} * * @param a the first object * @param b the second object * @param msg the message for the thrown exception * * @see IllegalStateException */ public static void badStateIfEquals(final Object a, final Object b, final String msg) { Misc.badStateIfTrue(a.equals(b), msg); } /** * Log a message to the logger of the caller at the given offset in the stack * trace. * * If A.f() calls B.g() that finally calls * dynamicLog(1, msg) then, the msg will be logged with a code * similar to:
* getLogger(B.getClass().getName()).log(level, msg);
* * If the call was dynamicLog(2, msg) then, the code would be:
* getLogger(A.getClass().getName()).log(level, msg);
* * * @param offset the offset in the stack trace * @param level the level to log the message to * @param msg the message to log * @return */ public static void dynamicLog(final int offset, final Level level, final String msg) { final StackTraceElement callerSTE = Misc.getCaller(offset); final String className = callerSTE.getClassName(); final String methodName = callerSTE.getMethodName(); final Logger logger = Logger.getLogger(className); final LogRecord record = new LogRecord(level, msg); record.setSourceClassName(className); record.setSourceMethodName(methodName); record.setLoggerName(logger.getName()); logger.log(record); } /** * Log the given message at the given level using caller's Logger. * * @param level a level * @param msg the message * @see #dynamicLog(int, Level, String) */ public static void log(final Level level, final String msg) { Misc.dynamicLog(2, level, msg); } /** * This method logs at the given level a "warning message" if the given * parameter is null * * @param level a log level * @param valueToCheck the value to check * @param variableName the variable name holding valueToCheck. Can be null. * */ public static void warnIfNull(final Level level, final Object valueToCheck, final String variableName) { if (valueToCheck == null) { final String msg = "Warning: " + ((variableName == null) ? "a variable" : variableName) + " is null!"; Misc.dynamicLog(1, level, msg); } } /** * This method logs at the given level a "warning" if the given parameter is * not null * * @param level a log level * @param valueToCheck the value to check * @param variableName the variable name holding valueToCheck. Can be null. */ public static void warnIfNotNull(final Level level, final Object valueToCheck, final String variableName) { if (valueToCheck != null) { final String msg = "Warning: " + ((variableName == null) ? "a variable" : variableName) + " is not null!"; Misc.dynamicLog(1, level, msg); } } /** * This method logs at the given level a "warning" if the given parameter is * true * * @param level a log level * @param valueToCheck the value to check * @param variableName the variable name holding valueToCheck. Can be null. */ public static void warnIfTrue(final Level level, final boolean valueToCheck, final String variableName) { if (valueToCheck) { final String msg = "Warning: " + ((variableName == null) ? "a variable" : variableName) + " is true!"; Misc.dynamicLog(1, level, msg); } } /** * This method logs at the given level a "warning" if the given parameter is * false * * @param level a log level * @param valueToCheck the value to check * @param variableName the variable name holding valueToCheck. Can be null. */ public static void warnIfFalse(final Level level, final boolean valueToCheck, final String variableName) { if (!valueToCheck) { final String msg = "Warning: " + ((variableName == null) ? "a variable" : variableName) + " is false!"; Misc.dynamicLog(1, level, msg); } } /** * This method logs at the given level a "warning" if the given parameter are * equals * * @param level a log level * @param a an object * @param b another object */ public static void warnIfEquals(final Level level, final Object a, final Object b) { if (a.equals(b)) { Misc.dynamicLog(1, level, "Warning: equals objects: " + Misc.LINE_SEPARATOR + Misc.details(a, b)); } } private static String details(final Object a, final Object b) { return "a.toString(): " + a.toString() + Misc.LINE_SEPARATOR + "b.toString(): " + b.toString() + Misc.LINE_SEPARATOR + "a.idendityToString(): " + Misc.identityToString(a) + Misc.LINE_SEPARATOR + "b.identityToString(): " + Misc.identityToString(b); } /** * This method logs at the given level a "warning" if the given parameter are * not equals * * @param level a log level * @param a an object * @param b another object */ public static void warnIfNotEquals(final Level level, final Object a, final Object b) { if (!a.equals(b)) { Misc.dynamicLog(1, level, "Warning: non-equals objects: " + Misc.LINE_SEPARATOR + Misc.details(a, b)); } } public static String getCurrentThreadStackTrace() { final StackTraceElement[] elements = Thread.currentThread().getStackTrace(); final StringBuilder stringBuilder = new StringBuilder(); for (final StackTraceElement element : elements) { stringBuilder.append(element.toString()); stringBuilder.append(Misc.LINE_SEPARATOR); } return stringBuilder.toString(); } public static String getStackTraceFrom(final Throwable t) { final StringWriter stringBuilder = new StringWriter(); for (final StackTraceElement element : t.getStackTrace()) { stringBuilder.append(" at "); stringBuilder.append(element.toString()); stringBuilder.append(Misc.LINE_SEPARATOR); } return stringBuilder.toString(); } public static String deepToString(final Object o) { return Misc.recursiveDeepToString(o, new HashMap()); } private static String recursiveDeepToString(final Object o, final Map cache) { String result = cache.get(o); final String id = "@" + Integer.toHexString(System.identityHashCode(o)); if (result != null && result != id) { return result; } if (o == null) { result = "null"; } else { cache.put(o, id); final Class< ? > clazz = o.getClass(); final Package pack = clazz.getPackage(); if (clazz.isPrimitive() || (pack != null) && (pack.getName().startsWith("java.")) || clazz.isEnum()) { result = o.toString(); } else if (clazz.isArray()) { final Class< ? > componentType = clazz.getComponentType(); if (componentType.isPrimitive()) { result = Misc.primitiveComponentsToString(o); } else { result = Misc.componentsToString((Object[]) o, true); } } else { final StringBuilder sb = new StringBuilder(clazz.getName()); sb.append('('); sb.append(id); sb.append(')'); sb.append("["); final Field[] fields = clazz.getDeclaredFields(); for (final Field field : fields) { try { field.setAccessible(true); sb.append(field.getName()); sb.append(": "); // final Class type = field.getType(); final Object f = field.get(o); final String v = cache.get(f); sb.append(v == id ? id : Misc.recursiveDeepToString(f, cache)); } catch (final IllegalAccessException e) { Misc.LOG.warning("An exception occured during information fetching on field: " + field + Misc.LINE_SEPARATOR + "Stack trace is: " + Misc.getStackTraceFrom(e) + "Fallbacking to non-intrusive algorithm for toString()."); sb.append("(*"); sb.append(field.toGenericString()); sb.append("*)"); } sb.append(", "); } if (fields.length != 0) { sb.delete(sb.length() - 2, sb.length()); } sb.append("]"); result = new String(sb); } } cache.put(o, result); return result; } /** * Delete a given directory and all its contents (whether they are file or * directory) * * WARNING: this method unconditionally modifies the underlying filesystem by * erasing files and directories. Use with care! * * @param dir the directory to delete */ public static boolean deleteDir(final File dir) { Misc.checkArgsNotNull(dir); boolean result = true; if (!dir.exists()) { return false; } if (!dir.isDirectory()) { throw new IllegalArgumentException("Given file: " + dir.getAbsolutePath() + " is not a directory!"); } final Stack dirStack = new Stack(); dirStack.push(dir); boolean containsSubFolder; while (!dirStack.isEmpty()) { final File currDir = dirStack.peek(); containsSubFolder = false; final String[] fileArray = currDir.list(); for (final String element : fileArray) { final String fileName = currDir.getAbsolutePath() + File.separator + element; final File file = new File(fileName); if (file.isDirectory()) { dirStack.push(file); containsSubFolder = true; } else { result = result && file.delete(); // delete file } } if (!containsSubFolder) { dirStack.pop(); // remove curr dir from stack result = result && currDir.delete(); // delete curr dir } } return result; } // public static Collection addAllDeep(Collection src, Collection // dst, Cloner cloner) { // for (T t : src) { // dst.add(cloner.newClone(t)); // } // return dst; // } public static void unreachableStatement() { Misc.unreachableStatement("This statement should never be reached!"); } public static void unreachableStatement(final String reason) { throw new IllegalStateException(reason); } // This code has been taken from: // http://forum.java.sun.com/thread.jspa?threadID=760266&messageID=4340490 // It has been slightly adapted to our needs. public static > E stringToEnum(final Class c, final String s) { final EnumSet set = EnumSet.allOf(c); for (final E e : set) { if (e.toString().equals(s)) { return e; } } throw new IllegalArgumentException("Unknown enum string for " + c.getName() + ": " + s + ". Possible values are: " + set.toString()); } public static byte[] serialize(final Serializable object) throws IOException, ClassNotFoundException { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(object); out.flush(); out.close(); // Get the bytes of the serialized object final byte[] buf = bos.toByteArray(); return buf; } public static Serializable deserialize(final byte[] buf) throws IOException, ClassNotFoundException { final ByteArrayInputStream bais = new ByteArrayInputStream(buf); final ObjectInputStream ois = new ObjectInputStream(bais) { @Override protected Class< ? > resolveClass(final ObjectStreamClass desc) throws IOException, ClassNotFoundException { final String className = desc.getName(); return Thread.currentThread().getContextClassLoader().loadClass(className); } }; final Serializable newObject = (Serializable) ois.readObject(); ois.close(); return newObject; } /** * Check that the given object is actually serializable. * * Implementation tries to serialize and deserialize the given object (in * memory). Note that null is returned when the given object is * serializable. It returns the throwable thrown by either the serialization * or the deserialization process. This means, that the object is not really * serializable. Therefore the pattern for checking should be written like:
* * final Throwable error = checkReallySerializable(myObject); * if (error == null) { * // success * } else { * // failure, do something with error... * error.printStackTrace(); * } * * * @param A type (usually extending {@link Serializable} * @param object the object to check * @return null on success, the exception thrown on error */ public static Throwable checkReallySerializable(final T object) { try { final byte[] buf = Misc.serialize(object); Misc.deserialize(buf); return null; } catch (final Throwable t) { return t; } } /** * Write the given String to the given file using the default encoding. * * @param s the string to be written * @param f the file to write the given string to * @throws IOException if an IO error is encoutered (file not found, read-only * file, and so on). */ public static void write(final String s, final File f) throws IOException { Misc.checkArgsNotNull(s, f); final FileWriter writer = new FileWriter(f); try { writer.write(s); writer.flush(); } finally { Misc.close(writer); } } public static void write(final File file, final byte[] fileContent) throws IOException { Misc.checkArgsNotNull(file, fileContent); if (!file.exists()) { if (file.mkdirs()) { throw new IOException("Can't create some directories in: " + file.getCanonicalPath()); } } OutputStream os = null; try { os = new FileOutputStream(file); os.write(fileContent); os.flush(); } finally { Misc.close(os); } } /** * Perform java.io.File.createTempFile with retries when it fail (limit of 10 * retries) (Use to by-pass bug #6325169 on SUN JDK 1.5 on windows) Sames * parameter as {@link java.io.File.createTempFile} method * * @param prefix Prefix of the file * @param suffix Suffix of the file * @param directory Target directory * @return An abstract pathname denoting a newly-created empty file * @throws IOException If a file could not be created */ public static File createTempFile(final String prefix, final String suffix, final File directory) throws IOException { // By-pass for the bug #6325169 on SUN JDK 1.5 on windows // The createTempFile could fail while creating a file with the same name of // an existing directory // So if the file creation fail, it retry (with a limit of 10 retry) // Rethrow the IOException if all retries failed File tmpDir = null; final int retryNumber = 10; int j = 0; boolean succeded = false; do { try { tmpDir = File.createTempFile(prefix, suffix, directory); succeded = true; } catch (final IOException e) { if (j == retryNumber) { throw e; } try { Thread.sleep(100); } catch (final InterruptedException e1) { } j++; } } while (!succeded); return tmpDir; } public static byte[] generateJar(final Class< ? >... classes) throws IOException { return Misc.generateJar(Misc.getResources(classes)); } public static Map getResources(final Class< ? >... classes) throws IOException { if (classes == null || classes.length == 0) { throw new IOException("No classes available"); } final Map resources = new HashMap(); for (final Class< ? > clazz : classes) { resources.put(clazz.getName() + ".class", ClassDataTool.getClassData(clazz)); } return resources; } public static byte[] generateJar(final Map resources) throws IOException { if (resources == null || resources.size() == 0) { throw new IOException("No Resources available"); } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final JarOutputStream out = new JarOutputStream(new BufferedOutputStream(baos)); for (final Map.Entry resource : resources.entrySet()) { out.putNextEntry(new JarEntry(resource.getKey())); out.write(resource.getValue()); } out.flush(); Misc.close(out); return baos.toByteArray(); } public static Map getResourcesFromZip(final byte[] barContent) throws IOException { final Map resources = new HashMap(); final InputStream in = new ByteArrayInputStream(barContent); final ZipInputStream zis = new ZipInputStream(in); ZipEntry zipEntry = null; while ((zipEntry = zis.getNextEntry()) != null) { if (!zipEntry.isDirectory()) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); int c; final byte[] buffer = new byte[512]; while ((c = zis.read(buffer)) != -1) { baos.write(buffer, 0, c); } baos.flush(); resources.put(zipEntry.getName(), baos.toByteArray()); Misc.close(baos); } } zis.close(); in.close(); return resources; } @SuppressWarnings("unchecked") public static T lookup(final String name, final Hashtable environment) throws NamingException { InitialContext initialContext = null; if (environment != null) { initialContext = new InitialContext(environment); } else { initialContext = new InitialContext(); } return (T) initialContext.lookup(name); } /** * Return a new string based on the given message string where all lines are * prefixed by the given prefix. * * * @param message the message to transform * @param prefix the prefix to use * @return the prefixed string */ public static String prefixAllLines(final String message, final String prefix) { Misc.checkArgsNotNull(message, prefix); if (message.length() == 0) { return prefix; } final BufferedReader reader = new BufferedReader(new StringReader(message)); final StringBuilder builder = new StringBuilder(); String line; try { while ((line = reader.readLine()) != null) { if (builder.length() != 0) { builder.append(Misc.LINE_SEPARATOR); } builder.append(prefix).append(line); } } catch (final IOException e) { Misc.unreachableStatement("Ouch! How can it be that a StringReader throws an IOException?"); } finally { Misc.close(reader); } return builder.toString(); } }