7026509: Cannot use JavaCompiler to create multiple CompilationTasks for partial compilations
authorjjg
Mon, 14 Mar 2011 11:48:41 -0700
changeset 8844 18170a311747
parent 8843 2602bd5c9c5f
child 8845 42fb82dfbf52
7026509: Cannot use JavaCompiler to create multiple CompilationTasks for partial compilations Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java
langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java
langtools/test/tools/javac/api/TestJavacTask_Lock.java
langtools/test/tools/javac/api/TestJavacTask_Multiple.java
langtools/test/tools/javac/api/TestJavacTask_ParseAttrGen.java
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Mar 14 11:42:15 2011 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java	Mon Mar 14 11:48:41 2011 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, 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
@@ -129,19 +129,11 @@
 
     public Boolean call() {
         if (!used.getAndSet(true)) {
-            beginContext();
+            initContext();
             notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
-            try {
-                compilerMain.setFatalErrors(true);
-                result = compilerMain.compile(args, context, fileObjects, processors);
-            } finally {
-                endContext();
-            }
-            compilerMain = null;
-            args = null;
-            context = null;
-            fileObjects = null;
-            notYetEntered = null;
+            compilerMain.setFatalErrors(true);
+            result = compilerMain.compile(args, context, fileObjects, processors);
+            cleanup();
             return result == 0;
         } else {
             throw new IllegalStateException("multiple calls to method 'call'");
@@ -163,8 +155,11 @@
     }
 
     private void prepareCompiler() throws IOException {
-        if (!used.getAndSet(true)) {
-            beginContext();
+        if (used.getAndSet(true)) {
+            if (compiler == null)
+                throw new IllegalStateException();
+        } else {
+            initContext();
             compilerMain.setOptions(Options.instance(context));
             compilerMain.filenames = new ListBuffer<File>();
             List<File> filenames = compilerMain.processArgs(CommandLine.parse(args));
@@ -185,13 +180,12 @@
         }
     }
 
-    private void beginContext() {
+    private void initContext() {
         context.put(JavacTaskImpl.class, this);
         if (context.get(TaskListener.class) != null)
             context.put(TaskListener.class, (TaskListener)null);
         if (taskListener != null)
             context.put(TaskListener.class, wrap(taskListener));
-        tool.beginContext(context);
         //initialize compiler's default locale
         JavacMessages.instance(context).setCurrentLocale(locale);
     }
@@ -218,8 +212,15 @@
         };
     }
 
-    private void endContext() {
-        tool.endContext();
+    void cleanup() {
+        if (compiler != null)
+            compiler.close();
+        compiler = null;
+        compilerMain = null;
+        args = null;
+        context = null;
+        fileObjects = null;
+        notYetEntered = null;
     }
 
     /**
@@ -446,12 +447,12 @@
             }
             if (genList.isEmpty()) {
                 compiler.reportDeferredDiagnostics();
-                compiler.log.flush();
-                endContext();
+                cleanup();
             }
         }
         finally {
-            compiler.log.flush();
+            if (compiler != null)
+                compiler.log.flush();
         }
         return results;
     }
--- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java	Mon Mar 14 11:42:15 2011 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTool.java	Mon Mar 14 11:48:41 2011 -0700
@@ -152,36 +152,6 @@
         return new JavacFileManager(context, true, charset);
     }
 
-    private boolean compilationInProgress = false;
-
-    /**
-     * Register that a compilation is about to start.
-     */
-    void beginContext(Context context) {
-        if (compilationInProgress)
-            throw new IllegalStateException("Compilation in progress");
-        compilationInProgress = true;
-        final JavaFileManager givenFileManager = context.get(JavaFileManager.class);
-        context.put(JavaFileManager.class, (JavaFileManager)null);
-        context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() {
-            public JavaFileManager make(Context c) {
-                if (givenFileManager != null) {
-                    c.put(JavaFileManager.class, givenFileManager);
-                    return givenFileManager;
-                } else {
-                    return new JavacFileManager(c, true, null);
-                }
-            }
-        });
-    }
-
-    /**
-     * Register that a compilation is completed.
-     */
-    void endContext() {
-        compilationInProgress = false;
-    }
-
     public JavacTask getTask(Writer out,
                              JavaFileManager fileManager,
                              DiagnosticListener<? super JavaFileObject> diagnosticListener,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/api/TestJavacTask_Lock.java	Mon Mar 14 11:48:41 2011 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7026509
+ * @summary Cannot use JavaCompiler to create multiple CompilationTasks for partial compilations
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.tools.*;
+import javax.tools.JavaCompiler.CompilationTask;
+import com.sun.source.util.*;
+
+public class TestJavacTask_Lock {
+    public static void main(String... args) throws Exception {
+        new TestJavacTask_Lock().run();
+    }
+
+    enum MethodKind {
+        CALL {
+            int test(CompilationTask t) {
+                boolean ok = t.call();
+                if (!ok)
+                    throw new Error("compilation failed");
+                return 1;
+            }
+        },
+        PARSE {
+            int test(CompilationTask t) {
+                try {
+                    ((JavacTask) t).parse();
+                return 1;
+                } catch (IOException ex) {
+                    throw new Error(ex);
+                }
+            }
+
+        };
+        abstract int test(CompilationTask t);
+    }
+
+    JavaCompiler comp;
+    StandardJavaFileManager fm;
+
+    void run() throws Exception {
+        comp = ToolProvider.getSystemJavaCompiler();
+        fm = comp.getStandardFileManager(null, null, null);
+
+        for (MethodKind first: MethodKind.values()) {
+            for (MethodKind second: MethodKind.values()) {
+                test(first, second);
+            }
+        }
+
+        if (errors > 0)
+            throw new Exception(errors + " errors found");
+    }
+
+    void test(MethodKind first, MethodKind second) {
+        System.err.println("test: " + first + ", " + second);
+        File testSrc = new File(System.getProperty("test.src"));
+        String thisClassName = TestJavacTask_Lock.class.getName();
+        Iterable<? extends JavaFileObject> files =
+                fm.getJavaFileObjects(new File(testSrc, thisClassName + ".java"));
+        File tmpDir = new File(first + "_" + second);
+        tmpDir.mkdirs();
+        List<String> options = Arrays.asList( "-d", tmpDir.getPath() );
+        CompilationTask t = comp.getTask(null, fm, null, options, null, files);
+
+        try {
+            first.test(t);
+            second.test(t);
+            error("No exception thrown");
+        } catch (IllegalStateException e) {
+            System.err.println("Expected exception caught: " + e);
+        } catch (Exception e) {
+            error("Unexpected exception caught: " + e);
+            e.printStackTrace(System.err);
+        }
+
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/api/TestJavacTask_Multiple.java	Mon Mar 14 11:48:41 2011 -0700
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7026509
+ * @summary Cannot use JavaCompiler to create multiple CompilationTasks for partial compilations
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.tools.*;
+import javax.tools.JavaCompiler.CompilationTask;
+import com.sun.source.util.*;
+
+public class TestJavacTask_Multiple {
+    public static void main(String... args) throws Exception {
+        new TestJavacTask_Multiple().run();
+    }
+
+    final int MAX_TASKS = 3;
+
+    enum TestKind {
+        CALL {
+            int test(CompilationTask t) {
+                boolean ok = t.call();
+                if (!ok)
+                    throw new Error("compilation failed");
+                return 1;
+            }
+        },
+        PARSE {
+            int test(CompilationTask t) {
+                try {
+                    ((JavacTask) t).parse();
+                return 1;
+                } catch (IOException ex) {
+                    throw new Error(ex);
+                }
+            }
+
+        };
+        abstract int test(CompilationTask t);
+    }
+
+    int count;
+
+    void run() throws Exception {
+        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
+        for (TestKind tk: TestKind.values()) {
+            test(comp, fm, tk);
+        }
+
+        int expect = TestKind.values().length * MAX_TASKS;
+        if (count != expect) {
+            throw new Exception("Unexpected number of tests completed: " + count
+                    + ", expected: " + expect);
+        }
+
+    }
+
+    void test(JavaCompiler comp, StandardJavaFileManager fm, TestKind tk) {
+        System.err.println("test " + tk);
+        File testSrc = new File(System.getProperty("test.src"));
+        String thisClassName = TestJavacTask_Multiple.class.getName();
+        Iterable<? extends JavaFileObject> files =
+                fm.getJavaFileObjects(new File(testSrc, thisClassName + ".java"));
+
+        List<CompilationTask> tasks = new ArrayList<CompilationTask>();
+        for (int i = 1; i <= MAX_TASKS; i++) {
+            File tmpDir = new File(tk + "_" + i);
+            tmpDir.mkdirs();
+            List<String> options = Arrays.asList( "-d", tmpDir.getPath() );
+            CompilationTask t = comp.getTask(null, fm, null, options, null, files);
+            ((JavacTask) t).setTaskListener(createTaskListener(tk, i));
+            tasks.add(t);
+        }
+
+        for (CompilationTask t: tasks)
+            count += tk.test(t);
+
+        System.err.println();
+    }
+
+    TaskListener createTaskListener(final TestKind tk, final int i) {
+        return new TaskListener() {
+
+            public void started(TaskEvent e) {
+                System.err.println(tk + "." + i + ": " + e + " started");
+            }
+
+            public void finished(TaskEvent e) {
+                System.err.println(tk + "." + i + ": " + e + " finished");
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/api/TestJavacTask_ParseAttrGen.java	Mon Mar 14 11:48:41 2011 -0700
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7026509
+ * @summary Cannot use JavaCompiler to create multiple CompilationTasks for partial compilations
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.lang.model.element.*;
+import javax.tools.*;
+import com.sun.source.tree.*;
+import com.sun.source.util.*;
+
+public class TestJavacTask_ParseAttrGen {
+    public static void main(String... args) throws Exception {
+        new TestJavacTask_ParseAttrGen().run();
+    }
+
+    JavaCompiler comp;
+    StandardJavaFileManager fm;
+
+    void run() throws Exception {
+        comp = ToolProvider.getSystemJavaCompiler();
+        fm = comp.getStandardFileManager(null, null, null);
+
+        final boolean[] booleanValues = { false, true };
+        for (boolean pk: booleanValues) {
+            for (boolean ak: booleanValues) {
+                for (boolean gk: booleanValues) {
+                    test(pk, ak, gk);
+                }
+            }
+        }
+    }
+
+    void test(boolean pk, boolean ak, boolean gk) throws Exception {
+        if (!pk && !ak && !gk)  // nothing to do
+            return;
+
+        System.err.println("test: pk:" + pk + ", ak:" + ak + ", gk: " + gk);
+        File testSrc = new File(System.getProperty("test.src"));
+        String thisClassName = TestJavacTask_ParseAttrGen.class.getName();
+        Iterable<? extends JavaFileObject> files =
+                fm.getJavaFileObjects(new File(testSrc, thisClassName + ".java"));
+        File tmpDir = new File((pk ? "p" : "") + (ak ? "a" : "") + (gk ? "g" : ""));
+        tmpDir.mkdirs();
+        fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(tmpDir));
+        JavacTask t = (JavacTask) comp.getTask(null, fm, null, null, null, files);
+        //t.setTaskListener(createTaskListener());
+
+        try {
+            if (pk) {
+                Iterable<? extends CompilationUnitTree> trees = t.parse();
+                System.err.println(count(trees) + " trees parsed");
+            }
+
+            if (ak) {
+                Iterable<? extends Element> elems = t.analyze();
+                System.err.println(count(elems) + " elements analyzed");
+            }
+
+            if (gk) {
+                Iterable<? extends JavaFileObject> classfiles = t.generate();
+                System.err.println(count(classfiles) + " class files generated");
+            }
+        } catch (IOException e) {
+            error("unexpected exception caught: " + e);
+        }
+
+        File[] genFiles = tmpDir.listFiles();
+        int expect = (gk ? 2 : 0); // main class and anon class for TaskListener
+        if (genFiles.length != expect)
+            error("unexpected number of files generated: " + genFiles.length
+                    + ", expected: " + expect);
+
+        System.err.println();
+    }
+
+    TaskListener createTaskListener() {
+        return new TaskListener() {
+            public void started(TaskEvent e) {
+                System.err.println(e + " started");
+            }
+
+            public void finished(TaskEvent e) {
+                System.err.println(e + " finished");
+            }
+        };
+    }
+
+    <T> int count(Iterable<T> items) {
+        int count = 0;
+        for (T item: items)
+            count++;
+        return count;
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    int errors;
+}