1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util.spi; 27 28 import java.io.PrintStream; 29 import java.io.PrintWriter; 30 import java.util.Objects; 31 import java.util.Optional; 32 import java.util.ServiceLoader; 33 34 /** 35 * An interface for command-line tools to provide a way to 36 * be invoked without necessarily starting a new VM. 37 * 38 * <p>Tool providers are normally located using the service-provider 39 * loading facility defined by {@link ServiceLoader}. 40 * Each provider must provide a name, and a method to run 41 * an instance of the corresponding tool. When a tool is run, 42 * it will be provided with an array of string arguments, and a 43 * pair of streams: one for normal (or expected) output and the other 44 * for reporting any errors that may occur. 45 * The interpretation of the string arguments will normally be defined by 46 * each individual tool provider, but will generally correspond to the 47 * arguments that could be provided to the tool when invoking the tool 48 * from the command line. 49 * 50 * @since 9 51 */ 52 public interface ToolProvider { 53 /** 54 * Returns the name of this tool provider. 55 * @apiNote It is recommended that the name be the same as would 56 * be used on the command line: for example, "javac", "jar", "jlink". 57 * @return the name of this tool provider 58 */ 59 String name(); 60 61 /** 62 * Runs an instance of the tool, returning zero for a successful run. 63 * Any nonzero return value indicates a tool-specific error during the 64 * execution. 65 * Two streams should be provided, for "expected" output, and for any 66 * error messages. If it is not necessary to distinguish the output, 67 * the same stream may be used for both. 68 * @apiNote The interpretation of the arguments will be specific to 69 * each tool. 70 * @param out a stream to which "expected" output should be written 71 * @param err a stream to which any error messages should be written 72 * @param args the command-line arguments for the tool 73 * @return the result of executing the tool. 74 * A return value of 0 means the tool did not encounter any errors; 75 * any other value indicates that at least one error occurred during 76 * execution. 77 * @throws NullPointerException if any of the arguments are {@code null}, 78 * or if there are any {@code null} values in the {@code args} array 79 */ 80 int run(PrintWriter out, PrintWriter err, String... args); 81 82 /** 83 * Runs an instance of the tool, returning zero for a successful run. 84 * Any non-zero return value indicates a tool-specific error during the 85 * execution. 86 * Two streams should be provided, for "expected" output, and for any 87 * error messages. If it is not necessary to distinguish the output, 88 * the same stream may be used for both. 89 * @apiNote The interpretation of the arguments will be specific to 90 * each tool. 91 * @implNote This implementation wraps the {@code out} and {@code err} 92 * streams within {@link PrintWriter}s, and then calls 93 * {@link run(PrintWriter, PrintWriter, String[])}. 94 * @param out a stream to which "expected" output should be written 95 * @param err a stream to which any error messages should be written 96 * @param args the command-line arguments for the tool 97 * @return the result of executing the tool. 98 * A return value of 0 means the tool did not encounter any errors; 99 * any other value indicates that at least one error occurred during 100 * execution. 101 * @throws NullPointerException if any of the arguments are {@code null}, 102 * or if there are any {@code null} values in the {@code args} array 103 */ 104 default int run(PrintStream out, PrintStream err, String... args) { 105 Objects.requireNonNull(out); 106 Objects.requireNonNull(err); 107 for (String arg : args) { 108 Objects.requireNonNull(args); 109 } 110 111 PrintWriter outWriter = new PrintWriter(out); 112 PrintWriter errWriter = new PrintWriter(err); 113 try { 114 try { 115 return run(outWriter, errWriter, args); 116 } finally { 117 outWriter.flush(); 118 } 119 } finally { 120 errWriter.flush(); 121 } 122 } 123 124 /** 125 * Returns the first instance of a {@code ToolProvider} with the given name, 126 * as loaded by {@link ServiceLoader} using the system class loader. 127 * @param name the name of the desired tool provider 128 * @return an {@code Optional<ToolProvider>} of the first instance found 129 * @throws NullPointerException if {@code name} is {@code null} 130 */ 131 static Optional<ToolProvider> findFirst(String name) { 132 Objects.requireNonNull(name); 133 for (ToolProvider p : ServiceLoader.load(ToolProvider.class, 134 ClassLoader.getSystemClassLoader())) { 135 if (p.name().equals(name)) { 136 return Optional.of(p); 137 } 138 } 139 return Optional.empty(); 140 } 141 } 142