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

au.net.causal.maven.plugins.boxdb.JavaRunner Maven / Gradle / Ivy

package au.net.causal.maven.plugins.boxdb;

import au.net.causal.maven.plugins.boxdb.db.RunnerDependency;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.DependencyResolutionException;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Runs Java main classes.
 */
public class JavaRunner
{
    private final List jarFiles;
    private final String mainClassName;
    private final ClassLoaderCache classLoaderCache;

    private Thread runnerThread;

    public JavaRunner(List jarFiles, String mainClassName, ClassLoaderCache classLoaderCache)
    {
        Objects.requireNonNull(jarFiles, "jarFiles == null");
        Objects.requireNonNull(mainClassName, "mainClassName == null");
        Objects.requireNonNull(classLoaderCache, "classLoaderCache == null");
        this.jarFiles = new ArrayList<>(jarFiles);
        this.mainClassName = mainClassName;
        this.classLoaderCache = classLoaderCache;
    }

    public static JavaRunner createFromDependencies(String mainClassName,
                                                    List dependencies,
                                                    RepositorySystem repositorySystem,
                                                    RepositorySystemSession repositorySystemSession,
                                                    List remoteRepositories, 
                                                    ClassLoaderCache classLoaderCache)
    throws DependencyResolutionException
    {
        return new JavaRunner(DependencyUtils.resolveDependencies(dependencies, repositorySystem, repositorySystemSession, remoteRepositories),
                        mainClassName, classLoaderCache);
    }

    public Class makeClass()
    throws IOException, ClassNotFoundException
    {
        List urls = new ArrayList<>(jarFiles.size());
        for (Path jarFile : jarFiles)
        {
            urls.add(jarFile.toUri().toURL());
        }
        URL[] urlArray = urls.toArray(new URL[urls.size()]);
        URLClassLoader loader = classLoaderCache.create(urlArray);

        return Class.forName(mainClassName, true, loader);
    }

    private Method createMainMethod()
    throws IOException, ClassNotFoundException, NoSuchMethodException
    {
        Class mainClass = makeClass();
        return mainClass.getMethod("main", String[].class);
    }

    public void execute(String... args)
    throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException
    {
        ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
        try
        {
            Method mainMethod = createMainMethod();
            Thread.currentThread().setContextClassLoader(mainMethod.getDeclaringClass().getClassLoader());
            runMain(mainMethod, args);
        }
        finally
        {
            Thread.currentThread().setContextClassLoader(oldLoader);
        }
    }

    /**
     * Starts executing, does not wait for completion.
     */
    public void executeAsync(String... args)
    throws IOException, ClassNotFoundException, NoSuchMethodException
    {
        Method mainMethod = createMainMethod();

        runnerThread = new Thread(() -> runMainSafely(mainMethod, args));
        runnerThread.setContextClassLoader(mainMethod.getDeclaringClass().getClassLoader());
        runnerThread.setName("JavaRunner-" + mainMethod.getDeclaringClass().getSimpleName());
        //runnerThread.setUncaughtExceptionHandler();

        runnerThread.start();
    }

    public void runMethodAsync(Method method, Object target, Object... args)
    {
        runnerThread = new Thread(() -> runMethod(method, target, args));
        runnerThread.setContextClassLoader(method.getDeclaringClass().getClassLoader());
        runnerThread.setName("JavaRunner-" + method.getDeclaringClass().getSimpleName());
        //runnerThread.setUncaughtExceptionHandler();

        runnerThread.start();
    }

    public void runMethod(Method method, Object target, Object... args)
    {
        try
        {
            method.invoke(target, args);
        }
        catch (ReflectiveOperationException e)
        {
            throw new RuntimeException(e);
        }
    }

    private void runMainSafely(Method mainMethod, String... args)
    {
        try
        {
            mainMethod.invoke(null, new Object[] {args});
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    private void runMain(Method mainMethod, String... args)
    throws InvocationTargetException
    {
        try
        {
            mainMethod.invoke(null, new Object[] {args});
        }
        catch (InvocationTargetException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            throw new InvocationTargetException(e);
        }
    }

    public void waitForAsyncCompletion()
    throws InterruptedException
    {
        if (runnerThread == null)
            throw new IllegalStateException("Thread never started");

        runnerThread.join();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy