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.util;
037:
038: import java.text.DateFormat;
039: import java.util.HashSet;
040: import java.util.Iterator;
041: import java.util.Set;
042:
043: import net.sourceforge.cruisecontrol.CruiseControlException;
044: import net.sourceforge.cruisecontrol.DateFormatFactory;
045: import net.sourceforge.cruisecontrol.Modification;
046:
047: import org.jdom.Element;
048:
049: /**
050: * Wrapper for the cruisecontrol build log. This class serves two purposes:<br>
051: * <ul>
052: * <li>Provide a convenient way to get relevant information about the build</li>
053: * <li>Abstract the build information so that the XML for the build log can change easily</li>
054: * </ul>
055: * <p>
056: * The CruiseControl log is expected to be in the following format: <p>
057: *
058: * <pre>
059: * <cruisecontrol>
060: * <info>
061: * <property name="label" value=""/>
062: * <property name="lastbuildtime" value=""/>
063: * <property name="lastgoodbuildtime" value=""/>
064: * <property name="lastbuildsuccessful" value=""/>
065: * <property name="buildfile" value=""/>
066: * <property name="buildtarget" value=""/>
067: * </info>
068: * <build error="">
069: * <properties>
070: * </properties>
071: * </build>
072: * <modifications>
073: * </modifications>
074: * </cruisecontrol>
075: * </pre>
076: *
077: * Note: buildtarget is only present when a target is forced via the JMX interface.
078: *
079: * @author Alden Almagro
080: * @author Jonny Boman
081: * @version $Id: XMLLogHelper.java 3136 2007-06-27 06:58:42Z bhamail $
082: */
083: public class XMLLogHelper {
084:
085: private Element log;
086: private DateFormat dateFormat;
087:
088: public XMLLogHelper(Element log) {
089: this (log, DateFormatFactory.getDateFormat());
090: }
091:
092: XMLLogHelper(Element log, DateFormat dateFormat) {
093: this .log = log;
094: this .dateFormat = dateFormat;
095: }
096:
097: /**
098: * @return the build log name
099: */
100: public String getLogFileName() throws CruiseControlException {
101: return getCruiseControlInfoProperty("logfile");
102: }
103:
104: /**
105: * @return the label for this build
106: */
107: public String getLabel() throws CruiseControlException {
108: return getCruiseControlInfoProperty("label");
109: }
110:
111: public String getBuildTimestamp() throws CruiseControlException {
112: return getCruiseControlInfoProperty("cctimestamp");
113: }
114:
115: /**
116: * @return true if the previous build was successful, false if it was not
117: */
118: public boolean wasPreviousBuildSuccessful()
119: throws CruiseControlException {
120: return getCruiseControlInfoProperty("lastbuildsuccessful")
121: .equals("true");
122: }
123:
124: /**
125: * @return true if the build was necessary
126: */
127: public boolean isBuildNecessary() {
128: if (log.getChild("build") != null
129: && log.getChild("build").getAttributeValue("error") != null) {
130:
131: return !log.getChild("build").getAttributeValue("error")
132: .equals("No Build Necessary");
133: }
134:
135: return true;
136: }
137:
138: /**
139: * @return project name as defined in the ant build file
140: */
141: public String getProjectName() throws CruiseControlException {
142: return getCruiseControlInfoProperty("projectname");
143: }
144:
145: /**
146: * @return true if the build was successful, false otherwise
147: */
148: public boolean isBuildSuccessful() {
149: return (log.getChild("build").getAttribute("error") == null);
150: }
151:
152: /**
153: * Looks in modifications/changelist/ or modifications/modification/user depending on SouceControl implementation.
154: * @return <code>Set</code> of usernames that have modified code since the last build
155: */
156: public Set getBuildParticipants() {
157: Set results = new HashSet();
158: if (isP4Modifications()) {
159:
160: Iterator changelistIterator = log.getChild("modifications")
161: .getChildren("changelist").iterator();
162: while (changelistIterator.hasNext()) {
163: Element changelistElement = (Element) changelistIterator
164: .next();
165: String val = changelistElement
166: .getAttributeValue("email");
167: if ((val == null) || (val.length() == 0)) {
168: val = changelistElement.getAttributeValue("user");
169: }
170: results.add(val);
171: }
172: } else {
173: Iterator modificationIterator = log.getChild(
174: "modifications").getChildren("modification")
175: .iterator();
176: while (modificationIterator.hasNext()) {
177: Element modification = (Element) modificationIterator
178: .next();
179: Element emailElement = modification.getChild("email");
180: if (emailElement == null) {
181: emailElement = modification.getChild("user");
182: }
183: results.add(emailElement.getText());
184: }
185: }
186: return results;
187: }
188:
189: private boolean isP4Modifications() {
190: return log.getChild("modifications").getChildren("changelist") != null
191: && !log.getChild("modifications").getChildren(
192: "changelist").isEmpty();
193: }
194:
195: /**
196: * @param propertyName the name of the ant property
197: * @return the value of the ant property
198: */
199: public String getAntProperty(String propertyName)
200: throws CruiseControlException {
201: Iterator props = log.getChild("build").getChild("properties")
202: .getChildren("property").iterator();
203: return findProperty(props, propertyName);
204: }
205:
206: private String findProperty(Iterator props, String expected)
207: throws CruiseControlException {
208: while (props.hasNext()) {
209: Element property = (Element) props.next();
210: if (property.getAttributeValue("name").equals(expected)) {
211: return property.getAttributeValue("value");
212: }
213: }
214: throw new CruiseControlException("Property: " + expected
215: + " not found.");
216: }
217:
218: public String getCruiseControlInfoProperty(String name)
219: throws CruiseControlException {
220: Iterator props = log.getChild("info").getChildren("property")
221: .iterator();
222: return findProperty(props, name);
223: }
224:
225: public Set getModifications() {
226: Set results = new HashSet();
227: if (isP4Modifications()) {
228: //TODO: implement this
229: } else {
230: Iterator modificationIterator = log.getChild(
231: "modifications").getChildren("modification")
232: .iterator();
233: while (modificationIterator.hasNext()) {
234: Element modification = (Element) modificationIterator
235: .next();
236: Modification mod = new Modification();
237: mod.fromElement(modification, dateFormat);
238: results.add(mod);
239: }
240: }
241: return results;
242: }
243:
244: public boolean isBuildFix() throws CruiseControlException {
245: return !this.wasPreviousBuildSuccessful()
246: && this.isBuildSuccessful();
247: }
248:
249: }
|