1 /*
2  * Copyright (c) 1997, 2018, 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 com.sun.tools.javadoc.main;
27 
28 import java.io.PrintWriter;
29 import java.util.Locale;
30 import java.util.ResourceBundle;
31 
32 import com.sun.javadoc.*;
33 import com.sun.tools.javac.util.Context;
34 import com.sun.tools.javac.util.Context.Factory;
35 import com.sun.tools.javac.util.JCDiagnostic;
36 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
37 import com.sun.tools.javac.util.JavacMessages;
38 import com.sun.tools.javac.util.Log;
39 
40 /**
41  * Utility for integrating with javadoc tools and for localization.
42  * Handle Resources. Access to error and warning counts.
43  * Message formatting.
44  * <br>
45  * Also provides implementation for DocErrorReporter.
46  *
47  *  <p><b>This is NOT part of any supported API.
48  *  If you write code that depends on this, you do so at your own risk.
49  *  This code and its internal interfaces are subject to change or
50  *  deletion without notice.</b>
51  *
52  * @see java.util.ResourceBundle
53  * @see java.text.MessageFormat
54  * @author Neal Gafter (rewrite)
55  */
56 @Deprecated(since="9", forRemoval=true)
57 @SuppressWarnings("removal")
58 public class Messager extends Log implements DocErrorReporter {
59     public static final SourcePosition NOPOS = null;
60 
61     /** Get the current messager, which is also the compiler log. */
instance0(Context context)62     public static Messager instance0(Context context) {
63         Log instance = context.get(logKey);
64         if (instance == null || !(instance instanceof Messager))
65             throw new InternalError("no messager instance!");
66         return (Messager)instance;
67     }
68 
preRegister(Context context, final String programName)69     public static void preRegister(Context context,
70                                    final String programName) {
71         context.put(logKey, (Factory<Log>)c -> new Messager(c, programName));
72     }
preRegister(Context context, final String programName, final PrintWriter errWriter, final PrintWriter warnWriter, final PrintWriter noticeWriter)73     public static void preRegister(Context context,
74                                    final String programName,
75                                    final PrintWriter errWriter,
76                                    final PrintWriter warnWriter,
77                                    final PrintWriter noticeWriter) {
78         context.put(logKey, (Factory<Log>)c -> new Messager(c,
79                             programName,
80                             errWriter,
81                             warnWriter,
82                             noticeWriter));
83     }
84 
85     public class ExitJavadoc extends Error {
86         private static final long serialVersionUID = 0;
87     }
88 
89     final String programName;
90 
91     private Locale locale;
92     private final JavacMessages messages;
93     private final JCDiagnostic.Factory javadocDiags;
94 
95     /** The default writer for diagnostics
96      */
97     static final PrintWriter defaultErrWriter = new PrintWriter(System.err);
98     static final PrintWriter defaultWarnWriter = new PrintWriter(System.err);
99     static final PrintWriter defaultNoticeWriter = new PrintWriter(System.out);
100 
101     /**
102      * Constructor
103      * @param programName  Name of the program (for error messages).
104      */
Messager(Context context, String programName)105     protected Messager(Context context, String programName) {
106         this(context, programName, defaultErrWriter, defaultWarnWriter, defaultNoticeWriter);
107     }
108 
109     /**
110      * Constructor
111      * @param programName  Name of the program (for error messages).
112      * @param errWriter    Stream for error messages
113      * @param warnWriter   Stream for warnings
114      * @param noticeWriter Stream for other messages
115      */
116     @SuppressWarnings("deprecation")
Messager(Context context, String programName, PrintWriter errWriter, PrintWriter warnWriter, PrintWriter noticeWriter)117     protected Messager(Context context,
118                        String programName,
119                        PrintWriter errWriter,
120                        PrintWriter warnWriter,
121                        PrintWriter noticeWriter) {
122         super(context, errWriter, warnWriter, noticeWriter);
123         messages = JavacMessages.instance(context);
124         messages.add(locale -> ResourceBundle.getBundle("com.sun.tools.javadoc.resources.javadoc",
125                                                          locale));
126         javadocDiags = new JCDiagnostic.Factory(messages, "javadoc");
127         this.programName = programName;
128 
129     }
130 
setLocale(Locale locale)131     public void setLocale(Locale locale) {
132         this.locale = locale;
133     }
134 
135     /**
136      * get and format message string from resource
137      *
138      * @param key selects message from resource
139      * @param args arguments for the message
140      */
getText(String key, Object... args)141     String getText(String key, Object... args) {
142         return messages.getLocalizedString(locale, key, args);
143     }
144 
145     /**
146      * Print error message, increment error count.
147      * Part of DocErrorReporter.
148      *
149      * @param msg message to print
150      */
printError(String msg)151     public void printError(String msg) {
152         printError(null, msg);
153     }
154 
155     /**
156      * Print error message, increment error count.
157      * Part of DocErrorReporter.
158      *
159      * @param pos the position where the error occurs
160      * @param msg message to print
161      */
printError(SourcePosition pos, String msg)162     public void printError(SourcePosition pos, String msg) {
163         if (diagListener != null) {
164             report(DiagnosticType.ERROR, pos, msg);
165             return;
166         }
167 
168         if (nerrors < MaxErrors) {
169             String prefix = (pos == null) ? programName : pos.toString();
170             PrintWriter errWriter = getWriter(WriterKind.ERROR);
171             errWriter.println(prefix + ": " + getText("javadoc.error") + " - " + msg);
172             errWriter.flush();
173             prompt();
174             nerrors++;
175         }
176     }
177 
178     /**
179      * Print warning message, increment warning count.
180      * Part of DocErrorReporter.
181      *
182      * @param msg message to print
183      */
printWarning(String msg)184     public void printWarning(String msg) {
185         printWarning(null, msg);
186     }
187 
188     /**
189      * Print warning message, increment warning count.
190      * Part of DocErrorReporter.
191      *
192      * @param pos the position where the error occurs
193      * @param msg message to print
194      */
printWarning(SourcePosition pos, String msg)195     public void printWarning(SourcePosition pos, String msg) {
196         if (diagListener != null) {
197             report(DiagnosticType.WARNING, pos, msg);
198             return;
199         }
200 
201         if (nwarnings < MaxWarnings) {
202             String prefix = (pos == null) ? programName : pos.toString();
203             PrintWriter warnWriter = getWriter(WriterKind.WARNING);
204             warnWriter.println(prefix +  ": " + getText("javadoc.warning") +" - " + msg);
205             warnWriter.flush();
206             nwarnings++;
207         }
208     }
209 
210     /**
211      * Print a message.
212      * Part of DocErrorReporter.
213      *
214      * @param msg message to print
215      */
printNotice(String msg)216     public void printNotice(String msg) {
217         printNotice(null, msg);
218     }
219 
220     /**
221      * Print a message.
222      * Part of DocErrorReporter.
223      *
224      * @param pos the position where the error occurs
225      * @param msg message to print
226      */
printNotice(SourcePosition pos, String msg)227     public void printNotice(SourcePosition pos, String msg) {
228         if (diagListener != null) {
229             report(DiagnosticType.NOTE, pos, msg);
230             return;
231         }
232 
233         PrintWriter noticeWriter = getWriter(WriterKind.NOTICE);
234         if (pos == null)
235             noticeWriter.println(msg);
236         else
237             noticeWriter.println(pos + ": " + msg);
238         noticeWriter.flush();
239     }
240 
241     /**
242      * Print error message, increment error count.
243      *
244      * @param key selects message from resource
245      */
error(SourcePosition pos, String key, Object... args)246     public void error(SourcePosition pos, String key, Object... args) {
247         printError(pos, getText(key, args));
248     }
249 
250     /**
251      * Print warning message, increment warning count.
252      *
253      * @param key selects message from resource
254      */
warning(SourcePosition pos, String key, Object... args)255     public void warning(SourcePosition pos, String key, Object... args) {
256         printWarning(pos, getText(key, args));
257     }
258 
259     /**
260      * Print a message.
261      *
262      * @param key selects message from resource
263      */
notice(String key, Object... args)264     public void notice(String key, Object... args) {
265         printNotice(getText(key, args));
266     }
267 
268     /**
269      * Return total number of errors, including those recorded
270      * in the compilation log.
271      */
nerrors()272     public int nerrors() { return nerrors; }
273 
274     /**
275      * Return total number of warnings, including those recorded
276      * in the compilation log.
277      */
nwarnings()278     public int nwarnings() { return nwarnings; }
279 
280     /**
281      * Print exit message.
282      */
exitNotice()283     public void exitNotice() {
284         if (nerrors > 0) {
285             notice((nerrors > 1) ? "main.errors" : "main.error",
286                    "" + nerrors);
287         }
288         if (nwarnings > 0) {
289             notice((nwarnings > 1) ?  "main.warnings" : "main.warning",
290                    "" + nwarnings);
291         }
292     }
293 
294     /**
295      * Force program exit, e.g., from a fatal error.
296      * <p>
297      * TODO: This method does not really belong here.
298      */
exit()299     public void exit() {
300         throw new ExitJavadoc();
301     }
302 
report(DiagnosticType type, SourcePosition pos, String msg)303     private void report(DiagnosticType type, SourcePosition pos, String msg) {
304         switch (type) {
305             case ERROR:
306             case WARNING:
307                 Object prefix = (pos == null) ? programName : pos;
308                 report(javadocDiags.create(type, null, null, "msg", prefix, msg));
309                 break;
310 
311             case NOTE:
312                 String key = (pos == null) ? "msg" : "pos.msg";
313                 report(javadocDiags.create(type, null, null, key, pos, msg));
314                 break;
315 
316             default:
317                 throw new IllegalArgumentException(type.toString());
318         }
319     }
320 }
321