Source Code Cross Referenced for BuildAgent.java in  » Build » cruisecontrol » net » sourceforge » cruisecontrol » distributed » 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.distributed 
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.distributed;
037:
038:        import java.io.IOException;
039:        import java.net.URL;
040:        import java.net.MalformedURLException;
041:        import java.rmi.Remote;
042:        import java.rmi.RemoteException;
043:        import java.rmi.server.ExportException;
044:        import java.util.prefs.Preferences;
045:        import java.util.prefs.BackingStoreException;
046:        import java.util.Iterator;
047:        import java.util.Properties;
048:        import java.util.Arrays;
049:        import java.util.List;
050:        import java.util.ArrayList;
051:        import java.util.Enumeration;
052:        import java.awt.GraphicsEnvironment;
053:
054:        import net.jini.core.lookup.ServiceID;
055:        import net.jini.core.lookup.ServiceRegistrar;
056:        import net.jini.core.discovery.LookupLocator;
057:        import net.jini.discovery.DiscoveryEvent;
058:        import net.jini.discovery.DiscoveryListener;
059:        import net.jini.discovery.LookupLocatorDiscovery;
060:        import net.jini.lookup.ServiceIDListener;
061:        import net.jini.lookup.JoinManager;
062:        import net.jini.export.Exporter;
063:        import net.jini.jeri.BasicILFactory;
064:        import net.jini.jeri.BasicJeriExporter;
065:        import net.jini.jeri.tcp.TcpServerEndpoint;
066:        import net.sourceforge.cruisecontrol.distributed.core.PropertiesHelper;
067:        import net.sourceforge.cruisecontrol.distributed.core.ReggieUtil;
068:        import net.sourceforge.cruisecontrol.distributed.core.CCDistVersion;
069:        import net.sourceforge.cruisecontrol.util.MainArgs;
070:
071:        import org.apache.log4j.Logger;
072:
073:        public class BuildAgent implements  DiscoveryListener, ServiceIDListener {
074:
075:            static final String MAIN_ARG_AGENT_PROPS = "agentprops";
076:            static final String MAIN_ARG_USER_PROPS = "userprops";
077:            static final String MAIN_ARG_SKIP_UI = "skipUI";
078:
079:            // package visible to allow BuildAgentUI console logger access to this Logger
080:            static final Logger LOG = Logger.getLogger(BuildAgent.class);
081:
082:            public static final String JAVA_SECURITY_POLICY = "java.security.policy";
083:            private static final String JINI_POLICY_FILE = "jini.policy.file";
084:
085:            /** Optional unicast Lookup Registry URL.
086:             * A Unicast Lookup Locater is useful if multicast isn't working. */
087:            private static final String REGISTRY_URL = "registry.url";
088:
089:            private final BuildAgentServiceImpl serviceImpl;
090:            private final PropertyEntry[] origEntries;
091:            private final Exporter exporter;
092:            private final JoinManager joinManager;
093:            private ServiceID serviceID;
094:            private final Remote proxy;
095:
096:            private Properties entryProperties;
097:            private Properties configProperties;
098:
099:            private final BuildAgentUI ui;
100:
101:            static interface LUSCountListener {
102:                public void lusCountChanged(final int newLUSCount);
103:            }
104:
105:            private final List lusCountListeners = new ArrayList();
106:
107:            void addLUSCountListener(final LUSCountListener listener) {
108:                lusCountListeners.add(listener);
109:            }
110:
111:            void removeLUSCountListener(final LUSCountListener listener) {
112:                lusCountListeners.remove(listener);
113:            }
114:
115:            private int registrarCount = 0;
116:
117:            private void fireLUSCountChanged() {
118:                for (int i = 0; i < lusCountListeners.size(); i++) {
119:                    ((LUSCountListener) lusCountListeners.get(i))
120:                            .lusCountChanged(registrarCount);
121:                }
122:            }
123:
124:            private void setRegCount(final int regCount) {
125:                registrarCount = regCount;
126:                LOG.info("Lookup Services found: " + registrarCount);
127:                fireLUSCountChanged();
128:            }
129:
130:            /** Only used for unit testing. */
131:            private final int testAgentID;
132:            /** Only used for unit testing. */
133:            private final ServiceIDListener testListener;
134:
135:            /**
136:             * @param propsFile the agent properties file
137:             * @param userDefinedPropertiesFilename the user defined properties file
138:             * @param isSkipUI if true, do not show the build agent UI.
139:             */
140:            private BuildAgent(final String propsFile,
141:                    final String userDefinedPropertiesFilename,
142:                    final boolean isSkipUI) {
143:
144:                this (propsFile, userDefinedPropertiesFilename, isSkipUI, null,
145:                        0);
146:            }
147:
148:            /**
149:             * This constructor only intended for unit tests.
150:             * @param propsFile the agent properties file
151:             * @param userDefinedPropertiesFilename the user defined properties file
152:             * @param isSkipUI if true, do not show the build agent UI.
153:             * @param testListener only used for unit testing.
154:             * @param testAgentID only used for unit testing.
155:             */
156:            BuildAgent(final String propsFile,
157:                    final String userDefinedPropertiesFilename,
158:                    final boolean isSkipUI,
159:                    final ServiceIDListener testListener, final int testAgentID) {
160:
161:                // for unit testing only
162:                this .testAgentID = testAgentID;
163:                // for unit testing only
164:                this .testListener = testListener;
165:
166:                loadProperties(propsFile, userDefinedPropertiesFilename);
167:
168:                serviceImpl = new BuildAgentServiceImpl(this );
169:                serviceImpl.setAgentPropertiesFilename(propsFile);
170:
171:                origEntries = SearchablePropertyEntries
172:                        .getPropertiesAsEntryArray(entryProperties);
173:                if (!isSkipUI && !GraphicsEnvironment.isHeadless()) {
174:                    LOG.info("Loading Build Agent UI (use param -"
175:                            + MAIN_ARG_SKIP_UI + " to bypass).");
176:                    ui = new BuildAgentUI(this );
177:                    //ui.updateAgentInfoUI(getService());
178:                } else {
179:                    LOG.info("Bypassing Build Agent UI (headless).");
180:                    ui = null;
181:                }
182:
183:                exporter = new BasicJeriExporter(TcpServerEndpoint
184:                        .getInstance(0), new BasicILFactory(), false, true);
185:
186:                try {
187:                    proxy = exporter.export(getService());
188:                } catch (ExportException e) {
189:                    final String message = "Error exporting service";
190:                    LOG.error(message, e);
191:                    throw new RuntimeException(message, e);
192:                }
193:
194:                // Use a comma separated list of Unicast Lookup Locaters (URL's) if defined in agent.properties. 
195:                // Useful if multicast isn't working.
196:                final String registryURLList = configProperties
197:                        .getProperty(REGISTRY_URL);
198:                final LookupLocatorDiscovery lld;
199:                if (registryURLList == null) {
200:                    lld = null;
201:                } else {
202:                    lld = new LookupLocatorDiscovery(
203:                            parseUnicastLocators(registryURLList));
204:                }
205:
206:                try {
207:                    if (serviceID == null) {
208:                        joinManager = new JoinManager(getProxy(), getEntries(),
209:                                this , lld, null);
210:                    } else {
211:                        LOG
212:                                .warn("Didn't expect to have a serviceID: "
213:                                        + serviceID
214:                                        + " (agentID: "
215:                                        + testAgentID
216:                                        + "). Are we storing and re-using the serviceID now?");
217:                        joinManager = new JoinManager(getProxy(), getEntries(),
218:                                serviceID, lld, null);
219:                    }
220:                } catch (IOException e) {
221:                    final String message = "Error starting discovery";
222:                    LOG.error(message, e);
223:                    throw new RuntimeException(message, e);
224:                }
225:
226:                getJoinManager().getDiscoveryManager().addDiscoveryListener(
227:                        this );
228:            }
229:
230:            /**
231:             * Parses a comma separated list of Unicast Lookup Locaters (URL's).
232:             * Useful if multicast isn't working.
233:             * @param registryURLList a comma separated list of Unicast Lookup Locaters (URL's).
234:             * @return null if the given registryURLList is null, or a LookupLocator array populated with the given URL's.
235:             */
236:            private static LookupLocator[] parseUnicastLocators(
237:                    String registryURLList) {
238:                final LookupLocator[] lookups;
239:                if (registryURLList == null) {
240:                    lookups = null;
241:                } else {
242:                    final String[] registryURLs = registryURLList.split(",");
243:                    lookups = new LookupLocator[registryURLs.length];
244:                    for (int i = 0; i < registryURLs.length; i++) {
245:                        try {
246:                            lookups[i] = new LookupLocator(registryURLs[i]);
247:                        } catch (MalformedURLException e) {
248:                            final String message = "Error creating unicast lookup locator: "
249:                                    + registryURLs[i] + "; " + e.getMessage();
250:                            LOG.error(message, e);
251:                            throw new RuntimeException(message, e);
252:                        }
253:                        LOG.info("Using Unicast LookupLocator URL: "
254:                                + registryURLs[i]);
255:                    }
256:                }
257:                return lookups;
258:            }
259:
260:            private final Preferences prefsBase = Preferences
261:                    .userNodeForPackage(this .getClass());
262:
263:            Preferences getPrefsRoot() {
264:                return prefsBase;
265:            }
266:
267:            /**
268:             * Gets the EntryOverrides preferences node this this user, shared among all BuildAgents running
269:             * under this userID on the current machine.
270:             * @todo Should this node be more granular, like per Agent ServiceID? if so we must store/resuse serviceID
271:             */
272:            private final Preferences prefsEntryOverrides = prefsBase
273:                    .node("entryOverrides");
274:
275:            void setEntryOverrides(final PropertyEntry[] entryOverrides) {
276:                // clear stored override preferences settings
277:                clearOverridePrefs();
278:
279:                // store override props using Preferences api
280:                for (int i = 0; i < entryOverrides.length; i++) {
281:                    prefsEntryOverrides.put(entryOverrides[i].name,
282:                            entryOverrides[i].value);
283:                }
284:
285:                // publish using entries reloaded via getEntries, which adds entry overrides from prefs
286:                joinManager.setAttributes(getEntries());
287:            }
288:
289:            void clearEntryOverrides() {
290:
291:                // clear stored override preferences settings
292:                clearOverridePrefs();
293:
294:                // publish using entries reloaded via getEntries, which adds entry overrides from prefs
295:                joinManager.setAttributes(getEntries());
296:            }
297:
298:            private void clearOverridePrefs() {
299:                // clear stored override preferences settings
300:                try {
301:                    prefsEntryOverrides.clear();
302:                } catch (BackingStoreException e) {
303:                    LOG.error("Error clearing entry override prefs.", e);
304:                    throw new RuntimeException(e);
305:                }
306:            }
307:
308:            private Properties getEntryOverrideProps() {
309:                // check for entry overrides in preferences
310:                final String[] overrideKeys;
311:                try {
312:                    overrideKeys = prefsEntryOverrides.keys();
313:                } catch (BackingStoreException e) {
314:                    LOG.error("Error reading entry override prefs keys.", e);
315:                    throw new RuntimeException(e);
316:                }
317:                final Properties overrideEntryProps = new Properties();
318:                if (overrideKeys.length > 0) {
319:                    String key;
320:                    for (int i = 0; i < overrideKeys.length; i++) {
321:                        key = overrideKeys[i];
322:                        overrideEntryProps.put(key, prefsEntryOverrides.get(
323:                                key, "unknown value"));
324:                    }
325:                }
326:                return overrideEntryProps;
327:            }
328:
329:            PropertyEntry[] getEntryOverrides() {
330:                return SearchablePropertyEntries
331:                        .getPropertiesAsEntryArray(getEntryOverrideProps());
332:            }
333:
334:            /**
335:             * @param propsFile path to config properties file
336:             * @param userDefinedPropertiesFilename path to user properties file
337:             */
338:            private void loadProperties(final String propsFile,
339:                    final String userDefinedPropertiesFilename) {
340:                configProperties = (Properties) PropertiesHelper
341:                        .loadRequiredProperties(propsFile);
342:                entryProperties = new SearchablePropertyEntries(
343:                        userDefinedPropertiesFilename).getProperties();
344:
345:                final String policyFileValue = configProperties
346:                        .getProperty(JINI_POLICY_FILE);
347:                LOG.info("policyFileValue: " + policyFileValue);
348:
349:                // resource loading technique below dies in webstart
350:                //URL policyFile = ClassLoader.getSystemClassLoader().getResource(policyFileValue);
351:                final URL policyFile = BuildAgent.class.getClassLoader()
352:                        .getResource(policyFileValue);
353:                LOG.info("policyFile: " + policyFile);
354:                System.setProperty(JAVA_SECURITY_POLICY, policyFile
355:                        .toExternalForm());
356:                ReggieUtil.setupRMISecurityManager();
357:            }
358:
359:            private Exporter getExporter() {
360:                return exporter;
361:            }
362:
363:            private JoinManager getJoinManager() {
364:                return joinManager;
365:            }
366:
367:            PropertyEntry[] getEntries() {
368:
369:                final PropertyEntry[] currentEntries;
370:                final Properties entryOverrideProps = getEntryOverrideProps();
371:                if (entryOverrideProps.size() > 0) {
372:                    // add system entries first (preserves order)
373:                    final Properties systemEntryProps = SearchablePropertyEntries
374:                            .getSystemEntryProps();
375:                    // use a props object to enforce precendence of overrides over original settings
376:                    final Properties allEntries = new Properties();
377:                    allEntries.putAll(systemEntryProps);
378:                    // add props loaded from user-defined.properties file
379:                    allEntries.putAll(entryProperties);
380:                    // now add override entries that do NOT step on system entries
381:                    String key;
382:                    String value;
383:                    final Enumeration enm = entryOverrideProps.keys();
384:                    while (enm.hasMoreElements()) {
385:                        key = (String) enm.nextElement();
386:                        value = (String) entryOverrideProps.get(key);
387:                        // don't allow override of system entry props
388:                        if (!systemEntryProps.containsKey(key)) {
389:                            allEntries.put(key, value);
390:                        } else {
391:                            LOG.warn("WARNING: Can't override system entry: "
392:                                    + key + "=" + systemEntryProps.get(key)
393:                                    + " with new value: " + value);
394:                        }
395:                    }
396:
397:                    // add to original entries
398:                    currentEntries = SearchablePropertyEntries
399:                            .getPropertiesAsEntryArray(allEntries);
400:                } else {
401:                    // use original props file entries
402:                    currentEntries = origEntries;
403:                }
404:                return currentEntries;
405:            }
406:
407:            void addAgentStatusListener(
408:                    final BuildAgent.AgentStatusListener listener) {
409:                serviceImpl.addAgentStatusListener(listener);
410:            }
411:
412:            void removeAgentStatusListener(
413:                    final BuildAgent.AgentStatusListener listener) {
414:                serviceImpl.removeAgentStatusListener(listener);
415:            }
416:
417:            /** Only for unit testing. */
418:            private static boolean isTerminateFast;
419:
420:            /** Only for unit testing. */
421:            static void setTerminateFast() {
422:                isTerminateFast = true;
423:            }
424:
425:            /** Only for unit testing.
426:             * @param agent the unit test agent to terminate.
427:             */
428:            void terminateTestAgent(final BuildAgent agent) {
429:                LOG.info("Terminating test agent (agentID: "
430:                        + agent.testAgentID + ")");
431:                agent.terminate();
432:                if (agent.testAgentID == 0) {
433:                    throw new IllegalStateException(
434:                            "This does not appear to be a unit test Agent, agentID: "
435:                                    + agent.testAgentID);
436:                }
437:            }
438:
439:            private void terminate() {
440:                LOG.info("Terminating build agent.");
441:                int unexportAttempts = 0;
442:                while (!getExporter().unexport(false) && unexportAttempts < 10) {
443:                    // wait a bit
444:                    try {
445:                        Thread.sleep(500);
446:                    } catch (InterruptedException e) {
447:                        LOG.warn("Sleep interrupted during terminate.unexport",
448:                                e);
449:                    }
450:                    unexportAttempts++;
451:                }
452:                if (!getExporter().unexport(false)) {
453:                    LOG
454:                            .warn("Unexport of Agent service failed. Forcing export.");
455:                    getExporter().unexport(true);
456:                }
457:                getJoinManager().terminate();
458:
459:                if (!isTerminateFast) {
460:                    // allow some time for cleanup
461:                    try {
462:                        Thread.sleep(2000);
463:                    } catch (InterruptedException e) {
464:                        LOG.warn("Sleep interrupted during terminate", e);
465:                    }
466:                }
467:
468:                if (ui != null) {
469:                    ui.dispose();
470:                    LOG.info("UI disposed");
471:                }
472:            }
473:
474:            private Remote getProxy() {
475:                return proxy;
476:            }
477:
478:            public BuildAgentService getService() {
479:                return serviceImpl;
480:            }
481:
482:            /** 
483:             * Called when the JoinManager gets a valid ServiceID from a lookup
484:             * service.
485:             *
486:             *@param serviceID  the service ID assigned by the lookup service.
487:             */
488:            public void serviceIDNotify(final ServiceID serviceID) {
489:                // @todo technically, should serviceID be stored permanently and reused?....
490:                this .serviceID = serviceID;
491:                LOG.info("ServiceID assigned: " + this .serviceID
492:                        + (testAgentID == 0 ? "" : " (agentID: " + testAgentID)
493:                        + ")");
494:                if (ui != null) {
495:                    ui.updateAgentInfoUI(getService());
496:                }
497:
498:                // for unit testing only
499:                if (testListener != null) {
500:                    testListener.serviceIDNotify(serviceID);
501:                }
502:            }
503:
504:            ServiceID getServiceID() {
505:                return serviceID;
506:            }
507:
508:            private void logRegistration(final ServiceRegistrar registrar) {
509:                String host = null;
510:                try {
511:                    host = registrar.getLocator().getHost();
512:                } catch (RemoteException e) {
513:                    LOG.warn("Failed to get registrar's hostname");
514:                }
515:                LOG.info("Registering BuildAgentService with Registrar: "
516:                        + host);
517:
518:                final String machineName = (String) entryProperties
519:                        .get(SearchablePropertyEntries.HOSTNAME);
520:                LOG.debug("Registered machineName: " + machineName);
521:
522:                LOG.debug("Entries: ");
523:                for (Iterator iter = entryProperties.keySet().iterator(); iter
524:                        .hasNext();) {
525:                    final String key = (String) iter.next();
526:                    LOG.debug("  " + key + " = " + entryProperties.get(key));
527:                }
528:            }
529:
530:            private boolean isNotFirstDiscovery;
531:
532:            public void discovered(final DiscoveryEvent evt) {
533:                final ServiceRegistrar[] registrarsArray = evt.getRegistrars();
534:                ServiceRegistrar registrar;
535:                for (int n = 0; n < registrarsArray.length; n++) {
536:                    registrar = registrarsArray[n];
537:                    logRegistration(registrar);
538:                    LOG.debug("Registered with registrar: "
539:                            + registrar.getServiceID());
540:                }
541:                if (!isNotFirstDiscovery) {
542:                    LOG.info("BuildAgentService open for business...");
543:                    isNotFirstDiscovery = true;
544:                }
545:
546:                setRegCount(getJoinManager().getDiscoveryManager()
547:                        .getRegistrars().length);
548:            }
549:
550:            public void discarded(final DiscoveryEvent evt) {
551:                final ServiceRegistrar[] registrarsArray = evt.getRegistrars();
552:                ServiceRegistrar registrar;
553:                for (int n = 0; n < registrarsArray.length; n++) {
554:                    registrar = registrarsArray[n];
555:                    LOG.debug("Discarded registrar: "
556:                            + registrar.getServiceID());
557:                }
558:
559:                setRegCount(getJoinManager().getDiscoveryManager()
560:                        .getRegistrars().length);
561:            }
562:
563:            private static final Object KEEP_ALIVE = new Object();
564:            private static Thread mainThread;
565:
566:            private static void setMainThread(final Thread newMainThread) {
567:                mainThread = newMainThread;
568:            }
569:
570:            static Thread getMainThread() {
571:                return mainThread;
572:            }
573:
574:            /** Intended only for unit tests to avoid killing the unit test VM. */
575:            private static boolean isSkipMainSystemExit;
576:
577:            static void setSkipMainSystemExit() {
578:                isSkipMainSystemExit = true;
579:            }
580:
581:            public static void main(final String[] args) {
582:
583:                setMainThread(Thread.currentThread());
584:
585:                LOG.info("Starting agent...args: "
586:                        + Arrays.asList(args).toString());
587:
588:                CCDistVersion.printCCDistVersion();
589:
590:                if (shouldPrintUsage(args)) {
591:                    printUsage();
592:                }
593:
594:                final BuildAgent buildAgent = new BuildAgent(
595:                        MainArgs
596:                                .parseArgument(
597:                                        args,
598:                                        MAIN_ARG_AGENT_PROPS,
599:                                        BuildAgentServiceImpl.DEFAULT_AGENT_PROPERTIES_FILE,
600:                                        BuildAgentServiceImpl.DEFAULT_AGENT_PROPERTIES_FILE),
601:
602:                        MainArgs
603:                                .parseArgument(
604:                                        args,
605:                                        MAIN_ARG_USER_PROPS,
606:                                        BuildAgentServiceImpl.DEFAULT_USER_DEFINED_PROPERTIES_FILE,
607:                                        BuildAgentServiceImpl.DEFAULT_USER_DEFINED_PROPERTIES_FILE),
608:
609:                        MainArgs.argumentPresent(args, MAIN_ARG_SKIP_UI));
610:
611:                // stay around forever
612:                synchronized (KEEP_ALIVE) {
613:                    try {
614:                        KEEP_ALIVE.wait();
615:                    } catch (InterruptedException e) {
616:                        LOG.info("Keep Alive wait interrupted", e);
617:                    } finally {
618:                        buildAgent.terminate();
619:                    }
620:                }
621:
622:                final String mainThreadName = Thread.currentThread().getName();
623:                LOG.info("Agent main thread (" + mainThreadName + ") exiting.");
624:                // don't call sys exit during unit tests
625:                if (!isSkipMainSystemExit) {
626:                    // on some JVM's (webstart - restart) the BuildAgent.kill() call doesn't return,
627:                    // so sys exit is also done here.            
628:                    LOG.info("Agent main thread (" + mainThreadName
629:                            + ") calling System.exit().");
630:                    System.exit(0);
631:                } else {
632:                    LOG
633:                            .debug("Agent main thread ("
634:                                    + mainThreadName
635:                                    + ") skipping System.exit(), only valid in unit tests.");
636:                }
637:            }
638:
639:            private static boolean shouldPrintUsage(String[] args) {
640:                return MainArgs.findIndex(args, "?") != MainArgs.NOT_FOUND
641:                        || MainArgs.findIndex(args, "help") != MainArgs.NOT_FOUND;
642:            }
643:
644:            private static void printUsage() {
645:                System.out.println("");
646:                System.out.println("Usage:");
647:                System.out.println("");
648:                System.out.println("Starts a distributed Build Agent");
649:                System.out.println("");
650:                System.out.println(BuildAgent.class.getName() + " [options]");
651:                System.out.println("");
652:                System.out.println("Build Agent options are:");
653:                System.out.println("");
654:                System.out.println("  -" + MAIN_ARG_AGENT_PROPS
655:                        + " file     agent properties file; default "
656:                        + BuildAgentServiceImpl.DEFAULT_AGENT_PROPERTIES_FILE);
657:                System.out
658:                        .println("  -"
659:                                + MAIN_ARG_USER_PROPS
660:                                + " file      user defined properties file; default "
661:                                + BuildAgentServiceImpl.DEFAULT_USER_DEFINED_PROPERTIES_FILE);
662:                System.out.println("  -" + MAIN_ARG_SKIP_UI
663:                        + "              run in headless mode");
664:                System.out
665:                        .println("  -? or -help          print this usage message");
666:                System.out.println("");
667:            }
668:
669:            public static void kill() {
670:                final Thread main = getMainThread();
671:                if (main != null) {
672:                    final String mainThreadName = main.getName();
673:                    main.interrupt();
674:                    LOG.info("Waiting for main thread (" + mainThreadName
675:                            + ") to finish.");
676:                    try {
677:                        main.join(30 * 1000);
678:                        //main.join();
679:                    } catch (InterruptedException e) {
680:                        LOG.error("Error while waiting for Agent thread ("
681:                                + mainThreadName + ") to die.", e);
682:                    }
683:                    if (main.isAlive()) {
684:                        main.interrupt(); // how can this happen?
685:                        LOG.error("Main thread (" + mainThreadName
686:                                + ") should have died.");
687:                    }
688:                    setMainThread(null);
689:                } else {
690:                    LOG
691:                            .info("WARNING: Kill called, MainThread is null. Doing nothing. Acceptable only in Unit Tests.");
692:                }
693:            }
694:
695:            static interface AgentStatusListener {
696:                public void statusChanged(
697:                        BuildAgentService buildAgentServiceImpl);
698:            }
699:
700:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.