KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > ModificationSet


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001-2003, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37
38 package net.sourceforge.cruisecontrol;
39
40 import net.sourceforge.cruisecontrol.util.ValidationHelper;
41
42 import org.apache.log4j.Logger;
43 import org.apache.oro.io.GlobFilenameFilter;
44 import org.apache.oro.text.MalformedCachePatternException;
45 import org.jdom.Element;
46
47 import java.io.File JavaDoc;
48 import java.text.DateFormat JavaDoc;
49 import java.util.ArrayList JavaDoc;
50 import java.util.Date JavaDoc;
51 import java.util.Hashtable JavaDoc;
52 import java.util.Iterator JavaDoc;
53 import java.util.List JavaDoc;
54 import java.util.StringTokenizer JavaDoc;
55
56 /**
57  * Set of modifications collected from included SourceControls
58  *
59  * @see SourceControl
60  */

61 public class ModificationSet {
62
63     private boolean lieOnIsModified = false;
64     private static final Logger LOG = Logger.getLogger(ModificationSet.class);
65     private static final int ONE_SECOND = 1000;
66
67     private List JavaDoc modifications = new ArrayList JavaDoc();
68     private List JavaDoc sourceControls = new ArrayList JavaDoc();
69     private int quietPeriod = 60 * ONE_SECOND;
70     private Date JavaDoc timeOfCheck;
71     private final DateFormat JavaDoc formatter = DateFormatFactory.getDateFormat();
72
73     /**
74      * File-Patterns (as org.apache.oro.io.GlobFilenameFilter) to be ignored
75      */

76     private List JavaDoc ignoreFiles;
77
78     /**
79      * Set the amount of time in which there is no source control activity
80      * after which it is assumed that it is safe to update from the source
81      * control system and initiate a build.
82      */

83     public void setQuietPeriod(int seconds) {
84         quietPeriod = seconds * ONE_SECOND;
85     }
86
87     /**
88      * Set the list of Glob-File-Patterns to be ignored
89      *
90      * @param filePatterns a comma separated list of glob patterns. "*" and "?" are valid wildcards
91      * example: "?razy-*-.txt,*.jsp"
92      * @throws CruiseControlException if at least one of the patterns is malformed
93      */

94     public void setIgnoreFiles(String JavaDoc filePatterns) throws CruiseControlException {
95         if (filePatterns != null) {
96             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(filePatterns, ",");
97             ignoreFiles = new ArrayList JavaDoc();
98             while (st.hasMoreTokens()) {
99                 String JavaDoc pattern = st.nextToken();
100                 // Compile the pattern
101
try {
102                     ignoreFiles.add (new GlobFilenameFilter(pattern));
103                 } catch (MalformedCachePatternException e) {
104                     throw new CruiseControlException("Invalid filename pattern '" + pattern + "'", e);
105                 }
106             }
107         }
108     }
109
110     protected List JavaDoc getIgnoreFiles() {
111         return this.ignoreFiles;
112     }
113
114     /** @deprecated **/
115     public void addSourceControl(SourceControl sourceControl) {
116         add(sourceControl);
117     }
118
119     public void add(SourceControl sourceControl) {
120         sourceControls.add(sourceControl);
121     }
122     
123     public List JavaDoc getSourceControls() {
124         return sourceControls;
125     }
126
127     protected boolean isLastModificationInQuietPeriod(Date JavaDoc timeOfCheck, List JavaDoc modificationList) {
128         long lastModificationTime = getLastModificationMillis(modificationList);
129         final long quietPeriodStart = timeOfCheck.getTime() - quietPeriod;
130         final boolean modificationInFuture = new Date JavaDoc().getTime() < lastModificationTime;
131         if (modificationInFuture) {
132             LOG.warn("A modification has been detected in the future. Building anyway.");
133         }
134         return (quietPeriodStart <= lastModificationTime) && !modificationInFuture;
135     }
136
137     protected long getLastModificationMillis(List JavaDoc modificationList) {
138         Date JavaDoc timeOfLastModification = new Date JavaDoc(0);
139         Iterator JavaDoc iterator = modificationList.iterator();
140         while (iterator.hasNext()) {
141             Object JavaDoc object = iterator.next();
142             Modification modification = null;
143             if (object instanceof Modification) {
144                 modification = (Modification) object;
145             }
146             if (object instanceof Element) {
147                 Element element = (Element) object;
148                 modification = new Modification("unknown");
149                 modification.fromElement(element, formatter);
150             }
151             if (modification != null) {
152                 Date JavaDoc modificationDate = modification.modifiedTime;
153                 if (modificationDate.after(timeOfLastModification)) {
154                     timeOfLastModification = modificationDate;
155                 }
156             }
157         }
158         LOG.debug("Last modification: " + formatter.format(timeOfLastModification));
159         return timeOfLastModification.getTime();
160     }
161
162     protected long getQuietPeriodDifference(Date JavaDoc now, List JavaDoc modificationList) {
163         long diff = quietPeriod - (now.getTime() - getLastModificationMillis(modificationList));
164         return Math.max(0, diff);
165     }
166
167     /**
168      * Returns a Hashtable of name-value pairs representing any properties set by the
169      * SourceControl.
170      * @return Hashtable of properties.
171      */

172     public Hashtable JavaDoc getProperties() {
173         Hashtable JavaDoc table = new Hashtable JavaDoc();
174         for (Iterator JavaDoc iter = sourceControls.iterator(); iter.hasNext();) {
175             SourceControl control = (SourceControl) iter.next();
176             table.putAll(control.getProperties());
177         }
178         return table;
179     }
180
181     /**
182      *
183      */

184     public Element getModifications(Date JavaDoc lastBuild) {
185         Element modificationsElement;
186         do {
187             timeOfCheck = new Date JavaDoc();
188             modifications = new ArrayList JavaDoc();
189             Iterator JavaDoc sourceControlIterator = sourceControls.iterator();
190             while (sourceControlIterator.hasNext()) {
191                 SourceControl sourceControl = (SourceControl) sourceControlIterator.next();
192                 modifications.addAll(sourceControl.getModifications(lastBuild, timeOfCheck));
193             }
194
195             // Postfilter all modifications of ignored files
196
filterIgnoredModifications(modifications);
197
198             if (modifications.size() > 0) {
199                 LOG.info(
200                         modifications.size()
201                         + ((modifications.size() > 1)
202                         ? " modifications have been detected."
203                         : " modification has been detected."));
204             }
205             modificationsElement = new Element("modifications");
206             Iterator JavaDoc modificationIterator = modifications.iterator();
207             while (modificationIterator.hasNext()) {
208                 Object JavaDoc object = modificationIterator.next();
209                 if (object instanceof Element) {
210                     modificationsElement.addContent(((Element) object).detach());
211                 } else {
212                     Modification modification = (Modification) object;
213                     Element modificationElement = (modification).toElement(formatter);
214                     modification.log(formatter);
215                     modificationsElement.addContent(modificationElement);
216                 }
217             }
218
219             if (isLastModificationInQuietPeriod(timeOfCheck, modifications)) {
220                 LOG.info("A modification has been detected in the quiet period. ");
221                 if (LOG.isDebugEnabled()) {
222                     final Date JavaDoc quietPeriodStart = new Date JavaDoc(timeOfCheck.getTime() - quietPeriod);
223                     LOG.debug(formatter.format(quietPeriodStart) + " <= Quiet Period <= "
224                             + formatter.format(timeOfCheck));
225                 }
226                 Date JavaDoc now = new Date JavaDoc();
227                 long timeToSleep = getQuietPeriodDifference(now, modifications);
228                 LOG.info("Sleeping for " + (timeToSleep / 1000) + " seconds before retrying.");
229                 try {
230                     Thread.sleep(timeToSleep);
231                 } catch (InterruptedException JavaDoc e) {
232                     LOG.error(e);
233                 }
234             }
235         } while (isLastModificationInQuietPeriod(timeOfCheck, modifications));
236
237
238         return modificationsElement;
239     }
240
241     /**
242      * Remove all Modifications that match any of the ignoreFiles-patterns
243      */

244     protected void filterIgnoredModifications (List JavaDoc modifications) {
245         if (this.ignoreFiles != null) {
246             for (Iterator JavaDoc iterator = modifications.iterator(); iterator.hasNext(); ) {
247                 Object JavaDoc object = iterator.next();
248                 Modification modification = null;
249                 if (object instanceof Modification) {
250                     modification = (Modification) object;
251                 } else if (object instanceof Element) {
252                     Element element = (Element) object;
253                     modification = new Modification();
254                     modification.fromElement(element, formatter);
255                 }
256     
257                 if (isIgnoredModification(modification)) {
258                     iterator.remove();
259                 }
260             }
261         }
262     }
263
264     private boolean isIgnoredModification(Modification modification) {
265         File JavaDoc file;
266         if (modification.getFolderName() == null) {
267             if (modification.getFileName() == null) {
268                 return false;
269             } else {
270                 file = new File JavaDoc(modification.getFileName());
271             }
272         } else {
273             file = new File JavaDoc(modification.getFolderName(), modification.getFileName());
274         }
275         String JavaDoc path = file.toString();
276
277         // On systems with a '\' as pathseparator convert it to a forward slash '/'
278
// That makes patterns platform independent
279
if (File.separatorChar == '\\') {
280             path = path.replace('\\', '/');
281         }
282
283         for (Iterator JavaDoc iterator = ignoreFiles.iterator(); iterator.hasNext(); ) {
284             GlobFilenameFilter pattern = (GlobFilenameFilter) iterator.next();
285
286             // We have to use a little tweak here, since GlobFilenameFilter only matches the filename, but not
287
// the path, so we use the complete path as the 'filename'-argument.
288
if (pattern.accept(file, path)) {
289                 return true;
290             }
291         }
292         return false;
293     }
294
295     public Date JavaDoc getTimeOfCheck() {
296         return timeOfCheck;
297     }
298
299     public boolean isModified() {
300         return (!modifications.isEmpty()) || lieOnIsModified;
301     }
302
303     public void validate() throws CruiseControlException {
304         ValidationHelper.assertFalse(sourceControls.isEmpty(),
305             "modificationset element requires at least one nested source control element");
306     }
307
308     int getQuietPeriod() {
309         return quietPeriod;
310     }
311
312     public void setRequireModification(boolean isModifiedAccurate) {
313         lieOnIsModified = !isModifiedAccurate;
314     }
315 }
316
Popular Tags