wordnice.utils.JavaUtils.java Source code

Java tutorial

Introduction

Here is the source code for wordnice.utils.JavaUtils.java

Source

/*******************************************************************************
 * The MIT License (MIT)
 * 
 * Copyright (c) 2016 Dalibor Drgo <emptychannelmc@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

package wordnice.utils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.io.IOUtils;

import gnu.trove.set.hash.THashSet;
import sun.misc.Unsafe;
import wordnice.api.Nice;
import wordnice.api.Nice.VHandler;
import wordnice.javaagent.JavaAgent;
import wordnice.streams.ArrayOutputStream;
import wordnice.streams.IUtils;
import wordnice.threads.TimeoutThread;
import wordnice.threads.TimeoutThread.Result;

public class JavaUtils {

    public static class RuntimeThrowable extends RuntimeException {

        private static final long serialVersionUID = 1L;

        public RuntimeThrowable(Throwable t) {
            initCauseOfThis(t);
        }

        @Override
        public void setStackTrace(StackTraceElement[] st) {
            this.getCause().setStackTrace(st);
        }

        @Override
        public StackTraceElement[] getStackTrace() {
            return this.getCause().getStackTrace();
        }

        protected Throwable initCauseOfThis(Throwable cuz) {
            return super.initCause(cuz);
        }

        @Override
        public Throwable initCause(Throwable cuz) {
            return this.getCause().initCause(cuz);
        }

        @Override
        public Throwable getCause() {
            return this.getCause();
        }

        @Override
        public Throwable fillInStackTrace() {
            return this.getCause();
        }

        public void throwIt() throws Throwable {
            throw this.getCause();
        }

        @Override
        public boolean equals(Object obj) {
            return this.getCause().equals(obj);
        }

    }

    protected static Unsafe unsafe;
    protected static Method getThreads;

    /*** C & UNSAFE ***/

    public static Instrumentation getInstrumentation() {
        return JavaAgent.get();
    }

    public static Unsafe getUnsafe() {
        if (unsafe == null) {
            Class<?> clz = Unsafe.class;
            Field[] fields = clz.getDeclaredFields();
            for (int i = 0, n = fields.length; i < n; i++) {
                Field f = fields[i];
                if (!f.getType().equals(Unsafe.class)) {
                    continue;
                }
                try {
                    f.setAccessible(true);
                    Unsafe unf = (Unsafe) f.get(null);
                    if (unf != null) {
                        return (unsafe = unf);
                    }
                } catch (Throwable t) {
                }
            }
        }
        return unsafe;
    }

    public static boolean is64() {
        return (Unsafe.ADDRESS_SIZE == 8);
    }

    public static void throv(Throwable t) {
        Unsafe unf = getUnsafe();
        if (unf != null) {
            unf.throwException(t);
        }
        throw new RuntimeException(t);
    }

    /*** MEMORY ***/

    public static void memcpy(Object to, Object from, int size) {
        System.arraycopy(from, 0, to, 0, size);
    }

    public static void memcpy(Object to, int posto, Object from, int posfrom, int size) {
        System.arraycopy(from, posfrom, to, posto, size);
    }

    public static void memcpy(long to, long from, long sz) {
        getUnsafe().copyMemory(from, to, sz);
    }

    public static void memset(long to, byte val, long sz) {
        getUnsafe().setMemory(to, sz, val);
    }

    public static long malloc(long sz) {
        return getUnsafe().allocateMemory(sz);
    }

    public static long zalloc(long sz) {
        return getUnsafe().allocateMemory(sz);
    }

    public static long realloc(long ptr, long nevsz) {
        return getUnsafe().reallocateMemory(ptr, nevsz);
    }

    public static void free(long ptr) {
        getUnsafe().freeMemory(ptr);
    }

    public static long getPointer(Object obj) {
        Object arr[] = new Object[] { obj };
        long base_offset = getUnsafe().arrayBaseOffset(Object[].class);
        if (is64()) {
            return getUnsafe().getLong(arr, base_offset);
        } else {
            return getUnsafe().getInt(arr, base_offset);
        }
    }

    /*** CLASS LOADERS ***/
    public static ClassLoader getClassLoader() {
        return Thread.currentThread().getContextClassLoader();
    }

    public static Set<Class<?>> filterClasses(Collection<Class<?>> in, Class<?> ext) {
        Set<Class<?>> out = new THashSet<Class<?>>();
        filterClasses(out, in, ext);
        return out;
    }

    public static void filterClasses(Collection<Class<?>> ret, Collection<Class<?>> in, Class<?> ext) {
        Iterator<Class<?>> it = in.iterator();
        while (it.hasNext()) {
            Class<?> clz = it.next();
            if (ext.isAssignableFrom(clz)) {
                ret.add(clz);
            }
        }
    }

    public static boolean instanceOf(Object o, Class<?> c) {
        if (o == null || c == null) {
            return false;
        }
        return c.isAssignableFrom(o.getClass());
    }

    public static boolean instanceOf(Class<?> o, Class<?> c) {
        if (o == null || c == null) {
            return false;
        }
        return c.isAssignableFrom(o);
    }

    public static Class<?> getClass(String name) throws Throwable {
        return (Class<?>) Class.forName(name);
    }

    public static Set<String> filterClassesString(Collection<String> in, String pref) {
        Set<String> out = Nice.createSet();
        filterClassesString(out, in, pref);
        return out;
    }

    public static void filterClassesString(Collection<String> out, Collection<String> in, String pref) {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            String cur = it.next();
            if (cur.startsWith(pref)) {
                out.add(cur);
            }
        }
    }

    public static Set<Class<?>> filterClasses(Collection<Class<?>> in, String pref) {
        Set<Class<?>> out = new THashSet<Class<?>>();
        filterClasses(out, in, pref);
        return out;
    }

    public static void filterClasses(Collection<Class<?>> out, Collection<Class<?>> in, String pref) {
        Iterator<Class<?>> it = in.iterator();
        while (it.hasNext()) {
            Class<?> cur = it.next();
            if (cur.getName().startsWith(pref)) {
                out.add(cur);
            }
        }
    }

    public static Set<String> filterClassesStringEquals(Collection<String> in, String pref) {
        Set<String> out = Nice.createSet();
        filterClassesStringEquals(out, in, pref);
        return out;
    }

    public static void filterClassesStringEquals(Collection<String> out, Collection<String> in, String pref) {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            String cur = it.next();
            if (cur.equals(pref)) {
                out.add(cur);
            }
        }
    }

    public static Set<Class<?>> filterClassesEquals(Collection<Class<?>> in, String pref) {
        Set<Class<?>> out = new THashSet<Class<?>>();
        filterClassesEquals(out, in, pref);
        return out;
    }

    public static void filterClassesEquals(Collection<Class<?>> out, Collection<Class<?>> in, String pref) {
        Iterator<Class<?>> it = in.iterator();
        while (it.hasNext()) {
            Class<?> cur = it.next();
            if (cur.getName().equals(pref)) {
                out.add(cur);
            }
        }
    }

    public static Set<String> filterPackagesString(Collection<String> in, String pref) {
        Set<String> out = Nice.createSet();
        filterPackagesString(out, in, pref);
        return out;
    }

    public static void filterPackagesString(Collection<String> out, Collection<String> in, String pref) {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            String cur = it.next();
            if (cur.startsWith(pref)) {
                out.add(cur);
            }
        }
    }

    public static Set<Package> filterPackages(Collection<Package> in, String pref) {
        Set<Package> out = new THashSet<Package>();
        filterPackages(out, in, pref);
        return out;
    }

    public static void filterPackages(Collection<Package> out, Collection<Package> in, String pref) {
        Iterator<Package> it = in.iterator();
        while (it.hasNext()) {
            Package cur = it.next();
            if (cur.getName().startsWith(pref)) {
                out.add(cur);
            }
        }
    }

    public static void loadClasses(Collection<Class<?>> out, Collection<String> in) throws Throwable {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            out.add(getClass(it.next()));
        }
    }

    public static void loadClasses(Collection<Class<?>> out, Collection<String> in, ClassLoader cl)
            throws Throwable {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            out.add(cl.loadClass(it.next()));
        }
    }

    public static void loadPackages(Collection<Package> out, Collection<String> in) throws Throwable {
        Iterator<String> it = in.iterator();
        while (it.hasNext()) {
            out.add(Package.getPackage(it.next()));
        }
    }

    public static File getClassesLocation(Class<?> cls) throws URISyntaxException {
        return new File(cls.getProtectionDomain().getCodeSource().getLocation().toURI());
    }

    public static File getClassesLocation(ClassLoader cl) throws URISyntaxException {
        return new File(cl.getResource("").toURI());
    }

    protected static void getClassesFolder(Collection<String> set, File fd, String pref) {
        String[] ls = fd.list();
        int i = 0;
        for (; i < ls.length; i++) {
            String curstr = ls[i];
            File cur = new File(fd, curstr);
            if (cur.isDirectory()) {
                getClassesFolder(set, cur, (pref + curstr + "."));
            } else {
                String clsn = pref + curstr;
                if (clsn.endsWith(".class") && clsn.indexOf('$') == -1) {
                    set.add(clsn.substring(0, clsn.length() - 6).replace(File.separatorChar, '.'));
                }
            }
        }
    }

    protected static void getClassesFolder(VHandler<String> handler, File fd, String pref) {
        String[] ls = fd.list();
        int i = 0;
        for (; i < ls.length; i++) {
            String curstr = ls[i];
            File cur = new File(fd, curstr);
            if (cur.isDirectory()) {
                getClassesFolder(handler, cur, (pref + curstr + "."));
            } else {
                String clsn = pref + curstr;
                if (clsn.endsWith(".class") && clsn.indexOf('$') == -1) {
                    handler.handle(clsn.substring(0, clsn.length() - 6).replace(File.separatorChar, '.'));
                }
            }
        }
    }

    public static Set<String> getClassesNear(Class<?> cls) throws Exception {
        Set<String> out = Nice.createSet();
        getClasses(out, getClassesLocation(cls));
        return out;
    }

    public static Set<String> getClasses(ClassLoader cl) throws Exception {
        Set<String> out = Nice.createSet();
        getClasses(out, getClassesLocation(cl));
        return out;
    }

    public static Set<String> getClasses(File fd) throws Exception {
        Set<String> out = Nice.createSet();
        getClasses(out, fd);
        return out;
    }

    public static void getClasses(Collection<String> set, File fd) throws Exception {
        if (fd.isDirectory()) {
            getClassesFolder(set, fd, "");
            return;
        }
        getClassesZip(set, new ZipInputStream(Nice.input(fd)));
    }

    public static void getClasses(VHandler<String> handler, File fd) throws Exception {
        if (fd.isDirectory()) {
            getClassesFolder(handler, fd, "");
            return;
        }
        getClassesZip(handler, new ZipInputStream(Nice.input(fd)));
    }

    public static Set<String> getClassesZip(ZipInputStream zip) throws Exception {
        Set<String> set = Nice.createSet();
        getClassesZip(set, zip);
        return set;
    }

    public static void getClassesZip(Collection<String> set, ZipInputStream zip) throws Exception {
        ZipEntry ent = null;
        while ((ent = zip.getNextEntry()) != null) {
            if (!ent.isDirectory()) {
                String clsn = ent.getName();
                if (clsn.endsWith(".class") && clsn.indexOf('$') == -1) {
                    set.add(clsn.substring(0, clsn.length() - 6).replace(File.separatorChar, '.'));
                }
            }
            zip.closeEntry();
        }
        zip.close();
    }

    public static void getClassesZip(VHandler<String> handler, ZipInputStream zip) throws Exception {
        ZipEntry ent = null;
        while ((ent = zip.getNextEntry()) != null) {
            if (!ent.isDirectory()) {
                String clsn = ent.getName();
                if (clsn.endsWith(".class") && clsn.indexOf('$') == -1) {
                    handler.handle(clsn.substring(0, clsn.length() - 6).replace(File.separatorChar, '.'));
                }
            }
            zip.closeEntry();
        }
        zip.close();
    }

    public static Thread[] getThreads() {
        try {
            getThreads = Thread.class.getDeclaredMethod("getThreads");
            getThreads.setAccessible(true);
            return (Thread[]) getThreads.invoke(null);
        } catch (Throwable t) {
        }
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        return threadSet.toArray(new Thread[threadSet.size()]);
    }

    public static Class<?> getClassSafe(String cls) {
        try {
            return Class.forName(cls);
        } catch (Throwable t) {
        }
        return null;
    }

    public static Class<?> getClassSafe(String cls, ClassLoader cl) {
        try {
            return Class.forName(cls, true, cl);
        } catch (Throwable t) {
        }
        return null;
    }

    public static interface OnFinishConsumer {
        void accept(CommandData cd);
    }

    public static class CommandData {
        protected boolean readError = false;
        protected boolean readOutput = true;
        protected boolean redirectError = false;
        protected int exitStatus = -1;
        protected OutputStream output = null;
        protected OutputStream error = null;
        protected Throwable throwable = null;
        protected int timeout = 0;
        /** Called on finish */
        protected OnFinishConsumer onFinish;
        /** Run in another thread? Ignored if onFinish == null */
        protected boolean multithreaded = false;
        /** Used when timedout > 0 */
        protected Result<Boolean> result = null;

        public Throwable getThrowable() {
            return this.throwable;
        }

        public CommandData setThrowable(Throwable t) {
            this.throwable = t;
            return this;
        }

        public boolean isReadError() {
            return readError;
        }

        public CommandData setReadError(boolean readError) {
            this.readError = readError;
            return this;
        }

        public boolean isReadOutput() {
            return readOutput;
        }

        public CommandData setReadOutput(boolean readOutput) {
            this.readOutput = readOutput;
            return this;
        }

        public boolean isRedirectError() {
            return redirectError;
        }

        public CommandData setRedirectError(boolean joinError) {
            this.redirectError = joinError;
            return this;
        }

        public int getExitStatus() {
            return exitStatus;
        }

        public CommandData setExitStatus(int exitStatus) {
            this.exitStatus = exitStatus;
            return this;
        }

        public boolean isExitOK() {
            return this.exitStatus == 0;
        }

        public OutputStream getOutput() {
            return output;
        }

        public CommandData setOutput(OutputStream output) {
            this.output = output;
            return this;
        }

        public OutputStream getError() {
            return error;
        }

        public CommandData setError(OutputStream error) {
            this.error = error;
            return this;
        }

        public int getTimeout() {
            return this.timeout;
        }

        public CommandData setTimeout(int tim) {
            this.timeout = (tim >= 0) ? tim : 0;
            return this;
        }

        public String getErrorString() {
            return (error == null) ? "" : error.toString();
        }

        public String getOutputString() {
            return (output == null) ? "" : output.toString();
        }

        public void writeOutput(byte[] buff, int off, int len) throws IOException {
            if (!this.readOutput || len == 0)
                return;
            if (this.output == null)
                this.output = Nice.createArrayOutput();
            this.output.write(buff, off, len);
        }

        public void writeOutput(InputStream in) throws IOException {
            if (!this.readOutput) {
                IUtils.readFullyNowhere(in);
                return;
            }
            if (this.output == null)
                this.output = Nice.createArrayOutput();
            if (this.output instanceof ArrayOutputStream) {
                ((ArrayOutputStream) this.output).write(in);
            } else {
                IOUtils.copy(in, this.output);
            }
        }

        public void writeError(byte[] buff, int off, int len) throws IOException {
            if (!this.readError || len == 0)
                return;
            if (this.error == null)
                this.error = Nice.createArrayOutput();
            this.error.write(buff, off, len);
        }

        public void writeError(InputStream in) throws IOException {
            if (!this.readError) {
                IUtils.readFullyNowhere(in);
                return;
            }
            if (this.error == null)
                this.error = Nice.createArrayOutput();
            if (this.error instanceof ArrayOutputStream) {
                ((ArrayOutputStream) this.error).write(in);
            } else {
                IOUtils.copy(in, this.error);
            }
        }

        public OnFinishConsumer getOnFinish() {
            return onFinish;
        }

        public CommandData setOnFinish(OnFinishConsumer onFinish) {
            this.onFinish = onFinish;
            return this;
        }

        public boolean isMultithreaded() {
            return multithreaded;
        }

        public CommandData setMultithreaded(boolean multithreaded) {
            this.multithreaded = multithreaded;
            return this;
        }

        public Result<Boolean> getTimeoutResult() {
            return this.result;
        }

        public CommandData setTimeoutResult(Result<Boolean> result) {
            this.result = result;
            return this;
        }

    };

    public static File getJRE() {
        return new File(System.getProperty("java.home"));
    }

    public static String executeAndGetOutput(String... args) {
        try {
            CommandData cd = executeDefault(args);
            if (cd.isExitOK())
                return cd.getOutputString();
        } catch (Exception e) {
        }
        return null;
    }

    public static CommandData executeDefault(String... args) throws IOException, InterruptedException {
        CommandData cd = new CommandData();
        execute(cd, args);
        return cd;
    }

    public static void execute(final CommandData out, final String... args)
            throws IOException, InterruptedException {
        if (out.getTimeout() > 0) {
            executeSpecial(out, args);
            return;
        } else if (out.isMultithreaded()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        executeBlock(out, args);
                    } catch (Exception e) {
                        out.setThrowable(e);
                    }
                }
            }).start();
        } else {
            executeBlock(out, args);
        }
    }

    protected static void executeBlock(CommandData out, String... args) throws IOException, InterruptedException {
        if (out.getTimeout() > 0) {
            executeSpecial(out, args);
            return;
        }
        ProcessBuilder pb = new ProcessBuilder(args);
        pb.redirectErrorStream(out.isRedirectError());
        Process proc = pb.start();
        try (InputStream in = proc.getInputStream(); InputStream err = proc.getErrorStream()) {
            out.writeOutput(in);
            out.writeError(err);
            proc.waitFor();
            out.setExitStatus(proc.exitValue());
            if (out.getOnFinish() != null)
                out.getOnFinish().accept(out);
        }
    }

    protected static void executeSpecial(final CommandData out, final String... args)
            throws IOException, InterruptedException {
        Runnable rn = new Runnable() {
            @Override
            public void run() {
                TimeoutThread<Boolean> tt = new TimeoutThread<Boolean>(new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        executeBlock(out, args);
                        return true;
                    }
                }, out.getTimeout());
                Result<Boolean> res = new Result<Boolean>();
                res.setResult(false);
                tt.runSafe(res);
                out.setTimeoutResult(res);
            }
        };
        if (out.isMultithreaded()) {
            new Thread(rn).start();
        } else {
            rn.run();
        }
    }

    public static boolean isWindows() {
        String os = System.getProperty("os.name");
        return (os != null && (os.contains("win") || os.contains("Win")));
    }

    public static File getJDK() {
        File lastChance = null;

        String ver = "jdk" + (System.getProperty("java.version").toLowerCase());

        String jdk = System.getenv("JAVA_HOME");
        if (jdk != null && !jdk.isEmpty() && ver != null) {
            lastChance = new File(jdk);
            if (lastChance.exists() && lastChance.getName().toLowerCase().contains(ver)) {
                return lastChance;
            }
        }

        String os = System.getProperty("os.name");
        boolean isWin = (os != null && (os.contains("win") || os.contains("Win")));
        if (!isWin) {
            String response = executeAndGetOutput("whereis", "javac");
            if (response != null && !response.isEmpty()) {
                int pathStartIndex = response.indexOf('/');
                if (pathStartIndex != -1) {
                    String[] paths = response.substring(pathStartIndex, response.length()).split(" ");
                    for (int i = 0, n = paths.length; i < n; i++) {
                        String path = paths[i];
                        if (!path.endsWith("javac")) {
                            continue;
                        }
                        lastChance = FilesAPI.readFinalLink(new File(path)).getParentFile().getParentFile();
                        if (lastChance.exists()) {
                            return lastChance;
                        }
                    }
                }
            }
            if (lastChance == null) {
                lastChance = getJRE().getParentFile();
            }
        } else {
            String path = executeAndGetOutput("where.exe", "javac");
            if (path != null && !path.isEmpty()) {
                lastChance = new File(path).getParentFile().getParentFile();
                if (lastChance.exists() && lastChance.getName().toLowerCase().contains(ver)) {
                    return lastChance;
                }
            }

            if (ver == null) {
                return lastChance;
            }
            path = System.getenv("PATH");
            if (path == null) {
                path = System.getenv("Path");
            }

            if (path != null) {
                String[] paths = path.split(File.pathSeparator);
                for (int i = 0, n = paths.length; i < n; i++) {
                    String p = paths[i];
                    if (p.toLowerCase().contains(ver)) {
                        File f = new File(p);
                        if (f.exists()) {
                            return f;
                        } else if (lastChance == null) {
                            lastChance = f;
                        }
                    }
                }
            }

            File[] roots = File.listRoots();
            if (roots == null || roots.length == 0) {
                return null;
            }
            File jp = new File(roots[0], "Program Files/Java/");
            if (!jp.exists() || !jp.isDirectory()) {
                jp = new File(roots[0], "Program Files (x86)/Java/");
                if (!jp.exists() || !jp.isDirectory()) {
                    return null;
                }
            }
            File[] jvs = jp.listFiles();
            if (jvs == null || jvs.length == 0) {
                return null;
            }
            if (jvs.length == 1) {
                return jvs[0];
            }
            for (int i = 0, n = jvs.length; i < n; i++) {
                File f = jvs[i];
                String nm = f.getName().toLowerCase();
                if (nm.contains(ver)) {
                    return f;
                } else if (nm.contains("jdk")) {
                    if (lastChance == null || !lastChance.exists()) {
                        lastChance = f;
                    }
                }
            }
        }
        if (lastChance == null) {
            if (jdk != null && !jdk.isEmpty()) {
                lastChance = new File(jdk);
            }
        }
        return lastChance;
    }

}