Source Code Cross Referenced for CMSynergy.java in  » Build » cruisecontrol » net » sourceforge » cruisecontrol » sourcecontrols » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Build » cruisecontrol » net.sourceforge.cruisecontrol.sourcecontrols 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.sourcecontrols;
037:
038:        import java.io.File;
039:        import java.io.IOException;
040:        import java.text.ParseException;
041:        import java.text.SimpleDateFormat;
042:        import java.util.ArrayList;
043:        import java.util.Arrays;
044:        import java.util.Date;
045:        import java.util.Iterator;
046:        import java.util.List;
047:        import java.util.Locale;
048:        import java.util.Map;
049:        import java.util.Properties;
050:
051:        import net.sourceforge.cruisecontrol.CruiseControlException;
052:        import net.sourceforge.cruisecontrol.SourceControl;
053:        import net.sourceforge.cruisecontrol.util.ManagedCommandline;
054:        import net.sourceforge.cruisecontrol.util.Util;
055:        import net.sourceforge.cruisecontrol.util.ValidationHelper;
056:
057:        import org.apache.log4j.Logger;
058:
059:        /**
060:         * Checks for modifications made to a Telelogic CM Synergy repository. It does
061:         * this by examining a provided reference project, getting the tasks from all
062:         * folders in that project, and checking the completion time of those tasks
063:         * against the last build.
064:         *
065:         * @author <a href="mailto:rjmpsmith@gmail.com">Robert J. Smith</a>
066:         */
067:        public class CMSynergy implements  SourceControl {
068:
069:            /**
070:             * A delimiter used for data values returned from a CM Synergy query
071:             */
072:            public static final String CCM_ATTR_DELIMITER = "@#@#@#@";
073:
074:            /**
075:             * A delimiter used to mark the end of a multi-lined result from a query
076:             */
077:            public static final String CCM_END_OBJECT = "<<<#@#@#>>>";
078:
079:            /**
080:             * The default CM Synergy command line client executable
081:             */
082:            public static final String CCM_EXE = "ccm";
083:
084:            /**
085:             * The environment variable used by CM Synergy to determine which backend
086:             * ccmSession to use when issuing commands.
087:             */
088:            public static final String CCM_SESSION_VAR = "CCM_ADDR";
089:
090:            /**
091:             * The default CM Synergy session map file
092:             */
093:            public static final String CCM_SESSION_FILE = System
094:                    .getProperty("user.home")
095:                    + File.separator + ".ccmsessionmap";
096:
097:            /**
098:             * An instance of the logging class
099:             */
100:            private static final Logger LOG = Logger.getLogger(CMSynergy.class);
101:
102:            /**
103:             * A collection of properties which will be passed to and set within the
104:             * builder.
105:             */
106:            private SourceControlProperties properties = new SourceControlProperties();
107:
108:            /**
109:             * The name of the property which will be set and passed to the builder if
110:             * any object has changed since the last build.
111:             */
112:            private String property = "cc.ccm.haschanged";
113:
114:            /**
115:             * The version number delimeter used by the database with which this CM
116:             * Synergy session is connected.
117:             */
118:            private String ccmDelimiter = "-";
119:
120:            /**
121:             * The URL for your installation of Change Synergy
122:             */
123:            private String changeSynergyURL;
124:
125:            /**
126:             * The CCM database with which we wish to connect
127:             */
128:            private String ccmDb;
129:
130:            /**
131:             * The CM Synergy executable used for executing commands. If not set, we
132:             * will use the default value "ccm".
133:             */
134:            private String ccmExe;
135:
136:            /**
137:             * The CM Synergy project spec (2 part name).
138:             */
139:            private String projectSpec;
140:
141:            /**
142:             * The instance number of the project. This is almost always "1", but might
143:             * need to be overridden if you are using DCM?
144:             */
145:            private String projectInstance = "1";
146:
147:            /**
148:             * The CM Synergy project four part name we will use as a template to
149:             * determine if any new tasks have been completed.
150:             */
151:            private String projectFourPartName;
152:
153:            /**
154:             * If set to true, the contents of the folders contained within the
155:             * project's reconfigure properties will be updated before we query to find
156:             * new tasks.
157:             */
158:            private boolean updateFolders = true;
159:
160:            /**
161:             * The file which contains the mapping between CM Synergy session names and
162:             * IDs.
163:             */
164:            private File sessionFile;
165:
166:            /**
167:             * The name of the CM Synergy session to use.
168:             */
169:            private String sessionName;
170:
171:            /**
172:             * The date format as returned by your installation of CM Synergy.
173:             */
174:            private String ccmDateFormat = "EEE MMM dd HH:mm:ss yyyy"; // Fri Dec 3
175:
176:            // 17:51:56 2004
177:
178:            /**
179:             * If set to true, the project will be reconfigured when changes are
180:             * detected.
181:             */
182:            private boolean reconfigure = false;
183:
184:            /**
185:             * Used in conjunction with reconfigure. If set to true, all subprojects
186:             * will be reconfigured when changes are detected.
187:             */
188:            private boolean recurse = true;
189:
190:            /**
191:             * If set to true, the time a task came into a reconfigure folder is used
192:             * to determine modified tasks instead of the tasks completion time. Works
193:             * for Synergy 6.3SP1 and newer only.
194:             */
195:            private boolean useBindTime = false;
196:
197:            /**
198:             * If set to true, the work area location will not be queried and passed to
199:             * the builder.
200:             */
201:            private boolean ignoreWorkarea = false;
202:
203:            /**
204:             * The locale used for parsing dates.
205:             */
206:            private Locale locale;
207:
208:            /**
209:             * The language used to set the locale for parsing CM Synergy dates.
210:             */
211:            private String language = "en";
212:
213:            /**
214:             * A reusable commandline for issuing CM Synergy commands
215:             */
216:            private ManagedCommandline cmd;
217:
218:            /**
219:             * The country used to set the locale for parsing CM Synergy dates.
220:             */
221:            private String country = "US";
222:
223:            /**
224:             * The number of modified tasks found
225:             */
226:            private int numTasks;
227:
228:            /**
229:             * The number of modified objects found
230:             */
231:            private int numObjects;
232:
233:            /**
234:             * Sets the name of the CM Synergy executable to use when issuing commands.
235:             *
236:             * @param ccmExe
237:             *            the name of the CM Synergy executable
238:             */
239:            public void setCcmExe(String ccmExe) {
240:                this .ccmExe = ccmExe;
241:            }
242:
243:            /**
244:             * Sets the CM Synergy project spec to be used as a template for calculating
245:             * changes. The value set here can be accessed from within the build as the
246:             * property "cc.ccm.project".
247:             *
248:             * @param projectSpec
249:             *            The project spec (in 2 part name format).
250:             */
251:            public void setProject(String projectSpec) {
252:                this .projectSpec = projectSpec;
253:            }
254:
255:            /**
256:             * Sets the project's instance value. This value will be used in any query
257:             * which involves the project. Defaults to "1". This default should work for
258:             * most people. You might, however, need to override this value when using
259:             * DCM?
260:             *
261:             * @param projectInstance
262:             *            The instance number of the project.
263:             */
264:            public void setInstance(String projectInstance) {
265:                this .projectInstance = projectInstance;
266:            }
267:
268:            /**
269:             * Sets the URL for your installation of Change Synergy. This is used to
270:             * create active links from the modification report to the Change Requests
271:             * associated with the modified tasks. If not set, the links will not be
272:             * created. If you wish to use this feature, you must also set the ccmdb
273:             * attribute to the remote location of the Synergy database.
274:             *
275:             * @param url
276:             *            The URL of your ChangeSynergy installation
277:             */
278:            public void setChangeSynergyURL(String url) {
279:                this .changeSynergyURL = url;
280:            }
281:
282:            /**
283:             * Sets the remote Synergy database with which to connect. This is only
284:             * needed if you wish to create active links from the build results page to
285:             * your installation of Change Synergy. If you set this attribute, you must
286:             * also set the changesynergyurl attribute.
287:             *
288:             * @param db
289:             *            The remote Synergy database with which to connect (e.g.
290:             *            /ccmdb/mydb).
291:             */
292:            public void setCcmDb(String db) {
293:                this .ccmDb = db;
294:            }
295:
296:            /**
297:             * Sets the value of the updateFolders attribute. If set to true, the
298:             * contents of the folders contained within the project's reconfigure
299:             * properties will be updated before we query to find new tasks.
300:             */
301:            public void setUpdateFolders(boolean updateFolders) {
302:                this .updateFolders = updateFolders;
303:            }
304:
305:            /**
306:             * Sets the file which contains the mapping between CM Synergy session names
307:             * and IDs. This file should be in the standard properties file format. Each
308:             * line should map one name to a CM Synergy session ID (as returned by the
309:             * "ccm status" command).
310:             * <p>
311:             * example: <br>
312:             * <br>
313:             * session1=localhost:65024:192.168.1.17
314:             *
315:             * @param sessionFile
316:             *            The session file
317:             */
318:            public void setSessionFile(String sessionFile) {
319:                this .sessionFile = new File(sessionFile);
320:            }
321:
322:            /**
323:             * Sets the name of the CM Synergy session to use with this plugin. This
324:             * name should appear in the specified session file.
325:             *
326:             * @param sessionName
327:             *            The session name
328:             *
329:             * @see #setSessionFile(String)
330:             */
331:            public void setSessionName(String sessionName) {
332:                this .sessionName = sessionName;
333:            }
334:
335:            /**
336:             * Sets the date format used by your installation of CM Synergy. The format
337:             * string should use the syntax described in <code>SimpleDateFormat</code>.
338:             * The default is "EEE MMM dd HH:mm:ss yyyy" The value set here can be
339:             * accessed from within the build as the property "cc.ccm.dateformat".
340:             *
341:             * @param format
342:             *            the date format
343:             */
344:            public void setCcmDateFormat(String format) {
345:                this .ccmDateFormat = format;
346:            }
347:
348:            /**
349:             * Sets the value of the reconfigure attribute. If set to true, the project
350:             * will be reconfigured when changes are detected. Default value is false.
351:             */
352:            public void setReconfigure(boolean reconfigure) {
353:                this .reconfigure = reconfigure;
354:            }
355:
356:            /**
357:             * Sets the value of the useBindtime attribute. If set to true, the time the
358:             * task came into the reconfigure folders is used to query the modifications
359:             * instead of the time the task was completed. Works
360:             * for Synergy 6.3SP1 and newer only.
361:             * Default value is false.
362:             */
363:            public void setUseBindTime(boolean useBindTime) {
364:                this .useBindTime = useBindTime;
365:            }
366:
367:            /**
368:             * Sets the value of the recurse attribute. Used in conjuction with the
369:             * reconfigure attribute. If set to true, all subprojects will also be
370:             * reconfigured when changes are detected. Default is true.
371:             */
372:            public void setRecurse(boolean recurse) {
373:                this .recurse = recurse;
374:            }
375:
376:            /**
377:             * Sets the value of the ignoreWorkarea attribute. If set to true, we will
378:             * not attempt to determine the location of the project's workarea, nor will
379:             * we pass the cc.ccm.workarea attribute to the builders. Default is false.
380:             */
381:            public void setIgnoreWorkarea(boolean ignoreWorkarea) {
382:                this .ignoreWorkarea = ignoreWorkarea;
383:            }
384:
385:            /**
386:             * Sets the language used to create the locale for parsing CM Synergy dates.
387:             * The format should follow the ISO standard as specified by
388:             * <code>java.util.Locale</code>. The default is "en" (English).
389:             *
390:             * @param language
391:             *            The language to use when creating the <code>Locale</code>
392:             */
393:            public void setLanguage(String language) {
394:                this .language = language;
395:            }
396:
397:            /**
398:             * Sets the country used to create the locale for parsing CM Synergy dates.
399:             * The format should follow the ISO standard as specified by
400:             * <code>java.util.Locale</code>. The default is "US" (United States).
401:             *
402:             * @param country
403:             *            The ISO country code to use
404:             */
405:            public void setCountry(String country) {
406:                this .country = country;
407:            }
408:
409:            public Map getProperties() {
410:                return properties.getPropertiesAndReset();
411:            }
412:
413:            public void setProperty(String property) {
414:                this .property = property;
415:            }
416:
417:            public void validate() throws CruiseControlException {
418:                ValidationHelper.assertIsSet(projectSpec, "project", this 
419:                        .getClass());
420:            }
421:
422:            public List getModifications(Date lastBuild, Date now) {
423:                // Create a Locale appropriate for this installation
424:                locale = new Locale(language, country);
425:                if (!locale.equals(Locale.US)) {
426:                    LOG.info("Locale has been set to " + locale.toString());
427:                }
428:
429:                // Attempt to get the database delimiter
430:                cmd = createCcmCommand(ccmExe, sessionName, sessionFile);
431:                cmd.createArgument("delimiter");
432:                try {
433:                    cmd.execute();
434:                    cmd.assertExitCode(0);
435:                    this .ccmDelimiter = cmd.getStdoutAsString().trim();
436:                } catch (Exception e) {
437:                    StringBuffer buff = new StringBuffer(
438:                            "Could not connect to provided CM Synergy session");
439:                    LOG.error(buff.toString(), e);
440:                    return null;
441:                }
442:
443:                // Create the projectFourPartName needed for projects with instance
444:                // other than 1 to reconfigure properly
445:                projectFourPartName = projectSpec + ":project:"
446:                        + projectInstance;
447:
448:                LOG.info("Checking for modifications between "
449:                        + lastBuild.toString() + " and " + now.toString());
450:
451:                // If we were asked to update the folders, do so
452:                if (updateFolders) {
453:                    refreshReconfigureProperties();
454:                }
455:
456:                // Create a list of modifications based upon tasks completed
457:                // since the last build.
458:                numObjects = 0;
459:                numTasks = 0;
460:                List modifications = getModifiedTasks(lastBuild);
461:
462:                LOG.info("Found " + numObjects + " modified object(s) in "
463:                        + numTasks + " new task(s).");
464:
465:                // If we were asked to reconfigure the project, do so
466:                if (reconfigure && (numObjects > 0)) {
467:                    reconfigureProject();
468:                }
469:
470:                // Pass to the build any relevent properties
471:                properties.put("cc.ccm.project", projectFourPartName);
472:                properties.put("cc.ccm.dateformat", ccmDateFormat);
473:                String sessionID = cmd.getVariable(CCM_SESSION_VAR);
474:                if (sessionID != null) {
475:                    properties.put("cc.ccm.session", sessionID);
476:                }
477:                if (numObjects > 0) {
478:                    properties.put(property, "true");
479:                }
480:                if (!ignoreWorkarea) {
481:                    properties.put("cc.ccm.workarea", getWorkarea());
482:                }
483:
484:                return modifications;
485:            }
486:
487:            /**
488:             * Update the folders within the given project's reconfigure properties.
489:             */
490:            private void refreshReconfigureProperties() {
491:                // Construct the CM Synergy command
492:                cmd.clearArgs();
493:                cmd.createArgument("reconfigure_properties");
494:                if (recurse) {
495:                    cmd.createArgument("-recurse");
496:                }
497:                cmd.createArguments("-refresh", projectFourPartName);
498:                try {
499:                    cmd.execute();
500:                    cmd.assertExitCode(0);
501:                } catch (Exception e) {
502:                    LOG.warn(
503:                            "Could not refresh reconfigure properties for project \""
504:                                    + projectFourPartName + "\".", e);
505:                }
506:            }
507:
508:            /**
509:             * Get a list of all tasks which are contained in all folders in the
510:             * reconfigure properties of the specified project and were completed after
511:             * the last build. If useBindTime is <code>true</code> not the completion time of
512:             * the task is considered but the time the task came into the folder.
513:             *
514:             * @return A list of <code>CMSynergyModifications</code> which represent
515:             *         the new tasks
516:             */
517:            private List getModifiedTasks(Date lastBuild) {
518:
519:                // The format used for converting Java dates into CM Synergy dates
520:                // Note that the format used to submit commands differs from the
521:                // format used in the results of that command!?!
522:                SimpleDateFormat toCcmDate = new SimpleDateFormat(
523:                        "yyyy/MM/dd HH:mm:ss", locale);
524:
525:                // Construct the CM Synergy command
526:                cmd.clearArgs();
527:                cmd.createArgument("query");
528:                cmd.createArgument("-u");
529:
530:                // Set up the output format
531:                cmd.createArgument("-f");
532:                cmd.createArgument("%displayname" + CCM_ATTR_DELIMITER + // 0
533:                        "%release" + CCM_ATTR_DELIMITER + // 1
534:                        "%owner" + CCM_ATTR_DELIMITER + // 2
535:                        "%completion_date" + CCM_ATTR_DELIMITER + // 3
536:                        "%task_synopsis" + CCM_END_OBJECT); // 4
537:
538:                // Construct the query string
539:                if (useBindTime) {
540:                    cmd
541:                            .createArgument("is_task_in_folder_of(is_folder_in_rp_of('"
542:                                    + projectFourPartName
543:                                    + "'), '>', time('"
544:                                    + toCcmDate.format(lastBuild) + "'))");
545:                } else {
546:                    cmd
547:                            .createArgument("is_task_in_folder_of(is_folder_in_rp_of('"
548:                                    + projectFourPartName
549:                                    + "')) and completion_date>time('"
550:                                    + toCcmDate.format(lastBuild) + "')");
551:                }
552:
553:                // Execute the command
554:                try {
555:                    cmd.execute();
556:                } catch (Exception e) {
557:                    LOG.error(
558:                            "Could not query for new tasks. The modification list "
559:                                    + "will be empty!", e);
560:                }
561:
562:                // create a modification list with discovered tasks
563:                List modificationList = new ArrayList();
564:                Iterator tasks = format(cmd.getStdoutAsList()).iterator();
565:                while (tasks.hasNext()) {
566:                    numTasks++;
567:                    String[] attributes = tokeniseEntry((String) tasks.next(),
568:                            5);
569:                    if (attributes == null) {
570:                        LOG
571:                                .warn("Could not determine attributes for at least one "
572:                                        + "discovered task! The modification set is suspect.");
573:                        continue;
574:                    }
575:                    CMSynergyModification mod = new CMSynergyModification();
576:                    mod.taskNumber = attributes[0];
577:                    mod.revision = attributes[1];
578:                    mod.userName = attributes[2];
579:                    mod.modifiedTime = getDateFromSynergy(attributes[3]);
580:                    mod.comment = attributes[4];
581:
582:                    // Populate the included files by quering for objects in the task
583:                    getModifiedObjects(mod);
584:
585:                    // Find any Change Requests with which the task is associated
586:                    getAssociatedCRs(mod);
587:
588:                    // Add the modification to the list
589:                    modificationList.add(mod);
590:                }
591:
592:                return modificationList;
593:            }
594:
595:            /**
596:             * Split the results of a CM Synergy query into individual tokens. This
597:             * method was added for compatibility with the 1.3 JRE.
598:             *
599:             * @param line
600:             *            The line to be tokenised.
601:             * @param maxTokens
602:             *            The maximum number of tokens in the line
603:             *
604:             * @return The tokens found
605:             */
606:            private String[] tokeniseEntry(String line, int maxTokens) {
607:                int minTokens = maxTokens - 1; // comment may be absent.
608:                String[] tokens = new String[maxTokens];
609:                Arrays.fill(tokens, "");
610:                int tokenIndex = 0;
611:                for (int oldIndex = 0, index = line.indexOf(CCM_ATTR_DELIMITER,
612:                        0); true; oldIndex = index
613:                        + CCM_ATTR_DELIMITER.length(), index = line.indexOf(
614:                        CCM_ATTR_DELIMITER, oldIndex), tokenIndex++) {
615:                    if (tokenIndex > maxTokens) {
616:                        LOG.debug("Too many tokens; skipping entry");
617:                        return null;
618:                    }
619:                    if (index == -1) {
620:                        tokens[tokenIndex] = line.substring(oldIndex);
621:                        break;
622:                    }
623:
624:                    tokens[tokenIndex] = line.substring(oldIndex, index);
625:                }
626:                if (tokenIndex < minTokens) {
627:                    LOG.debug("Not enough tokens; skipping entry");
628:                    return null;
629:                }
630:                return tokens;
631:            }
632:
633:            /**
634:             * Populate the object list of a Modification by querying for objects
635:             * associated with the task.
636:             */
637:            private void getModifiedObjects(CMSynergyModification mod) {
638:                // Construct the CM Synergy command
639:                cmd.clearArgs();
640:                cmd.createArgument("task");
641:                cmd.createArguments("-show", "objects");
642:
643:                // Set up the output format
644:                cmd.createArgument("-f");
645:                cmd.createArgument("%name" + CCM_ATTR_DELIMITER + // 0
646:                        "%version" + CCM_ATTR_DELIMITER + // 1
647:                        "%type" + CCM_ATTR_DELIMITER + // 2
648:                        "%instance" + CCM_ATTR_DELIMITER + // 3
649:                        "%project" + CCM_ATTR_DELIMITER + // 4
650:                        "%comment" + CCM_END_OBJECT); // 5
651:
652:                // Construct the query string
653:                cmd.createArgument(mod.taskNumber);
654:
655:                // Execute the command
656:                try {
657:                    cmd.execute();
658:                } catch (Exception e) {
659:                    LOG.warn("Could not query for objects in task \""
660:                            + mod.taskNumber
661:                            + "\". The modification list will be incomplete!",
662:                            e);
663:                }
664:
665:                // Populate the modification with the object data from the task
666:                Iterator objects = format(cmd.getStdoutAsList()).iterator();
667:                while (objects.hasNext()) {
668:                    numObjects++;
669:                    String object = (String) objects.next();
670:                    String[] attributes = tokeniseEntry(object, 6);
671:                    if (attributes == null) {
672:                        LOG
673:                                .warn("Could not determine attributes for object associated "
674:                                        + "with task \"" + mod.revision + "\".");
675:                        continue;
676:                    }
677:                    // Add each object to the CMSynergyModification
678:                    mod.createModifiedObject(attributes[0], attributes[1],
679:                            attributes[2], attributes[3], attributes[4],
680:                            attributes[5]);
681:                }
682:            }
683:
684:            /**
685:             * Queries the CM Synergy repository to find any Change Requests with which
686:             * a task is associated. If the Change Synergy URL and database were
687:             * provided, we will add HTML based links to those CRs.
688:             *
689:             * @param mod
690:             *            The modification object
691:             */
692:            private void getAssociatedCRs(CMSynergyModification mod) {
693:                // Construct the CM Synergy command
694:                cmd.clearArgs();
695:                cmd.createArgument("query");
696:                cmd.createArgument("-u");
697:
698:                // Set up the output format
699:                cmd.createArguments("-f", "%displayname");
700:
701:                // Construct the query string
702:                cmd
703:                        .createArgument("cvtype='problem' and has_associated_task('task"
704:                                + mod.taskNumber
705:                                + ccmDelimiter
706:                                + "1:task:probtrac')");
707:
708:                // Execute the command
709:                try {
710:                    cmd.execute();
711:                } catch (Exception e) {
712:                    LOG.warn(
713:                            "Could not query for associated CRs. The modification list "
714:                                    + "may be incomplete!", e);
715:                }
716:
717:                // Add the Change Request(s) to the modification
718:                List crList = cmd.getStdoutAsList();
719:                if (crList != null) {
720:                    Iterator crs = crList.iterator();
721:                    while (crs.hasNext()) {
722:                        String crNum = ((String) crs.next()).trim();
723:                        CMSynergyModification.ChangeRequest cr = mod
724:                                .createChangeRequest(crNum);
725:                        if (changeSynergyURL != null && ccmDb != null) {
726:                            StringBuffer href = new StringBuffer(
727:                                    changeSynergyURL);
728:                            href
729:                                    .append("/servlet/com.continuus.webpt.servlet.PTweb?");
730:                            href
731:                                    .append("ACTION_FLAG=frameset_form&#38;TEMPLATE_FLAG=ProblemReportView&#38;database=");
732:                            href.append(ccmDb);
733:                            href.append("&#38;role=User&#38;problem_number=");
734:                            href.append(crNum);
735:                            cr.href = href.toString();
736:                        }
737:                    }
738:                }
739:            }
740:
741:            /**
742:             * Determine the work area location for the specified project.
743:             *
744:             * @return The work area location
745:             */
746:            private String getWorkarea() {
747:                String defaultWorkarea = ".";
748:
749:                // Get the literal workarea from Synergy
750:                cmd.clearArgs();
751:                cmd.createArgument("attribute");
752:                cmd.createArguments("-show", "wa_path");
753:                cmd.createArguments("-project", projectFourPartName);
754:
755:                try {
756:                    cmd.execute();
757:                    cmd.assertExitCode(0);
758:                } catch (Exception e) {
759:                    LOG.warn(
760:                            "Could not determine the workarea location for project \""
761:                                    + projectFourPartName + "\".", e);
762:                    return defaultWorkarea;
763:                }
764:
765:                // The command will return the literal work area, but what we are
766:                // really interested in is the top level directory within that work
767:                // area.
768:                File workareaPath = new File(cmd.getStdoutAsString().trim());
769:                if (!workareaPath.isDirectory()) {
770:                    LOG
771:                            .warn("The workarea reported by Synergy does not exist or is not accessible by this session - \""
772:                                    + workareaPath.toString() + "\".");
773:                    return defaultWorkarea;
774:                }
775:                String[] dirs = workareaPath.list();
776:                if (dirs.length != 1) {
777:                    LOG.warn("The workarea reported by Synergy is invalid - \""
778:                            + workareaPath.toString() + "\".");
779:                    return defaultWorkarea;
780:                }
781:
782:                // Found it!
783:                return workareaPath.getAbsolutePath() + File.separator
784:                        + dirs[0];
785:            }
786:
787:            /**
788:             * Reconfigure the project
789:             */
790:            private void reconfigureProject() {
791:                LOG.info("Reconfiguring project " + projectFourPartName + ".");
792:
793:                // Construct the CM Synergy command
794:                cmd.clearArgs();
795:                cmd.createArgument("reconfigure");
796:                if (recurse) {
797:                    cmd.createArgument("-recurse");
798:                }
799:                cmd.createArguments("-project", projectFourPartName);
800:
801:                try {
802:                    cmd.execute();
803:                    cmd.assertExitCode(0);
804:                } catch (Exception e) {
805:                    LOG.warn("Could not reconfigure project \""
806:                            + projectFourPartName + "\".", e);
807:                }
808:            }
809:
810:            /**
811:             * Format the output of a CM Synergy query by removing newlines introduced
812:             * by comments.
813:             *
814:             * @param in
815:             *            The <code>List</code> to be formated
816:             * @return The formated <code>List</code>
817:             */
818:            private List format(List in) {
819:                // Concatenate output lines until we hit the end of object delimiter.
820:                List out = new ArrayList();
821:                Iterator it = in.iterator();
822:                StringBuffer buff = new StringBuffer();
823:                while (it.hasNext()) {
824:                    buff.append((String) it.next());
825:                    int index = buff.toString().lastIndexOf(CCM_END_OBJECT);
826:                    if (index > -1) {
827:                        buff.delete(index, buff.length());
828:                        out.add(buff.toString());
829:                        buff = new StringBuffer();
830:                    }
831:                }
832:                return out;
833:            }
834:
835:            /**
836:             * Parse a CM Synergy date string into a Java <code>Date</code>. If the
837:             * string cannot be parsed, a warning is written to the log, and the current
838:             * date is returned.
839:             *
840:             * @param dateString
841:             *            the date string to parse
842:             * @return The date
843:             *
844:             * @see #setCcmDateFormat(String)
845:             */
846:            private Date getDateFromSynergy(String dateString) {
847:                SimpleDateFormat fromCcmDate = new SimpleDateFormat(
848:                        ccmDateFormat, locale);
849:                Date date;
850:                try {
851:                    date = fromCcmDate.parse(dateString);
852:                } catch (ParseException e) {
853:                    LOG.warn("Could not parse CM Synergy date \"" + dateString
854:                            + "\" into Java Date using format \""
855:                            + ccmDateFormat + "\".", e);
856:                    date = new Date();
857:                }
858:                return date;
859:            }
860:
861:            /**
862:             * Given a CM Synergy session name, looks up the corresponding session ID.
863:             *
864:             * @param sessionName
865:             *            The CM Synergy session name
866:             * @param sessionFile
867:             *            The session map file
868:             * @return The session ID.
869:             */
870:            public static String getSessionID(String sessionName,
871:                    File sessionFile) throws CruiseControlException {
872:
873:                // If no session file was provided, try to use the default
874:                if (sessionFile == null) {
875:                    sessionFile = new File(CCM_SESSION_FILE);
876:                }
877:
878:                // Load the persisted session information from file
879:                Properties sessionProperties;
880:                try {
881:                    sessionProperties = Util
882:                            .loadPropertiesFromFile(sessionFile);
883:                } catch (IOException e) {
884:                    throw new CruiseControlException(e);
885:                }
886:
887:                // Look up and return the full session ID
888:                return sessionProperties.getProperty(sessionName);
889:            }
890:
891:            /**
892:             * Creates a <code>ManagedCommandline</code> configured to run CM Synergy
893:             * commands.
894:             *
895:             * @param ccmExe
896:             *            Full path of the CM Synergy command line client (or
897:             *            <code>null</code> to use the default).
898:             * @param sessionName
899:             *            The name of the session as stored in the map file (or
900:             *            <code>null</code> to use the default session).
901:             * @param sessionFile
902:             *            The CM Synergy session map file (or <code>null</code> to use
903:             *            the default).
904:             * @return A configured <code>ManagedCommandline</code>
905:             */
906:            public static ManagedCommandline createCcmCommand(String ccmExe,
907:                    String sessionName, File sessionFile) {
908:
909:                // If no executable name was provided, use the default
910:                if (ccmExe == null) {
911:                    ccmExe = CCM_EXE;
912:                }
913:
914:                // Attempt to get the appropriate CM Synergy session
915:                String sessionID = null;
916:                if (sessionName != null) {
917:                    try {
918:                        sessionID = getSessionID(sessionName, sessionFile);
919:                        if (sessionID == null) {
920:                            LOG
921:                                    .error("Could not find a session ID for CM Synergy session named \""
922:                                            + sessionName
923:                                            + "\". Attempting to use the default (current) session.");
924:                        }
925:                    } catch (CruiseControlException e) {
926:                        LOG
927:                                .error(
928:                                        "Failed to look up CM Synergy session named \""
929:                                                + sessionName
930:                                                + "\". Attempting to use the default (current) session.",
931:                                        e);
932:                    }
933:                }
934:
935:                // Create a managed command line
936:                ManagedCommandline command = new ManagedCommandline(ccmExe);
937:
938:                // If we were able to find a CM Synergy session ID, use it
939:                if (sessionID != null) {
940:                    command.setVariable(CCM_SESSION_VAR, sessionID);
941:                }
942:
943:                return command;
944:            }
945:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.