package org.oddjob.jmx.client; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.RemoteException; import javax.management.ObjectName; import org.apache.log4j.Logger; import org.oddjob.arooa.ClassResolver; import org.oddjob.framework.Exportable; import org.oddjob.framework.Transportable; import org.oddjob.jmx.RemoteOddjobBean; import org.oddjob.jmx.handlers.ExportableHandlerFactory; import org.oddjob.jmx.server.ServerInfo; import org.oddjob.util.ClassLoaderSorter; /** * The client side representation of a remote node. A proxy is used to implement * a mirror of the remote node. This class is the invocation handler for that * proxy. This class is never accessed directly by client code. * <p> * On creation the client node will lookup up various things on the server * on configure the proxy, register for notifications and start a resync. * <p> * It is possible that a serverside node has bean created and destroyed and * that the client hasn't caught up. In this case dead placeholder nodes are * put in the tree. They should be short lived, and removed when the client * catches up with the notifications. * * @author Rob Gordon */ public class ClientNode implements InvocationHandler, Exportable { private static final Logger logger = Logger.getLogger(ClientNode.class); /** The name of the mbean this node represents. */ private final ObjectName objectName; /** Save the proxy object created to shadow the remote node. */ private final Object proxy; private final ClientInterfaceManager interfaceManager; /** * Constructor. * * @param objectName * The name of the mbean were monitoring. * @param serverConnection * The connection to the remote server. * * @throws Exception * if anything goes wrong. */ private ClientNode(ObjectName objectName, ClientSideToolkit toolkit) { this.objectName = objectName; RemoteOddjobBean remote = new DirectInvocationClientFactory<RemoteOddjobBean>( RemoteOddjobBean.class).createClientHandler( null, toolkit); ServerInfo serverInfo = remote.serverInfo(); ClassResolver classResolver = toolkit.getClientSession().getArooaSession( ).getArooaDescriptor().getClassResolver(); ClientInterfaceManagerFactory managerFactory = new ClientInterfaceManagerFactory( new ResolverHelper(classResolver ).resolveAll(serverInfo.getClientResolvers())); // all proxies are exportable. managerFactory.addHandlerFactory(new ExportableHandlerFactory()); Class<?>[] interfaces = managerFactory.interfaces(); this.proxy = Proxy.newProxyInstance( new ClassLoaderSorter().getTopLoader(interfaces), interfaces, this); // create the ClientInterfaceManager interfaceManager = managerFactory.create( proxy, toolkit); logger.debug("Client Node creation complete [" + proxy.toString() + "], objectName=" + objectName); } /** * Static factory method. * * @param objectName * The remote node. * @param serverConnection * The server connection. * @return A proxy oject that implements it's interfaces. * * @throws RemoteException */ public static Handle createProxyFor(ObjectName objectName, ClientSideToolkit toolkit) { ClientNode client = new ClientNode( objectName, toolkit); return client.new Handle(); } /** * Called by the proxy to invoke a method. */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return interfaceManager.invoke(method, args); } public String toString() { return "ClientNode: " + objectName; } /** * Part of the implementation of the HostRelative interface. This is called when * the proxy is just about to be sent over the network. * * @return The object for transit. */ public Transportable exportTransportable() { logger.debug("[" + proxy + "] exported with name [" + objectName + "]"); ComponentTransportable transportable = new ComponentTransportable(objectName); return transportable; } public class Handle { public Object getproxy() { return proxy; } public Destroyable getDestroyer() { return interfaceManager; } } }