/* * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package javax.management.remote.rmi; import com.sun.jmx.remote.security.MBeanServerFileAccessController; import com.sun.jmx.remote.internal.IIOPHelper; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.net.MalformedURLException; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.Set; import javax.management.InstanceNotFoundException; import javax.management.MBeanServer; import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; import javax.naming.InitialContext; import javax.naming.NamingException; /** *
A JMX API connector server that creates RMI-based connections * from remote clients. Usually, such connector servers are made * using {@link javax.management.remote.JMXConnectorServerFactory * JMXConnectorServerFactory}. However, specialized applications can * use this class directly, for example with an {@link RMIServerImpl} * object.
* * @since 1.5 */ public class RMIConnectorServer extends JMXConnectorServer { /** *Name of the attribute that specifies whether the {@link
* RMIServer} stub that represents an RMI connector server should
* override an existing stub at the same address. The value
* associated with this attribute, if any, should be a string that
* is equal, ignoring case, to "true"
or
* "false"
. The default value is false.
Name of the attribute that specifies the {@link
* RMIClientSocketFactory} for the RMI objects created in
* conjunction with this connector. The value associated with this
* attribute must be of type RMIClientSocketFactory
and can
* only be specified in the Map
argument supplied when
* creating a connector server.
Name of the attribute that specifies the {@link
* RMIServerSocketFactory} for the RMI objects created in
* conjunction with this connector. The value associated with this
* attribute must be of type RMIServerSocketFactory
and can
* only be specified in the Map
argument supplied when
* creating a connector server.
Makes an RMIConnectorServer
.
* This is equivalent to calling {@link #RMIConnectorServer(
* JMXServiceURL,Map,RMIServerImpl,MBeanServer)
* RMIConnectorServer(directoryURL,environment,null,null)}
url
is null.
*
* @exception MalformedURLException if url
does not
* conform to the syntax for an RMI connector, or if its protocol
* is not recognized by this implementation. Only "rmi" and "iiop"
* are valid when this constructor is used.
*
* @exception IOException if the connector server cannot be created
* for some reason or if it is inevitable that its {@link #start()
* start} method will fail.
*/
public RMIConnectorServer(JMXServiceURL url, MapMakes an RMIConnectorServer
for the given MBean
* server.
* This is equivalent to calling {@link #RMIConnectorServer(
* JMXServiceURL,Map,RMIServerImpl,MBeanServer)
* RMIConnectorServer(directoryURL,environment,null,mbeanServer)}
url
is null.
*
* @exception MalformedURLException if url
does not
* conform to the syntax for an RMI connector, or if its protocol
* is not recognized by this implementation. Only "rmi" and "iiop"
* are valid when this constructor is used.
*
* @exception IOException if the connector server cannot be created
* for some reason or if it is inevitable that its {@link #start()
* start} method will fail.
*/
public RMIConnectorServer(JMXServiceURL url, MapMakes an RMIConnectorServer
for the given MBean
* server.
url
is null.
*
* @exception MalformedURLException if url
does not
* conform to the syntax for an RMI connector, or if its protocol
* is not recognized by this implementation. Only "rmi" and "iiop"
* are recognized when rmiServerImpl is null.
*
* @exception IOException if the connector server cannot be created
* for some reason or if it is inevitable that its {@link #start()
* start} method will fail.
*
* @see #start
*/
public RMIConnectorServer(JMXServiceURL url, MapReturns a client stub for this connector server. A client * stub is a serializable object whose {@link * JMXConnector#connect(Map) connect} method can be used to make * one new connection to this connector server.
* * @param env client connection parameters of the same sort that * could be provided to {@link JMXConnector#connect(Map) * JMXConnector.connect(Map)}. Can be null, which is equivalent * to an empty map. * * @return a client stub that can be used to make a new connection * to this connector server. * * @exception UnsupportedOperationException if this connector * server does not support the generation of client stubs. * * @exception IllegalStateException if the JMXConnectorServer is * not started (see {@link #isActive()}). * * @exception IOException if a communications problem means that a * stub cannot be created. **/ public JMXConnector toJMXConnector(MapActivates the connector server, that is starts listening for
* client connections. Calling this method when the connector
* server is already active has no effect. Calling this method
* when the connector server has been stopped will generate an
* IOException
.
The behavior of this method when called for the first time * depends on the parameters that were supplied at construction, * as described below.
* *First, an object of a subclass of {@link RMIServerImpl} is * required, to export the connector server through RMI:
* *RMIServerImpl
was supplied to the
* constructor, it is used.
*
* JMXServiceURL
supplied to the constructor was
* iiop
, an object of type {@link RMIIIOPServerImpl}
* is created.
*
* JMXServiceURL
* was null, or its protocol part was rmi
, an object
* of type {@link RMIJRMPServerImpl} is created.
*
* If the given address includes a JNDI directory URL as
* specified in the package documentation for {@link
* javax.management.remote.rmi}, then this
* RMIConnectorServer
will bootstrap by binding the
* RMIServerImpl
to the given address.
If the URL path part of the JMXServiceURL
was
* empty or a single slash (/
), then the RMI object
* will not be bound to a directory. Instead, a reference to it
* will be encoded in the URL path of the RMIConnectorServer
* address (returned by {@link #getAddress()}). The encodings for
* rmi
and iiop
are described in the
* package documentation for {@link
* javax.management.remote.rmi}.
The behavior when the URL path is neither empty nor a JNDI
* directory URL, or when the protocol is neither rmi
* nor iiop
, is implementation defined, and may
* include throwing {@link MalformedURLException} when the
* connector server is created or when it is started.
Deactivates the connector server, that is, stops listening for * client connections. Calling this method will also close all * client connections that were made by this server. After this * method returns, whether normally or with an exception, the * connector server will not create any new client * connections.
* *Once a connector server has been stopped, it cannot be started * again.
* *Calling this method when the connector server has already * been stopped has no effect. Calling this method when the * connector server has not yet been started will disable the * connector server object permanently.
* *If closing a client connection produces an exception, that * exception is not thrown from this method. A {@link * JMXConnectionNotification} is emitted from this MBean with the * connection ID of the connection that could not be closed.
* *Closing a connector server is a potentially slow operation. * For example, if a client machine with an open connection has * crashed, the close operation might have to wait for a network * protocol timeout. Callers that do not want to block in a close * operation should do it in a separate thread.
* *This method calls the method {@link RMIServerImpl#close()
* close} on the connector server's RMIServerImpl
* object.
If the RMIServerImpl
was bound to a JNDI
* directory by the {@link #start() start} method, it is unbound
* from the directory by this method.
RMIServerImpl
cannot be unbound from the
* directory. When this exception is thrown, the server has
* already attempted to close all client connections, if
* appropriate; to call {@link RMIServerImpl#close()}; and to
* unbind the RMIServerImpl
from its directory, if
* appropriate. All client connections are closed except possibly
* those that generated exceptions when the server attempted to
* close them.
*/
public void stop() throws IOException {
final boolean tracing = logger.traceOn();
synchronized (this) {
if (state == STOPPED) {
if (tracing) logger.trace("stop","already stopped.");
return;
} else if (state == CREATED) {
if (tracing) logger.trace("stop","not started yet.");
}
if (tracing) logger.trace("stop", "stopping.");
state = STOPPED;
}
synchronized(openedServers) {
openedServers.remove(this);
}
IOException exception = null;
// rmiServerImpl can be null if stop() called without start()
if (rmiServerImpl != null) {
try {
if (tracing) logger.trace("stop", "closing RMI server.");
rmiServerImpl.close();
} catch (IOException e) {
if (tracing) logger.trace("stop", "failed to close RMI server: " + e);
if (logger.debugOn()) logger.debug("stop",e);
exception = e;
}
}
if (boundJndiUrl != null) {
try {
if (tracing)
logger.trace("stop",
"unbind from external directory: " + boundJndiUrl);
final Hashtable, ?> usemap = EnvHelp.mapToHashtable(attributes);
InitialContext ctx =
new InitialContext(usemap);
ctx.unbind(boundJndiUrl);
ctx.close();
} catch (NamingException e) {
if (tracing) logger.trace("stop", "failed to unbind RMI server: "+e);
if (logger.debugOn()) logger.debug("stop",e);
// fit e in as the nested exception if we are on 1.4
if (exception == null)
exception = newIOException("Cannot bind to URL: " + e, e);
}
}
if (exception != null) throw exception;
if (tracing) logger.trace("stop", "stopped");
}
public synchronized boolean isActive() {
return (state == STARTED);
}
public JMXServiceURL getAddress() {
if (!isActive())
return null;
return address;
}
public MapJMXServiceURL
.
* @param attributes A Hashtable containing environment parameters,
* built from the Map specified at this object creation.
* @param rmiServer The object to bind in the registry
* @param rebind true if the object must be rebound.
**/
void bind(String jndiUrl, Hashtable, ?> attributes,
RMIServer rmiServer, boolean rebind)
throws NamingException, MalformedURLException {
// if jndiURL is not null, we nust bind the stub to a
// directory.
InitialContext ctx =
new InitialContext(attributes);
if (rebind)
ctx.rebind(jndiUrl, rmiServer);
else
ctx.bind(jndiUrl, rmiServer);
ctx.close();
}
/**
* Creates a new RMIServerImpl.
**/
RMIServerImpl newServer() throws IOException {
final boolean iiop = isIiopURL(address,true);
final int port;
if (address == null)
port = 0;
else
port = address.getPort();
if (iiop)
return newIIOPServer(attributes);
else
return newJRMPServer(attributes, port);
}
/**
* Encode a stub into the JMXServiceURL.
* @param rmiServer The stub object to encode in the URL
* @param attributes A Map containing environment parameters,
* built from the Map specified at this object creation.
**/
private void encodeStubInAddress(
RMIServer rmiServer, Map