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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.testlibrary.tasks;
  25 
  26 import java.util.ArrayList;
  27 import java.util.Arrays;
  28 import java.util.Collections;
  29 import java.util.List;
  30 import java.util.Map;
  31 
  32 /**
  33  * The supertype for tasks.
  34  * Complex operations are modeled by building and running a "Task" object.
  35  * Tasks are typically configured in a fluent series of calls.
  36  */
  37 public interface Task {
  38     /** The platform line separator. */
  39     static final String lineSeparator = System.getProperty("line.separator");
  40     /**
  41      * Returns the name of the task.
  42      * @return the name of the task
  43      */
  44     String name();
  45 
  46     /**
  47      * Executes the task as currently configured.
  48      * @return a Result object containing the results of running the task
  49      * @throws TaskError if the outcome of the task was not as expected
  50      */
  51     Result run() throws TaskError;
  52 
  53     /**
  54      * Exception thrown by {@code Task.run} when the outcome is not as
  55      * expected.
  56      */
  57     public static class TaskError extends Error {
  58         /**
  59          * Creates a TaskError object with the given message.
  60          * @param message the message
  61          */
  62         public TaskError(String message) {
  63             super(message);
  64         }
  65     }
  66 
  67     /**
  68      * An enum to indicate the mode a task should use it is when executed.
  69      */
  70     public enum Mode {
  71         /**
  72          * The task should use the interface used by the command
  73          * line launcher for the task.
  74          * For example, for javac: com.sun.tools.javac.Main.compile
  75          */
  76         CMDLINE,
  77         /**
  78          * The task should use a publicly defined API for the task.
  79          * For example, for javac: javax.tools.JavaCompiler
  80          */
  81         API,
  82         /**
  83          * The task should use the standard launcher for the task.
  84          * For example, $JAVA_HOME/bin/javac
  85          */
  86         EXEC
  87     }
  88 
  89     /**
  90      * An enum to indicate the expected success or failure of executing a task.
  91      */
  92     public enum Expect {
  93         /** It is expected that the task will complete successfully. */
  94         SUCCESS,
  95         /** It is expected that the task will not complete successfully. */
  96         FAIL
  97     }
  98 
  99     /**
 100      * An enum to identify the streams that may be written by a {@code Task}.
 101      */
 102     public enum OutputKind {
 103         /** Identifies output written to {@code System.out} or {@code stdout}. */
 104         STDOUT,
 105         /** Identifies output written to {@code System.err} or {@code stderr}. */
 106         STDERR,
 107         /** Identifies output written to a stream provided directly to the task. */
 108         DIRECT
 109     };
 110 
 111     /**
 112      * The results from running a {@link Task}.
 113      * The results contain the exit code returned when the tool was invoked,
 114      * and a map containing the output written to any streams during the
 115      * execution of the tool.
 116      * All tools support "stdout" and "stderr".
 117      * Tools that take an explicit PrintWriter save output written to that
 118      * stream as "main".
 119      */
 120     public static class Result {
 121         final Task task;
 122         final int exitCode;
 123         final Map<OutputKind, String> outputMap;
 124         final List<String> command;
 125 
 126         Result(Task task, int exitCode, Map<OutputKind, String> outputMap, 
 127                List<String> command) {
 128             this.task = task;
 129             this.exitCode = exitCode;
 130             this.outputMap = outputMap;
 131             this.command = command;
 132         }
 133 
 134         Result(Task task, int exitCode, Map<OutputKind, String> outputMap) {
 135             this(task, exitCode, outputMap, Collections.EMPTY_LIST);
 136         }
 137 
 138         /**
 139          * Returns the exit code.
 140          * @return the exit code.
 141          */
 142         public int getExitCode() {
 143             return exitCode;
 144         }
 145 
 146         /**
 147          * Returns the exit code.
 148          * @return the exit code.
 149          */
 150         public List<String> getCommand() {
 151             return command;
 152         }
 153 
 154         /**
 155          * Returns the content of a specified stream.
 156          * @param outputKind the kind of the selected stream
 157          * @return the content that was written to that stream when the tool
 158          *  was executed.
 159          */
 160         public String getOutput(OutputKind outputKind) {
 161             return outputMap.get(outputKind);
 162         }
 163 
 164         /**
 165          * Returns the content of named streams as a list of lines.
 166          * @param outputKinds the kinds of the selected streams
 167          * @return the content that was written to the given streams when the tool
 168          *  was executed.
 169          */
 170         public List<String> getOutputLines(OutputKind... outputKinds) {
 171             List<String> result = new ArrayList<>();
 172             for (OutputKind outputKind : outputKinds) {
 173                 result.addAll(Arrays.asList(outputMap.get(outputKind).split(lineSeparator)));
 174             }
 175             return result;
 176         }
 177 
 178         /**
 179          * Writes the content of the specified stream to the log.
 180          * @param kind the kind of the selected stream
 181          * @return this Result object
 182          */
 183         public Result write(OutputKind kind) {
 184             String text = getOutput(kind);
 185             if (text == null || text.isEmpty())
 186                 System.out.println("[" + task.name() + ":" + kind + "]: empty");
 187             else {
 188                 System.out.println("[" + task.name() + ":" + kind + "]:");
 189                 System.out.print(text);
 190             }
 191             return this;
 192         }
 193 
 194         /**
 195          * Writes the content of all streams with any content to the log.
 196          * @return this Result object
 197          */
 198         public Result writeAll() {
 199             outputMap.forEach((name, text) -> {
 200                 if (!text.isEmpty()) {
 201                     System.out.println("[" + name + "]:");
 202                     System.out.print(text);
 203                 }
 204             });
 205             return this;
 206         }
 207     }
 208 }
 209