KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > sourcecontrols > ClearCase


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001, 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 package net.sourceforge.cruisecontrol.sourcecontrols;
38
39 import net.sourceforge.cruisecontrol.CruiseControlException;
40 import net.sourceforge.cruisecontrol.SourceControl;
41 import net.sourceforge.cruisecontrol.util.ValidationHelper;
42 import net.sourceforge.cruisecontrol.util.StreamPumper;
43
44 import org.apache.log4j.Logger;
45
46 import java.io.BufferedReader JavaDoc;
47 import java.io.File JavaDoc;
48 import java.io.IOException JavaDoc;
49 import java.io.InputStream JavaDoc;
50 import java.io.InputStreamReader JavaDoc;
51 import java.text.ParseException JavaDoc;
52 import java.text.SimpleDateFormat JavaDoc;
53 import java.util.ArrayList JavaDoc;
54 import java.util.Arrays JavaDoc;
55 import java.util.Date JavaDoc;
56 import java.util.Hashtable JavaDoc;
57 import java.util.List JavaDoc;
58 import java.util.Map JavaDoc;
59 import java.util.StringTokenizer JavaDoc;
60 import java.util.Vector JavaDoc;
61
62 /**
63  * This class implements the SourceControlElement methods for a Clear Case
64  * repository.
65  *
66  * @author Thomas Leseney
67  * @author <a HREF="mailto:jcyip@thoughtworks.com">Jason Yip</a>
68  * @author Eric Lefevre
69  * @author Ralf Krakowski
70  */

71 public class ClearCase implements SourceControl {
72     private static final int DEFAULT = 0;
73     private static final int DISABLED = 1;
74     private static final int ENABLED = 2;
75
76     private static final Logger LOG = Logger.getLogger(ClearCase.class);
77
78     private Hashtable JavaDoc properties = new Hashtable JavaDoc();
79
80     private String JavaDoc property;
81
82     /**
83      * The path of the clear case view
84      */

85     private String JavaDoc viewPath;
86
87     /**
88      * The branch to check for modifications
89      */

90     private String JavaDoc branch;
91     private int recursive = DEFAULT; // default is true
92
private int all = DEFAULT; // default is false
93

94     /**
95      * Date format required by commands passed to Clear Case
96      */

97     private final SimpleDateFormat JavaDoc inDateFormatter =
98             new SimpleDateFormat JavaDoc("dd-MMMM-yyyy.HH:mm:ss");
99
100     /**
101      * Date format returned in the output of Clear Case commands.
102      */

103     private final SimpleDateFormat JavaDoc outDateFormatter =
104             new SimpleDateFormat JavaDoc("yyyyMMdd.HHmmss");
105
106     /**
107      * Unlikely combination of characters to separate fields in a ClearCase query
108      */

109     static final String JavaDoc DELIMITER = "#~#";
110
111     /**
112      * Even more unlikely combination of characters to indicate end of one line in query.
113      * Carriage return (\n) can be used in comments and so is not available to us.
114      */

115     static final String JavaDoc END_OF_STRING_DELIMITER = "@#@#@#@#@#@#@#@#@#@#@#@";
116
117     /**
118      * Sets the local working copy to use when making queries.
119      *
120      * @param path
121      */

122     public void setViewpath(String JavaDoc path) {
123         //_viewPath = getAntTask().getProject().resolveFile(path).getAbsolutePath();
124
viewPath = new File JavaDoc(path).getAbsolutePath();
125     }
126
127     /**
128      * Sets the branch that we're concerned about checking files into.
129      *
130      * @param branch
131      */

132     public void setBranch(String JavaDoc branch) {
133         this.branch = branch;
134     }
135
136     /**
137      * Set whether to check against sub-folders in the view path
138      */

139     public void setRecursive(boolean recursive) {
140         this.recursive = recursive ? ENABLED : DISABLED;
141     }
142
143
144     /**
145      * Set when checking the entire view path.
146      * <p/>
147      * When checking the entire view path this option invokes 'lshistory -all'
148      * instead of 'lshistory -recursive', which is much faster.
149      * <p/>
150      * This option is mutually exclusive with the recursive property.
151      * <p/>
152      * Note that 'all' does not use your view's config-spec rules. It behaves
153      * like having a single line config-spec that selects just ELEMENT * /<branch>/LATEST
154      * (i.e. 'lshistory -all' results that contain @@ are discarded). This differs from
155      * 'recurse', which only shows items selected by your current view.
156      */

157     public void setAll(boolean all) {
158         this.all = all ? ENABLED : DISABLED;
159
160         if (this.recursive == DEFAULT && all) {
161             this.recursive = DISABLED;
162         }
163     }
164
165     public void setProperty(String JavaDoc property) {
166         this.property = property;
167     }
168
169     public Map JavaDoc getProperties() {
170         return properties;
171     }
172
173     public void validate() throws CruiseControlException {
174         ValidationHelper.assertIsSet(branch, "branch", this.getClass());
175         ValidationHelper.assertIsSet(viewPath, "viewpath", this.getClass());
176         if (recursive == ENABLED && all == ENABLED) {
177             ValidationHelper.fail("'recursive' and 'all' are mutually exclusive attributes for ClearCase");
178         }
179     }
180
181     /**
182      * Returns an {@link java.util.List List} of {@link ClearCaseModification}
183      * detailing all the changes between now and the last build.
184      *
185      * @param lastBuild the last build time
186      * @param now time now, or time to check, NOT USED
187      * @return the list of modifications, an empty (not null) list if no
188      * modifications.
189      */

190     public List JavaDoc getModifications(Date JavaDoc lastBuild, Date JavaDoc now) {
191         String JavaDoc lastBuildDate = inDateFormatter.format(lastBuild);
192         String JavaDoc nowDate = inDateFormatter.format(now);
193         properties.put("clearcaselastbuild", lastBuildDate);
194         properties.put("clearcasenow", nowDate);
195
196         /*
197          * let's try a different clearcase command--this one just takes
198              * waaaaaaaay too long.
199          * String command = "cleartool find " + _viewPath +
200          * " -type f -exec \"cleartool lshistory" +
201          * " -since " + lastBuildDate;
202          * if(_branch != null)
203          * command += " -branch " + _branch;
204          * command += " -nco" + // exclude check out events
205          * " -fmt \\\" %u;%Nd;%n;%o \\n \\\" \\\"%CLEARCASE_XPN%\\\" \"";
206          */

207         String JavaDoc command = "cleartool lshistory";
208
209         if (branch != null) {
210             command += " -branch " + branch;
211         }
212
213         if (recursive == DEFAULT || recursive == ENABLED) {
214             command += " -r";
215         } else if (all == ENABLED) {
216             command += " -all";
217         }
218
219         command += " -nco -since " + lastBuildDate;
220         command += " -fmt %u"
221                 + DELIMITER
222                 + "%Nd"
223                 + DELIMITER
224                 + "%En"
225                 + DELIMITER
226                 + "%Vn"
227                 + DELIMITER
228                 + "%o"
229                 + DELIMITER
230                 + "!%l"
231                 + DELIMITER
232                 + "!%a"
233                 + DELIMITER
234                 + "%Nc"
235                 + END_OF_STRING_DELIMITER
236                 + "\\n";
237
238         File JavaDoc root = new File JavaDoc(viewPath);
239
240         LOG.info("ClearCase: getting modifications for " + viewPath);
241
242         LOG.debug("Command to execute : " + command);
243         List JavaDoc modifications = null;
244         try {
245             Process JavaDoc p = Runtime.getRuntime().exec(command, null, root);
246
247             StreamPumper errorPumper = new StreamPumper(p.getErrorStream());
248             new Thread JavaDoc(errorPumper).start();
249
250             InputStream JavaDoc input = p.getInputStream();
251             modifications = parseStream(input);
252
253             p.waitFor();
254             p.getInputStream().close();
255             p.getOutputStream().close();
256             p.getErrorStream().close();
257         } catch (Exception JavaDoc e) {
258             LOG.error("Error in executing the Clear Case command : ", e);
259         }
260
261         if (modifications == null) {
262             modifications = new ArrayList JavaDoc();
263         }
264
265         return modifications;
266     }
267
268     /**
269      * Parses the input stream to construct the modifications list.
270      * Package-private to make it available to the unit test.
271      *
272      * @param input the stream to parse
273      * @return a list of modification elements
274      * @throws IOException
275      */

276     List JavaDoc parseStream(InputStream JavaDoc input) throws IOException JavaDoc {
277         ArrayList JavaDoc modifications = new ArrayList JavaDoc();
278         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(input));
279         String JavaDoc ls = System.getProperty("line.separator");
280
281         String JavaDoc line;
282         String JavaDoc lines = "";
283
284         while ((line = reader.readLine()) != null) {
285             if (!lines.equals("")) {
286                 lines += ls;
287             }
288             lines += line;
289             ClearCaseModification mod = null;
290             if (lines.indexOf(END_OF_STRING_DELIMITER) > -1) {
291                 mod = parseEntry(lines.substring(0, lines.indexOf(END_OF_STRING_DELIMITER)));
292                 lines = "";
293             }
294             if (mod != null) {
295                 modifications.add(mod);
296             }
297         }
298         return modifications;
299     }
300
301     /**
302      * Parses a single line from the reader. Each line contains a signe revision
303      * with the format : <br>
304      * username#~#date_of_revision#~#element_name#~#operation_type#~#comments <br>
305      *
306      * @param line the line to parse
307      * @return a modification element corresponding to the given line
308      */

309     private ClearCaseModification parseEntry(String JavaDoc line) {
310         LOG.debug("parsing entry: " + line);
311         String JavaDoc[] tokens = tokeniseEntry(line);
312         if (tokens == null) {
313             return null;
314         }
315         String JavaDoc username = tokens[0].trim();
316
317         String JavaDoc timeStamp = tokens[1].trim();
318         String JavaDoc elementName = tokens[2].trim();
319         String JavaDoc version = tokens[3].trim();
320         String JavaDoc operationType = tokens[4].trim();
321
322         String JavaDoc labelList = tokens[5].substring(1).trim();
323         Vector JavaDoc labels = extractLabelsList(labelList);
324
325         String JavaDoc attributeList = tokens[6].substring(1).trim();
326         Hashtable JavaDoc attributes = extractAttributesMap(attributeList);
327
328         String JavaDoc comment = tokens[7].trim();
329
330         // A branch event shouldn't trigger a build
331
if (operationType.equals("mkbranch") || operationType.equals("rmbranch")) {
332             return null;
333         }
334
335         // Element names that contain @@ are discarded (see setAll(boolean))
336
if (elementName.indexOf("@@") >= 0) {
337             return null;
338         }
339
340         ClearCaseModification mod = new ClearCaseModification();
341
342         mod.userName = username;
343         mod.revision = version;
344
345         String JavaDoc folderName, fileName;
346         int sep = elementName.lastIndexOf(File.separator);
347         if (sep > -1) {
348             folderName = elementName.substring(0, sep);
349             fileName = elementName.substring(sep + 1);
350         } else {
351             folderName = null;
352             fileName = elementName;
353         }
354         ClearCaseModification.ModifiedFile modfile = mod.createModifiedFile(fileName, folderName);
355
356         try {
357             mod.modifiedTime = outDateFormatter.parse(timeStamp);
358         } catch (ParseException JavaDoc e) {
359             mod.modifiedTime = null;
360         }
361
362         modfile.action = operationType;
363         modfile.revision = version;
364
365         mod.type = "clearcase";
366         mod.labels = labels;
367         mod.attributes = attributes;
368
369         mod.comment = comment;
370
371         if (property != null) {
372             properties.put(property, "true");
373         }
374
375         // TODO: check if operation type is a delete
376

377         return mod;
378     }
379
380     private String JavaDoc[] tokeniseEntry(String JavaDoc line) {
381         int maxTokens = 8;
382         int minTokens = maxTokens - 1; // comment may be absent.
383
String JavaDoc[] tokens = new String JavaDoc[maxTokens];
384         Arrays.fill(tokens, "");
385         int tokenIndex = 0;
386         for (int oldIndex = 0, index = line.indexOf(DELIMITER, 0); true;
387              oldIndex = index + DELIMITER.length(), index = line.indexOf(DELIMITER, oldIndex), tokenIndex++) {
388             if (tokenIndex > maxTokens) {
389                 LOG.debug("Too many tokens; skipping entry");
390                 return null;
391             }
392             if (index == -1) {
393                 tokens[tokenIndex] = line.substring(oldIndex);
394                 break;
395             } else {
396                 tokens[tokenIndex] = line.substring(oldIndex, index);
397             }
398         }
399         if (tokenIndex < minTokens) {
400             LOG.debug("Not enough tokens; skipping entry");
401             return null;
402         }
403         return tokens;
404     }
405
406     /**
407      * @param attributeList
408      * @return parsed list
409      */

410     private Hashtable JavaDoc extractAttributesMap(String JavaDoc attributeList) {
411         Hashtable JavaDoc attributes = null;
412         if (attributeList.length() > 0) {
413             attributes = new Hashtable JavaDoc();
414             StringTokenizer JavaDoc attrST = new StringTokenizer JavaDoc(attributeList, "(), ");
415             while (attrST.hasMoreTokens()) {
416                 String JavaDoc attr = attrST.nextToken();
417                 int idx = attr.indexOf('=');
418                 if (idx > 0) {
419                     String JavaDoc attrName = attr.substring(0, idx);
420                     String JavaDoc attrValue = attr.substring(idx + 1);
421                     if (attrValue.startsWith("\"")) {
422                         attrValue = attrValue.substring(1, attrValue.length() - 1);
423                     }
424                     attributes.put(attrName, attrValue);
425                 }
426             }
427         }
428         return attributes;
429     }
430
431     /**
432      * @param labelList
433      * @return parsed list
434      */

435     private Vector JavaDoc extractLabelsList(String JavaDoc labelList) {
436         Vector JavaDoc labels = null;
437         if (labelList.length() > 0) {
438             labels = new Vector JavaDoc();
439             StringTokenizer JavaDoc labelST = new StringTokenizer JavaDoc(labelList, "(), ");
440             while (labelST.hasMoreTokens()) {
441                 labels.add(labelST.nextToken().trim());
442             }
443         }
444         return labels;
445     }
446 }
447
Popular Tags