414 lines · 15.4 KB · Java
RawDownload
/* * Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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.  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. */  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, or not registered     * in any 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.     */    @Override    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 final List<String> connectionIds = new ArrayList<String>();     private static final int[] sequenceNumberLock = new int[0];    private static long sequenceNumber;}