View Javadoc

1   package org.devaki.nextobjects.util;
2   /*
3    *  nextobjects Copyright (C) 2001-2005 Emmanuel Florent
4    *  This program is free software; you can redistribute it and/or modify
5    *  it under the terms of the GNU General Public License as published by the
6    *  Free Software Foundation; either version 2 of the License, or (at your
7    *  option) any later version.
8    *  This program is distributed in the hope that it will
9    *  be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
10   *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11   *  PURPOSE. See the GNU General Public License for more details.
12   *  You should have received a copy of the GNU General Public License along
13   *  with this program; if not, write to the Free Software Foundation, Inc., 59
14   *  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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      //FIXME this should be stderr instead ?
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         // Filter out messages based on priority
227         if (priority <= msgOutputLevel)
228         {
229             StringBuffer message = new StringBuffer();
230             if (event.getTask() != null && !emacsMode)
231             {
232                 // Print out the name of the task if we're in one
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                     // shouldn't be possible
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 }