001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2004, 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 java.io.File;
039: import java.io.Serializable;
040: import java.text.DateFormat;
041: import java.text.ParseException;
042: import java.text.SimpleDateFormat;
043: import java.util.ArrayList;
044: import java.util.Collections;
045: import java.util.Date;
046: import java.util.List;
047:
048: import net.sourceforge.cruisecontrol.taglib.CruiseControlLogFileFilter;
049: import net.sourceforge.cruisecontrol.taglib.CruiseControlSuccessfulLogFileFilter;
050:
051: /**
052: * Contains various information about a specific build. The
053: * information is extracted from the name of the log file
054: * generated by the build.
055: *
056: * @author <a href="mailto:robertdw@users.sourceforge.net">Robert Watkins</a>
057: * @author <a href="mailto:hak@2mba.dk">Hack Kampbjorn</a>
058: */
059: public class BuildInfo implements Comparable, Serializable {
060: public static final String LOG_PREFIX = "log";
061: public static final char LABEL_SEPARATOR = 'L';
062: public static final String LOG_DATE_PATTERN = "yyyyMMddHHmmss";
063: private final Date buildDate;
064: private final String dateStamp;
065: private final String label;
066: private final LogFile logFile;
067:
068: // Convenience constructor used by the testcasess
069: BuildInfo(String infoText) throws ParseException {
070: this (new File(infoText));
071: }
072:
073: public BuildInfo(File logFile) throws ParseException {
074: this (new LogFile(logFile));
075: }
076:
077: public BuildInfo(LogFile logFile) throws ParseException {
078: this .logFile = logFile;
079: dateStamp = deriveDateStamp();
080: buildDate = deriveDate();
081: label = deriveLabel();
082: }
083:
084: private String deriveLabel() {
085: String infoText = logFile.getName();
086: boolean buildSuccessful = new CruiseControlSuccessfulLogFileFilter()
087: .isSuccessful(infoText);
088: String theLabel;
089: if (buildSuccessful) {
090: int labelStartIndex = (LOG_PREFIX + LOG_DATE_PATTERN + LABEL_SEPARATOR)
091: .length();
092: theLabel = infoText.substring(labelStartIndex);
093: } else {
094: theLabel = null;
095: }
096: return theLabel;
097: }
098:
099: private String deriveDateStamp() throws ParseException {
100: String infoText = logFile.getName();
101: try {
102: return infoText.substring(LOG_PREFIX.length(), LOG_PREFIX
103: .length()
104: + LOG_DATE_PATTERN.length());
105: } catch (StringIndexOutOfBoundsException e) {
106: throw new IllegalStateException(
107: "infoText has wrong format: " + infoText + " "
108: + e.getMessage());
109: }
110: }
111:
112: private Date deriveDate() throws ParseException {
113: String infoText = logFile.getName();
114: Date theDate;
115: final DateFormat logDateFormat = new SimpleDateFormat(
116: LOG_DATE_PATTERN);
117: try {
118: theDate = logDateFormat.parse(dateStamp);
119: } catch (ParseException e) {
120: throw new ParseException("Invalid format: " + infoText
121: + ". Format must be logyyyyMMddHHmmSS.xml or "
122: + "logyyyyMMddHHmmSSLlabel.xml", e.getErrorOffset());
123: }
124: return theDate;
125: }
126:
127: public Date getBuildDate() {
128: return buildDate;
129: }
130:
131: /**
132: * Gets the date stamp of the log name.
133: * @return the build date as a stamp.
134: */
135: public String getDateStamp() {
136: return dateStamp;
137: }
138:
139: public String getLabel() {
140: return label;
141: }
142:
143: public boolean isSuccessful() {
144: return getLabel() != null;
145: }
146:
147: /**
148: * Gets the log's name with a file extension.
149: */
150: public String getLogName() {
151: return logFile.getName();
152: }
153:
154: public LogFile getLogFile() {
155: return logFile;
156: }
157:
158: public static BuildInfoSummary loadFromDir(File logDir)
159: throws CruiseControlWebAppException {
160: File[] logFileNames = logDir
161: .listFiles(new CruiseControlLogFileFilter());
162: if (logFileNames == null) {
163: throw new CruiseControlWebAppException(
164: "Could not access the directory "
165: + logDir.getAbsolutePath());
166: } else if (logFileNames.length == 0) {
167: throw new CruiseControlWebAppException(
168: "Configuration problem? No logs found in logDir: "
169: + logDir.getAbsolutePath());
170: }
171: List buildInfoList = new ArrayList(logFileNames.length);
172: for (int i = 0; i < logFileNames.length; i++) {
173: File file = logFileNames[i];
174: try {
175: buildInfoList.add(new BuildInfo(file));
176: } catch (ParseException e) {
177: throw new CruiseControlWebAppException(
178: "Could not parse log file name "
179: + file.getName()
180: + ". Is the filter broken?", e);
181: }
182: }
183: Collections.sort(buildInfoList);
184: return new BuildInfoSummary(buildInfoList);
185: }
186:
187: /**
188: * Return a comparison based on the build time.
189: * @see java.lang.Comparable#compareTo(java.lang.Object)
190: */
191: public int compareTo(Object arg0) {
192: BuildInfo other = (BuildInfo) arg0;
193: return this.buildDate.compareTo(other.buildDate);
194: }
195: }
|