KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > listeners > CMSynergySessionMonitor


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.listeners;
38
39 import java.io.File JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.util.ArrayList JavaDoc;
42 import java.util.Iterator JavaDoc;
43 import java.util.List JavaDoc;
44 import java.util.Properties JavaDoc;
45
46 import org.apache.log4j.Logger;
47
48 import net.sourceforge.cruisecontrol.CruiseControlException;
49 import net.sourceforge.cruisecontrol.Listener;
50 import net.sourceforge.cruisecontrol.ProjectEvent;
51 import net.sourceforge.cruisecontrol.ProjectState;
52 import net.sourceforge.cruisecontrol.sourcecontrols.CMSynergy;
53 import net.sourceforge.cruisecontrol.util.ManagedCommandline;
54 import net.sourceforge.cruisecontrol.util.Util;
55 import net.sourceforge.cruisecontrol.util.ValidationHelper;
56
57 /**
58  * Monitors a set of one or more CM Synergy sessions, launching new sessions as
59  * needed. The session information is persisted and made available to other CM
60  * Synergy plugins through the session file - a simple properties file which
61  * maps a session name to a CM Synergy session ID.
62  *
63  * @author <a HREF="mailto:rjmpsmith@gmail.com">Robert J. Smith </a>
64  */

65 public class CMSynergySessionMonitor implements Listener {
66     
67     private static final Logger LOG = Logger
68             .getLogger(CMSynergySessionMonitor.class);
69
70     private File JavaDoc sessionFile;
71     private String JavaDoc ccmExe = CMSynergy.CCM_EXE;
72     private ArrayList JavaDoc sessions = new ArrayList JavaDoc();
73
74     /**
75      * Sets the name of the CM Synergy executable to use when issuing commands.
76      *
77      * @param ccmExe
78      * the name of the CM Synergy executable
79      */

80     public void setCcmExe(String JavaDoc ccmExe) {
81         this.ccmExe = ccmExe;
82     }
83
84     /**
85      * Sets the file which contains the mapping between CM Synergy session names
86      * and IDs. This file should be in the standard properties file format. Each
87      * line should map one name to a CM Synergy session ID (as returned by the
88      * "ccm status" command).
89      * <p>
90      * example: <br>
91      * <br>
92      * session1=localhost:65024:192.168.1.17
93      *
94      * @param sessionFile
95      * The session file
96      */

97     public void setSessionFile(String JavaDoc sessionFile) {
98         this.sessionFile = new File JavaDoc(sessionFile);
99     }
100
101     /**
102      * Creates a new <code>CMSynergySession</code> object and adds it to our
103      * list of monitored sessions.
104      *
105      * @return The newly created <code>CMSynergySession</code> object.
106      */

107     public CMSynergySession createSession() {
108         CMSynergySession session = new CMSynergySession();
109         sessions.add(session);
110         return session;
111     }
112
113     /**
114      * A simple representation of a CM Synergy commandline session
115      *
116      * @author <a HREF="mailto:rjmpsmith@hotmail.com">Robert J. Smith</a>
117      */

118     public class CMSynergySession {
119                 
120         private String JavaDoc name;
121         private String JavaDoc db;
122         private String JavaDoc role;
123         private String JavaDoc user;
124         private String JavaDoc password;
125         private String JavaDoc host;
126         
127         /**
128          * Gets the given name of the session.
129          *
130          * @return The name.
131          */

132         public String JavaDoc getName() {
133             return name;
134         }
135  
136         /**
137          * Sets the name of the session as it will be referenced in the
138          * Cruise Control config file
139          *
140          * @param name The session's given name.
141          */

142         public void setName(String JavaDoc name) {
143             this.name = name;
144         }
145
146         /**
147          * Gets the password used to start the session.
148          *
149          * @return The password.
150          */

151         public String JavaDoc getPassword() {
152             return password;
153         }
154
155         /**
156          * Sets the password which will be used to start the session.
157          *
158          * @param password The password.
159          */

160         public void setPassword(String JavaDoc password) {
161             this.password = password;
162         }
163
164         /**
165          * Gets the CM Synergy role under which the session was started.
166          *
167          * @return The role.
168          */

169         public String JavaDoc getRole() {
170             return role;
171         }
172
173         /**
174          * Sets the CM Synergy role under which the session will be started.
175          *
176          * @param role The role.
177          */

178         public void setRole(String JavaDoc role) {
179             this.role = role;
180         }
181
182         /**
183          * Gets the user ID under which the session was started.
184          *
185          * @return The user ID.
186          */

187         public String JavaDoc getUser() {
188             return user;
189         }
190
191         /**
192          * Sets the user ID under which the session will be started.
193          *
194          * @param user The user ID.
195          */

196         public void setUser(String JavaDoc user) {
197             this.user = user;
198         }
199         
200         /**
201          * Gets the CM Synergy database with which the session is associated
202          *
203          * @return The database.
204          */

205         public String JavaDoc getDatabase() {
206             return db;
207         }
208
209         /**
210          * Sets the CM Synergy database with which the session will be
211          * associated
212          *
213          * @param db The database.
214          */

215         public void setDatabase(String JavaDoc db) {
216             this.db = db;
217         }
218         
219         /**
220          * Gets the host upon which the session is running.
221          *
222          * @return The host.
223          */

224         public String JavaDoc getHost() {
225             return host;
226         }
227         
228         /**
229          * Sets the host upon which the session will run.
230          *
231          * @param host The host.
232          */

233         public void setHost(String JavaDoc host) {
234             this.host = host;
235         }
236
237         /**
238          * Sets the attribute (properties) file from which the session
239          * information will be loaded.
240          *
241          * @param attributeFile
242          * The file from which to read our session attributes.
243          */

244         public void setAttributeFile(String JavaDoc attributeFile) {
245             try {
246                 Properties JavaDoc properties = Util.loadPropertiesFromFile(new File JavaDoc(
247                         attributeFile));
248                 db = properties.getProperty("database");
249                 role = properties.getProperty("role");
250                 user = properties.getProperty("user");
251                 password = properties.getProperty("password");
252                 host = properties.getProperty("host");
253             } catch (Exception JavaDoc e) {
254                 LOG.error(
255                         "Could not load CM Synergy session properties from file \""
256                                 + attributeFile + "\".", e);
257             }
258         }
259
260         /**
261          * Validates the fields of this object.
262          *
263          * @throws CruiseControlException
264          */

265         public void validate() throws CruiseControlException {
266             ValidationHelper.assertIsSet(name, "name", "the <session> child element");
267             ValidationHelper.assertIsSet(db, "db", "the <session> child element");
268             ValidationHelper.assertIsSet(role, "role", "the <session> child element");
269             ValidationHelper.assertIsSet(user, "user", "the <session> child element");
270             ValidationHelper.assertIsSet(password, "password", "the <session> child element");
271         }
272     }
273
274     /**
275      * Checks the given session file. If it is does not exist, it is created.
276      * This method is synchronized to prevent multiple threads from attempting
277      * to create the same file.
278      *
279      * @param sessionFile
280      * The session file to check
281      *
282      * @throws CruiseControlException
283      */

284     private static synchronized void checkSessionFile(File JavaDoc sessionFile) throws CruiseControlException {
285         // Create the session file if it does not already exist
286
if (!sessionFile.exists()) {
287             try {
288                 if (sessionFile.createNewFile()) {
289                     LOG.info("Created CM Synergy session file at "
290                             + sessionFile.getAbsolutePath());
291                 }
292             } catch (IOException JavaDoc e) {
293                 throw new CruiseControlException(
294                         "Could not create CM Synergy session file at "
295                                 + sessionFile.getAbsolutePath(), e);
296             }
297         }
298         
299         // Make certain that it's writable
300
if (!sessionFile.canWrite()) {
301             throw new CruiseControlException("Session file \""
302                     + sessionFile.getAbsolutePath()
303                     + "\" does not exist, or is not writable.");
304         }
305     }
306
307     /**
308      * Checks that all named sessions given to the listener are still running
309      * (and accessible). If they are not, new sessions are started as needed.
310      * This method is synchronized to prevent multiple threads from each
311      * starting their own CM Synergy sessions.
312      *
313      * @param ccmExe
314      * The CM Synergy command line executable
315      * @param sessionFile
316      * The CM Synergy session map file
317      * @param sessions
318      * A list of monitored CM Synergy sessions
319      *
320      * @throws CruiseControlException
321      */

322     private static synchronized void checkSessions(String JavaDoc ccmExe,
323             File JavaDoc sessionFile, List JavaDoc sessions) throws CruiseControlException {
324         LOG.debug("Using persisted data from " + sessionFile.getAbsolutePath());
325
326         // Load the persisted session information from file
327
Properties JavaDoc sessionMap;
328         try {
329             sessionMap = Util.loadPropertiesFromFile(sessionFile);
330         } catch (IOException JavaDoc e) {
331             throw new CruiseControlException(e);
332         }
333
334         // Get a list of currently running CM Synergy sessions
335
ManagedCommandline cmd = new ManagedCommandline(ccmExe);
336         cmd.createArgument().setValue("status");
337         String JavaDoc availableSessions;
338         try {
339             cmd.execute();
340             cmd.assertExitCode(0);
341             availableSessions = cmd.getStdoutAsString();
342         } catch (Exception JavaDoc e) {
343             LOG.warn("CM Synergy failed to provide a list of valid sessions.",
344                     e);
345             availableSessions = "";
346         }
347
348         // Check each monitored session in turn
349
for (Iterator JavaDoc it = sessions.iterator(); it.hasNext();) {
350             CMSynergySession session = (CMSynergySession) it.next();
351             String JavaDoc name = session.getName();
352             String JavaDoc id = sessionMap.getProperty(name);
353             LOG.info("Checking " + name + ".");
354             if (id == null || availableSessions.indexOf(id) < 0) {
355                 // Start a new session and record the ID in the map
356
String JavaDoc newID = startSession(ccmExe, session);
357                 if (newID != null) {
358                     LOG.info("Started CM Synergy session \"" + newID + "\".");
359                     sessionMap.setProperty(name, newID);
360                 }
361             } else {
362                 LOG.info("Using existing session \"" + id + "\".");
363             }
364         }
365
366         // Update the persisted session information
367
try {
368             Util.storePropertiesToFile(sessionMap, "CM Synergy session map",
369                     sessionFile);
370         } catch (IOException JavaDoc e) {
371             throw new CruiseControlException(e);
372         }
373     }
374
375     /**
376      * Launches a new CM Synergy command line session
377      *
378      * @param session
379      * The session information
380      */

381     private static String JavaDoc startSession(String JavaDoc ccmExe, CMSynergySession session) {
382         
383         LOG.info("Starting a new CM Synergy session for \"" + session.getName()
384                 + "\".");
385
386         // Create CM Synergy startup command
387
ManagedCommandline cmd = new ManagedCommandline(ccmExe);
388         cmd.createArgument().setValue("start");
389         cmd.createArgument().setValue("-q");
390         cmd.createArgument().setValue("-nogui");
391         cmd.createArgument().setValue("-m");
392         cmd.createArgument().setValue("-d");
393         cmd.createArgument().setValue(session.getDatabase());
394         cmd.createArgument().setValue("-r");
395         cmd.createArgument().setValue(session.getRole());
396         cmd.createArgument().setValue("-n");
397         cmd.createArgument().setValue(session.getUser());
398         cmd.createArgument().setValue("-pw");
399         cmd.createArgument().setValue(session.getPassword());
400         if (session.getHost() != null) {
401             cmd.createArgument().setValue("-h");
402             cmd.createArgument().setValue(session.getHost());
403         }
404
405         try {
406             cmd.execute();
407             cmd.assertExitCode(0);
408         } catch (Exception JavaDoc e) {
409             LOG.error("Could not start a CM Synergy session for "
410                     + session.getName(), e);
411             return null;
412         }
413
414         return cmd.getStdoutAsString().trim();
415     }
416         
417     /*
418      * (non-Javadoc)
419      *
420      * @see net.sourceforge.cruisecontrol.Listener#handleEvent(net.sourceforge.cruisecontrol.ProjectEvent)
421      */

422     public void handleEvent(ProjectEvent event) throws CruiseControlException {
423         if (event instanceof ProjectStateChangedEvent) {
424             final ProjectStateChangedEvent stateChanged = (ProjectStateChangedEvent) event;
425             // Check sessions before the bootstrappers run
426
if (stateChanged.getNewState().getCode() == ProjectState.BOOTSTRAPPING
427                     .getCode()) {
428                 checkSessionFile(sessionFile);
429                 checkSessions(ccmExe, sessionFile, sessions);
430             }
431         }
432     }
433
434     /* (non-Javadoc)
435      * @see net.sourceforge.cruisecontrol.Listener#validate()
436      */

437     public void validate() throws CruiseControlException {
438         // We must have at least one session to monitor
439
ValidationHelper.assertTrue(sessions.size() > 0,
440             "You must provide at least one nested <session> element.");
441
442         // Validate the details of each provided session
443
for (Iterator JavaDoc it = sessions.iterator(); it.hasNext(); ) {
444             CMSynergySession session = (CMSynergySession) it.next();
445             session.validate();
446         }
447
448         // If no session file was provided, use the default
449
if (sessionFile == null) {
450             sessionFile = new File JavaDoc(CMSynergy.CCM_SESSION_FILE);
451         }
452     }
453
454 }
455
Popular Tags