langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
changeset 40232 4995ab1a4558
parent 32799 ee577901f4bb
child 40308 274367a99f98
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Wed Aug 03 11:30:27 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Wed Aug 03 16:01:09 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -27,10 +27,13 @@
 
 import java.io.*;
 import java.util.Arrays;
+import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
+
 import javax.tools.DiagnosticListener;
 import javax.tools.JavaFileObject;
 
@@ -56,9 +59,12 @@
     /** The context key for the log. */
     public static final Context.Key<Log> logKey = new Context.Key<>();
 
-    /** The context key for the output PrintWriter. */
+    /** The context key for the standard output PrintWriter. */
     public static final Context.Key<PrintWriter> outKey = new Context.Key<>();
 
+    /** The context key for the diagnostic PrintWriter. */
+    public static final Context.Key<PrintWriter> errKey = new Context.Key<>();
+
     /* TODO: Should unify this with prefix handling in JCDiagnostic.Factory. */
     public enum PrefixKind {
         JAVAC("javac."),
@@ -111,6 +117,7 @@
             install(log);
         }
 
+        @Override
         public void report(JCDiagnostic diag) { }
     }
 
@@ -134,6 +141,7 @@
             install(log);
         }
 
+        @Override
         public void report(JCDiagnostic diag) {
             if (!diag.isFlagSet(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE) &&
                 (filter == null || filter.accepts(diag))) {
@@ -163,13 +171,9 @@
         }
     }
 
-    public enum WriterKind { NOTICE, WARNING, ERROR }
-
-    protected PrintWriter errWriter;
+    public enum WriterKind { NOTICE, WARNING, ERROR, STDOUT, STDERR }
 
-    protected PrintWriter warnWriter;
-
-    protected PrintWriter noticeWriter;
+    private final Map<WriterKind, PrintWriter> writers;
 
     /** The maximum number of errors/warnings that are reported.
      */
@@ -223,14 +227,130 @@
      */
     private DiagnosticHandler diagnosticHandler;
 
-    /** Construct a log with given I/O redirections.
+    /** Get the Log instance for this context. */
+    public static Log instance(Context context) {
+        Log instance = context.get(logKey);
+        if (instance == null)
+            instance = new Log(context);
+        return instance;
+    }
+
+    /**
+     * Register a Context.Factory to create a Log.
+     */
+    public static void preRegister(Context context, PrintWriter w) {
+        context.put(Log.class, (Context.Factory<Log>) (c -> new Log(c, w)));
+    }
+
+    /**
+     * Construct a log with default settings.
+     * If no streams are set in the context, the log will be initialized to use
+     * System.out for normal output, and System.err for all diagnostic output.
+     * If one stream is set in the context, with either Log.outKey or Log.errKey,
+     * it will be used for all output.
+     * Otherwise, the log will be initialized to use both streams found in the context.
+     */
+    protected Log(Context context) {
+        this(context, initWriters(context));
+    }
+
+    /**
+     * Initialize a map of writers based on values found in the context
+     * @param context the context in which to find writers to use
+     * @return a map of writers
+     */
+    private static Map<WriterKind, PrintWriter> initWriters(Context context) {
+        PrintWriter out = context.get(outKey);
+        PrintWriter err = context.get(errKey);
+        if (out == null && err == null) {
+            out = new PrintWriter(System.out, true);
+            err = new PrintWriter(System.err, true);
+            return initWriters(out, err);
+        } else if (out == null || err == null) {
+            PrintWriter pw = (out != null) ? out : err;
+            return initWriters(pw, pw);
+        } else {
+            return initWriters(out, err);
+        }
+    }
+
+    /**
+     * Construct a log with all output sent to a single output stream.
+     */
+    protected Log(Context context, PrintWriter writer) {
+        this(context, initWriters(writer, writer));
+    }
+
+    /**
+     * Construct a log.
+     * The log will be initialized to use stdOut for normal output, and stdErr
+     * for all diagnostic output.
      */
+    protected Log(Context context, PrintWriter out, PrintWriter err) {
+        this(context, initWriters(out, err));
+    }
+
+    /**
+     * Initialize a writer map for a stream for normal output, and a stream for diagnostics.
+     * @param out a stream to be used for normal output
+     * @param err a stream to be used for diagnostic messages, such as errors, warnings, etc
+     * @return a map of writers
+     */
+    private static Map<WriterKind, PrintWriter> initWriters(PrintWriter out, PrintWriter err) {
+        Map<WriterKind, PrintWriter> writers = new EnumMap<>(WriterKind.class);
+        writers.put(WriterKind.ERROR, err);
+        writers.put(WriterKind.WARNING, err);
+        writers.put(WriterKind.NOTICE, err);
+
+        writers.put(WriterKind.STDOUT, out);
+        writers.put(WriterKind.STDERR, err);
+
+        return writers;
+    }
+
+    /**
+     * Construct a log with given I/O redirections.
+     * @deprecated
+     * This constructor is provided to support the supported but now-deprecated javadoc entry point
+     *      com.sun.tools.javadoc.Main.execute(String programName,
+     *          PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter,
+     *          String defaultDocletClassName, String... args)
+     */
+    @Deprecated
     protected Log(Context context, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) {
+        this(context, initWriters(errWriter, warnWriter, noticeWriter));
+    }
+
+    /**
+     * Initialize a writer map with different streams for different types of diagnostics.
+     * @param errWriter a stream for writing error messages
+     * @param warnWriter a stream for writing warning messages
+     * @param noticeWriter a stream for writing notice messages
+     * @return a map of writers
+     * @deprecated This method exists to support a supported but now deprecated javadoc entry point.
+     */
+    @Deprecated
+    private static Map<WriterKind, PrintWriter>  initWriters(PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter) {
+        Map<WriterKind, PrintWriter> writers = new EnumMap<>(WriterKind.class);
+        writers.put(WriterKind.ERROR, errWriter);
+        writers.put(WriterKind.WARNING, warnWriter);
+        writers.put(WriterKind.NOTICE, noticeWriter);
+
+        writers.put(WriterKind.STDOUT, noticeWriter);
+        writers.put(WriterKind.STDERR, errWriter);
+
+        return writers;
+    }
+
+    /**
+     * Creates a log.
+     * @param context the context in which the log should be registered
+     * @param writers a map of writers that can be accessed by the kind of writer required
+     */
+    private Log(Context context, Map<WriterKind, PrintWriter> writers) {
         super(JCDiagnostic.Factory.instance(context));
         context.put(logKey, this);
-        this.errWriter = errWriter;
-        this.warnWriter = warnWriter;
-        this.noticeWriter = noticeWriter;
+        this.writers = writers;
 
         @SuppressWarnings("unchecked") // FIXME
         DiagnosticListener<? super JavaFileObject> dl =
@@ -245,6 +365,7 @@
         final Options options = Options.instance(context);
         initOptions(options);
         options.addListener(new Runnable() {
+            @Override
             public void run() {
                 initOptions(options);
             }
@@ -293,42 +414,6 @@
             return 100;
         }
 
-    /** The default writer for diagnostics
-     */
-    static PrintWriter defaultWriter(Context context) {
-        PrintWriter result = context.get(outKey);
-        if (result == null)
-            context.put(outKey, result = new PrintWriter(System.err));
-        return result;
-    }
-
-    /** Construct a log with default settings.
-     */
-    protected Log(Context context) {
-        this(context, defaultWriter(context));
-    }
-
-    /** Construct a log with all output redirected.
-     */
-    protected Log(Context context, PrintWriter defaultWriter) {
-        this(context, defaultWriter, defaultWriter, defaultWriter);
-    }
-
-    /** Get the Log instance for this context. */
-    public static Log instance(Context context) {
-        Log instance = context.get(logKey);
-        if (instance == null)
-            instance = new Log(context);
-        return instance;
-    }
-
-    /**
-     * Register a Context.Factory to create a Log.
-     */
-    public static void preRegister(Context context, PrintWriter w) {
-        context.put(Log.class, (Context.Factory<Log>) (c -> new Log(c, w)));
-    }
-
     /** The number of errors encountered so far.
      */
     public int nerrors = 0;
@@ -371,26 +456,18 @@
     }
 
     public PrintWriter getWriter(WriterKind kind) {
-        switch (kind) {
-            case NOTICE:    return noticeWriter;
-            case WARNING:   return warnWriter;
-            case ERROR:     return errWriter;
-            default:        throw new IllegalArgumentException();
-        }
+        return writers.get(kind);
     }
 
     public void setWriter(WriterKind kind, PrintWriter pw) {
         Assert.checkNonNull(pw);
-        switch (kind) {
-            case NOTICE:    noticeWriter = pw;  break;
-            case WARNING:   warnWriter = pw;    break;
-            case ERROR:     errWriter = pw;     break;
-            default:        throw new IllegalArgumentException();
-        }
+        writers.put(kind, pw);
     }
 
     public void setWriters(PrintWriter pw) {
-        noticeWriter = warnWriter = errWriter = Assert.checkNonNull(pw);
+        Assert.checkNonNull(pw);
+        for (WriterKind k: WriterKind.values())
+            writers.put(k, pw);
     }
 
     /**
@@ -407,9 +484,9 @@
     /** Flush the logs
      */
     public void flush() {
-        errWriter.flush();
-        warnWriter.flush();
-        noticeWriter.flush();
+        for (PrintWriter pw: writers.values()) {
+            pw.flush();
+        }
     }
 
     public void flush(WriterKind kind) {
@@ -470,6 +547,7 @@
     }
 
     public void printNewline() {
+        PrintWriter noticeWriter = writers.get(WriterKind.NOTICE);
         noticeWriter.println();
     }
 
@@ -478,10 +556,12 @@
     }
 
     public void printLines(String key, Object... args) {
+        PrintWriter noticeWriter = writers.get(WriterKind.NOTICE);
         printRawLines(noticeWriter, localize(key, args));
     }
 
     public void printLines(PrefixKind pk, String key, Object... args) {
+        PrintWriter noticeWriter = writers.get(WriterKind.NOTICE);
         printRawLines(noticeWriter, localize(pk, key, args));
     }
 
@@ -497,6 +577,7 @@
      *  for the platform.
      */
     public void printRawLines(String msg) {
+        PrintWriter noticeWriter = writers.get(WriterKind.NOTICE);
         printRawLines(noticeWriter, msg);
     }
 
@@ -524,10 +605,13 @@
      * noticeWriter stream.
      */
     public void printVerbose(String key, Object... args) {
+        PrintWriter noticeWriter = writers.get(WriterKind.NOTICE);
         printRawLines(noticeWriter, localize("verbose." + key, args));
     }
 
+    @Override
     protected void directError(String key, Object... args) {
+        PrintWriter errWriter = writers.get(WriterKind.ERROR);
         printRawLines(errWriter, localize(key, args));
         errWriter.flush();
     }
@@ -546,6 +630,7 @@
      * Primary method to report a diagnostic.
      * @param diagnostic
      */
+    @Override
     public void report(JCDiagnostic diagnostic) {
         diagnosticHandler.report(diagnostic);
      }
@@ -556,6 +641,7 @@
      * reported so far, the diagnostic may be handed off to writeDiagnostic.
      */
     private class DefaultDiagnosticHandler extends DiagnosticHandler {
+        @Override
         public void report(JCDiagnostic diagnostic) {
             if (expectDiagKeys != null)
                 expectDiagKeys.remove(diagnostic.getCode());
@@ -631,13 +717,13 @@
             throw new IllegalArgumentException();
 
         case NOTE:
-            return noticeWriter;
+            return writers.get(WriterKind.NOTICE);
 
         case WARNING:
-            return warnWriter;
+            return writers.get(WriterKind.WARNING);
 
         case ERROR:
-            return errWriter;
+            return writers.get(WriterKind.ERROR);
 
         default:
             throw new Error();
@@ -683,26 +769,27 @@
 
     /** print an error or warning message:
      */
-    private void printRawError(int pos, String msg) {
+    private void printRawDiag(PrintWriter pw, String prefix, int pos, String msg) {
         if (source == null || pos == Position.NOPOS) {
-            printRawLines(errWriter, "error: " + msg);
+            printRawLines(pw, prefix + msg);
         } else {
             int line = source.getLineNumber(pos);
             JavaFileObject file = source.getFile();
             if (file != null)
-                printRawLines(errWriter,
+                printRawLines(pw,
                            file.getName() + ":" +
                            line + ": " + msg);
-            printErrLine(pos, errWriter);
+            printErrLine(pos, pw);
         }
-        errWriter.flush();
+        pw.flush();
     }
 
     /** report an error:
      */
     public void rawError(int pos, String msg) {
+        PrintWriter errWriter = writers.get(WriterKind.ERROR);
         if (nerrors < MaxErrors && shouldReport(currentSourceFile(), pos)) {
-            printRawError(pos, msg);
+            printRawDiag(errWriter, "error: ", pos, msg);
             prompt();
             nerrors++;
         }
@@ -712,12 +799,13 @@
     /** report a warning:
      */
     public void rawWarning(int pos, String msg) {
+        PrintWriter warnWriter = writers.get(WriterKind.ERROR);
         if (nwarnings < MaxWarnings && emitWarnings) {
-            printRawError(pos, "warning: " + msg);
+            printRawDiag(warnWriter, "warning: ", pos, msg);
         }
         prompt();
         nwarnings++;
-        errWriter.flush();
+        warnWriter.flush();
     }
 
     public static String format(String fmt, Object... args) {