1 /* 2 * Copyright (c) 2001, 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 /* 27 * This source code is provided to illustrate the usage of a given feature 28 * or technique and has been deliberately simplified. Additional steps 29 * required for a production-quality application, such as security checks, 30 * input validation and proper error handling, might not be present in 31 * this sample code. 32 */ 33 34 package com.sun.tools.example.debug.tty; 35 36 import java.io.ByteArrayOutputStream; 37 import java.io.PrintWriter; 38 import java.util.*; 39 import java.text.MessageFormat; 40 /** 41 * Internationalization (i18n) convenience methods for jdb. 42 * 43 * All program output should flow through these methods, and this is 44 * the only class that should be printing directly or otherwise 45 * accessing System.[out,err]. 46 * 47 * @bug 4348376 48 * @author Tim Bell 49 */ 50 public class MessageOutput { 51 /** 52 * The resource bundle containing localizable message content. 53 * This is loaded by TTY.main() at start-up 54 */ 55 static ResourceBundle textResources; 56 57 /** If set then used to buffer the output before writing it to System.out */ 58 private final static ThreadLocal<BufferedOutput> bufferedOutput = new ThreadLocal<>(); 59 60 /** Default writer to System.out */ 61 private final static PrintWriter systemOutWriter = new PrintWriter(System.out, true); 62 63 /** Our message formatter. Allocated once, used many times */ 64 private static MessageFormat messageFormat; 65 66 /** 67 * Fatal shutdown notification. This is sent to System.err 68 * instead of System.out 69 */ 70 static void fatalError(String messageKey) { 71 System.err.println(); 72 System.err.println(format("Fatal error")); 73 System.err.println(format(messageKey)); 74 Env.shutdown(); 75 } 76 77 /** 78 * "Format" a string by doing a simple key lookup. 79 */ 80 static String format(String key) { 81 return (textResources.getString(key)); 82 } 83 84 /** 85 * Fetch and format a message with one string argument. 86 * This is the most common usage. 87 */ 88 static String format(String key, String argument) { 89 return format(key, new Object [] {argument}); 90 } 91 92 /** 93 * Fetch a string by key lookup and format in the arguments. 94 */ 95 static synchronized String format(String key, Object [] arguments) { 96 if (messageFormat == null) { 97 messageFormat = new MessageFormat (textResources.getString(key)); 98 } else { 99 messageFormat.applyPattern (textResources.getString(key)); 100 } 101 return (messageFormat.format (arguments)); 102 } 103 104 /** 105 * Print directly to System.out. 106 * Every rule has a few exceptions. 107 * The exceptions to "must use the MessageOutput formatters" are: 108 * VMConnection.dumpStream() 109 * TTY.monitorCommand() 110 * TTY.TTY() (for the '!!' command only) 111 * Commands.java (multiple locations) 112 * These are the only sites that should be calling this 113 * method. 114 */ 115 static void printDirectln(String line) { 116 getWriter().println(line); 117 } 118 static void printDirect(String line) { 119 getWriter().print(line); 120 } 121 static void printDirect(char c) { 122 getWriter().print(c); 123 } 124 125 /** 126 * Print a newline. 127 * Use this instead of '\n' 128 */ 129 static void println() { 130 getWriter().println(); 131 } 132 133 /** 134 * Format and print a simple string. 135 */ 136 static void print(String key) { 137 getWriter().print(format(key)); 138 } 139 /** 140 * Format and print a simple string. 141 */ 142 static void println(String key) { 143 getWriter().println(format(key)); 144 } 145 146 147 /** 148 * Fetch, format and print a message with one string argument. 149 * This is the most common usage. 150 */ 151 static void print(String key, String argument) { 152 getWriter().print(format(key, argument)); 153 } 154 static void println(String key, String argument) { 155 getWriter().println(format(key, argument)); 156 } 157 158 /** 159 * Fetch, format and print a message with an arbitrary 160 * number of message arguments. 161 */ 162 static void println(String key, Object [] arguments) { 163 getWriter().println(format(key, arguments)); 164 } 165 166 /** 167 * Print a newline, followed by the string. 168 */ 169 static void lnprint(String key) { 170 getWriter().println(); 171 getWriter().print(textResources.getString(key)); 172 } 173 174 static void lnprint(String key, String argument) { 175 getWriter().println(); 176 getWriter().print(format(key, argument)); 177 } 178 179 static void lnprint(String key, Object [] arguments) { 180 getWriter().println(); 181 getWriter().print(format(key, arguments)); 182 } 183 184 /** 185 * Print an exception message with a stack trace. 186 */ 187 static void printException(String key, Exception e) { 188 if (key != null) { 189 try { 190 println(key); 191 } catch (MissingResourceException mex) { 192 printDirectln(key); 193 } 194 } 195 getWriter().flush(); 196 e.printStackTrace(getWriter()); 197 } 198 199 static void printPrompt() { 200 printPrompt(false); 201 } 202 203 static void printPrompt(boolean simple) { 204 ThreadInfo threadInfo = ThreadInfo.getCurrentThreadInfo(); 205 if (simple || threadInfo == null) { 206 getWriter().print 207 (MessageOutput.format("jdb prompt with no current thread")); 208 } else { 209 getWriter().print 210 (MessageOutput.format("jdb prompt thread name and current stack frame", 211 new Object [] { 212 threadInfo.getThread().name(), 213 Integer.valueOf(threadInfo.getCurrentFrameIndex() + 1)})); 214 } 215 getWriter().flush(); 216 } 217 218 /** Starts buffering the output to the internal buffer */ 219 static void startBuffering() { 220 assert (bufferedOutput.get() == null); 221 bufferedOutput.set(new BufferedOutput()); 222 } 223 224 /** Stops buffering the output and writes the buffer to System.out */ 225 static void stopBuffering() { 226 BufferedOutput bo = bufferedOutput.get(); 227 assert (bo != null); 228 bufferedOutput.set(null); 229 bo.close(); 230 systemOutWriter.print(bo.toString()); 231 systemOutWriter.flush(); 232 } 233 234 /** 235 * If bufferedOutput is set returns the writer the writes to the internal buffer, otherwise 236 * returns writer that writes to System.out 237 */ 238 private static PrintWriter getWriter() { 239 return bufferedOutput.get() != null? bufferedOutput.get().getPrintWriter() : systemOutWriter; 240 } 241 242 /** Provides a writer that buffers the output to the string */ 243 private static class BufferedOutput { 244 private final ByteArrayOutputStream baos; 245 private final PrintWriter pw; 246 247 BufferedOutput() { 248 baos = new ByteArrayOutputStream(); 249 pw = new PrintWriter(baos); 250 } 251 252 PrintWriter getPrintWriter() { 253 return pw; 254 } 255 256 void close() { 257 pw.flush(); 258 pw.close(); 259 } 260 261 @Override 262 public String toString() { 263 return baos.toString(); 264 } 265 266 } 267 }