package org.archstudio.sysutils;
import static com.google.common.base.Preconditions.checkArgument;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Array;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@NonNullByDefault
public class SystemUtils {
public static final String fileSeparator = System.getProperty("file.separator");
public enum OperatingSystem {
OS_UNKNOWN, OS_WINDOWS, OS_UNIX
}
public static String getCanonicalPath(File f) {
try {
return f.getCanonicalPath();
}
catch (Exception e) {
return f.getAbsolutePath();
}
}
public static @Nullable
File findFileOnSystemPath(String fileName) {
String systemPath = System.getProperty("java.library.path");
StringTokenizer st = new StringTokenizer(systemPath, System.getProperty("path.separator"));
while (st.hasMoreTokens()) {
String pathDirString = st.nextToken();
File pathDir = new File(pathDirString);
if (pathDir.exists()) {
if (pathDir.isDirectory()) {
File possibleMatch = new File(pathDir, fileName);
if (possibleMatch.exists()) {
if (!possibleMatch.isDirectory()) {
return possibleMatch;
}
}
}
}
}
return null;
}
public static @Nullable
File getFileIfExists(String dir, String filename) {
try {
File f = new File(dir, filename);
//System.out.println("Looking for: " + f);
if (f.exists()) {
//System.out.println("Found: " + f);
return f;
}
}
catch (Exception e) {
}
return null;
}
public static String[] guessJVMs() {
OperatingSystem os = guessOperatingSystem();
String javaExecutableName = "java";
if (os.equals(OperatingSystem.OS_WINDOWS)) {
javaExecutableName = "java.exe";
}
else if (os.equals(OperatingSystem.OS_UNIX)) {
javaExecutableName = "java";
}
HashSet<String> pathSet = new HashSet<String>();
File javaExecutable = null;
String javaHome = System.getProperty("java.home");
if (javaHome != null) {
javaExecutable = getFileIfExists(javaHome, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
javaHome = javaHome + fileSeparator + "bin";
if (javaHome != null) {
javaExecutable = getFileIfExists(javaHome, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
if (os.equals(OperatingSystem.OS_UNIX)) {
String[] pathsToSearch = new String[] { "/usr/java/bin", "/usr/lib/java/bin", "/usr/local/java/bin",
"/opt/java/bin", "/usr/lib/java/bin" };
for (String element : pathsToSearch) {
javaExecutable = getFileIfExists(element, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
try {
String procOutput = runAndCaptureProcess("which java");
if (procOutput != null) {
javaExecutable = getFileIfExists(procOutput, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
}
catch (IOException ioe) {
}
}
else if (os.equals(OperatingSystem.OS_WINDOWS)) {
String[] pathsToSearch = new String[] { "C:\\WINDOWS", "C:\\WINDOWS\\SYSTEM", "C:\\WINDOWS\\SYSTEM32",
"C:\\WINNT", "C:\\WINNT\\SYSTEM", "C:\\WINNT\\SYSTEM32" };
for (String element : pathsToSearch) {
javaExecutable = getFileIfExists(element, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
}
String[] libraryPaths = getLibraryPathEntries();
if (libraryPaths != null) {
for (String element : libraryPaths) {
javaExecutable = getFileIfExists(element, javaExecutableName);
if (javaExecutable != null) {
pathSet.add(getCanonicalPath(javaExecutable));
}
}
}
return pathSet.toArray(new String[0]);
}
public static String[] guessLibLocations(String libraryName) {
HashSet<String> pathSet = new HashSet<String>();
File library = null;
String javaHome = System.getProperty("java.home");
if (javaHome != null) {
library = getFileIfExists(javaHome, libraryName);
if (library != null) {
pathSet.add(getCanonicalPath(library));
}
}
javaHome = javaHome + fileSeparator + "lib";
if (javaHome != null) {
library = getFileIfExists(javaHome, libraryName);
if (library != null) {
pathSet.add(getCanonicalPath(library));
}
}
String[] libraryPaths = getClassPathEntries();
if (libraryPaths != null) {
for (String element : libraryPaths) {
if (element.endsWith(libraryName)) {
File f = new File(element);
if (f.exists()) {
pathSet.add(getCanonicalPath(f));
}
}
}
}
return pathSet.toArray(new String[0]);
}
public static OperatingSystem guessOperatingSystem() {
String osname = System.getProperty("os.name");
if (osname != null) {
osname = osname.toLowerCase();
if (osname.indexOf("windows") != -1) {
return OperatingSystem.OS_WINDOWS;
}
if (osname.indexOf("unix") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("solaris") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("aix") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("hpux") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("hp-ux") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("linux") != -1) {
return OperatingSystem.OS_UNIX;
}
if (osname.indexOf("os x") != -1) {
return OperatingSystem.OS_UNIX;
}
}
String fileSeparator = System.getProperty("file.separator");
if (fileSeparator != null) {
if (fileSeparator.equals("\\")) {
return OperatingSystem.OS_WINDOWS;
}
if (fileSeparator.equals("/")) {
return OperatingSystem.OS_UNIX;
}
}
String pathSeparator = System.getProperty("path.separator");
if (pathSeparator != null) {
if (pathSeparator.equals(";")) {
return OperatingSystem.OS_WINDOWS;
}
if (pathSeparator.equals(":")) {
return OperatingSystem.OS_UNIX;
}
}
return OperatingSystem.OS_UNKNOWN;
}
public static int runAndLogProcess(Process p, OutputStream logFileOutputStream) throws IOException {
int exitValue = -1; // returned to caller when p is finished
InputStream in = p.getInputStream();
InputStream err = p.getErrorStream();
ByteArrayOutputStream inBuf = new ByteArrayOutputStream();
ByteArrayOutputStream errBuf = new ByteArrayOutputStream();
//StringBuffer inBuf = new StringBuffer();
//StringBuffer errBuf = new StringBuffer();
boolean finished = false; // Set to true when p is finished
while (!finished) {
try {
while (in.available() > 0) {
blt_noblock(in, inBuf);
}
while (err.available() > 0) {
blt_noblock(err, errBuf);
}
// Ask the process for its exitValue. If the process
// is not finished, an IllegalThreadStateException
// is thrown. If it is finished, we fall through and
// the variable finished is set to true.
exitValue = p.exitValue();
finished = true;
}
catch (IllegalThreadStateException e) {
// Process is not finished yet;
// Sleep a little to save on CPU cycles
try {
Thread.sleep(250);
}
catch (InterruptedException ie) {
}
}
}
//Grab any leftovers.
while (in.available() > 0) {
blt_noblock(in, inBuf);
}
while (err.available() > 0) {
blt_noblock(err, errBuf);
}
in.close();
err.close();
//Log the streams:
println(logFileOutputStream, "Standard output:");
//inBuf.writeTo(logFileOutputStream);
println(logFileOutputStream, fixNewlines(inBuf.toString()));
println(logFileOutputStream, "Standard error:");
//errBuf.writeTo(logFileOutputStream);
println(logFileOutputStream, fixNewlines(errBuf.toString()));
// return completion status to caller
return exitValue;
}
protected static byte[] buf = new byte[2048];
public static synchronized void blt_noblock(InputStream is, OutputStream os) throws IOException {
while (is.available() > 0) {
int len = is.read(buf);
if (len == -1) {
break;
}
os.write(buf, 0, len);
}
}
public static synchronized void blt(InputStream is, OutputStream os) throws IOException {
while (true) {
int len = is.read(buf);
if (len == -1) {
break;
}
os.write(buf, 0, len);
}
is.close();
}
public static byte[] blt(InputStream is) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
blt(is, baos);
return baos.toByteArray();
}
public static String runAndCaptureProcess(String cmd) throws IOException {
Process process = Runtime.getRuntime().exec(cmd);
return runAndCaptureProcess(process);
}
public static String runAndCaptureProcess(Process p) throws IOException {
InputStream in = null;
InputStream err = null;
try {
in = p.getInputStream();
err = p.getErrorStream();
ByteArrayOutputStream inBuf = new ByteArrayOutputStream();
ByteArrayOutputStream errBuf = new ByteArrayOutputStream();
//StringBuffer inBuf = new StringBuffer();
//StringBuffer errBuf = new StringBuffer();
boolean finished = false; // Set to true when p is finished
while (!finished) {
try {
while (in.available() > 0) {
blt_noblock(in, inBuf);
}
while (err.available() > 0) {
blt_noblock(err, errBuf);
}
// Ask the process for its exitValue. If the process
// is not finished, an IllegalThreadStateException
// is thrown. If it is finished, we fall through and
// the variable finished is set to true.
finished = true;
}
catch (IllegalThreadStateException e) {
// Process is not finished yet;
// Sleep a little to save on CPU cycles
try {
Thread.sleep(250);
}
catch (InterruptedException ie) {
}
}
}
//Grab any leftovers.
while (in.available() > 0) {
blt_noblock(in, inBuf);
}
while (err.available() > 0) {
blt_noblock(err, errBuf);
}
if (errBuf.toString().trim().length() > 0) {
return inBuf.toString() + System.getProperty("line.separator") + errBuf.toString();
}
else {
return inBuf.toString();
}
}
finally {
if (in != null) {
try {
in.close();
}
catch (IOException ioe2) {
}
}
if (err != null) {
try {
err.close();
}
catch (IOException ioe3) {
}
}
}
}
private static void println(OutputStream os) throws IOException {
os.write(System.getProperty("line.separator").getBytes());
}
private static void println(OutputStream os, String s) throws IOException {
os.write(s.getBytes());
println(os);
}
public static String toString(Object value) {
StringBuffer buf = new StringBuffer();
toString(value, buf);
return buf.toString();
}
public static void toString(Object value, StringBuffer buf) {
toString(value, buf, new HashSet<Object>());
}
private static void toString(@Nullable Object value, StringBuffer buf, Set<Object> dejaVu) {
if (value == null) {
buf.append(value);
return;
}
dejaVu.add(value);
Class<?> clazz = value.getClass();
if (clazz.isArray()) {
if (clazz == byte[].class) {
buf.append(Arrays.toString((byte[]) value));
}
else if (clazz == short[].class) {
buf.append(Arrays.toString((short[]) value));
}
else if (clazz == int[].class) {
buf.append(Arrays.toString((int[]) value));
}
else if (clazz == long[].class) {
buf.append(Arrays.toString((long[]) value));
}
else if (clazz == char[].class) {
buf.append(Arrays.toString((char[]) value));
}
else if (clazz == float[].class) {
buf.append(Arrays.toString((float[]) value));
}
else if (clazz == double[].class) {
buf.append(Arrays.toString((double[]) value));
}
else if (clazz == boolean[].class) {
buf.append(Arrays.toString((boolean[]) value));
}
else {
buf.append("[");
for (int i = 0; i < Array.getLength(value); i++) {
if (i > 0) {
buf.append(", ");
}
Object element = Array.get(value, i);
if (dejaVu.contains(element)) {
buf.append("...");
}
else {
toString(Array.get(value, i), buf, dejaVu);
}
}
buf.append("]");
}
}
else {
buf.append(value);
}
dejaVu.remove(value);
}
public static boolean containsJavaFiles(File srcDir) throws IOException {
if (!srcDir.exists()) {
throw new IllegalArgumentException(srcDir.getAbsolutePath() + " does not exist.");
}
if (!srcDir.isDirectory()) {
throw new IllegalArgumentException(srcDir.getAbsolutePath() + " is not a directory.");
}
File[] children = srcDir.listFiles();
for (File element : children) {
if (element.getName().toLowerCase().endsWith(".java")) {
return true;
}
}
return false;
}
public static void createDirectory(File srcDir) throws IOException {
if (!srcDir.mkdirs()) {
throw new IOException("Can't create directory: " + srcDir.getAbsolutePath());
}
}
public static void removeDirectory(File srcDir) throws IOException {
if (!srcDir.exists()) {
return;
}
if (!srcDir.isDirectory()) {
throw new IllegalArgumentException(srcDir.getAbsolutePath() + " is not a directory.");
}
File baseDir = srcDir.getParentFile();
String[] src = getFilesRecursive(srcDir.getAbsolutePath());
for (int i = src.length - 1; i >= 0; i--) {
File s = new File(baseDir, src[i]);
s.delete();
}
}
public static void copyContents(File baseDirFile, File targetDir) throws IOException {
copyContents(baseDirFile, targetDir, null);
}
public static void copyContents(File baseDirFile, File targetDir, @Nullable FilenameFilter ff) throws IOException {
if (!baseDirFile.exists()) {
throw new IllegalArgumentException("Invalid recursion base: " + baseDirFile.getAbsolutePath());
}
//Vector v = new Vector();
File[] children = baseDirFile.listFiles();
for (File element : children) {
if (element.isDirectory()) {
copyDirectory(element, targetDir, ff);
}
else {
if (ff != null) {
if (ff.accept(baseDirFile, element.getName())) {
copyFile(element, new File(targetDir, element.getName()));
}
}
else {
copyFile(element, new File(targetDir, element.getName()));
}
}
}
}
public static void copyDirectory(File srcDir, File targetDir) throws IOException {
copyDirectory(srcDir, targetDir, null);
}
public static void copyDirectory(File srcDir, File targetDir, @Nullable FilenameFilter ff) throws IOException {
if (!targetDir.exists()) {
throw new IllegalArgumentException(targetDir.getAbsolutePath() + " does not exist.");
}
if (!targetDir.isDirectory()) {
throw new IllegalArgumentException(targetDir.getAbsolutePath() + " is not a directory.");
}
File baseDir = srcDir.getParentFile();
String[] src = getFilesRecursive(srcDir.getAbsolutePath());
for (String element : src) {
File s = new File(baseDir, element);
File d = new File(targetDir, element);
if (s.isDirectory()) {
if (d.exists() && d.isDirectory()) {
}
else if (!d.mkdir()) {
throw new IOException("Couldn't create directory: " + d.getAbsolutePath());
}
}
else {
if (ff != null) {
if (ff.accept(s.getParentFile(), s.getName())) {
copyFile(s, d);
}
}
else {
copyFile(s, d);
}
}
}
}
public static String fixNewlines(String s) {
try {
StringReader sr = new StringReader(s);
BufferedReader br = new BufferedReader(sr);
StringWriter sw = new StringWriter();
String lineSep = System.getProperty("line.separator");
while (true) {
String line = br.readLine();
if (line == null) {
return sw.toString();
}
sw.write(line);
sw.write(lineSep);
}
}
catch (IOException doesntHappen) {
throw new UnsupportedOperationException(doesntHappen);
}
}
public static void copyFile(File inFile, File outFile) throws IOException {
FileOutputStream fos = new FileOutputStream(outFile);
FileInputStream fis = new FileInputStream(inFile);
blt(fis, fos);
fos.close();
}
public static String[] getContentsRecursive(String baseDir) {
File baseDirFile = new File(baseDir);
if (!baseDirFile.exists()) {
throw new IllegalArgumentException("Invalid recursion base: " + baseDir);
}
Vector<String> v = new Vector<String>();
File[] children = baseDirFile.listFiles();
for (File element : children) {
if (element.isDirectory()) {
String[] arr = getFilesRecursive(element.getAbsolutePath());
for (String element2 : arr) {
v.addElement(element2);
}
}
}
String[] ret = new String[v.size()];
v.copyInto(ret);
return ret;
}
public static String[] getFilesRecursive(String baseDir) {
File baseDirFile = new File(baseDir);
if (!baseDirFile.exists()) {
throw new IllegalArgumentException("Invalid recursion base: " + baseDir);
}
Vector<File> directories = new Vector<File>();
Vector<File> files = new Vector<File>();
getFilesRecursive(baseDirFile, directories, files);
String[] ret = new String[directories.size() + files.size()];
int i = 0;
for (File element : directories) {
ret[i++] = getRelativePath(baseDirFile, element);
}
for (File element : files) {
ret[i++] = getRelativePath(baseDirFile, element);
}
return ret;
}
public static String getRelativePath(File baseDir, File f) {
String p;
if (f.isDirectory()) {
p = f.getName() + fileSeparator;
}
else {
p = f.getName();
}
if (baseDir.equals(f)) {
return p;
}
while (true) {
f = f.getParentFile();
if (f == null) {
throw new IllegalArgumentException("File was not contained in base!");
}
else if (f.equals(baseDir)) {
p = f.getName() + fileSeparator + p;
return p;
}
else {
p = f.getName() + fileSeparator + p;
}
}
}
public static <K, V> V getOrCreateValue(Map<K, V> m, K key, Class<? extends V> valueClass) {
V value = m.get(key);
if (value == null) {
try {
value = valueClass.newInstance();
m.put(key, value);
}
catch (InstantiationException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return value;
}
public static void getFilesRecursive(File base, Vector<File> directories, Vector<File> files) {
if (base.isDirectory()) {
directories.addElement(base);
File[] children = base.listFiles();
for (File element : children) {
getFilesRecursive(element, directories, files);
}
}
else {
files.addElement(base);
}
}
public static int waitForProcess(Process p) {
while (true) {
try {
int rv = p.exitValue();
return rv;
}
catch (IllegalThreadStateException itse) {
}
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
}
}
}
static class ExcludingFilenameFilter implements java.io.FilenameFilter {
String[] extensionsToExclude;
public ExcludingFilenameFilter(String[] extensionsToExclude) {
this.extensionsToExclude = extensionsToExclude;
for (int i = 0; i < extensionsToExclude.length; i++) {
extensionsToExclude[i] = extensionsToExclude[i].toLowerCase();
}
}
@Override
public boolean accept(@Nullable File dir, @Nullable String name) {
if (name != null) {
for (String element : extensionsToExclude) {
if (name.toLowerCase().endsWith(element)) {
return false;
}
}
}
return true;
}
}
public static @Nullable
String[] getLibraryPathEntries() {
String libraryPath = System.getProperty("java.library.path");
if (libraryPath == null) {
return null;
}
String pathSeparator = System.getProperty("path.separator");
if (pathSeparator == null) {
return null;
}
StringTokenizer tok = new StringTokenizer(libraryPath, pathSeparator);
ArrayList<String> pathEntries = new ArrayList<String>();
while (tok.hasMoreTokens()) {
pathEntries.add(tok.nextToken().trim());
}
return pathEntries.toArray(new String[0]);
}
public static String[] getClassPathEntries() {
return getClassPathEntries(false);
}
public static String[] getClassPathEntries(boolean includeCurrentDirectory) {
String libraryPath = System.getProperty("java.class.path");
if (libraryPath == null) {
return new String[0];
}
String pathSeparator = System.getProperty("path.separator");
if (pathSeparator == null) {
return new String[0];
}
StringTokenizer tok = new StringTokenizer(libraryPath, pathSeparator);
ArrayList<String> pathEntries = new ArrayList<String>();
if (includeCurrentDirectory) {
pathEntries.add(".");
}
while (tok.hasMoreTokens()) {
pathEntries.add(tok.nextToken().trim());
}
return pathEntries.toArray(new String[0]);
}
public static final DateFormat DATE_TIME_FORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG);
public static String getDateAndTime() {
return DATE_TIME_FORMAT.format(new java.util.Date());
}
public static @Nullable
Date parseDate(String s) {
java.util.Date d = null;
d = parseDate(s, DateFormat.FULL);
if (d != null) {
return d;
}
d = parseDate(s, DateFormat.LONG);
if (d != null) {
return d;
}
d = parseDate(s, DateFormat.MEDIUM);
if (d != null) {
return d;
}
d = parseDate(s, DateFormat.SHORT);
if (d != null) {
return d;
}
return null;
}
public static @Nullable
Date parseDate(String s, int format) {
try {
DateFormat df = DateFormat.getDateInstance(format, Locale.US);
//I finally figured out what "lenient" means--this means that dates like
//"Feburary 95, 1999" will be the 95th day after Feb 1, 1999. It doesn't
//allow off-formats at all, as the Java documentation describes!!!
df.setLenient(false);
Date newDate = df.parse(s);
if (newDate != null) {
return new Date(newDate.getTime());
}
else {
return null;
}
}
catch (java.text.ParseException e) {
return null;
}
}
public static InputStream openURL(String urlString) throws MalformedURLException, FileNotFoundException,
IOException {
return openURL(urlString, null);
}
public static InputStream openURL(String urlString, @Nullable Class<?> resourceClass) throws MalformedURLException,
FileNotFoundException, IOException {
if (urlString.startsWith("file:")) {
URL fileURL = new URL(urlString);
String filePath = fileURL.getFile(); //Amazingly, this works (albeit for file:// URLs only)
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(file.getPath());
}
if (!file.canRead()) {
throw new IOException("Can't read file: " + file.getPath());
}
FileInputStream fis = new FileInputStream(file);
return fis;
}
else if (urlString.startsWith("http:")) {
URL httpURL = new URL(urlString);
return httpURL.openStream();
}
else if (urlString.startsWith("res:")) {
String path = urlString.substring(4);
while (path.startsWith("/")) {
path = path.substring(1);
}
if (resourceClass == null) {
resourceClass = SystemUtils.class;
}
//return ClassLoader.getSystemResourceAsStream(path);
return resourceClass.getResourceAsStream("/" + path);
}
else {
throw new MalformedURLException("Invalid URL: " + urlString);
}
}
public static @Nullable
String capFirst(@Nullable String s) {
if (s != null && s.length() > 0) {
char ch = s.charAt(0);
char uch = Character.toUpperCase(ch);
if (ch != uch) {
char[] chars = s.toCharArray();
chars[0] = uch;
s = new String(chars);
}
}
return s;
}
public static @Nullable
String uncapFirst(@Nullable String s) {
if (s != null && s.length() > 0) {
char ch = s.charAt(0);
char lch = Character.toLowerCase(ch);
if (ch != lch) {
char[] chars = s.toCharArray();
chars[0] = lch;
s = new String(chars);
}
}
return s;
}
public static <T> Set<T> diffSet(@Nullable Collection<? extends T> a, @Nullable Collection<? extends T> b) {
Set<T> diff;
if (a != null) {
diff = new HashSet<T>(a);
if (b != null) {
for (T o : b) {
if (diff.contains(o)) {
diff.remove(o);
}
else {
diff.add(o);
}
}
}
}
else if (b != null) {
diff = new HashSet<T>(b);
}
else {
diff = Collections.emptySet();
}
return diff;
}
public static final boolean nullEquals(@Nullable Object o1, @Nullable Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
public static boolean deepEquals(@Nullable Object o1, @Nullable Object o2) {
if (o1 == o2) {
return true;
}
if (o1 == null || o2 == null) {
return false;
}
Class<?> c1 = o1.getClass();
Class<?> c2 = o2.getClass();
if (!c1.equals(c2)) {
return false;
}
if (c1.isArray()) {
if (c1 == byte[].class) {
return Arrays.equals((byte[]) o1, (byte[]) o2);
}
else if (c1 == short[].class) {
return Arrays.equals((short[]) o1, (short[]) o2);
}
else if (c1 == int[].class) {
return Arrays.equals((int[]) o1, (int[]) o2);
}
else if (c1 == long[].class) {
return Arrays.equals((long[]) o1, (long[]) o2);
}
else if (c1 == char[].class) {
return Arrays.equals((char[]) o1, (char[]) o2);
}
else if (c1 == float[].class) {
return Arrays.equals((float[]) o1, (float[]) o2);
}
else if (c1 == double[].class) {
return Arrays.equals((double[]) o1, (double[]) o2);
}
else if (c1 == boolean[].class) {
return Arrays.equals((boolean[]) o1, (boolean[]) o2);
}
else {
int l1 = Array.getLength(o1);
int l2 = Array.getLength(o2);
if (l1 != l2) {
return false;
}
for (int i = 0; i < l1; i++) {
if (!deepEquals(Array.get(o1, i), Array.get(o2, i))) {
return false;
}
}
return true;
}
}
return o1.equals(o2);
}
public static String join(String front, String seperator, String end, Iterable<?> objects) {
if (objects == null || Iterables.isEmpty(objects)) {
return "";
}
StringBuilder sb = new StringBuilder();
sb.append(front);
boolean needsSeparator = false;
for (Object object : objects) {
if (needsSeparator) {
sb.append(seperator);
}
sb.append(object);
needsSeparator = true;
}
sb.append(end);
return sb.toString();
}
public static final String message(String message, Object... variables) {
StringBuffer sb = new StringBuffer(2 * message.length());
Matcher m = Pattern.compile("\\$([0-9]+)").matcher(message);
while (m.find()) {
int v = Integer.valueOf(m.group(1));
if (v >= 0 && v < variables.length) {
m.appendReplacement(sb, variables[v] == null ? "null" : variables[v].toString());
}
else {
sb.append(m.group());
}
}
m.appendTail(sb);
return sb.toString();
}
public static final String simpleName(String className) {
int index = className.lastIndexOf('.');
if (index >= 0) {
className = className.substring(index + 1);
}
return className;
}
public static final String simpleName(Class<?> clazz) {
return simpleName(clazz.getName());
}
private static Map<Class<?>, Function<?, ?>> comparables = Maps.newHashMap();
static {
comparables.put(AtomicInteger.class, new Function<AtomicInteger, Object>() {
@Override
public Object apply(AtomicInteger input) {
return input.intValue();
}
});
comparables.put(AtomicLong.class, new Function<AtomicLong, Object>() {
@Override
public Object apply(AtomicLong input) {
return input.longValue();
}
});
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static final int compare(@Nullable Object o1, @Nullable Object o2) {
if (o1 == null) {
return o2 != null ? -1 : 0;
}
if (o2 == null) {
return 1;
}
if (comparables.containsKey(o1.getClass())) {
o1 = ((Function<Object, Object>) comparables.get(o1.getClass())).apply(o1);
}
if (comparables.containsKey(o2.getClass())) {
o2 = ((Function<Object, Object>) comparables.get(o2.getClass())).apply(o2);
}
if (o1 instanceof Comparable) {
return ((Comparable) o1).compareTo(o2);
}
return o1.toString().compareTo(o2.toString());
}
private static final Comparator<Object> genericComparator = new Comparator<Object>() {
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
return SystemUtils.compare(o1, o2);
};
};
private static final Comparator<Map.Entry<?, ?>> mapEntryKeyComparator = new Comparator<Map.Entry<?, ?>>() {
@Override
public int compare(Map.Entry<?, ?> o1, Map.Entry<?, ?> o2) {
return SystemUtils.compare(o1 != null ? o1.getKey() : null, o2 != null ? o2.getKey() : null);
}
};
private static final Comparator<Map.Entry<?, ?>> mapEntryValueComparator = new Comparator<Map.Entry<?, ?>>() {
@Override
public int compare(Map.Entry<?, ?> o1, Map.Entry<?, ?> o2) {
return SystemUtils.compare(o1 != null ? o1.getValue() : null, o2 != null ? o2.getValue() : null);
}
};
private static final Predicate<Map.Entry<?, ?>> nonNullMapEntryKeyPredicate = new Predicate<Map.Entry<?, ?>>() {
@Override
public boolean apply(Map.Entry<?, ?> input) {
return input != null ? input.getKey() != null : false;
}
};
private static final Predicate<Map.Entry<?, ?>> nonNullMapEntryValuePredicate = new Predicate<Map.Entry<?, ?>>() {
@Override
public boolean apply(Map.Entry<?, ?> input) {
return input != null ? input.getValue() != null : false;
}
};
public static final <T> List<T> sorted(Iterable<? extends T> iterable, Comparator<? super T> comparator) {
List<T> list = Lists.newArrayList(iterable);
Collections.sort(list, comparator);
return list;
}
public static final <T> List<T> sorted(Iterable<? extends T> iterable) {
return sorted(iterable, genericComparator);
}
public static final <E extends Map.Entry<?, ?>> List<E> sortedByKey(Iterable<E> entries) {
return sorted(//
Iterables.filter(entries, nonNullMapEntryKeyPredicate),//
mapEntryKeyComparator);
}
public static final <E extends Map.Entry<?, ?>> List<E> sortedByValue(Iterable<E> entries) {
return sorted(//
Iterables.filter(entries, nonNullMapEntryValuePredicate),//
mapEntryValueComparator);
}
@SuppressWarnings("unchecked")
public static final <K, V> Iterable<Map.Entry<K, V>> filterByKey(Iterable<Entry<?, V>> entries,
final Class<K> keyClass) {
return (Iterable<Map.Entry<K, V>>) (Object) Iterables.filter(entries, new Predicate<Entry<?, V>>() {
@Override
public boolean apply(@Nullable Entry<?, V> input) {
return keyClass.isInstance(input != null ? input.getKey() : null);
}
});
}
@SuppressWarnings("unchecked")
public static final @Nullable
<T> T castOrNull(@Nullable Object o, Class<T> tClass) {
if (tClass == null || tClass.isInstance(o)) {
return (T) o;
}
return null;
}
public static @Nullable
<T extends InputStream> T closeQuietly(@Nullable T is) {
try {
if (is != null) {
is.close();
}
}
catch (Throwable t) {
}
return null;
}
public static @Nullable
<T extends OutputStream> T closeQuietly(@Nullable T is) {
try {
if (is != null) {
is.close();
}
}
catch (Throwable t) {
}
return null;
}
public static final int bound(int lower, int value, int upper) {
if (lower < upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
}
else {
if (value < upper) {
return upper;
}
if (value > lower) {
return lower;
}
}
return value;
}
public static final long bound(long lower, long value, long upper) {
if (lower < upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
}
else {
if (value < upper) {
return upper;
}
if (value > lower) {
return lower;
}
}
return value;
}
public static final float bound(float lower, float value, float upper) {
if (lower < upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
}
else {
if (value < upper) {
return upper;
}
if (value > lower) {
return lower;
}
}
return value;
}
public static final double bound(double lower, double value, double upper) {
if (lower < upper) {
if (value < lower) {
return lower;
}
if (value > upper) {
return upper;
}
}
else {
if (value < upper) {
return upper;
}
if (value > lower) {
return lower;
}
}
return value;
}
public static final int loop(int lower, int value, int upper) {
int span = upper - lower;
return bound(lower, lower + value - value / span * span, upper);
}
public static final long loop(long lower, long value, long upper) {
long span = upper - lower;
return bound(lower, lower + value - value / span * span, upper);
}
public static final float loop(float lower, float value, float upper) {
float span = upper - lower;
return bound(lower, lower + value - (float) Math.floor(value / span) * span, upper);
}
public static final double loop(double lower, double value, double upper) {
double span = upper - lower;
return bound(lower, lower + value - Math.floor(value / span) * span, upper);
}
public static final @Nullable
<T> T firstOrNull(Iterable<?> elements, Class<T> andOfType) {
return castOrNull(firstOrNull(elements), andOfType);
}
public static final @Nullable
<T> T firstOrNull(Iterable<T> elements) {
if (elements != null) {
for (T o : elements) {
return o;
}
}
return null;
}
public static final <T> Iterable<T> emptyIfNull(@Nullable Iterable<T> elements) {
return elements != null ? elements : Collections.<T> emptyList();
}
public static final <T> Iterable<T> emptyIfNull(@SuppressWarnings("unchecked") @Nullable T... elements) {
return elements != null ? Arrays.asList(elements) : Collections.<T> emptyList();
}
public static final @Nullable
<V> V getValue(Iterable<V> values, Pattern pattern) {
for (V value : values) {
if (pattern.matcher("" + value).matches()) {
return value;
}
}
return null;
}
public static final @Nullable
<V> V getValue(Map<?, V> map, Pattern keyPattern) {
for (Map.Entry<?, V> e : map.entrySet()) {
if (keyPattern.matcher("" + e.getKey()).matches()) {
return e.getValue();
}
}
return null;
}
public static final @Nullable
<V extends Comparable<V>> V max(Iterable<V> values) {
V maxValue = null;
for (V value : values) {
if (maxValue == null) {
maxValue = value;
}
else if (maxValue.compareTo(value) < 0) {
maxValue = value;
}
}
return maxValue;
}
public static final @Nullable
<V extends Comparable<V>> V min(Iterable<V> values) {
V minValue = null;
for (V value : values) {
if (minValue == null) {
minValue = value;
}
else if (minValue.compareTo(value) > 0) {
minValue = value;
}
}
return minValue;
}
public static final <T> T nonNullOr(@Nullable T value, T valueIfNull) {
return value != null ? value : valueIfNull;
}
public static final <T> List<T> filter(Iterable<?> elements, Class<T> ofType) {
return Lists.newArrayList(Iterables.filter(elements, ofType));
}
public static final int floor(double v) {
double w = Math.floor(v);
checkArgument(w >= Integer.MIN_VALUE && w <= Integer.MAX_VALUE, v);
return (int) w;
}
public static final int floor(float v) {
return floor((double) v);
}
public static final int floorB(double v) {
double w = Math.floor(v);
return bound(Integer.MIN_VALUE, (int) w, Integer.MAX_VALUE);
}
public static final int floorB(float v) {
return floor((double) v);
}
public static final int ceil(double v) {
double w = Math.ceil(v);
checkArgument(w >= Integer.MIN_VALUE && w <= Integer.MAX_VALUE, v);
return (int) w;
}
public static final int ceil(float v) {
return ceil((double) v);
}
public static final int ceilB(double v) {
double w = Math.ceil(v);
return bound(Integer.MIN_VALUE, (int) w, Integer.MAX_VALUE);
}
public static final int ceilB(float v) {
return ceil((double) v);
}
public static final int round(double v) {
double w = Math.round(v);
checkArgument(w >= Integer.MIN_VALUE && w <= Integer.MAX_VALUE, v);
return (int) w;
}
public static final int round(float v) {
return round((double) v);
}
public static final int roundB(double v) {
double w = Math.round(v);
return bound(Integer.MIN_VALUE, (int) w, Integer.MAX_VALUE);
}
public static final int roundB(float v) {
return round((double) v);
}
public static final <T> Collection<T> getAndClear(Collection<T> collection) {
List<T> copy = Lists.newArrayList(collection);
collection.clear();
return copy;
}
public static final void dispose(Disposable... disposables) {
for (Disposable disposable : disposables) {
try {
if (disposable != null) {
disposable.dispose();
}
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
public static final void close(AutoCloseable... closeables) {
for (AutoCloseable closeable : closeables) {
try {
if (closeable != null) {
closeable.close();
}
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
}