/**
* Copyright (C) 2002-2012 The FreeCol Team
*
* This file is part of FreeCol.
*
* FreeCol is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* FreeCol 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FreeCol. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.freecol.common.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Collection of small static helper methods.
*/
public class Utils {
private static final Logger logger = Logger.getLogger(Utils.class.getName());
/** Hex constant digits for get/restoreRandomState. */
private static final String HEX_DIGITS = "0123456789ABCDEF";
/**
* Joins the given strings.
*
* @param delimiter The delimiter to place between the individual strings.
* @param strings The strings to be joined.
* @return Each of the strings in the given array delimited by the given
* string.
*/
public static String join(String delimiter, String... strings) {
if (strings == null || strings.length == 0) {
return null;
} else {
StringBuilder result = new StringBuilder(strings[0]);
for (int i = 1; i < strings.length; i++) {
result.append(delimiter);
result.append(strings[i]);
}
return result.toString();
}
}
/**
* Joins the given strings.
*
* @param delimiter The delimiter to place between the individual strings.
* @param strings The strings to be joined.
* @return Each of the strings in the given array delimited by the given
* string.
*/
public static String join(String delimiter, List<String> strings) {
return join(delimiter, strings.toArray(new String[0]));
}
/**
* Will check if both objects are equal but also checks for null.
*
* @param one First object to compare
* @param two Second object to compare
* @return <code>(one == null && two != null) || (one != null && one.equals(two))</code>
*/
public static boolean equals(Object one, Object two) {
return one == null ? two == null : one.equals(two);
}
/**
* Gets the last part of a string after a supplied delimiter.
*
* @param s The string to operate on.
* @param delim The delimiter.
* @return The last part of the string after the last instance of
* the delimiter, or the original string if the delimiter is
* not present.
*/
public static String lastPart(String s, String part) {
int last = (s == null) ? -1 : s.lastIndexOf(part);
return (last > 0) ? s.substring(last+part.length(), s.length())
: s;
}
/**
* Generalize this method instead of calling it directly elsewhere.
*
* @return String
*/
public static String getUserDirectory() {
return System.getProperty("user.home");
}
/**
* Convenience to aid logging uses of Randoms.
*
* @param logger The <code>Logger</code> to log to.
* @param logMe A string to log with the result.
* @param random A pseudo-<code>Random</code> number source.
* @param range The exclusive maximum integer to return.
* @return A pseudo-random integer r, 0 <= r < range.
*/
public static int randomInt(Logger logger, String logMe, Random random,
int range) {
int ret = random.nextInt(range);
if (logger != null) {
logger.finest(logMe + " random(" + range + ") = " + ret);
}
return ret;
}
/**
* Convenience to aid logging uses of Randoms.
*
* @param logger The <code>Logger</code> to log to.
* @param logMe A string to log with the result.
* @param random A pseudo-<code>Random</code> number source.
* @param range The exclusive maximum integer to return.
* @param n The number of randoms.
* @return A vector of pseudo-random integers r, 0 <= r < range.
*/
public static int[] randomInts(Logger logger, String logMe, Random random,
int range, int n) {
int[] ret = new int[n];
for (int i = 0; i < n; i++) ret[i] = random.nextInt(range);
if (logger != null) {
String msg = logMe + " random(" + range + ") = [";
for (int i = 0; i < n; i++) msg += " " + Integer.toString(ret[i]);
msg += " ]";
logger.finest(msg);
}
return ret;
}
/**
* Convenience to aid logging uses of Randoms.
*
* @param logger The <code>Logger</code> to log to.
* @param logMe A string to log with the result.
* @param random A pseudo-<code>Random</code> number source.
* @return A pseudo-random double r, 0 <= r < 1.0.
*/
public static double randomDouble(Logger logger, String logMe,
Random random) {
double ret = random.nextDouble();
if (logger != null) {
logger.finest(logMe + " random(1.0) = " + ret);
}
return ret;
}
/**
* Gets a random member of a list.
*
* @param logger The <code>Logger</code> to log to.
* @param logMe A string to log with the result.
* @param list The list.
* @param random A random number source.
* @return A random member from the list.
*/
public static <T> T getRandomMember(Logger logger, String logMe,
List<T> list, Random random) {
return list.get(randomInt(logger, logMe, random, list.size()));
}
/**
* Get the internal state of a random number generator as a
* string. It would have been more convenient to simply return
* the current seed, but unfortunately it is private.
*
* @return A <code>String</code> encapsulating the object state.
*/
public static synchronized String getRandomState(Random random) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(random);
oos.flush();
} catch (IOException e) {
throw new IllegalStateException("IO exception in memory!?", e);
}
byte[] bytes = bos.toByteArray();
StringBuffer sb = new StringBuffer(bytes.length * 2);
for (byte b : bytes) {
sb.append(HEX_DIGITS.charAt((b >> 4) & 0x0F));
sb.append(HEX_DIGITS.charAt(b & 0x0F));
}
return sb.toString();
}
/**
* Restore a previously saved state.
*
* @param state The saved state (@see #getRandomState()).
* @return The restored <code>Random</code>.
*/
public static synchronized Random restoreRandomState(String state) {
if (state == null || state.length() == 0) return null;
byte[] bytes = new byte[state.length() / 2];
int pos = 0;
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) HEX_DIGITS.indexOf(state.charAt(pos++));
bytes[i] <<= 4;
bytes[i] |= (byte) HEX_DIGITS.indexOf(state.charAt(pos++));
}
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
try {
ObjectInputStream ois = new ObjectInputStream(bis);
return (Random) ois.readObject();
} catch (Exception e) {
logger.log(Level.WARNING, "Unable to restore random state.", e);
}
return null;
}
}