/******************************************************************************* * Copyright (c) 2001, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jem.internal.proxy.remote; /* */ import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jem.internal.proxy.core.ProxyPlugin; /** * This class is a controller for all of the registries. * @author richkulp */ public class REMRegistryController { private Map fActiveRegistries = new HashMap(); // Access to this must be sync(REMRegistryController) private static final long CLEANUP_INTERVAL = 60000l; // The interval between clean up job execution. protected boolean inShutdown; // Are we in shutdown mode. Terminate registries runs differently in shutdown mode. // Thread to clean up GC'd proxies. Runs as a daemon at the lowest priority private Job processQueueJob= new Job(ProxyRemoteMessages.CleanupJob_title) { public IStatus run(IProgressMonitor m) { REMProxyFactoryRegistry[] registries = null; synchronized (REMRegistryController.this) { // This list may be updated by others, so we need to make a copy // or else we could get a failure. registries = (REMProxyFactoryRegistry[]) fActiveRegistries.values().toArray( new REMProxyFactoryRegistry[fActiveRegistries.size()]); } for (int i = 0; i < registries.length; i++) { try { ((REMStandardBeanProxyFactory) registries[i].getBeanProxyFactory()).processQueue(); } catch (RuntimeException e) { // When debugging, getBeanProxyFactory can throw exception because it hasn't been initialized // yet when the thread wakes up, though the registry has been registered. It has to do with it // can take significant time for the user to start up the debugger, and during that time this // thread could kick in. } } synchronized(this) { if (!m.isCanceled()) this.schedule(CLEANUP_INTERVAL); // Schedule to start again in one minute. } return Status.OK_STATUS; } }; //$NON-NLS-1$ public REMRegistryController() { ProxyPlugin.getPlugin().addProxyShutdownListener(new ProxyPlugin.IProxyPluginShutdownListener() { /* * (non-Javadoc) * * @see org.eclipse.jem.internal.proxy.core.ProxyPlugin.IProxyPluginShutdownListener#shutdown() */ public void shutdown() { REMRegistryController.this.shutdown(); } }); masterThread = new REMMasterServerThread(this); masterThread.start(); processQueueJob.setSystem(true); // So that it won't show processing in process view. Not of interest to general users. processQueueJob.setPriority(Job.SHORT); processQueueJob.schedule(CLEANUP_INTERVAL); } /** * Answer whether we are shutting down or not. * @return * * @since 1.1.0 */ public boolean inShutDown() { return inShutdown; } /* * Add registry to list of active. Return a unique number to be the key. * Package-protected so that only locals can access it. */ synchronized Integer registerRegistry(REMProxyFactoryRegistry registry) { Integer hashcode = new Integer(registry.hashCode()); while (true) { REMProxyFactoryRegistry existing = (REMProxyFactoryRegistry) fActiveRegistries.get(hashcode); if (existing == null) break; // Not yet registered, use use the hashcode else if (existing != registry) hashcode = new Integer(hashcode.intValue()+1); else return hashcode; // Same guy, use the hashcode. } fActiveRegistries.put(hashcode, registry); return hashcode; } /* * deregister the registry. */ synchronized void deregisterRegistry(Integer key) { fActiveRegistries.remove(key); } /* * Return the registry for the given key */ synchronized REMProxyFactoryRegistry getRegistry(Integer key) { return (REMProxyFactoryRegistry) fActiveRegistries.get(key); } /** * Master server thread. Handles keep-alive requests and register remote server threads. * It will be created when needed. */ protected REMMasterServerThread masterThread; /* * Shuts down this plug-in and discards all plug-in state. * * In this case, terminate all of the active registries so that they can be shutdown. * Don't want them hanging around after termination of the desktop. */ void shutdown() { synchronized(processQueueJob) { processQueueJob.cancel(); } REMProxyFactoryRegistry[] registries = null; synchronized (this) { // This list will be updated in the terminateRegistry, so we need to make a copy // or else we get a failure. registries = (REMProxyFactoryRegistry[]) fActiveRegistries.values().toArray( new REMProxyFactoryRegistry[fActiveRegistries.size()]); } inShutdown = true; // We are now in shutdown mode. // In shutdown mode the registries will not create the job that waits for the process // to terminate, and if it doesn't in 1.5 secs it does a force. // Instead what we will do is shutdown all of the registries. If they don't // shutdown on their own then they stay out there. But they do have an // internal timer that checks every five minutes to see if the host is // still there, and if it isn't they will shut themselves down. They // would have to be really hosed if the suicide timer wasn't working. for (int i = 0; i < registries.length; i++) registries[i].terminateRegistry(); if (masterThread != null) { try { masterThread.requestShutdown(); masterThread.join(20000); // Wait 20 seconds for everything to go down. masterThread = null; } catch (InterruptedException e) { } } try { processQueueJob.join(); } catch(InterruptedException e) { } REMProxyFactoryRegistry.cancelAllTerminateJobs(); } /** * Return the master socket port number. */ public int getMasterSocketPort() { return masterThread != null ? masterThread.getMasterSocket().getLocalPort() : -1; } }