FileDocCategorySizeDatePackage
RMIServerImpl.javaAPI DocJava SE 5 API18387Fri Aug 26 14:57:38 BST 2005javax.management.remote.rmi

RMIServerImpl

public abstract class RMIServerImpl extends Object implements RMIServer

An RMI object representing a connector server. Remote clients can make connections using the {@link #newClient(Object)} method. This method returns an RMI object representing the connection.

User code does not usually reference this class directly. RMI connection servers are usually created with the class {@link RMIConnectorServer}. Remote clients usually create connections either with {@link JMXConnectorFactory} or by instantiating {@link RMIConnector}.

This is an abstract class. Concrete subclasses define the details of the client connection objects, such as whether they use JRMP or IIOP.

since
1.5
since.unbundled
1.0

Fields Summary
private static final ClassLogger
logger
private final List
clientList
List of WeakReference values. Each one references an RMIConnection created by this object, or null if the RMIConnection has been garbage-collected.
private ClassLoader
cl
private MBeanServer
mbeanServer
private final Map
env
private RMIConnectorServer
connServer
private static int
connectionIdNumber
private NotificationBuffer
notifBuffer
private final AccessControlContext
callerACC
Constructors Summary
public RMIServerImpl(Map env)

Constructs a new RMIServerImpl.

param
env the environment containing attributes for the new RMIServerImpl. Can be null, which is equivalent to an empty Map.

        this.env = (env == null) ? Collections.EMPTY_MAP : env;

	callerACC = AccessController.getContext();

	if (logger.debugOn()) 
	    logger.trace("RMIServerImpl","class="+this.getClass().getName());
    
Methods Summary
protected voidclientClosed(javax.management.remote.rmi.RMIConnection client)

Method called when a client connection created by {@link #makeClient makeClient} is closed. A subclass that defines makeClient must arrange for this method to be called when the resultant object's {@link RMIConnection#close() close} method is called. This enables it to be removed from the RMIServerImpl's list of connections. It is not an error for client not to be in that list.

After removing client from the list of connections, this method calls {@link #closeClient closeClient(client)}.

param
client the client connection that has been closed.
exception
IOException if {@link #closeClient} throws this exception.
exception
NullPointerException if client is null.

	final boolean debug = logger.debugOn();

	if (debug) logger.trace("clientClosed","client="+client);

	if (client == null)
	    throw new NullPointerException("Null client");

        synchronized (clientList) {
            dropDeadReferences();
            for (Iterator it = clientList.iterator(); it.hasNext(); ) {
                WeakReference wr = (WeakReference) it.next();
                if (wr.get() == client) {
                    it.remove();
                    break;
                }
            }
            /* It is not a bug for this loop not to find the client.  In
               our close() method, we remove a client from the list before
               calling its close() method.  */
        }

	if (debug) logger.trace("clientClosed", "closing client.");
        closeClient(client);

	if (debug) logger.trace("clientClosed", "sending notif");
	connServer.connectionClosed(client.getConnectionId(),
				    "Client connection closed", null);

	if (debug) logger.trace("clientClosed","done");
    
public synchronized voidclose()

Closes this connection server. This method first calls the {@link #closeServer()} method so that no new client connections will be accepted. Then, for each remaining {@link RMIConnection} object returned by {@link #makeClient makeClient}, its {@link RMIConnection#close() close} method is called.

The behaviour when this method is called more than once is unspecified.

If {@link #closeServer()} throws an IOException, the individual connections are nevertheless closed, and then the IOException is thrown from this method.

If {@link #closeServer()} returns normally but one or more of the individual connections throws an IOException, then, after closing all the connections, one of those IOExceptions is thrown from this method. If more than one connection throws an IOException, it is unspecified which one is thrown from this method.

exception
IOException if {@link #closeServer()} or one of the {@link RMIConnection#close()} calls threw IOException.

	final boolean tracing = logger.traceOn();
	final boolean debug   = logger.debugOn();
	
	if (tracing) logger.trace("close","closing");

        IOException ioException = null;
        try {
	    if (debug)   logger.debug("close","closing Server");
            closeServer();
        } catch (IOException e) {
	    if (tracing) logger.trace("close","Failed to close server: " + e);
	    if (debug)   logger.debug("close",e);
            ioException = e;
        }

	if (debug)   logger.debug("close","closing Clients");
        // Loop to close all clients
        while (true) {
            synchronized (clientList) {
		if (debug) logger.debug("close","droping dead references");
                dropDeadReferences();

		if (debug) logger.debug("close","client count: "+clientList.size());
                if (clientList.size() == 0) 
                    break;
                /* Loop until we find a non-null client.  Because we called
                   dropDeadReferences(), this will usually be the first
                   element of the list, but a garbage collection could have
                   happened in between.  */
                for (Iterator it = clientList.iterator(); it.hasNext(); ) {
                    WeakReference wr = (WeakReference) it.next();
                    RMIConnection client = (RMIConnection) wr.get();
                    it.remove();
                    if (client != null) {
                        try {
                            client.close();
                        } catch (IOException e) {
			    if (tracing) 
				logger.trace("close","Failed to close client: " + e);
			    if (debug) logger.debug("close",e);
                            if (ioException == null)
                                ioException = e;
                        }
                        break;
                    }
                }
            }
        }

	if(notifBuffer != null)
	    notifBuffer.dispose();
	
        if (ioException != null) {
	    if (tracing) logger.trace("close","close failed.");
            throw ioException;
	}

	if (tracing) logger.trace("close","closed.");
    
protected abstract voidcloseClient(javax.management.remote.rmi.RMIConnection client)

Closes a client connection made by {@link #makeClient makeClient}.

param
client a connection previously returned by makeClient on which the closeClient method has not previously been called. The behavior is unspecified if these conditions are violated, including the case where client is null.
exception
IOException if the client connection cannot be closed.

protected abstract voidcloseServer()

Called by {@link #close()} to close the connector server. After returning from this method, the connector server must not accept any new connections.

exception
IOException if the attempt to close the connector server failed.

private javax.management.remote.rmi.RMIConnectiondoNewClient(java.lang.Object credentials)


	final boolean tracing = logger.traceOn();

	if (tracing) logger.trace("newClient","making new client");

	if (getMBeanServer() == null)
	    throw new IllegalStateException("Not attached to an MBean server");

        Subject subject = null;
        JMXAuthenticator authenticator =
            (JMXAuthenticator) env.get(JMXConnectorServer.AUTHENTICATOR);
	if (authenticator == null) {
	    /*
	     * Create the JAAS-based authenticator only if authentication
	     * has been enabled
	     */
	    if (env.get("jmx.remote.x.password.file") != null ||
		env.get("jmx.remote.x.login.config") != null) {
		authenticator = new JMXPluggableAuthenticator(env);
	    }
	}
        if (authenticator != null) {
	    if (tracing) logger.trace("newClient","got authenticator: " +
			       authenticator.getClass().getName());
	    try {
		subject = authenticator.authenticate(credentials);
	    } catch (SecurityException e) {
		logger.trace("newClient", "Authentication failed: " + e);
		throw e;
	    }
        }

	if (tracing) {
	    if (subject != null) 
		logger.trace("newClient","subject is not null");
	    else logger.trace("newClient","no subject");
	}

	final String connectionId = makeConnectionId(getProtocol(), subject);

	if (tracing) 
	    logger.trace("newClient","making new connection: " + connectionId);

        RMIConnection client = makeClient(connectionId, subject);

	connServer.connectionOpened(connectionId, "Connection opened", null);

        dropDeadReferences();
        WeakReference wr = new WeakReference(client);
        synchronized (clientList) {
            clientList.add(wr);
        }

	if (tracing) 
	    logger.trace("newClient","new connection done: " + connectionId );

        return client;
    
private voiddropDeadReferences()

        synchronized (clientList) {
            for (Iterator it = clientList.iterator(); it.hasNext(); ) {
                WeakReference wr = (WeakReference) it.next();
                if (wr.get() == null)
                    it.remove();
            }
        }
    
protected abstract voidexport()

Exports this RMI object.

exception
IOException if this RMI object cannot be exported.

public synchronized java.lang.ClassLoadergetDefaultClassLoader()

Gets the default ClassLoader used by this connector server.

return
the default ClassLoader used by this connector server.

see
#setDefaultClassLoader

        return cl;
    
public synchronized javax.management.MBeanServergetMBeanServer()

The MBeanServer to which this connector server is attached. This is the last value passed to {@link #setMBeanServer} on this object, or null if that method has never been called.

return
the MBeanServer to which this connector is attached.
see
#setMBeanServer

        return mbeanServer;
    
synchronized com.sun.jmx.remote.internal.NotificationBuffergetNotifBuffer()

	//Notification buffer is lazily created when the first client connects
	if(notifBuffer == null)
	    notifBuffer = 
		ArrayNotificationBuffer.getNotificationBuffer(mbeanServer,
							      env);
	return notifBuffer;
    
protected abstract java.lang.StringgetProtocol()

Returns the protocol string for this object. The string is rmi for RMI/JRMP and iiop for RMI/IIOP.

return
the protocol string for this object.

public java.lang.StringgetVersion()

	// Expected format is: "protocol-version implementation-name"
	return "1.0 java_runtime_" + (String)
	    AccessController.doPrivileged(new PrivilegedAction() {
		    public Object run() {
			return System.getProperty("java.runtime.version");
		    }
		});
    
protected abstract javax.management.remote.rmi.RMIConnectionmakeClient(java.lang.String connectionId, javax.security.auth.Subject subject)

Creates a new client connection. This method is called by the public method {@link #newClient(Object)}.

param
connectionId the ID of the new connection. Every connection opened by this connector server will have a different ID. The behavior is unspecified if this parameter is null.
param
subject the authenticated subject. Can be null.
return
the newly-created RMIConnection.
exception
IOException if the new client object cannot be created or exported.

private static synchronized java.lang.StringmakeConnectionId(java.lang.String protocol, javax.security.auth.Subject subject)

        connectionIdNumber++;

	String clientHost = "";
	try {
	    clientHost = RemoteServer.getClientHost();
	} catch (ServerNotActiveException e) {
	    logger.trace("makeConnectionId", "getClientHost", e);
	}

	StringBuffer buf = new StringBuffer();
	buf.append(protocol).append(":");
	if (clientHost.length() > 0)
	    buf.append("//").append(clientHost);
	buf.append(" ");
	if (subject != null) {
	    Set principals = subject.getPrincipals();
	    String sep = "";
	    for (Iterator it = principals.iterator(); it.hasNext(); ) {
		Principal p = (Principal) it.next();
		String name = p.getName().replace(' ", '_").replace(';", ':");
		buf.append(sep).append(name);
		sep = ";";
	    }
	}
	buf.append(" ").append(connectionIdNumber);
	if (logger.traceOn()) 
	    logger.trace("newConnectionId","connectionId="+buf);
        return buf.toString();
    
public javax.management.remote.rmi.RMIConnectionnewClient(java.lang.Object credentials)

Creates a new client connection. This method calls {@link #makeClient makeClient} and adds the returned client connection object to an internal list. When this RMIServerImpl is shut down via its {@link #close()} method, the {@link RMIConnection#close() close()} method of each object remaining in the list is called.

The fact that a client connection object is in this internal list does not prevent it from being garbage collected.

param
credentials this object specifies the user-defined credentials to be passed in to the server in order to authenticate the caller before creating the RMIConnection. Can be null.
return
the newly-created RMIConnection. This is usually the object created by makeClient, though an implementation may choose to wrap that object in another object implementing RMIConnection.
exception
IOException if the new client object cannot be created or exported.
exception
SecurityException if the given credentials do not allow the server to authenticate the user successfully.
exception
IllegalStateException if {@link #getMBeanServer()} is null.

	try {
	    final Object o = credentials;
	    return AccessController.doPrivileged(
		new PrivilegedExceptionAction<RMIConnection>() {
		    public RMIConnection run() throws IOException {
			return doNewClient(o);
		    }
	        }, callerACC);
	} catch (PrivilegedActionException pae) {
	    throw (IOException) pae.getCause();
	}
    
public synchronized voidsetDefaultClassLoader(java.lang.ClassLoader cl)

Sets the default ClassLoader for this connector server. New client connections will use this classloader. Existing client connections are unaffected.

param
cl the new ClassLoader to be used by this connector server.
see
#getDefaultClassLoader

        this.cl = cl;
    
public synchronized voidsetMBeanServer(javax.management.MBeanServer mbs)

Sets the MBeanServer to which this connector server is attached. New client connections will interact with this MBeanServer. Existing client connections are unaffected.

param
mbs the new MBeanServer. Can be null, but new client connections will be refused as long as it is.
see
#getMBeanServer

        this.mbeanServer = mbs;
    
voidsetRMIConnectorServer(javax.management.remote.rmi.RMIConnectorServer connServer)

	this.connServer = connServer;
    
public abstract java.rmi.RemotetoStub()
Returns a remotable stub for this server object.

return
a remotable stub.
exception
IOException if the stub cannot be obtained - e.g the RMIServerImpl has not been exported yet.