/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* <p>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.</p>
*
* @since 1.5
*/
/**
* <p>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 <code>"true"</code> or
* <code>"false"</code>. The default value is false.</p>
*/
"jmx.remote.jndi.rebind";
/**
* <p>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 <code>RMIClientSocketFactory</code> and can
* only be specified in the <code>Map</code> argument supplied when
* creating a connector server.</p>
*/
"jmx.remote.rmi.client.socket.factory";
/**
* <p>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 <code>RMIServerSocketFactory</code> and can
* only be specified in the <code>Map</code> argument supplied when
* creating a connector server.</p>
*/
"jmx.remote.rmi.server.socket.factory";
/**
* <p>Makes an <code>RMIConnectorServer</code>.
* This is equivalent to calling {@link #RMIConnectorServer(
* JMXServiceURL,Map,RMIServerImpl,MBeanServer)
* RMIConnectorServer(directoryURL,environment,null,null)}</p>
*
* @param url the URL defining how to create the connector server.
* Cannot be null.
*
* @param environment attributes governing the creation and
* storing of the RMI object. Can be null, which is equivalent to
* an empty Map.
*
* @exception IllegalArgumentException if <code>url</code> is null.
*
* @exception MalformedURLException if <code>url</code> 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.
*/
throws IOException {
}
/**
* <p>Makes an <code>RMIConnectorServer</code> for the given MBean
* server.
* This is equivalent to calling {@link #RMIConnectorServer(
* JMXServiceURL,Map,RMIServerImpl,MBeanServer)
* RMIConnectorServer(directoryURL,environment,null,mbeanServer)}</p>
*
* @param url the URL defining how to create the connector server.
* Cannot be null.
*
* @param environment attributes governing the creation and
* storing of the RMI object. Can be null, which is equivalent to
* an empty Map.
*
* @param mbeanServer the MBean server to which the new connector
* server is attached, or null if it will be attached by being
* registered as an MBean in the MBean server.
*
* @exception IllegalArgumentException if <code>url</code> is null.
*
* @exception MalformedURLException if <code>url</code> 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.
*/
throws IOException {
}
/**
* <p>Makes an <code>RMIConnectorServer</code> for the given MBean
* server.</p>
*
* @param url the URL defining how to create the connector server.
* Cannot be null.
*
* @param environment attributes governing the creation and
* storing of the RMI object. Can be null, which is equivalent to
* an empty Map.
*
* @param rmiServerImpl An implementation of the RMIServer interface,
* consistent with the protocol type specified in <var>url</var>.
* If this parameter is non null, the protocol type specified by
* <var>url</var> is not constrained, and is assumed to be valid.
* Otherwise, only "rmi" and "iiop" will be recognized.
*
* @param mbeanServer the MBean server to which the new connector
* server is attached, or null if it will be attached by being
* registered as an MBean in the MBean server.
*
* @exception IllegalArgumentException if <code>url</code> is null.
*
* @exception MalformedURLException if <code>url</code> 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 <var>rmiServerImpl</var> 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
*/
throws IOException {
super(mbeanServer);
IllegalArgumentException("Null JMXServiceURL");
if (rmiServerImpl == null) {
throw new MalformedURLException(msg);
}
"/jndi/";
throw new MalformedURLException(msg);
}
}
if (environment == null)
else {
}
this.rmiServerImpl = rmiServerImpl;
}
/**
* <p>Returns 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.</p>
*
* @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.
**/
// The serialized for of rmiServerImpl is automatically
// a RMI server stub.
if (!isActive()) throw new
IllegalStateException("Connector is not active");
// Merge maps
this.attributes);
}
}
/**
* <p>Activates 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
* <code>IOException</code>.</p>
*
* <p>The behavior of this method when called for the first time
* depends on the parameters that were supplied at construction,
* as described below.</p>
*
* <p>First, an object of a subclass of {@link RMIServerImpl} is
* required, to export the connector server through RMI:</p>
*
* <ul>
*
* <li>If an <code>RMIServerImpl</code> was supplied to the
* constructor, it is used.
*
* <li>Otherwise, if the protocol part of the
* <code>JMXServiceURL</code> supplied to the constructor was
* <code>iiop</code>, an object of type {@link RMIIIOPServerImpl}
* is created.
*
* <li>Otherwise, if the <code>JMXServiceURL</code>
* was null, or its protocol part was <code>rmi</code>, an object
* of type {@link RMIJRMPServerImpl} is created.
*
* <li>Otherwise, the implementation can create an
* implementation-specific {@link RMIServerImpl} or it can throw
* {@link MalformedURLException}.
*
* </ul>
*
* <p>If the given address includes a JNDI directory URL as
* specified in the package documentation for {@link
* javax.management.remote.rmi}, then this
* <code>RMIConnectorServer</code> will bootstrap by binding the
* <code>RMIServerImpl</code> to the given address.</p>
*
* <p>If the URL path part of the <code>JMXServiceURL</code> was
* empty or a single slash (<code>/</code>), 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
* <code>rmi</code> and <code>iiop</code> are described in the
* package documentation for {@link
* javax.management.remote.rmi}.</p>
*
* <p>The behavior when the URL path is neither empty nor a JNDI
* directory URL, or when the protocol is neither <code>rmi</code>
* nor <code>iiop</code>, is implementation defined, and may
* include throwing {@link MalformedURLException} when the
* connector server is created or when it is started.</p>
*
* @exception IllegalStateException if the connector server has
* not been attached to an MBean server.
* @exception IOException if the connector server cannot be
* started.
*/
return;
throw new IOException("The server has been stopped.");
}
if (getMBeanServer() == null)
throw new IllegalStateException("This connector server is not " +
"attached to an MBean server");
// Check the internal access file property to see
// if an MBeanServerForwarder is to be provided
//
if (attributes != null) {
// Check if access file property is specified
//
if (accessFile != null) {
// Access file property specified, create an instance
// of the MBeanServerFileAccessController class
//
try {
} catch (IOException e) {
new IllegalArgumentException(e.getMessage()), e);
}
// Set the MBeanServerForwarder
//
}
}
try {
attributes, getMBeanServer());
} catch (InstanceNotFoundException infc) {
IllegalArgumentException x = new
}
final RMIServerImpl rmiServer;
if (rmiServerImpl != null)
else
rmiServer.setRMIConnectorServer(this);
try {
if (tracing)
if (tracing)
try {
} catch (NamingException e) {
// fit e in the nested exception if we are on 1.4
+ e, e);
}
} else {
// if jndiURL is null, we must encode the stub into the URL.
}
} catch (Exception e) {
try {
} catch (Exception x) {
// OK: we are already throwing another exception
}
if (e instanceof RuntimeException)
throw (RuntimeException) e;
else if (e instanceof IOException)
throw (IOException) e;
else
throw newIOException("Got unexpected exception while " +
"starting the connector server: "
+ e, e);
}
synchronized(openedServers) {
openedServers.add(this);
}
if (tracing) {
}
}
/**
* <p>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.</p>
*
* <p>Once a connector server has been stopped, it cannot be started
* again.</p>
*
* <p>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.</p>
*
* <p>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.</p>
*
* <p>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.</p>
*
* <p>This method calls the method {@link RMIServerImpl#close()
* close} on the connector server's <code>RMIServerImpl</code>
* object.</p>
*
* <p>If the <code>RMIServerImpl</code> was bound to a JNDI
* directory by the {@link #start() start} method, it is unbound
* from the directory by this method.</p>
*
* @exception IOException if the server cannot be closed cleanly,
* or if the <code>RMIServerImpl</code> 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 <code>RMIServerImpl</code> from its directory, if
* appropriate. All client connections are closed except possibly
* those that generated exceptions when the server attempted to
* close them.
*/
synchronized (this) {
return;
}
}
synchronized(openedServers) {
openedServers.remove(this);
}
// rmiServerImpl can be null if stop() called without start()
if (rmiServerImpl != null) {
try {
} catch (IOException e) {
exception = e;
}
}
if (boundJndiUrl != null) {
try {
if (tracing)
"unbind from external directory: " + boundJndiUrl);
new InitialContext(usemap);
} catch (NamingException e) {
// fit e in as the nested exception if we are on 1.4
}
}
}
public synchronized boolean isActive() {
}
if (!isActive())
return null;
return address;
}
}
public synchronized
super.setMBeanServerForwarder(mbsf);
if (rmiServerImpl != null)
}
/* We repeat the definitions of connection{Opened,Closed,Failed}
here so that they are accessible to other classes in this package
even though they have protected access. */
}
}
}
/**
* Bind a stub to a registry.
* @param jndiUrl URL of the stub in the registry, extracted
* from the <code>JMXServiceURL</code>.
* @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.
**/
throws NamingException, MalformedURLException {
// if jndiURL is not null, we nust bind the stub to a
// directory.
new InitialContext(attributes);
if (rebind)
else
}
/**
* Creates a new RMIServerImpl.
**/
final int port;
port = 0;
else
if (iiop)
return newIIOPServer(attributes);
else
}
/**
* 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(
throws IOException {
final int port;
protocol = "iiop";
else
protocol = "rmi";
port = 0;
} else {
}
}
throws MalformedURLException {
return false;
return true;
else if (strict) {
throw new MalformedURLException("URL must have protocol " +
"\"rmi\" or \"iiop\": \"" +
protocol + "\"");
}
return false;
}
/**
* Returns the IOR of the given rmiServer.
**/
else
}
throws IOException {
return byteArrayToBase64(bytes);
}
throws IOException {
try {
} catch (RuntimeException x) {
throw newIOException(x.getMessage(), x);
}
}
/**
* Object that we will bind to the registry.
* This object is a stub connected to our RMIServerImpl.
**/
throws IOException {
return RMIConnector.
}
throws IOException {
}
throws IOException {
return new RMIIIOPServerImpl(env);
}
// Translate all full groups from byte array elements to Base64
int inCursor = 0;
for (int i=0; i<numFullGroups; i++) {
}
// Translate partial group if present
if (numBytesInPartialGroup != 0) {
if (numBytesInPartialGroup == 1) {
} else {
// assert numBytesInPartialGroup == 2;
}
}
// assert inCursor == a.length;
// assert result.length() == resultLen;
}
/**
* This array is a lookup table that translates 6-bit positive integer
* index values into their "Base64 Alphabet" equivalents as specified
* in Table 1 of RFC 2045.
*/
private static final char intToAlpha[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
/**
* Construct a new IOException with a nested exception.
* The nested exception is set only if JDK >= 1.4
*/
}
// Private variables
// -----------------
// state
new HashSet<RMIConnectorServer>();
}