Package winterwell.utils

Source Code of winterwell.utils.Utils

package winterwell.utils;

import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import winterwell.utils.containers.Containers;
import winterwell.utils.containers.Pair2;
import winterwell.utils.io.FastByteArrayInputStream;
import winterwell.utils.io.FastByteArrayOutputStream;
import winterwell.utils.io.FileUtils;
import winterwell.utils.reporting.Log;
import winterwell.utils.time.Time;
import winterwell.utils.web.XStreamUtils;

/**
* @testedby {@link UtilsTest}
* @author daniel
*
*/
public class Utils {

  private static final char[] consonants = "bcdfghjklmnpqrstvwxz"
      .toCharArray();
  private static final AtomicInteger id = new AtomicInteger(1);
  private final static Pattern notBlank = Pattern.compile("\\S");

  /**
   * Note Random is thread safe. Is using it across threads a bottleneck? If
   * you need repeatable results, you should create your own Random where you
   * can control both the seed and the usage.
   */
  private static final Random r = new Random();

  private static final char[] vowels = "aeiouy".toCharArray();

  /**
   * Check inputs are all non-null
   *
   * @param args
   * @throws NullPointerException
   *             if any of args are null
   */
  public static void check4null(Object... args) throws NullPointerException {
    for (int i = 0; i < args.length; i++) {
      if (args[i] == null)
        throw new NullPointerException("Argument " + i + " in "
            + Printer.toString(args));
    }
  }

  /**
   * A version of {@link Comparable#compareTo(Object)} for <i>any</i> two
   * objects. Arguments can be null (which come last).
   *
   * @param a
   * @param b
   * @return equivalent to a.compareTo(b) if that makes sense
   */
  public static int compare(Object a, Object b) {
    if (a == b)
      return 0;
    if (a == null)
      return 1;
    if (b == null)
      return -1;
    try {
      return ((Comparable) a).compareTo(b);
    } catch (ClassCastException e) {
      int ahash = a.hashCode();
      int bhash = b.hashCode();
      if (ahash == bhash)
        return 0;
      return ahash < bhash ? -1 : 1;
    }
  }

  /**
   * Perform a DEEP copy of the object, using XStream
   *
   * @param object
   * @return a copy of object, which should share no structure
   * @testedby {@link UtilsTest#testCopy()}
   */
  public static <X> X copy(X object) {
    FastByteArrayOutputStream out = new FastByteArrayOutputStream();
    XStreamUtils.xstream().toXML(object, out);
    FastByteArrayInputStream in = new FastByteArrayInputStream(
        out.getByteArray(), out.getSize());
    Object copy = XStreamUtils.xstream().fromXML(in);
    return (X) copy;
  }

  /**
   * Convenience for a==null? b==null : a.equals(b)
   * <p>
   * Beware: numerical values of different classes are NOT tested for
   * numerical equivalence. E.g. 1 != 1L != 1.0. You must cast them into
   * yourself if you need this behaviour. Note: experimented with this, but
   * there are issues, e.g. with large longs vs large doubles
   *
   * @param a
   * @param b
   * @return true if a.equals(b)
   */
  public static boolean equals(Object a, Object b) {
    if (a == null)
      return b == null;
    return a.equals(b);
  }

  /**
   * Who called this method?
   *
   * @param ignore
   *            list of class or method names to ignore (will then search
   *            higher up the stack)
   * @return Can be a dummy entry if the filters exclude everything. Never
   *         null.
   */
  public static StackTraceElement getCaller(String... ignore) {
    List<String> ignoreNames = Arrays.asList(ignore);
    try {
      throw new Exception();
    } catch (Exception e) {
      StackTraceElement[] trace = e.getStackTrace();
      for (int i = 2; i < trace.length; i++) {
        String clazz = trace[2].getClassName();
        String method = trace[2].getMethodName();
        if (ignoreNames.contains(clazz) || ignoreNames.contains(method)) {
          continue;
        }
        return trace[2]; // new Pair<String>(clazz, method);
      }
      return new StackTraceElement("filtered", "?", null, -1);
    }
  }

  /**
   *
   * @param f
   * @return time-of-commit, SHA1-key
   */
  public static Pair2<Time, String> getGitRevision(File f) {
    // git log --shortstat -n 1
    Process p = new Process("git log --shortstat -n 1 "
        + f.getAbsolutePath());
    p.run();
    p.waitFor();
    String output = p.getOutput();
    String[] tBits = StrUtils.find("Date:\\s*(.+)", output);
    String[] cBits = StrUtils.find("commit\\s*(\\w+)", output);
    assert tBits != null && tBits.length > 1 : f.getAbsolutePath() + "\n"
        + output;
    assert cBits != null && cBits.length > 1 : f.getAbsolutePath() + "\n"
        + output;
    Time time = new Time(tBits[1].trim());
    String key = cBits[1];
    return new Pair2<Time, String>(time, key);
  }

  /**
   * @return a number, starting with 1 and incremented each time. This is
   *         guaranteed to be unique _within this run of the jVM_, upto
   *         overflow.
   *
   * @see #getUID()
   */
  public static int getId() {
    return id.getAndIncrement();
  }

  /**
   * @return lower case string for the operating system. E.g. ??
   */
  public static String getOperatingSystem() {
    String osName = System.getProperty("os.name");
    return osName.toLowerCase();
  }

  /**
   * Load a password from HOME/.winterwell/password
   */
  public static String getPassword() {
    String home = System.getProperty("user.home");
    File pwdf = new File(home, ".winterwell/password");
    String pwd = FileUtils.read(pwdf).trim();
    return pwd;
  }

  /**
   * @return a Random instance for generating random numbers. This is to avoid
   *         generating new Random instances for each number as the results
   *         aren't well distributed.
   *         <p>
   *         If you need repeatable results, you should create your own
   *         Random.
   *         <p>
   *         Note: Java's Random <i>is</i> thread safe, and can be used by
   *         many threads - although for high simultaneous usage, you may wish
   *         to create your own Randoms.
   */
  public static Random getRandom() {
    return r;
  }

  /**
   * @param prob
   * @return true with P(prob)
   */
  public static boolean getRandomChoice(double prob) {
    assert MathUtils.isProb(prob) : prob;
    if (prob == 0)
      return false;
    if (prob == 1)
      return true;
    return getRandom().nextDouble() < prob;
  }

  /**
   * Pick an element using uniform random choice
   *
   * @param <X>
   * @param list
   *            Must not be empty
   * @return
   */
  public static <X> X getRandomMember(Collection<X> list) {
    assert list.size() != 0;
    int i = getRandom().nextInt(list.size());
    return Containers.get(list, i);
  }

  /**
   * Return a set of (uniformly) randomly selected elements of the specified
   * collection. Equality in the set is determined in the usual way i.e. by
   * calling equals(). If num is greater than choices return all the choices
   * in a fresh object.
   *
   * @param num
   * @param choices
   * @return set of randomly selected choices.
   */
  public static <X> Collection<X> getRandomSelection(int num,
      Collection<X> choices) {
    if (num >= choices.size())
      return new ArrayList<X>(choices);
    List<X> listChoices = Containers.getList(choices);
    Set<X> selected = new HashSet<X>(num);
    int iter = 0;
    while (selected.size() < num) {
      int i = r.nextInt(choices.size());
      X x = listChoices.get(i);
      selected.add(x);
      // time out if we get stuck
      iter++;
      if (iter == num * 100) {
        Log.report("Breaking out of random-selection loop early: Failed to select a full "
            + num + " from " + choices);
        break;
      }
    }
    return selected;
  }

  /**
   * A random lower case string
   *
   * @param len
   * @return
   */
  public static String getRandomString(int len) {
    Random r = getRandom();
    char[] s = new char[len];
    for (int i = 0; i < len; i++) {
      // roughly consonant-consonant-vowel for pronounceability
      char c;
      if (r.nextInt(3) == 0) {
        c = vowels[r.nextInt(vowels.length)];
      } else {
        c = consonants[r.nextInt(consonants.length)];
      }
      s[i] = c;
    }
    return new String(s);
  }

  /**
   * The original exception within a nested exception. Has some knowledge of
   * SQLExceptions
   *
   * @param e
   *            Any exception
   * @return the root cause, or e if it is the root cause. Never null.
   */
  public static Throwable getRootCause(Throwable e) {
    // Chained SQL exceptions?
    // SQL exceptions are horrible - they hide their true cause.
    if (e instanceof SQLException) {
      SQLException ex = (SQLException) e;
      SQLException ex2 = ex.getNextException();
      if (ex2 != null)
        return getRootCause(ex2);
    }
    Throwable cause = e.getCause();
    if (cause == null || cause == e)
      return e;
    return getRootCause(cause);
  }

  @Deprecated
  // since we don't use SVN anymore. Much
  public static int getSVNRevision(File f) {
    // workaround: svn can be a bit slow - which returns early & blank!
    for (int sleep : new int[] { 100, 2000 }) {
      Process p = new Process("svn info " + f.getAbsolutePath());
      p.run();
      Utils.sleep(sleep);
      p.waitFor();
      String output = p.getOutput();
      if (!output.contains("Revision")) {
        continue;
      }
      String[] bits = StrUtils.find("Revision:\\s*(\\d+)", output);
      assert bits != null && bits.length > 1 : f.getAbsolutePath() + " "
          + output;
      return Integer.valueOf(bits[1]);
    }
    throw new FailureException("svn info request failed");
  }

  /**
   * @return an id that shouldn't be in use anywhere else (inc. on any
   *         server).
   * @see #getId()
   */
  public static String getUID() {
    return getRandomString(6)
        + Long.toHexString(System.currentTimeMillis());
  }

  /**
   * @param line
   * @return true if line is null, empty, or contains nothing but whitespace
   */
  public static boolean isBlank(CharSequence line) {
    if (line == null || line.length() == 0)
      return true;
    Matcher m = notBlank.matcher(line);
    boolean nb = m.find();
    return !nb;
  }

  /**
   * Convenience for null or []
   *
   * @param list
   * @return true if list == null || list.isEmpty()
   */
  public static boolean isEmpty(Collection list) {
    return list == null || list.isEmpty();
  }

  public static boolean isEmpty(Map map) {
    return map == null || map.isEmpty();
  }

  public static boolean isInt(String matchid) {
    try {
      Integer.valueOf(matchid);
      return true;
    } catch (Exception e) {
      return false;
    }

  }

  /**
   * Generalized version of Math.max
   */
  public static <T extends Comparable<T>> T max(T a, T b) {
    if (a.compareTo(b) <= 0)
      return b;
    return a;
  }

  /**
   * Generalized version of Math.min
   */
  public static <T extends Comparable<T>> T min(T a, T b) {
    if (a.compareTo(b) <= 0)
      return a;
    return b;
  }

  /**
   * Convenience filter.
   *
   * @param objects
   *            Can be null
   * @return first non-null non-blank object (zero-length CharSequences count
   *         as blank), or null if all are null.
   */
  // Sadly no lazy evaluation, so this is less useful than it's lisp
  // counterpart.
  public static <X> X or(X... objects) {
    if (objects == null)
      return null;
    for (X object : objects) {
      if (object == null) {
        continue;
      }
      if (object instanceof CharSequence
          && ((CharSequence) object).length() == 0) {
        continue;
      }
      return object;
    }
    return null;
  }

  /**
   * @return true for linux or unix
   */
  public static boolean OSisUnix() {
    String os = getOperatingSystem();
    return os.contains("linux") || os.contains("unix");
  }

  /**
   * Includes some special case handling for SQL exceptions, to make debugging
   * a bit less painful (trys to avoid the "SQLException caused by: see next
   * exception, which you can't do now, mwhaha" message).
   *
   * @param e
   * @return
   */
  public static RuntimeException runtime(Throwable e) {
    if (e instanceof RuntimeException)
      return (RuntimeException) e;
    // SQL exceptions are horrible - throw the cause instead
    if (e instanceof SQLException) {
      e = getRootCause(e);
    }
    // get some more info out of Hibernate... would be nice but the
    // dependencies are horrible
    // if (e instanceof JDBCException) e.getSQL()
    return new WrappedException(e);
  }

  /**
   * Sleep. Converts InterruptedExceptions into unchecked wrapped exceptions.
   *
   * @param millis
   */
  public static void sleep(long millis) {
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
      throw Utils.runtime(e);
    }
  }

}
TOP

Related Classes of winterwell.utils.Utils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.