1 package org.devaki.nextobjects.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import java.io.BufferedReader;
17 import java.io.IOException;
18 import java.io.PrintStream;
19 import java.io.StringReader;
20 import org.apache.tools.ant.BuildEvent;
21 import org.apache.tools.ant.BuildException;
22 import org.apache.tools.ant.BuildLogger;
23 import org.apache.tools.ant.Project;
24 import org.apache.tools.ant.util.DateUtils;
25 import org.apache.tools.ant.util.StringUtils;
26 import org.devaki.nextobjects.ui.main.NOLog;
27 /***
28 * Writes build events to a PrintStream.Currently, it
29 * only writes which targets are being executed, and
30 * any messages that get logged.
31 * @see org.apache.tools.ant.DefaultLogger
32 * @author <a href="mailto:eflorent@devaki.org">Emmanuel Florent</a>
33 */
34 public final class NOBuildLogger implements BuildLogger
35 {
36 /***
37 * Size of left-hand column for right-justified task name.
38 * @see #messageLogged(BuildEvent)
39 */
40 public static final int LEFT_COLUMN_SIZE = 12;
41 /*** PrintStream to write non-error messages to */
42 private PrintStream out = new PrintStream(NOLog.getJTextOutStream(), true);
43 /*** PrintStream to write error messages to */
44
45 private PrintStream err = new PrintStream(NOLog.getJTextOutStream(), false);
46 /*** Lowest level of message to write out */
47 private int msgOutputLevel = Project.MSG_INFO;
48 /*** Time of the start of the build */
49 private long startTime = System.currentTimeMillis();
50 /*** Line separator */
51 private static final String LINE_SEP = StringUtils.LINE_SEP;
52 /*** Whether or not to use emacs-style output */
53 private boolean emacsMode = false;
54 /***
55 * Sole constructor
56 * Do nothing
57 */
58 public NOBuildLogger()
59 {
60 }
61 /***
62 * Sets the highest level of message this logger should respond to.
63 *
64 * Only messages with a message level lower than or equal to the
65 * given level should be written to the log.
66 * <P>
67 * Constants for the message levels are in the
68 * {@link Project Project} class. The order of the levels, from least
69 * to most verbose, is <code>MSG_ERR</code>, <code>MSG_WARN</code>,
70 * <code>MSG_INFO</code>, <code>MSG_VERBOSE</code>,
71 * <code>MSG_DEBUG</code>.
72 * <P>
73 * The default message level for DefaultLogger is Project.MSG_ERR.
74 *
75 * @param level the logging level for the logger.
76 */
77 public final void setMessageOutputLevel(final int level)
78 {
79 setMsgOutputLevel(level);
80 }
81 /***
82 * Sets the output stream to which this logger is to send its output.
83 *
84 * @param output The output stream for the logger.
85 * Must not be <code>null</code>.
86 */
87 public final void setOutputPrintStream(final PrintStream output)
88 {
89 out = new PrintStream(output, true);
90 }
91 /***
92 * Sets the output stream to which this logger is to send error messages.
93 *
94 * @param pErr The error stream for the logger.
95 * Must not be <code>null</code>.
96 */
97 public final void setErrorPrintStream(final PrintStream pErr)
98 {
99 err = new PrintStream(pErr, true);
100 }
101 /***
102 * Sets this logger to produce emacs (and other editor) friendly output.
103 *
104 * @param pEmacsMode <code>true</code> if output is to be unadorned so that
105 * emacs and other editors can parse files names, etc.
106 */
107 public final void setEmacsMode(final boolean pEmacsMode)
108 {
109 this.emacsMode = pEmacsMode;
110 }
111 /***
112 * Responds to a build being started by just remembering the current time.
113 *
114 * @param event Ignored.
115 */
116 public final void buildStarted(final BuildEvent event)
117 {
118 startTime = System.currentTimeMillis();
119 }
120 /***
121 * Prints whether the build succeeded or failed,
122 * any errors the occured during the build, and
123 * how long the build took.
124 *
125 * @param event An event with any relevant extra information.
126 * Must not be <code>null</code>.
127 */
128 public final void buildFinished(final BuildEvent event)
129 {
130 Throwable error = event.getException();
131 StringBuffer message = new StringBuffer();
132 if (error == null)
133 {
134 message.append(StringUtils.LINE_SEP);
135 message.append("BUILD SUCCESSFUL");
136 }
137 else
138 {
139 message.append(StringUtils.LINE_SEP);
140 message.append("BUILD FAILED");
141 message.append(StringUtils.LINE_SEP);
142 if (Project.MSG_VERBOSE <= msgOutputLevel
143 || !(error instanceof BuildException))
144 {
145 message.append(StringUtils.getStackTrace(error));
146 }
147 else
148 {
149 if (error instanceof BuildException)
150 {
151 message.append(error.toString()).append(LINE_SEP);
152 }
153 else
154 {
155 message.append(error.getMessage()).append(LINE_SEP);
156 }
157 }
158 }
159 message.append(StringUtils.LINE_SEP);
160 message.append("Total time: ");
161 message.append(formatTime(System.currentTimeMillis() - startTime));
162 String msg = message.toString();
163 if (error == null)
164 {
165 printMessage(msg, out, Project.MSG_VERBOSE);
166 }
167 else
168 {
169 printMessage(msg, err, Project.MSG_ERR);
170 }
171 log(msg);
172 }
173 /***
174 * Logs a message to say that the target has started if this
175 * logger allows information-level messages.
176 *
177 * @param event An event with any relevant extra information.
178 * Must not be <code>null</code>.
179 */
180 public final void targetStarted(final BuildEvent event)
181 {
182 if (Project.MSG_INFO <= msgOutputLevel
183 && !event.getTarget().getName().equals(""))
184 {
185 String msg =
186 StringUtils.LINE_SEP + event.getTarget().getName() + ":";
187 printMessage(msg, out, event.getPriority());
188 log(msg);
189 }
190 }
191 /***
192 * No-op implementation.
193 *
194 * @param event Ignored.
195 */
196 public final void targetFinished(final BuildEvent event)
197 {
198 }
199 /***
200 * No-op implementation.
201 *
202 * @param event Ignored.
203 */
204 public final void taskStarted(final BuildEvent event)
205 {
206 }
207 /***
208 * No-op implementation.
209 *
210 * @param event Ignored.
211 */
212 public final void taskFinished(final BuildEvent event)
213 {
214 }
215 /***
216 * Logs a message, if the priority is suitable.
217 * In non-emacs mode, task level messages are prefixed by the
218 * task name which is right-justified.
219 *
220 * @param event A BuildEvent containing message information.
221 * Must not be <code>null</code>.
222 */
223 public final void messageLogged(final BuildEvent event)
224 {
225 int priority = event.getPriority();
226
227 if (priority <= msgOutputLevel)
228 {
229 StringBuffer message = new StringBuffer();
230 if (event.getTask() != null && !emacsMode)
231 {
232
233 String name = event.getTask().getTaskName();
234 String label = "[" + name + "] ";
235 int size = LEFT_COLUMN_SIZE - label.length();
236 StringBuffer tmp = new StringBuffer();
237 for (int i = 0; i < size; i++)
238 {
239 tmp.append(" ");
240 }
241 tmp.append(label);
242 label = tmp.toString();
243 try
244 {
245 BufferedReader r =
246 new BufferedReader(
247 new StringReader(event.getMessage()));
248 String line = r.readLine();
249 boolean first = true;
250 while (line != null)
251 {
252 if (!first)
253 {
254 message.append(StringUtils.LINE_SEP);
255 }
256 first = false;
257 message.append(label).append(line);
258 line = r.readLine();
259 }
260 }
261 catch (IOException e)
262 {
263
264 message.append(label).append(event.getMessage());
265 }
266 }
267 else
268 {
269 message.append(event.getMessage());
270 }
271 String msg = message.toString();
272 if (priority != Project.MSG_ERR)
273 {
274 printMessage(msg, out, priority);
275 }
276 else
277 {
278 printMessage(msg, err, priority);
279 }
280 log(msg);
281 }
282 }
283 /***
284 * Convenience method to format a specified length of time.
285 *
286 * @param millis Length of time to format, in milliseonds.
287 *
288 * @return the time as a formatted string.
289 *
290 * @see DateUtils#formatElapsedTime(long)
291 */
292 protected static String formatTime(final long millis)
293 {
294 return DateUtils.formatElapsedTime(millis);
295 }
296 /***
297 * Prints a message to a PrintStream.
298 *
299 * @param message The message to print.
300 * Should not be <code>null</code>.
301 * @param stream A PrintStream to print the message to.
302 * Must not be <code>null</code>.
303 * @param priority The priority of the message.
304 * (Ignored in this implementation.)
305 */
306 protected final void printMessage(
307 final String message,
308 final PrintStream stream,
309 final int priority)
310 {
311 stream.println(message);
312 }
313 /***
314 * Empty implementation which allows subclasses to receive the
315 * same output that is generated here.
316 *
317 * @param message Message being logged. Should not be <code>null</code>.
318 */
319 protected final void log(final String message)
320 {
321 }
322 /***
323 * Set the log level of the logging panel
324 * @param pMsgOutputLevel the level
325 */
326 protected final void setMsgOutputLevel(final int pMsgOutputLevel)
327 {
328 this.msgOutputLevel = pMsgOutputLevel;
329 }
330 }