1 37 38 package net.sourceforge.cruisecontrol.distributed; 39 40 import java.io.IOException ; 41 import java.net.URL ; 42 import java.net.MalformedURLException ; 43 import java.rmi.Remote ; 44 import java.rmi.RemoteException ; 45 import java.rmi.server.ExportException ; 46 import java.util.Iterator ; 47 import java.util.Properties ; 48 import java.util.Arrays ; 49 50 import net.jini.core.entry.Entry; 51 import net.jini.core.lookup.ServiceID; 52 import net.jini.core.lookup.ServiceRegistrar; 53 import net.jini.core.discovery.LookupLocator; 54 import net.jini.discovery.DiscoveryEvent; 55 import net.jini.discovery.DiscoveryListener; 56 import net.jini.discovery.LookupLocatorDiscovery; 57 import net.jini.lookup.ServiceIDListener; 58 import net.jini.lookup.JoinManager; 59 import net.jini.export.Exporter; 60 import net.jini.jeri.BasicILFactory; 61 import net.jini.jeri.BasicJeriExporter; 62 import net.jini.jeri.tcp.TcpServerEndpoint; 63 import net.sourceforge.cruisecontrol.distributed.util.PropertiesHelper; 64 import net.sourceforge.cruisecontrol.distributed.util.ReggieUtil; 65 66 import org.apache.log4j.Logger; 67 68 69 70 public class BuildAgent implements DiscoveryListener, 71 ServiceIDListener { 72 73 static final String MAIN_ARG_SKIP_UI = "-skipUI"; 74 75 static final Logger LOG = Logger.getLogger(BuildAgent.class); 77 78 public static final String JAVA_SECURITY_POLICY = "java.security.policy"; 79 public static final String JINI_POLICY_FILE = "jini.policy.file"; 80 81 83 public static final String REGISTRY_URL = "registry.url"; 84 85 private final BuildAgentServiceImpl serviceImpl; 86 private final Entry[] entries; 87 private final Exporter exporter; 88 private final JoinManager joinManager; 89 private ServiceID serviceID; 90 private final Remote proxy; 91 92 private Properties entryProperties; 93 private Properties configProperties; 94 95 private final BuildAgentUI ui; 96 97 private int registrarCount = 0; 98 private synchronized void incrementRegCount() { 99 registrarCount++; 100 } 101 private synchronized void decrementRegCount() { 102 registrarCount--; 103 } 104 private synchronized int getRegCount() { 105 return registrarCount; 106 } 107 108 public BuildAgent(final boolean isSkipUI) { 109 this(BuildAgentServiceImpl.DEFAULT_AGENT_PROPERTIES_FILE, 110 BuildAgentServiceImpl.DEFAULT_USER_DEFINED_PROPERTIES_FILE, 111 isSkipUI); 112 } 113 114 public BuildAgent(final String propsFile, final String userDefinedPropertiesFilename, 115 final boolean isSkipUI) { 116 loadProperties(propsFile, userDefinedPropertiesFilename); 117 118 serviceImpl = new BuildAgentServiceImpl(); 119 serviceImpl.setAgentPropertiesFilename(propsFile); 120 121 entries = SearchablePropertyEntries.getPropertiesAsEntryArray(entryProperties); 122 if (!isSkipUI) { 123 LOG.info("Loading Build Agent UI (use param " + MAIN_ARG_SKIP_UI + " to bypass)."); 124 ui = new BuildAgentUI(this); 125 } else { 127 LOG.info("Bypassing Build Agent UI."); 128 ui = null; 129 } 130 131 exporter = new BasicJeriExporter(TcpServerEndpoint.getInstance(0), 132 new BasicILFactory(), false, true); 133 134 try { 135 proxy = exporter.export(getService()); 136 } catch (ExportException e) { 137 final String message = "Error exporting service"; 138 LOG.error(message, e); 139 throw new RuntimeException (message, e); 140 } 141 142 final String registryURL = configProperties.getProperty(REGISTRY_URL); 147 final LookupLocatorDiscovery lld; 148 if (registryURL == null) { 149 lld = null; 150 } else { 151 final LookupLocator lookup; 152 try { 153 lookup = new LookupLocator(registryURL); 154 } catch (MalformedURLException e) { 155 final String message = "Error creating unicast lookup locator"; 156 LOG.error(message, e); 157 throw new RuntimeException (message, e); 158 } 159 final LookupLocator[] lookups = new LookupLocator[] { lookup }; 160 lld = new LookupLocatorDiscovery(lookups); 161 } 162 163 try { 164 joinManager = new JoinManager(getProxy(), entries, this, lld, null); 165 } catch (IOException e) { 166 final String message = "Error starting discovery"; 167 LOG.error(message, e); 168 throw new RuntimeException (message, e); 169 } 170 171 getJoinManager().getDiscoveryManager().addDiscoveryListener(this); 172 } 173 174 177 private void loadProperties(final String propsFile, final String userDefinedPropertiesFilename) { 178 configProperties = (Properties ) PropertiesHelper.loadRequiredProperties(propsFile); 179 entryProperties = new SearchablePropertyEntries(userDefinedPropertiesFilename).getProperties(); 180 181 final String policyFileValue = configProperties.getProperty(JINI_POLICY_FILE); 182 LOG.info("policyFileValue: " + policyFileValue); 183 184 final URL policyFile = BuildAgent.class.getClassLoader().getResource(policyFileValue); 187 LOG.info("policyFile: " + policyFile); 188 System.setProperty(JAVA_SECURITY_POLICY, policyFile.toExternalForm()); 189 ReggieUtil.setupRMISecurityManager(); 190 } 191 192 private Exporter getExporter() { 193 return exporter; 194 } 195 196 private JoinManager getJoinManager() { 197 return joinManager; 198 } 199 200 Entry[] getEntries() { 201 return entries; 202 } 203 204 void addAgentStatusListener(final BuildAgent.AgentStatusListener listener) { 205 serviceImpl.addAgentStatusListener(listener); 206 } 207 void removeAgentStatusListener(final BuildAgent.AgentStatusListener listener) { 208 serviceImpl.removeAgentStatusListener(listener); 209 } 210 211 public void terminate() { 212 LOG.info("Terminating build agent."); 213 getExporter().unexport(true); 214 getJoinManager().terminate(); 215 try { 217 Thread.sleep(2000); 218 } catch (InterruptedException e) { 219 LOG.warn("Sleep interrupted during terminate", e); 220 } 221 222 if (ui != null) { 223 ui.dispose(); 224 LOG.info("UI disposed"); 225 } 226 } 227 228 229 private Remote getProxy() { 230 return proxy; 231 } 232 233 234 public synchronized BuildAgentService getService() { 235 return serviceImpl; 236 } 237 238 239 public synchronized void serviceIDNotify(final ServiceID serviceID) { 240 this.serviceID = serviceID; 242 LOG.info("ServiceID assigned: " + this.serviceID); 243 if (ui != null) { 244 ui.updateAgentInfoUI(getService()); 245 } 246 } 247 synchronized ServiceID getServiceID() { 248 return serviceID; 249 } 250 251 252 private void logRegistration(final ServiceRegistrar registrar) { 253 String host = null; 254 try { 255 host = registrar.getLocator().getHost(); 256 } catch (RemoteException e) { 257 LOG.warn("Failed to get registrar's hostname"); 258 } 259 LOG.info("Registering BuildAgentService with Registrar: " + host); 260 261 final String machineName = (String ) entryProperties.get("hostname"); 262 LOG.debug("Registered machineName: " + machineName); 263 264 LOG.debug("Entries: "); 265 for (Iterator iter = entryProperties.keySet().iterator(); iter.hasNext();) { 266 final String key = (String ) iter.next(); 267 LOG.debug(" " + key + " = " + entryProperties.get(key)); 268 } 269 } 270 271 private boolean isNotFirstDiscovery; 272 273 public void discovered(final DiscoveryEvent evt) { 274 final ServiceRegistrar[] registrarsArray = evt.getRegistrars(); 275 ServiceRegistrar registrar; 276 for (int n = 0; n < registrarsArray.length; n++) { 277 incrementRegCount(); 278 registrar = registrarsArray[n]; 279 logRegistration(registrar); 280 LOG.debug("Registered with registrar: " + registrar.getServiceID()); 281 } 282 if (!isNotFirstDiscovery) { 283 LOG.info("BuildAgentService open for business..."); 284 isNotFirstDiscovery = true; 285 } 286 } 287 288 public void discarded(final DiscoveryEvent evt) { 289 final ServiceRegistrar[] registrarsArray = evt.getRegistrars(); 290 ServiceRegistrar registrar; 291 for (int n = 0; n < registrarsArray.length; n++) { 292 decrementRegCount(); 293 registrar = registrarsArray[n]; 294 LOG.debug("Discarded registrar: " + registrar.getServiceID()); 295 } 296 } 297 298 299 private static final Object KEEP_ALIVE = new Object (); 300 private static Thread mainThread; 301 302 private static synchronized void setMainThread(final Thread newMainThread) { 303 mainThread = newMainThread; 304 } 305 static synchronized Thread getMainThread() { 306 return mainThread; 307 } 308 309 public static void main(final String [] args) { 310 311 LOG.info("Starting agent...args: " + Arrays.asList(args).toString()); 312 313 315 final boolean isSkipUI; 316 if (args.length < 3 || !args[2].equalsIgnoreCase(MAIN_ARG_SKIP_UI)) { 317 isSkipUI = false; 318 } else { 319 isSkipUI = true; 320 } 321 322 final BuildAgent buildAgent; 323 if (args.length > 0) { 324 if (args.length > 1) { 325 buildAgent = new BuildAgent(args[0], args[1], isSkipUI); 326 } else { 327 buildAgent = new BuildAgent(args[0], BuildAgentServiceImpl.DEFAULT_USER_DEFINED_PROPERTIES_FILE, 328 isSkipUI); 329 } 330 } else { 331 buildAgent = new BuildAgent(isSkipUI); 332 } 333 334 335 setMainThread(Thread.currentThread()); 336 337 synchronized (KEEP_ALIVE) { 339 try { 340 KEEP_ALIVE.wait(); 341 } catch (InterruptedException e) { 342 LOG.error("Keep Alive wait interrupted", e); 343 } finally { 344 buildAgent.terminate(); 345 } 346 } 347 } 348 349 public static void kill() { 350 final Thread main = getMainThread(); 351 if (main != null) { 352 main.interrupt(); 353 LOG.info("Waiting for main thread to finish."); 354 try { 355 main.join(30 * 1000); 356 } catch (InterruptedException e) { 358 LOG.error("Error during waiting from Agent to die.", e); 359 } 360 if (main.isAlive()) { 361 main.interrupt(); LOG.error("Main thread should have died."); 363 } 364 setMainThread(null); 365 } else { 366 LOG.info("WARNING: Kill was called, but MainThread is null. Doing nothing."); 367 } 368 } 369 370 static interface AgentStatusListener { 371 public void statusChanged(BuildAgentService buildAgentServiceImpl); 372 } 373 374 } 375 | Popular Tags |