--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/javax/management/remote/JMXConnectorServer.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+
+package javax.management.remote;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.ObjectName;
+
+/**
+ * <p>Superclass of every connector server. A connector server is
+ * attached to an MBean server. It listens for client connection
+ * requests and creates a connection for each one.</p>
+ *
+ * <p>A connector server is associated with an MBean server either by
+ * registering it in that MBean server, or by passing the MBean server
+ * to its constructor.</p>
+ *
+ * <p>A connector server is inactive when created. It only starts
+ * listening for client connections when the {@link #start() start}
+ * method is called. A connector server stops listening for client
+ * connections when the {@link #stop() stop} method is called or when
+ * the connector server is unregistered from its MBean server.</p>
+ *
+ * <p>Stopping a connector server does not unregister it from its
+ * MBean server. A connector server once stopped cannot be
+ * restarted.</p>
+ *
+ * <p>Each time a client connection is made or broken, a notification
+ * of class {@link JMXConnectionNotification} is emitted.</p>
+ *
+ * @since 1.5
+ */
+public abstract class JMXConnectorServer
+ extends NotificationBroadcasterSupport
+ implements JMXConnectorServerMBean, MBeanRegistration, JMXAddressable {
+
+ /**
+ * <p>Name of the attribute that specifies the authenticator for a
+ * connector server. The value associated with this attribute, if
+ * any, must be an object that implements the interface {@link
+ * JMXAuthenticator}.</p>
+ */
+ public static final String AUTHENTICATOR =
+ "jmx.remote.authenticator";
+
+ /**
+ * <p>Constructs a connector server that will be registered as an
+ * MBean in the MBean server it is attached to. This constructor
+ * is typically called by one of the <code>createMBean</code>
+ * methods when creating, within an MBean server, a connector
+ * server that makes it available remotely.</p>
+ */
+ public JMXConnectorServer() {
+ this(null);
+ }
+
+ /**
+ * <p>Constructs a connector server that is attached to the given
+ * MBean server. A connector server that is created in this way
+ * can be registered in a different MBean server.</p>
+ *
+ * @param mbeanServer the MBean server that this connector server
+ * is attached to. Null if this connector server will be attached
+ * to an MBean server by being registered in it.
+ */
+ public JMXConnectorServer(MBeanServer mbeanServer) {
+ this.mbeanServer = mbeanServer;
+ }
+
+ /**
+ * <p>Returns the MBean server that this connector server is
+ * attached to.</p>
+ *
+ * @return the MBean server that this connector server is attached
+ * to, or null if it is not yet attached to an MBean server.
+ */
+ public synchronized MBeanServer getMBeanServer() {
+ return mbeanServer;
+ }
+
+ public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf)
+ {
+ if (mbsf == null)
+ throw new IllegalArgumentException("Invalid null argument: mbsf");
+
+ if (mbeanServer != null) mbsf.setMBeanServer(mbeanServer);
+ mbeanServer = mbsf;
+ }
+
+ public String[] getConnectionIds() {
+ synchronized (connectionIds) {
+ return connectionIds.toArray(new String[connectionIds.size()]);
+ }
+ }
+
+ /**
+ * <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>
+ *
+ * <p>A given connector need not support the generation of client
+ * stubs. However, the connectors specified by the JMX Remote API do
+ * (JMXMP Connector and RMI Connector).</p>
+ *
+ * <p>The default implementation of this method uses {@link
+ * #getAddress} and {@link JMXConnectorFactory} to generate the
+ * stub, with code equivalent to the following:</p>
+ *
+ * <pre>
+ * JMXServiceURL addr = {@link #getAddress() getAddress()};
+ * return {@link JMXConnectorFactory#newJMXConnector(JMXServiceURL, Map)
+ * JMXConnectorFactory.newJMXConnector(addr, env)};
+ * </pre>
+ *
+ * <p>A connector server for which this is inappropriate must
+ * override this method so that it either implements the
+ * appropriate logic or throws {@link
+ * UnsupportedOperationException}.</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 JMXConnectorServerMBean#isActive()}).
+ *
+ * @exception IOException if a communications problem means that a
+ * stub cannot be created.
+ **/
+ public JMXConnector toJMXConnector(Map<String,?> env)
+ throws IOException
+ {
+ if (!isActive()) throw new
+ IllegalStateException("Connector is not active");
+ JMXServiceURL addr = getAddress();
+ return JMXConnectorFactory.newJMXConnector(addr, env);
+ }
+
+ /**
+ * <p>Returns an array indicating the notifications that this MBean
+ * sends. The implementation in <code>JMXConnectorServer</code>
+ * returns an array with one element, indicating that it can emit
+ * notifications of class {@link JMXConnectionNotification} with
+ * the types defined in that class. A subclass that can emit other
+ * notifications should return an array that contains this element
+ * plus descriptions of the other notifications.</p>
+ *
+ * @return the array of possible notifications.
+ */
+ public MBeanNotificationInfo[] getNotificationInfo() {
+ final String[] types = {
+ JMXConnectionNotification.OPENED,
+ JMXConnectionNotification.CLOSED,
+ JMXConnectionNotification.FAILED,
+ };
+ final String className = JMXConnectionNotification.class.getName();
+ final String description =
+ "A client connection has been opened or closed";
+ return new MBeanNotificationInfo[] {
+ new MBeanNotificationInfo(types, className, description),
+ };
+ }
+
+ /**
+ * <p>Called by a subclass when a new client connection is opened.
+ * Adds <code>connectionId</code> to the list returned by {@link
+ * #getConnectionIds()}, then emits a {@link
+ * JMXConnectionNotification} with type {@link
+ * JMXConnectionNotification#OPENED}.</p>
+ *
+ * @param connectionId the ID of the new connection. This must be
+ * different from the ID of any connection previously opened by
+ * this connector server.
+ *
+ * @param message the message for the emitted {@link
+ * JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getMessage()}.
+ *
+ * @param userData the <code>userData</code> for the emitted
+ * {@link JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getUserData()}.
+ *
+ * @exception NullPointerException if <code>connectionId</code> is
+ * null.
+ */
+ protected void connectionOpened(String connectionId,
+ String message,
+ Object userData) {
+
+ if (connectionId == null)
+ throw new NullPointerException("Illegal null argument");
+
+ synchronized (connectionIds) {
+ connectionIds.add(connectionId);
+ }
+
+ sendNotification(JMXConnectionNotification.OPENED, connectionId,
+ message, userData);
+ }
+
+ /**
+ * <p>Called by a subclass when a client connection is closed
+ * normally. Removes <code>connectionId</code> from the list returned
+ * by {@link #getConnectionIds()}, then emits a {@link
+ * JMXConnectionNotification} with type {@link
+ * JMXConnectionNotification#CLOSED}.</p>
+ *
+ * @param connectionId the ID of the closed connection.
+ *
+ * @param message the message for the emitted {@link
+ * JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getMessage()}.
+ *
+ * @param userData the <code>userData</code> for the emitted
+ * {@link JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getUserData()}.
+ *
+ * @exception NullPointerException if <code>connectionId</code>
+ * is null.
+ */
+ protected void connectionClosed(String connectionId,
+ String message,
+ Object userData) {
+
+ if (connectionId == null)
+ throw new NullPointerException("Illegal null argument");
+
+ synchronized (connectionIds) {
+ connectionIds.remove(connectionId);
+ }
+
+ sendNotification(JMXConnectionNotification.CLOSED, connectionId,
+ message, userData);
+ }
+
+ /**
+ * <p>Called by a subclass when a client connection fails.
+ * Removes <code>connectionId</code> from the list returned by
+ * {@link #getConnectionIds()}, then emits a {@link
+ * JMXConnectionNotification} with type {@link
+ * JMXConnectionNotification#FAILED}.</p>
+ *
+ * @param connectionId the ID of the failed connection.
+ *
+ * @param message the message for the emitted {@link
+ * JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getMessage()}.
+ *
+ * @param userData the <code>userData</code> for the emitted
+ * {@link JMXConnectionNotification}. Can be null. See {@link
+ * Notification#getUserData()}.
+ *
+ * @exception NullPointerException if <code>connectionId</code> is
+ * null.
+ */
+ protected void connectionFailed(String connectionId,
+ String message,
+ Object userData) {
+
+ if (connectionId == null)
+ throw new NullPointerException("Illegal null argument");
+
+ synchronized (connectionIds) {
+ connectionIds.remove(connectionId);
+ }
+
+ sendNotification(JMXConnectionNotification.FAILED, connectionId,
+ message, userData);
+ }
+
+ private void sendNotification(String type, String connectionId,
+ String message, Object userData) {
+ Notification notif =
+ new JMXConnectionNotification(type,
+ getNotificationSource(),
+ connectionId,
+ nextSequenceNumber(),
+ message,
+ userData);
+ sendNotification(notif);
+ }
+
+ private synchronized Object getNotificationSource() {
+ if (myName != null)
+ return myName;
+ else
+ return this;
+ }
+
+ private static long nextSequenceNumber() {
+ synchronized (sequenceNumberLock) {
+ return sequenceNumber++;
+ }
+ }
+
+ // implements MBeanRegistration
+ /**
+ * <p>Called by an MBean server when this connector server is
+ * registered in that MBean server. This connector server becomes
+ * attached to the MBean server and its {@link #getMBeanServer()}
+ * method will return <code>mbs</code>.</p>
+ *
+ * <p>If this connector server is already attached to an MBean
+ * server, this method has no effect. The MBean server it is
+ * attached to is not necessarily the one it is being registered
+ * in.</p>
+ *
+ * @param mbs the MBean server in which this connection server is
+ * being registered.
+ *
+ * @param name The object name of the MBean.
+ *
+ * @return The name under which the MBean is to be registered.
+ *
+ * @exception NullPointerException if <code>mbs</code> or
+ * <code>name</code> is null.
+ */
+ public synchronized ObjectName preRegister(MBeanServer mbs,
+ ObjectName name) {
+ if (mbs == null || name == null)
+ throw new NullPointerException("Null MBeanServer or ObjectName");
+ if (mbeanServer == null) {
+ mbeanServer = mbs;
+ myName = name;
+ }
+ return name;
+ }
+
+ public void postRegister(Boolean registrationDone) {
+ // do nothing
+ }
+
+ /**
+ * <p>Called by an MBean server when this connector server is
+ * unregistered from that MBean server. If this connector server
+ * was attached to that MBean server by being registered in it,
+ * and if the connector server is still active,
+ * then unregistering it will call the {@link #stop stop} method.
+ * If the <code>stop</code> method throws an exception, the
+ * unregistration attempt will fail. It is recommended to call
+ * the <code>stop</code> method explicitly before unregistering
+ * the MBean.</p>
+ *
+ * @exception IOException if thrown by the {@link #stop stop} method.
+ */
+ public synchronized void preDeregister() throws Exception {
+ if (myName != null && isActive()) {
+ stop();
+ myName = null; // just in case stop is buggy and doesn't stop
+ }
+ }
+
+ public void postDeregister() {
+ myName = null;
+ }
+
+ /**
+ * The MBeanServer used by this server to execute a client request.
+ */
+ private MBeanServer mbeanServer = null;
+
+ /**
+ * The name used to registered this server in an MBeanServer.
+ * It is null if the this server is not registered or has been unregistered.
+ */
+ private ObjectName myName;
+
+ private List<String> connectionIds = new ArrayList<String>();
+
+ private static final int[] sequenceNumberLock = new int[0];
+ private static long sequenceNumber;
+}