8159855: Create an SPI for tools

Reviewed-by: mchung
This commit is contained in:
Jonathan Gibbons 2016-10-07 16:49:39 -07:00
parent 4735558138
commit 6fef223c3f
15 changed files with 444 additions and 19 deletions
langtools
make
src
jdk.compiler/share/classes
jdk.javadoc/share/classes
jdk.jdeps/share/classes
com/sun/tools
module-info.java
test

@ -1,5 +1,5 @@
#
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 2016, 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
@ -47,7 +47,7 @@ define SetupInterimModule
$$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1)), \
EXCLUDES := sun com/sun/tools/jdeps com/sun/tools/javap \
com/sun/tools/jdeprscan, \
EXCLUDE_FILES := module-info.java, \
EXCLUDE_FILES := module-info.java JavacToolProvider.java JavadocToolProvider.java, \
COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/$(strip $1), \
ADD_JAVAC_FLAGS := -Xbootclasspath/p:$$(call PathList, \

@ -0,0 +1,48 @@
/*
* Copyright (c) 2016, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package com.sun.tools.javac.main;
import java.io.PrintWriter;
import java.util.spi.ToolProvider;
/**
* An implementation of the {@link java.util.spi.ToolProvider ToolProvider} SPI,
* providing access to JDK Java compiler, javac.
*
* @since 9
*/
// This is currently a stand-alone top-level class so that it can easily be excluded
// from interims builds of javac, used while building JDK.
public class JavacToolProvider implements ToolProvider {
public String name() {
return "javac";
}
public int run(PrintWriter out, PrintWriter err, String... args) {
Main compiler = new Main("javac", out, err);
return compiler.compile(args).exitCode;
}
}

@ -119,6 +119,18 @@ public class Main {
this.stdOut = this.stdErr = out;
}
/**
* Construct a compiler instance.
* @param name the name of this tool
* @param out a stream to which to write expected output
* @param err a stream to which to write diagnostic output
*/
public Main(String name, PrintWriter out, PrintWriter err) {
this.ownName = name;
this.stdOut = out;
this.stdErr = err;
}
/** Report a usage error.
*/
void error(String key, Object... args) {

@ -70,6 +70,9 @@ module jdk.compiler {
uses com.sun.source.util.Plugin;
uses com.sun.tools.javac.platform.PlatformProvider;
provides java.util.spi.ToolProvider
with com.sun.tools.javac.main.JavacToolProvider;
provides com.sun.tools.javac.platform.PlatformProvider
with com.sun.tools.javac.platform.JDKPlatformProvider;

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.javadoc.internal.tool;
import java.io.PrintWriter;
import java.util.spi.ToolProvider;
/**
* An implementation of the {@link java.util.spi.ToolProvider ToolProvider} SPI,
* providing access to JDK documentation tool, javadoc.
*
* @since 9
*/
// This is currently a stand-alone top-level class so that it can easily be excluded
// from interims builds of javadoc, used while building JDK.
public class JavadocToolProvider implements ToolProvider {
public String name() {
return "javadoc";
}
public int run(PrintWriter out, PrintWriter err, String... args) {
return Main.execute(args, out, err);
}
}

@ -66,12 +66,25 @@ public class Main {
/**
* Programmatic interface.
*
* @param writer PrintWriter to receive notice messages.
* @param writer a stream for all output
* @param args The command line parameters.
* @return The return code.
*/
public static int execute(String[] args, PrintWriter writer) {
Start jdoc = new Start(writer);
Start jdoc = new Start(writer, writer);
return jdoc.begin(args);
}
/**
* Programmatic interface.
*
* @param outWriter a stream for expected output
* @param errWriter a stream for diagnostic output
* @param args The command line parameters.
* @return The return code.
*/
public static int execute(String[] args, PrintWriter outWriter, PrintWriter errWriter) {
Start jdoc = new Start(outWriter, errWriter);
return jdoc.begin(args);
}
}

@ -165,8 +165,8 @@ public class Messager extends Log implements Reporter {
/**
* Constructor
* @param programName Name of the program (for error messages).
* @param stdOut Stream for notices etc.
* @param stdErr Stream for errors and warnings
* @param outWriter Stream for notices etc.
* @param errWriter Stream for errors and warnings
*/
@SuppressWarnings("deprecation")
public Messager(Context context, String programName, PrintWriter outWriter, PrintWriter errWriter) {

@ -119,20 +119,21 @@ public class Start extends ToolOption.Helper {
private JavaFileManager fileManager;
Start() {
this(null, null, null, null, null);
this(null, null, null, null, null, null);
}
Start(PrintWriter writer) {
this(null, null, writer, null, null);
Start(PrintWriter outWriter, PrintWriter errWriter) {
this(null, null, outWriter, errWriter, null, null);
}
Start(Context context, String programName, PrintWriter writer,
Start(Context context, String programName,
PrintWriter outWriter, PrintWriter errWriter,
String docletName, ClassLoader classLoader) {
this.context = context == null ? new Context() : context;
String pname = programName == null ? ProgramName : programName;
this.messager = writer == null
this.messager = (outWriter == null && errWriter == null)
? new Messager(this.context, pname)
: new Messager(this.context, pname, writer, writer);
: new Messager(this.context, pname, outWriter, errWriter);
this.docletName = docletName;
this.classLoader = classLoader;
this.docletClass = null;

@ -41,6 +41,9 @@ module jdk.javadoc {
exports jdk.javadoc.doclet.taglet;
exports jdk.javadoc.doclets;
provides java.util.spi.ToolProvider
with jdk.javadoc.internal.tool.JavadocToolProvider;
provides javax.tools.DocumentationTool
with jdk.javadoc.internal.api.JavadocTool;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2016, 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
@ -26,6 +26,7 @@
package com.sun.tools.javap;
import java.io.PrintWriter;
import java.util.spi.ToolProvider;
/**
* Main entry point.
@ -58,4 +59,14 @@ public class Main {
t.setLog(out);
return t.run(args);
}
public static class JavapToolProvider implements ToolProvider {
public String name() {
return "javap";
}
public int run(PrintWriter out, PrintWriter err, String... args) {
return Main.run(args, out);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2016, 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
@ -26,6 +26,7 @@
package com.sun.tools.jdeps;
import java.io.*;
import java.util.spi.ToolProvider;
/**
*
@ -62,4 +63,14 @@ public class Main {
t.setLog(out);
return t.run(args);
}
public static class JDepsToolProvider implements ToolProvider {
public String name() {
return "jdeps";
}
public int run(PrintWriter out, PrintWriter err, String... args) {
return Main.run(args, out);
}
}
}

@ -32,4 +32,10 @@ module jdk.jdeps {
requires jdk.compiler;
exports com.sun.tools.classfile to
jdk.jlink;
provides java.util.spi.ToolProvider
with com.sun.tools.javap.Main.JavapToolProvider;
provides java.util.spi.ToolProvider
with com.sun.tools.jdeps.Main.JDepsToolProvider;
}

@ -0,0 +1,133 @@
/*
* Copyright (c) 2016, 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 8159855
* @summary test javadoc's ToolProvider
* @library /tools/lib
* @build toolbox.TestRunner toolbox.ToolBox
* @run main ToolProviderTest
*/
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.spi.ToolProvider;
import toolbox.TestRunner;
import toolbox.ToolBox;
public class ToolProviderTest extends TestRunner {
public static void main(String... args) throws Exception {
new ToolProviderTest().runTests();
}
ToolBox tb = new ToolBox();
ToolProvider javadoc;
ToolProviderTest() {
super(System.err);
javadoc = ToolProvider.findFirst("javadoc").get();
}
@Test
public void testProviders() throws Exception {
Map<String, ToolProvider> providers = new LinkedHashMap<>();
for (ToolProvider tp : ServiceLoader.load(ToolProvider.class,
ClassLoader.getSystemClassLoader())) {
System.out.println("Provider: " + tp.name() + ": " + tp.getClass().getName());
providers.put(tp.name(), tp);
}
if (!providers.containsKey("javadoc")) {
error("javadoc ToolProvider not found");
}
}
@Test
public void testOneStream() throws Exception {
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
int rc = javadoc.run(pw, pw, "-help");
if (rc != 0) {
error("unexpected exit code: " + rc);
}
}
String out = sw.toString();
if (!out.contains("Usage:")) {
error("expected output not found");
}
}
@Test
public void testTwoStreamsOut() throws Exception {
StringWriter swOut = new StringWriter();
StringWriter swErr = new StringWriter();
try (PrintWriter pwOut = new PrintWriter(swOut);
PrintWriter pwErr = new PrintWriter(swErr)) {
int rc = javadoc.run(pwOut, pwErr, "-help");
if (rc != 0) {
error("unexpected exit code: " + rc);
}
}
String out = swOut.toString();
String err = swErr.toString();
if (!out.contains("Usage:")) {
error("stdout: expected output not found");
}
if (!err.isEmpty()) {
error("stderr: unexpected output");
}
}
@Test
public void testTwoStreamsErr() throws Exception {
Path src = Paths.get("src");
Path classes = Paths.get("classes");
tb.writeJavaFiles(src,
"import java.util.*; class C { # }");
StringWriter swOut = new StringWriter();
StringWriter swErr = new StringWriter();
try (PrintWriter pwOut = new PrintWriter(swOut);
PrintWriter pwErr = new PrintWriter(swErr)) {
int rc = javadoc.run(pwOut, pwErr,
"-d", classes.toString(),
src.resolve("C.java").toString());
if (rc != 1) {
error("unexpected exit code: " + rc);
}
}
String out = swOut.toString();
String err = swErr.toString();
if (!out.contains("Loading")) {
error("stdout: unexpected output");
}
if (!err.contains("illegal character")) {
error("stderr: expected output not found");
}
}
}

@ -0,0 +1,132 @@
/*
* Copyright (c) 2016, 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 8159855
* @summary test javac's ToolProvider
* @library /tools/lib
* @build toolbox.TestRunner toolbox.ToolBox
* @run main ToolProviderTest
*/
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.spi.ToolProvider;
import toolbox.TestRunner;
import toolbox.ToolBox;
public class ToolProviderTest extends TestRunner {
public static void main(String... args) throws Exception {
new ToolProviderTest().runTests();
}
ToolBox tb = new ToolBox();
ToolProvider javac;
ToolProviderTest() {
super(System.err);
javac = ToolProvider.findFirst("javac").get();
}
@Test
public void testProviders() throws Exception {
Map<String, ToolProvider> providers = new LinkedHashMap<>();
for (ToolProvider tp : ServiceLoader.load(ToolProvider.class,
ClassLoader.getSystemClassLoader())) {
System.out.println("Provider: " + tp.name() + ": " + tp.getClass().getName());
providers.put(tp.name(), tp);
}
if (!providers.containsKey("javac")) {
error("javac ToolProvider not found");
}
}
@Test
public void testOneStream() throws Exception {
StringWriter sw = new StringWriter();
try (PrintWriter pw = new PrintWriter(sw)) {
int rc = javac.run(pw, pw, "-help");
if (rc != 0) {
error("unexpected exit code: " + rc);
}
}
String out = sw.toString();
if (!out.contains("Usage:")) {
error("expected output not found");
}
}
@Test
public void testTwoStreamsOut() throws Exception {
StringWriter swOut = new StringWriter();
StringWriter swErr = new StringWriter();
try (PrintWriter pwOut = new PrintWriter(swOut);
PrintWriter pwErr = new PrintWriter(swErr)) {
int rc = javac.run(pwOut, pwErr, "-help");
if (rc != 0) {
error("unexpected exit code: " + rc);
}
}
String out = swOut.toString();
String err = swErr.toString();
if (!out.contains("Usage:")) {
error("stdout: expected output not found");
}
if (!err.isEmpty()) {
error("stderr: unexpected output");
}
}
@Test
public void testTwoStreamsErr() throws Exception {
Path src = Paths.get("src");
Path classes = Paths.get("classes");
tb.writeJavaFiles(src,
"import java.util.*; class C { # }");
StringWriter swOut = new StringWriter();
StringWriter swErr = new StringWriter();
try (PrintWriter pwOut = new PrintWriter(swOut);
PrintWriter pwErr = new PrintWriter(swErr)) {
int rc = javac.run(pwOut, pwErr,
"-d", classes.toString(),
src.resolve("C.java").toString());
if (rc != 1) {
error("unexpected exit code: " + rc);
}
}
String out = swOut.toString();
String err = swErr.toString();
if (!out.isEmpty()) {
error("stdout: unexpected output");
}
if (!err.contains("illegal character")) {
error("stderr: expected output not found");
}
}
}

@ -345,6 +345,7 @@ public class AddLimitMods extends ModuleTestBase {
Files.createDirectories(classpathOut);
System.err.println("Compiling classpath-src files:");
new JavacTask(tb)
.outdir(classpathOut)
.files(findJavaFiles(classpathSrc))
@ -360,6 +361,7 @@ public class AddLimitMods extends ModuleTestBase {
Files.createDirectories(automaticOut);
System.err.println("Compiling automatic-src files:");
new JavacTask(tb)
.outdir(automaticOut)
.files(findJavaFiles(automaticSrc))
@ -373,6 +375,7 @@ public class AddLimitMods extends ModuleTestBase {
Path automaticJar = modulePath.resolve("automatic.jar");
System.err.println("Creating automatic.jar:");
new JarTask(tb, automaticJar)
.baseDir(automaticOut)
.files("automatic/Automatic.class")
@ -385,6 +388,7 @@ public class AddLimitMods extends ModuleTestBase {
"module m1 { exports api; }",
"package api; public class Api { public void test() { } }");
System.err.println("Compiling module-src files:");
new JavacTask(tb)
.options("--module-source-path", moduleSrc.toString())
.outdir(modulePath)
@ -399,7 +403,7 @@ public class AddLimitMods extends ModuleTestBase {
for (String[] options : OPTIONS_VARIANTS) {
index++;
System.err.println("running check: " + moduleInfo + "; " + Arrays.asList(options));
System.err.println("Running check: " + moduleInfo + "; " + Arrays.asList(options));
Path m2Runtime = base.resolve(index + "-runtime").resolve("m2");
Path out = base.resolve(index + "-runtime").resolve("out").resolve("m2");
@ -427,6 +431,7 @@ public class AddLimitMods extends ModuleTestBase {
tb.writeJavaFiles(m2Runtime, moduleInfo, testClassNamed.toString());
System.err.println("Compiling " + m2Runtime + " files:");
new JavacTask(tb)
.options("--module-path", modulePath.toString())
.outdir(out)
@ -438,6 +443,7 @@ public class AddLimitMods extends ModuleTestBase {
String output;
try {
System.err.println("Running m2/test.Test:");
output = new JavaTask(tb)
.vmOptions(augmentOptions(options,
Collections.emptyList(),
@ -468,6 +474,8 @@ public class AddLimitMods extends ModuleTestBase {
"-Aoutput=" + output,
"-XDaccessInternalAPI=true"
) : Collections.emptyList();
System.err.println("Compiling/processing m2 files:");
new JavacTask(tb)
.options(augmentOptions(options,
auxOptions,
@ -510,8 +518,6 @@ public class AddLimitMods extends ModuleTestBase {
MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m1", "api.Api");
MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("m2", "test.Test");
MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.base", "java.lang.Object");
MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("java.compiler", "javax.tools.ToolProvider");
MODULES_TO_CHECK_TO_SAMPLE_CLASS.put("jdk.compiler", "com.sun.tools.javac.Main");
};
@SupportedAnnotationTypes("*")
@ -573,8 +579,7 @@ public class AddLimitMods extends ModuleTestBase {
private static final String[] MODULE_INFO_VARIANTS = {
"module m2 { exports test; }",
"module m2 { requires m1; exports test; }",
"module m2 { requires jdk.compiler; exports test; }",
"module m2 { requires m1; exports test; }"
};
private static final String[][] OPTIONS_VARIANTS = {