blob: 816c40c807c08e859e464ecfee2e473c8464b021 [file] [log] [blame]
/*******************************************************************************
* 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.net.Socket;
import java.util.*;
import org.eclipse.jem.internal.proxy.common.remote.Commands;
import org.eclipse.jem.internal.proxy.core.*;
import org.eclipse.jem.internal.proxy.core.ExpressionProxy.ProxyEvent;
/**
* This registry will handle callbacks.
* It is package protected because no one
* should access it outside.
*/
class REMCallbackRegistry implements ICallbackRegistry {
final REMProxyFactoryRegistry fFactory;
final String fNamePostfix;
List fThreads = Collections.synchronizedList(new LinkedList()); // List of active callback threads.
Map fIdToCallback = new HashMap(5); // ID to Callback map.
Map fCallbackProxyToId = new HashMap(5); // Callback to ID map. This will also hold onto the callback proxies so that they don't get GC'd while the callback is registered.
IREMMethodProxy fInitializeCallback;
IBeanProxy fRemoteServer;
boolean registryOpen = true;
public REMCallbackRegistry(String name, REMProxyFactoryRegistry aFactory) {
fFactory = aFactory;
fNamePostfix = name;
// Now register common proxies.
IREMBeanTypeProxy callbackType = new REMInterfaceBeanTypeProxy(fFactory, new Integer(Commands.ICALLBACK_CLASS), "org.eclipse.jem.internal.proxy.vm.remote.ICallback"); //$NON-NLS-1$
fInitializeCallback = (IREMMethodProxy) ((REMMethodProxyFactory) fFactory.getMethodProxyFactory()).methodType.newBeanProxy(new Integer(Commands.INITIALIZECALLBACK_METHOD_ID));
fRemoteServer = aFactory.getBeanProxyFactory().getIVMServerProxy(); // For us, the IVMServer on the remote vm ALSO implements IVMCallbackServer.
((REMStandardBeanTypeProxyFactory) fFactory.getBeanTypeProxyFactory()).registerBeanTypeProxy(callbackType, true);
((REMStandardBeanProxyFactory) fFactory.getBeanProxyFactory()).registerProxy(fInitializeCallback);
}
public boolean createCallback(Socket incoming) {
if (registryOpen) {
Thread st = new REMCallbackThread(incoming, this, "Callback Thread-"+fNamePostfix, fFactory, fFactory.fNoTimeouts); //$NON-NLS-1$
fThreads.add(st);
st.start();
return true;
} else
return false;
}
/**
* Use this to request a shutdown. If the server is already shutdown, this will return false.
*/
public boolean requestShutdown() {
if (registryOpen)
shutdown();
else
return false;
return true;
}
/**
* Remove a thread from the list.
*/
public void removeCallbackThread(REMCallbackThread thread) {
fThreads.remove(thread);
}
private void shutdown() {
// Go through each thread and ask it to close. Make a copy of the list so that we
// won't get into deadlocks.
REMCallbackThread[] threadsArray = (REMCallbackThread[]) fThreads.toArray(new REMCallbackThread[fThreads.size()]);
for (int i=0; i<threadsArray.length; i++) {
// This is a harsh way to shut a connection down, but there's no
// other way I know of to interrupt the read on a socket.
threadsArray[i].close();
}
// Now that they've been told to close, wait on each one to finish.
for (int i=0; i<threadsArray.length; i++)
try {
threadsArray[i].join(10000); // Wait ten seconds, if longer, just go on to next one.
} catch (InterruptedException e) {
}
fThreads.clear();
fIdToCallback.clear();
fCallbackProxyToId.clear();
fInitializeCallback = null;
fRemoteServer = null;
}
public ICallback getRegisteredCallback(int id) {
synchronized(fIdToCallback) {
return (ICallback) fIdToCallback.get(new Integer(id));
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.ICallbackRegistry#registerCallback(org.eclipse.jem.internal.proxy.core.IBeanProxy, org.eclipse.jem.internal.proxy.core.ICallback)
*/
public void registerCallback(IBeanProxy callbackProxy, ICallback cb) {
synchronized(fIdToCallback) {
fIdToCallback.put(((IREMBeanProxy) callbackProxy).getID(), cb);
fCallbackProxyToId.put(callbackProxy, ((IREMBeanProxy) callbackProxy).getID());
fInitializeCallback.invokeCatchThrowableExceptions(callbackProxy, new IBeanProxy[] {fRemoteServer, fFactory.getBeanProxyFactory().createBeanProxyWith(((IREMBeanProxy) callbackProxy).getID().intValue())});
}
}
/* (non-Javadoc)
* @see org.eclipse.jem.internal.proxy.core.ICallbackRegistry#registerCallback(org.eclipse.jem.internal.proxy.core.IProxy, org.eclipse.jem.internal.proxy.core.ICallback, org.eclipse.jem.internal.proxy.core.IExpression)
*/
public void registerCallback(IProxy callbackProxy, final ICallback cb, IExpression expression) {
final Integer id;
if (callbackProxy.isBeanProxy()) {
id = ((IREMBeanProxy) callbackProxy).getID();
synchronized(fIdToCallback) {
fIdToCallback.put(id, cb);
fCallbackProxyToId.put(callbackProxy, id);
}
} else {
id = new Integer(callbackProxy.hashCode());
synchronized (fIdToCallback) {
fIdToCallback.put(id, cb); // This is so that it is registered in case callback is invoked from remote vm during expression processing.
}
((ExpressionProxy) callbackProxy).addProxyListener(new ExpressionProxy.ProxyListener() {
public void proxyResolved(ProxyEvent event) {
synchronized(fIdToCallback) {
fCallbackProxyToId.put(event.getProxy(), id);
}
}
public void proxyNotResolved(ProxyEvent event) {
// Failed, so remove registration completely.
synchronized (fIdToCallback) {
fIdToCallback.remove(id);
}
}
public void proxyVoid(ProxyEvent event) {
// Failed, so remove registration completely.
synchronized (fIdToCallback) {
fIdToCallback.remove(id);
}
}
});
}
expression.createSimpleMethodInvoke(fInitializeCallback, callbackProxy, new IProxy[] {fRemoteServer, fFactory.getBeanProxyFactory().createBeanProxyWith(id.intValue())}, false);
}
/**
* The public interface for deregistering callbacks.
*/
public void deregisterCallback(IBeanProxy callbackProxy) {
synchronized(fIdToCallback) {
Integer id = (Integer) fCallbackProxyToId.remove(callbackProxy);
fIdToCallback.remove(id);
}
}
}