/******************************************************************************** * CruiseControl, a Continuous Integration Toolkit * Copyright (c) 2007, ThoughtWorks, Inc. * 200 E. Randolph, 25th Floor * Chicago, IL 60601 USA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * + Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ********************************************************************************/ package net.sourceforge.cruisecontrol.dashboard; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Arrays; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import net.sourceforge.cruisecontrol.Modification; import net.sourceforge.cruisecontrol.dashboard.exception.ShouldStopParsingException; import net.sourceforge.cruisecontrol.dashboard.saxhandler.CompositeExtractor; import net.sourceforge.cruisecontrol.dashboard.saxhandler.DurationExtractor; import net.sourceforge.cruisecontrol.dashboard.saxhandler.ModificationExtractor; import net.sourceforge.cruisecontrol.dashboard.saxhandler.SAXBasedExtractor; import net.sourceforge.cruisecontrol.dashboard.utils.CCDateFormatter; import net.sourceforge.cruisecontrol.dashboard.utils.TimeConverter; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.joda.time.DateTime; public class BuildSummary implements Build { private LogFile buildLogFile; private String projectName = ""; private DateTime buildingSince; private Map propertiesFromLogContent = new HashMap(); private static final Logger LOGGER = Logger.getLogger(BuildSummary.class); private final PreviousResult previousBuildResult; private CurrentStatus currentStatus = CurrentStatus.DISCONTINUED; private String serverName = "N/A"; private TimeConverter timeConverter = new TimeConverter(); /** * No logfile available. Inactive build. * @param projectName */ public BuildSummary(String projectName) { this.projectName = projectName; this.previousBuildResult = PreviousResult.UNKNOWN; this.buildLogFile = null; this.currentStatus = CurrentStatus.WAITING; } public BuildSummary(String projectName, PreviousResult previousResult, String buildLogFilename) { this.projectName = projectName; this.previousBuildResult = previousResult; this.buildLogFile = new LogFile(buildLogFilename); } /** * Used for mocking out the timeConverter. * @param timeConverter */ void setTimeConverter(TimeConverter timeConverter) { this.timeConverter = timeConverter; } public String getDateTime() { return buildLogFile.getDateTime(); } public boolean hasPassed() { return previousBuildResult.equals(PreviousResult.PASSED); } public String getLabel() { return buildLogFile.getLabel(); } public String getBuildLogFilename() { return buildLogFile.getName(); } public String getBuildLogFileDateTime() { String filename = buildLogFile.getName(); return filename.substring(3, 17); } public String getProjectName() { return projectName; } public DateTime getBuildDate() { return CCDateFormatter.format(getDateTime(), "yyyy-MM-dd HH:mm.ss"); } public DateTime getBuildingSince() { return buildingSince; } public void updateStatus(String statusStr) { CurrentStatus newStatus = CurrentStatus.getProjectBuildStatus(statusStr); this.currentStatus = newStatus; if (!CurrentStatus.BUILDING.equals(this.currentStatus)) { this.buildingSince = null; } } public void updateBuildSince(DateTime buildSince) { if (CurrentStatus.BUILDING.equals(this.currentStatus)) { this.buildingSince = buildSince; } } public String getDuration() { try { if (!propertiesFromLogContent.containsKey("duration")) { parseLogFile(new DurationExtractor()); } return (String) propertiesFromLogContent.get("duration"); } catch (Exception e) { return "0 second"; } } private void parseLogFile(SAXBasedExtractor extractor) { try { SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); saxParser.parse(buildLogFile.getInputStream(), new CompositeExtractor(Arrays .asList(new SAXBasedExtractor[] {extractor}))); } catch (ShouldStopParsingException se) { LOGGER.debug("Intentionally throwing exception to stop parsing " + se.getMessage()); } catch (Exception e) { throw new RuntimeException(e); } extractor.report(propertiesFromLogContent); } public int compareTo(Object other) { Build otherSummary = (Build) other; String originalOther = StringUtils.defaultString(otherSummary.getProjectName()); String originalThis = StringUtils.defaultString(this.getProjectName()); int result = originalThis.toLowerCase().compareTo(originalOther.toLowerCase()); if (result == 0) { return originalThis.compareTo(originalOther); } return result; } public String toString() { return this.getDateTime(); } public List<Modification> getModifications() { try { if (!propertiesFromLogContent.containsKey("modifications")) { parseLogFile(new ModificationExtractor()); } return (List<Modification>) propertiesFromLogContent.get("modifications"); } catch (Exception e) { return null; } } public CurrentStatus getCurrentStatus() { return currentStatus; } public boolean isInactive() { return !CurrentStatus.BUILDING.equals(currentStatus) && PreviousResult.UNKNOWN.equals(previousBuildResult); } public PreviousResult getPreviousBuildResult() { return previousBuildResult == null ? PreviousResult.UNKNOWN : previousBuildResult; } public String getServerName() { return serverName; } public void setServerName(String serverName) { this.serverName = serverName; } public String getConvertedTime() { if (buildLogFile == null) { return "waiting for first build..."; } return this.timeConverter.getConvertedTime(getBuildDate().toDate()); } }