001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001, ThoughtWorks, Inc.
004: * 200 E. Randolph, 25th Floor
005: * Chicago, IL 60601 USA
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * + Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * + Redistributions in binary form must reproduce the above
016: * copyright notice, this list of conditions and the following
017: * disclaimer in the documentation and/or other materials provided
018: * with the distribution.
019: *
020: * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
021: * names of its contributors may be used to endorse or promote
022: * products derived from this software without specific prior
023: * written permission.
024: *
025: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
026: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
027: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
028: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
030: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
031: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
032: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
033: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
034: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036: ********************************************************************************/package net.sourceforge.cruisecontrol;
037:
038: import net.sourceforge.cruisecontrol.taglib.CruiseControlLogFileFilter;
039: import net.sourceforge.cruisecontrol.taglib.CruiseControlSuccessfulLogFileFilter;
040:
041: import java.io.File;
042: import java.io.FileInputStream;
043: import java.io.FilenameFilter;
044: import java.io.IOException;
045: import java.io.InputStream;
046: import java.io.Serializable;
047: import java.text.ParseException;
048: import java.util.Arrays;
049: import java.util.Collections;
050: import java.util.zip.GZIPInputStream;
051: import org.jdom.Document;
052: import org.jdom.JDOMException;
053: import org.jdom.input.SAXBuilder;
054:
055: /**
056: * Represents a XML log file.
057: * Build information that is based on the log name is in the <code>BuildInfo</code>
058: * class
059: *
060: * @see BuildInfo
061: * @author <a href="mailto:hak@2mba.dk">Hack Kampbjorn</a>
062: */
063: public class LogFile implements Serializable {
064: // NOTE: LogFile must be Serializable for Metrics tab (charts) to work
065:
066: public static final String LOG_SUFFIX = ".xml";
067: public static final String LOG_COMPRESSED_SUFFIX = LOG_SUFFIX
068: + ".gz";
069: private static final FilenameFilter LOG_FILTER = new CruiseControlLogFileFilter();
070: private static final FilenameFilter SUCCESSFUL_FILTER = new CruiseControlSuccessfulLogFileFilter();
071:
072: private File xmlFile;
073:
074: /**
075: * Creates a new instance of LogFile
076: * @param logDir directory with the XML log file
077: * @param logName name of the XML log file
078: */
079: public LogFile(File logDir, String logName) {
080: this .xmlFile = new File(logDir, logName + LOG_SUFFIX);
081: if (!xmlFile.exists()) {
082: xmlFile = new File(logDir, logName + LOG_COMPRESSED_SUFFIX);
083: }
084: }
085:
086: /**
087: * Creates a new instance of LogFile
088: * @param xmlFile the XML log file
089: */
090: public LogFile(File xmlFile) {
091: this .xmlFile = xmlFile;
092: }
093:
094: /**
095: * Gets the latest log file in a given directory. Since all of our logs contain a date/time string, this method
096: * is actually getting the log file that comes last alphabetically.
097: *
098: * @return The latest log file or <code>null</code> if there are no log
099: * files in the given directory.
100: */
101: public static LogFile getLatestLogFile(File logDir) {
102: File[] logs = logDir.listFiles(LOG_FILTER);
103: if (logs != null && logs.length > 0) {
104: return new LogFile((File) Collections.max(Arrays
105: .asList(logs)));
106: } else {
107: return null;
108: }
109: }
110:
111: /**
112: * Gets the latest successful log file in a given directory.
113: * Since all of our logs contain a date/time string, this method
114: * is actually getting the log file that comes last alphabetically.
115: *
116: * @return The latest log file or <code>null</code> if there are no
117: * successful log files in the given directory
118: */
119: public static LogFile getLatestSuccessfulLogFile(File logDir) {
120: File[] logs = logDir.listFiles(SUCCESSFUL_FILTER);
121: if (logs != null && logs.length > 0) {
122: return new LogFile((File) Collections.max(Arrays
123: .asList(logs)));
124: } else {
125: return null;
126: }
127: }
128:
129: /**
130: * Gets the build information for this log file like the label and build
131: * date.
132: * @return the log file's build information
133: */
134: public BuildInfo getBuildInfo() throws ParseException {
135: return new BuildInfo(this );
136: }
137:
138: /**
139: * Gets the file object.
140: * @return the log file
141: */
142: public File getFile() {
143: return xmlFile;
144: }
145:
146: /**
147: * Whether the log file is compressed or not.
148: * @return <code>true</code> if the file is compressed
149: */
150: public boolean isCompressed() {
151: return getFile().getName().endsWith(LOG_COMPRESSED_SUFFIX);
152: }
153:
154: /**
155: * Gets the log's name.
156: * This is the file name without a file extension like <code>.xml<code> or
157: * <code>.xml.gz</code>. Use <code>getFile().getName()</code> to get the
158: * file name with extension.
159: *
160: * @return the name of the log
161: */
162: public String getName() {
163: return extractLogNameFromFileName(getFile().getName());
164: }
165:
166: private String extractLogNameFromFileName(String fileName) {
167: return fileName.substring(0, fileName.lastIndexOf(LOG_SUFFIX));
168: }
169:
170: /**
171: * Gets the log file's directory.
172: * @return the parent directory of the log file
173: */
174: public File getLogDirectory() {
175: return getFile().getParentFile();
176: }
177:
178: /**
179: * Gets a stream with the log file's content.
180: *
181: * @throws java.io.IOException if there is an error reading the file
182: * @return the file content as a stream
183: */
184: public InputStream getInputStream() throws IOException {
185: InputStream in = new FileInputStream(xmlFile);
186: if (isCompressed()) {
187: in = new GZIPInputStream(in);
188: }
189: return in;
190: }
191:
192: public Document asDocument() throws JDOMException, IOException {
193: SAXBuilder builder = new SAXBuilder();
194: InputStream in = getInputStream();
195: Document log = null;
196: try {
197: log = builder.build(in, getFile().getAbsolutePath());
198: } finally {
199: in.close();
200: }
201: return log;
202: }
203:
204: public LogFileReader getReader() throws JDOMException, IOException {
205: return new LogFileReader(asDocument());
206:
207: }
208:
209: }
|