001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.tools.ant.taskdefs;
019:
020: import java.io.FileOutputStream;
021: import java.io.IOException;
022: import java.io.PrintStream;
023: import org.apache.tools.ant.BuildEvent;
024: import org.apache.tools.ant.BuildException;
025: import org.apache.tools.ant.BuildLogger;
026: import org.apache.tools.ant.DefaultLogger;
027: import org.apache.tools.ant.Project;
028: import org.apache.tools.ant.SubBuildListener;
029: import org.apache.tools.ant.util.StringUtils;
030:
031: /**
032: * This is a class that represents a recorder. This is the listener to the
033: * build process.
034: *
035: * @since Ant 1.4
036: */
037: public class RecorderEntry implements BuildLogger, SubBuildListener {
038:
039: //////////////////////////////////////////////////////////////////////
040: // ATTRIBUTES
041:
042: /** The name of the file associated with this recorder entry. */
043: private String filename = null;
044: /** The state of the recorder (recorder on or off). */
045: private boolean record = true;
046: /** The current verbosity level to record at. */
047: private int loglevel = Project.MSG_INFO;
048: /** The output PrintStream to record to. */
049: private PrintStream out = null;
050: /** The start time of the last know target. */
051: private long targetStartTime = 0L;
052: /** Strip task banners if true. */
053: private boolean emacsMode = false;
054: /** project instance the recorder is associated with */
055: private Project project;
056:
057: //////////////////////////////////////////////////////////////////////
058: // CONSTRUCTORS / INITIALIZERS
059:
060: /**
061: * @param name The name of this recorder (used as the filename).
062: */
063: protected RecorderEntry(String name) {
064: targetStartTime = System.currentTimeMillis();
065: filename = name;
066: }
067:
068: //////////////////////////////////////////////////////////////////////
069: // ACCESSOR METHODS
070:
071: /**
072: * @return the name of the file the output is sent to.
073: */
074: public String getFilename() {
075: return filename;
076: }
077:
078: /**
079: * Turns off or on this recorder.
080: *
081: * @param state true for on, false for off, null for no change.
082: */
083: public void setRecordState(Boolean state) {
084: if (state != null) {
085: flush();
086: record = state.booleanValue();
087: }
088: }
089:
090: /**
091: * @see org.apache.tools.ant.BuildListener#buildStarted(BuildEvent)
092: */
093: /** {@inheritDoc}. */
094: public void buildStarted(BuildEvent event) {
095: log("> BUILD STARTED", Project.MSG_DEBUG);
096: }
097:
098: /**
099: * @see org.apache.tools.ant.BuildListener#buildFinished(BuildEvent)
100: */
101: /** {@inheritDoc}. */
102: public void buildFinished(BuildEvent event) {
103: log("< BUILD FINISHED", Project.MSG_DEBUG);
104:
105: if (record && out != null) {
106: Throwable error = event.getException();
107:
108: if (error == null) {
109: out.println(StringUtils.LINE_SEP + "BUILD SUCCESSFUL");
110: } else {
111: out.println(StringUtils.LINE_SEP + "BUILD FAILED"
112: + StringUtils.LINE_SEP);
113: error.printStackTrace(out);
114: }
115: }
116: cleanup();
117: }
118:
119: /**
120: * Cleans up any resources held by this recorder entry at the end
121: * of a subbuild if it has been created for the subbuild's project
122: * instance.
123: *
124: * @param event the buildFinished event
125: *
126: * @since Ant 1.6.2
127: */
128: public void subBuildFinished(BuildEvent event) {
129: if (event.getProject() == project) {
130: cleanup();
131: }
132: }
133:
134: /**
135: * Empty implementation to satisfy the BuildListener interface.
136: *
137: * @param event the buildStarted event
138: *
139: * @since Ant 1.6.2
140: */
141: public void subBuildStarted(BuildEvent event) {
142: }
143:
144: /**
145: * @see org.apache.tools.ant.BuildListener#targetStarted(BuildEvent)
146: */
147: /** {@inheritDoc}. */
148: public void targetStarted(BuildEvent event) {
149: log(">> TARGET STARTED -- " + event.getTarget(),
150: Project.MSG_DEBUG);
151: log(StringUtils.LINE_SEP + event.getTarget().getName() + ":",
152: Project.MSG_INFO);
153: targetStartTime = System.currentTimeMillis();
154: }
155:
156: /**
157: * @see org.apache.tools.ant.BuildListener#targetFinished(BuildEvent)
158: */
159: /** {@inheritDoc}. */
160: public void targetFinished(BuildEvent event) {
161: log("<< TARGET FINISHED -- " + event.getTarget(),
162: Project.MSG_DEBUG);
163:
164: String time = formatTime(System.currentTimeMillis()
165: - targetStartTime);
166:
167: log(event.getTarget() + ": duration " + time,
168: Project.MSG_VERBOSE);
169: flush();
170: }
171:
172: /**
173: * @see org.apache.tools.ant.BuildListener#taskStarted(BuildEvent)
174: */
175: /** {@inheritDoc}. */
176: public void taskStarted(BuildEvent event) {
177: log(">>> TASK STARTED -- " + event.getTask(), Project.MSG_DEBUG);
178: }
179:
180: /**
181: * @see org.apache.tools.ant.BuildListener#taskFinished(BuildEvent)
182: */
183: /** {@inheritDoc}. */
184: public void taskFinished(BuildEvent event) {
185: log("<<< TASK FINISHED -- " + event.getTask(),
186: Project.MSG_DEBUG);
187: flush();
188: }
189:
190: /**
191: * @see org.apache.tools.ant.BuildListener#messageLogged(BuildEvent)
192: */
193: /** {@inheritDoc}. */
194: public void messageLogged(BuildEvent event) {
195: log("--- MESSAGE LOGGED", Project.MSG_DEBUG);
196:
197: StringBuffer buf = new StringBuffer();
198:
199: if (event.getTask() != null) {
200: String name = event.getTask().getTaskName();
201:
202: if (!emacsMode) {
203: String label = "[" + name + "] ";
204: int size = DefaultLogger.LEFT_COLUMN_SIZE
205: - label.length();
206:
207: for (int i = 0; i < size; i++) {
208: buf.append(" ");
209: }
210: buf.append(label);
211: }
212: }
213: buf.append(event.getMessage());
214:
215: log(buf.toString(), event.getPriority());
216: }
217:
218: /**
219: * The thing that actually sends the information to the output.
220: *
221: * @param mesg The message to log.
222: * @param level The verbosity level of the message.
223: */
224: private void log(String mesg, int level) {
225: if (record && (level <= loglevel) && out != null) {
226: out.println(mesg);
227: }
228: }
229:
230: private void flush() {
231: if (record && out != null) {
232: out.flush();
233: }
234: }
235:
236: /**
237: * @see BuildLogger#setMessageOutputLevel(int)
238: */
239: /** {@inheritDoc}. */
240: public void setMessageOutputLevel(int level) {
241: if (level >= Project.MSG_ERR && level <= Project.MSG_DEBUG) {
242: loglevel = level;
243: }
244: }
245:
246: /**
247: * @see BuildLogger#setOutputPrintStream(PrintStream)
248: */
249: /** {@inheritDoc}. */
250: public void setOutputPrintStream(PrintStream output) {
251: closeFile();
252: out = output;
253: }
254:
255: /**
256: * @see BuildLogger#setEmacsMode(boolean)
257: */
258: /** {@inheritDoc}. */
259: public void setEmacsMode(boolean emacsMode) {
260: this .emacsMode = emacsMode;
261: }
262:
263: /**
264: * @see BuildLogger#setErrorPrintStream(PrintStream)
265: */
266: /** {@inheritDoc}. */
267: public void setErrorPrintStream(PrintStream err) {
268: setOutputPrintStream(err);
269: }
270:
271: private static String formatTime(long millis) {
272: long seconds = millis / 1000;
273: long minutes = seconds / 60;
274:
275: if (minutes > 0) {
276: return Long.toString(minutes) + " minute"
277: + (minutes == 1 ? " " : "s ")
278: + Long.toString(seconds % 60) + " second"
279: + (seconds % 60 == 1 ? "" : "s");
280: } else {
281: return Long.toString(seconds) + " second"
282: + (seconds % 60 == 1 ? "" : "s");
283: }
284:
285: }
286:
287: /**
288: * Set the project associated with this recorder entry.
289: *
290: * @param project the project instance
291: *
292: * @since 1.6.2
293: */
294: public void setProject(Project project) {
295: this .project = project;
296: if (project != null) {
297: project.addBuildListener(this );
298: }
299: }
300:
301: /**
302: * @since 1.6.2
303: */
304: public void cleanup() {
305: closeFile();
306: if (project != null) {
307: project.removeBuildListener(this );
308: }
309: project = null;
310: }
311:
312: /**
313: * Initially opens the file associated with this recorder.
314: * Used by Recorder.
315: * @param append Indicates if output must be appended to the logfile or that
316: * the logfile should be overwritten.
317: * @throws BuildException
318: * @since 1.6.3
319: */
320: void openFile(boolean append) throws BuildException {
321: openFileImpl(append);
322: }
323:
324: /**
325: * Closes the file associated with this recorder.
326: * Used by Recorder.
327: * @since 1.6.3
328: */
329: void closeFile() {
330: if (out != null) {
331: out.close();
332: out = null;
333: }
334: }
335:
336: /**
337: * Re-opens the file associated with this recorder.
338: * Used by Recorder.
339: * @throws BuildException
340: * @since 1.6.3
341: */
342: void reopenFile() throws BuildException {
343: openFileImpl(true);
344: }
345:
346: private void openFileImpl(boolean append) throws BuildException {
347: if (out == null) {
348: try {
349: out = new PrintStream(new FileOutputStream(filename,
350: append));
351: } catch (IOException ioe) {
352: throw new BuildException(
353: "Problems opening file using a "
354: + "recorder entry", ioe);
355: }
356: }
357: }
358:
359: }
|