| /* | |
| * Copyright (c) 2016, 2024, 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 java.util.spi; | |
| import java.io.PrintStream; | |
| import java.io.PrintWriter; | |
| import java.util.Objects; | |
| import java.util.Optional; | |
| import java.util.ServiceLoader; | |
| import java.util.stream.StreamSupport; | |
| /** | |
| * An interface for command-line tools to provide a way to | |
| * be invoked without necessarily starting a new VM. | |
| * | |
| * <p>Tool providers are normally located using the service-provider | |
| * loading facility defined by {@link ServiceLoader}. | |
| * Each provider must provide a name, and a method to run | |
| * an instance of the corresponding tool. When a tool is run, | |
| * it will be provided with an array of string arguments, and a | |
| * pair of streams: one for normal (or expected) output and the other | |
| * for reporting any errors that may occur. | |
| * The interpretation of the string arguments will normally be defined by | |
| * each individual tool provider, but will generally correspond to the | |
| * arguments that could be provided to the tool when invoking the tool | |
| * from the command line. | |
| * | |
| * @since 9 | |
| */ | |
| public interface ToolProvider { | |
| /** | |
| * Returns the name of this tool provider. | |
| * | |
| * @apiNote It is recommended that the name be the same as would be | |
| * used on the command line: for example, "javac", "jar", "jlink". | |
| * | |
| * @return the name of this tool provider | |
| */ | |
| String name(); | |
| /** | |
| * {@return a short description of the tool, or an empty | |
| * {@code Optional} if no description is available} | |
| * | |
| * @apiNote It is recommended that the description fits into a single | |
| * line in order to allow creating concise overviews like the following: | |
| * <pre>{@code | |
| * jar | |
| * Create, manipulate, and extract an archive of classes and resources. | |
| * javac | |
| * Read Java declarations and compile them into class files. | |
| * jlink | |
| * Assemble a set of modules (...) into a custom runtime image. | |
| * } | |
| * </pre> | |
| * | |
| * @implSpec This implementation returns an empty {@code Optional}. | |
| * | |
| * @since 19 | |
| */ | |
| default Optional<String> description() { | |
| return Optional.empty(); | |
| } | |
| /** | |
| * Runs an instance of the tool, returning zero for a successful run. | |
| * Any non-zero return value indicates a tool-specific error during the | |
| * execution. | |
| * | |
| * Two streams should be provided, for "expected" output, and for any | |
| * error messages. If it is not necessary to distinguish the output, | |
| * the same stream may be used for both. | |
| * | |
| * @apiNote The interpretation of the arguments will be specific to | |
| * each tool. | |
| * | |
| * @param out a stream to which "expected" output should be written | |
| * | |
| * @param err a stream to which any error messages should be written | |
| * | |
| * @param args the command-line arguments for the tool | |
| * | |
| * @return the result of executing the tool. | |
| * A return value of 0 means the tool did not encounter any errors; | |
| * any other value indicates that at least one error occurred | |
| * during execution. | |
| * | |
| * @throws NullPointerException if any of the arguments are {@code null}, | |
| * or if there are any {@code null} values in the {@code args} | |
| * array | |
| */ | |
| int run(PrintWriter out, PrintWriter err, String... args); | |
| /** | |
| * Runs an instance of the tool, returning zero for a successful run. | |
| * Any non-zero return value indicates a tool-specific error during the | |
| * execution. | |
| * | |
| * Two streams should be provided, for "expected" output, and for any | |
| * error messages. If it is not necessary to distinguish the output, | |
| * the same stream may be used for both. | |
| * | |
| * @apiNote The interpretation of the arguments will be specific to | |
| * each tool. | |
| * | |
| * @implNote This implementation wraps the {@code out} and {@code err} | |
| * streams within {@link PrintWriter}s, and then calls | |
| * {@link #run(PrintWriter, PrintWriter, String[])}. | |
| * | |
| * @param out a stream to which "expected" output should be written | |
| * | |
| * @param err a stream to which any error messages should be written | |
| * | |
| * @param args the command-line arguments for the tool | |
| * | |
| * @return the result of executing the tool. | |
| * A return value of 0 means the tool did not encounter any errors; | |
| * any other value indicates that at least one error occurred | |
| * during execution. | |
| * | |
| * @throws NullPointerException if any of the arguments are {@code null}, | |
| * or if there are any {@code null} values in the {@code args} | |
| * array | |
| */ | |
| default int run(PrintStream out, PrintStream err, String... args) { | |
| Objects.requireNonNull(out); | |
| Objects.requireNonNull(err); | |
| Objects.requireNonNull(args); | |
| for (String arg : args) { | |
| Objects.requireNonNull(arg); | |
| } | |
| PrintWriter outWriter = new PrintWriter(out); | |
| PrintWriter errWriter = new PrintWriter(err); | |
| try { | |
| try { | |
| return run(outWriter, errWriter, args); | |
| } finally { | |
| outWriter.flush(); | |
| } | |
| } finally { | |
| errWriter.flush(); | |
| } | |
| } | |
| /** | |
| * Returns the first instance of a {@code ToolProvider} with the given name, | |
| * as loaded by {@link ServiceLoader} using the system class loader. | |
| * | |
| * @param name the name of the desired tool provider | |
| * | |
| * @return an {@code Optional<ToolProvider>} of the first instance found | |
| * | |
| * @throws NullPointerException if {@code name} is {@code null} | |
| */ | |
| static Optional<ToolProvider> findFirst(String name) { | |
| Objects.requireNonNull(name); | |
| ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); | |
| ServiceLoader<ToolProvider> sl = | |
| ServiceLoader.load(ToolProvider.class, systemClassLoader); | |
| return StreamSupport.stream(sl.spliterator(), false) | |
| .filter(p -> p.name().equals(name)) | |
| .findFirst(); | |
| } | |
| } |