8174099: class ComboTask at the combo test library needs an execute() method
authorvromero
Fri, 10 Feb 2017 07:50:55 -0800
changeset 43769 c60feafb47db
parent 43768 45dd590fda77
child 43770 a321bed02000
8174099: class ComboTask at the combo test library needs an execute() method Reviewed-by: mcimadamore
langtools/test/tools/javac/lib/combo/ComboTask.java
--- a/langtools/test/tools/javac/lib/combo/ComboTask.java	Fri Feb 10 12:28:35 2017 +0000
+++ b/langtools/test/tools/javac/lib/combo/ComboTask.java	Fri Feb 10 07:50:55 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,9 +25,9 @@
 
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.util.JavacTask;
-import com.sun.source.util.TaskEvent.Kind;
 import com.sun.source.util.TaskListener;
 import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.util.Assert;
 import com.sun.tools.javac.util.List;
 import combo.ComboParameter.Resolver;
 
@@ -36,11 +36,18 @@
 import javax.tools.DiagnosticListener;
 import javax.tools.JavaFileObject;
 import javax.tools.SimpleJavaFileObject;
+
 import java.io.IOException;
 import java.io.Writer;
 import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
@@ -184,6 +191,28 @@
     }
 
     /**
+     * Parse, analyze, perform code generation for the sources associated with this task and finally
+     * executes them
+     */
+    public <Z> Optional<Z> execute(Function<ExecutionTask, Z> executionFunc) throws IOException {
+        Result<Iterable<? extends JavaFileObject>> generationResult = generate();
+        Iterable<? extends JavaFileObject> jfoIterable = generationResult.get();
+        if (generationResult.hasErrors()) {
+            // we have nothing else to do
+            return Optional.empty();
+        }
+        java.util.List<URL> urlList = new ArrayList<>();
+        for (JavaFileObject jfo : jfoIterable) {
+            String urlStr = jfo.toUri().toURL().toString();
+            urlStr = urlStr.substring(0, urlStr.length() - jfo.getName().length());
+            urlList.add(new URL(urlStr));
+        }
+        return Optional.of(
+                executionFunc.apply(
+                        new ExecutionTask(new URLClassLoader(urlList.toArray(new URL[urlList.size()])))));
+    }
+
+    /**
      * Fork a new compilation task; if possible the compilation context from previous executions is
      * retained (see comments in ReusableContext as to when it's safe to do so); otherwise a brand
      * new context is created.
@@ -215,6 +244,80 @@
     }
 
     /**
+     * This class represents an execution task. It allows the execution of one or more classes previously
+     * added to a given class loader. This class uses reflection to execute any given static public method
+     * in any given class. It's not restricted to the execution of the {@code main} method
+     */
+    public class ExecutionTask {
+        private ClassLoader classLoader;
+        private String methodName = "main";
+        private Class<?>[] parameterTypes = new Class<?>[]{String[].class};
+        private Object[] args = new String[0];
+        private Consumer<Throwable> handler;
+        private Class<?> c;
+
+        private ExecutionTask(ClassLoader classLoader) {
+            this.classLoader = classLoader;
+        }
+
+        /**
+         * Set the name of the class to be loaded.
+         */
+        public ExecutionTask withClass(String className) {
+            Assert.check(className != null, "class name value is null, impossible to proceed");
+            try {
+                c = classLoader.loadClass(className);
+            } catch (Throwable t) {
+                throw new IllegalStateException(t);
+            }
+            return this;
+        }
+
+        /**
+         * Set the name of the method to be executed along with the parameter types to
+         * reflectively obtain the method.
+         */
+        public ExecutionTask withMethod(String methodName, Class<?>... parameterTypes) {
+            this.methodName = methodName;
+            this.parameterTypes = parameterTypes;
+            return this;
+        }
+
+        /**
+         * Set the arguments to be passed to the method.
+         */
+        public ExecutionTask withArguments(Object... args) {
+            this.args = args;
+            return this;
+        }
+
+        /**
+         * Set a handler to handle any exception thrown.
+         */
+        public ExecutionTask withHandler(Consumer<Throwable> handler) {
+            this.handler = handler;
+            return this;
+        }
+
+        /**
+         * Executes the given method in the given class. Returns true if the execution was
+         * successful, false otherwise.
+         */
+        public Object run() {
+            try {
+                java.lang.reflect.Method meth = c.getMethod(methodName, parameterTypes);
+                meth.invoke(null, (Object)args);
+                return true;
+            } catch (Throwable t) {
+                if (handler != null) {
+                    handler.accept(t);
+                }
+                return false;
+            }
+        }
+    }
+
+    /**
      * This class is used to help clients accessing the results of a given compilation task.
      * Contains several helper methods to inspect diagnostics generated during the task execution.
      */