1. /*
  2. * Copyright 2001-2002,2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs;
  18. import java.io.FileOutputStream;
  19. import java.io.IOException;
  20. import java.io.PrintStream;
  21. import java.util.Hashtable;
  22. import org.apache.tools.ant.BuildException;
  23. import org.apache.tools.ant.Project;
  24. import org.apache.tools.ant.Task;
  25. import org.apache.tools.ant.types.EnumeratedAttribute;
  26. /**
  27. * Adds a listener to the current build process that records the
  28. * output to a file.
  29. * <p>Several recorders can exist at the same time. Each recorder is
  30. * associated with a file. The filename is used as a unique identifier for
  31. * the recorders. The first call to the recorder task with an unused filename
  32. * will create a recorder (using the parameters provided) and add it to the
  33. * listeners of the build. All subsequent calls to the recorder task using
  34. * this filename will modify that recorders state (recording or not) or other
  35. * properties (like logging level).</p>
  36. * <p>Some technical issues: the file's print stream is flushed for "finished"
  37. * events (buildFinished, targetFinished and taskFinished), and is closed on
  38. * a buildFinished event.</p>
  39. * @see RecorderEntry
  40. * @version 0.5
  41. * @since Ant 1.4
  42. * @ant.task name="record" category="utility"
  43. */
  44. public class Recorder extends Task {
  45. //////////////////////////////////////////////////////////////////////
  46. // ATTRIBUTES
  47. /** The name of the file to record to. */
  48. private String filename = null;
  49. /**
  50. * Whether or not to append. Need Boolean to record an unset state (null).
  51. */
  52. private Boolean append = null;
  53. /**
  54. * Whether to start or stop recording. Need Boolean to record an unset
  55. * state (null).
  56. */
  57. private Boolean start = null;
  58. /** The level to log at. A level of -1 means not initialized yet. */
  59. private int loglevel = -1;
  60. /** Strip task banners if true. */
  61. private boolean emacsMode = false;
  62. /** The list of recorder entries. */
  63. private static Hashtable recorderEntries = new Hashtable();
  64. //////////////////////////////////////////////////////////////////////
  65. // CONSTRUCTORS / INITIALIZERS
  66. //////////////////////////////////////////////////////////////////////
  67. // ACCESSOR METHODS
  68. /**
  69. * Sets the name of the file to log to, and the name of the recorder
  70. * entry.
  71. *
  72. * @param fname File name of logfile.
  73. */
  74. public void setName(String fname) {
  75. filename = fname;
  76. }
  77. /**
  78. * Sets the action for the associated recorder entry.
  79. *
  80. * @param action The action for the entry to take: start or stop.
  81. */
  82. public void setAction(ActionChoices action) {
  83. if (action.getValue().equalsIgnoreCase("start")) {
  84. start = Boolean.TRUE;
  85. } else {
  86. start = Boolean.FALSE;
  87. }
  88. }
  89. /** Whether or not the logger should append to a previous file. */
  90. public void setAppend(boolean append) {
  91. this.append = new Boolean(append);
  92. }
  93. public void setEmacsMode(boolean emacsMode) {
  94. this.emacsMode = emacsMode;
  95. }
  96. /**
  97. * Sets the level to which this recorder entry should log to.
  98. *
  99. * @see VerbosityLevelChoices
  100. */
  101. public void setLoglevel(VerbosityLevelChoices level) {
  102. //I hate cascading if/elseif clauses !!!
  103. String lev = level.getValue();
  104. if (lev.equalsIgnoreCase("error")) {
  105. loglevel = Project.MSG_ERR;
  106. } else if (lev.equalsIgnoreCase("warn")) {
  107. loglevel = Project.MSG_WARN;
  108. } else if (lev.equalsIgnoreCase("info")) {
  109. loglevel = Project.MSG_INFO;
  110. } else if (lev.equalsIgnoreCase("verbose")) {
  111. loglevel = Project.MSG_VERBOSE;
  112. } else if (lev.equalsIgnoreCase("debug")) {
  113. loglevel = Project.MSG_DEBUG;
  114. }
  115. }
  116. //////////////////////////////////////////////////////////////////////
  117. // CORE / MAIN BODY
  118. /** The main execution. */
  119. public void execute() throws BuildException {
  120. if (filename == null) {
  121. throw new BuildException("No filename specified");
  122. }
  123. getProject().log("setting a recorder for name " + filename,
  124. Project.MSG_DEBUG);
  125. // get the recorder entry
  126. RecorderEntry recorder = getRecorder(filename, getProject());
  127. // set the values on the recorder
  128. recorder.setMessageOutputLevel(loglevel);
  129. recorder.setRecordState(start);
  130. recorder.setEmacsMode(emacsMode);
  131. }
  132. //////////////////////////////////////////////////////////////////////
  133. // INNER CLASSES
  134. /**
  135. * A list of possible values for the <code>setAction()</code> method.
  136. * Possible values include: start and stop.
  137. */
  138. public static class ActionChoices extends EnumeratedAttribute {
  139. private static final String[] values = {"start", "stop"};
  140. public String[] getValues() {
  141. return values;
  142. }
  143. }
  144. /**
  145. * A list of possible values for the <code>setLoglevel()</code> method.
  146. * Possible values include: error, warn, info, verbose, debug.
  147. */
  148. public static class VerbosityLevelChoices extends EnumeratedAttribute {
  149. private static final String[] values = {"error", "warn", "info",
  150. "verbose", "debug"};
  151. public String[] getValues() {
  152. return values;
  153. }
  154. }
  155. /**
  156. * Gets the recorder that's associated with the passed in name. If the
  157. * recorder doesn't exist, then a new one is created.
  158. */
  159. protected RecorderEntry getRecorder(String name, Project proj)
  160. throws BuildException {
  161. Object o = recorderEntries.get(name);
  162. RecorderEntry entry;
  163. if (o == null) {
  164. // create a recorder entry
  165. try {
  166. entry = new RecorderEntry(name);
  167. PrintStream out = null;
  168. if (append == null) {
  169. out = new PrintStream(
  170. new FileOutputStream(name));
  171. } else {
  172. out = new PrintStream(
  173. new FileOutputStream(name, append.booleanValue()));
  174. }
  175. entry.setErrorPrintStream(out);
  176. entry.setOutputPrintStream(out);
  177. } catch (IOException ioe) {
  178. throw new BuildException("Problems creating a recorder entry",
  179. ioe);
  180. }
  181. entry.setProject(proj);
  182. recorderEntries.put(name, entry);
  183. } else {
  184. entry = (RecorderEntry) o;
  185. }
  186. return entry;
  187. }
  188. }