0N/A/*
2362N/A * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage javax.management.remote;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.util.ArrayList;
0N/Aimport java.util.List;
0N/Aimport java.util.Map;
0N/A
0N/Aimport javax.management.MBeanNotificationInfo;
0N/Aimport javax.management.MBeanRegistration;
0N/Aimport javax.management.MBeanServer;
0N/Aimport javax.management.Notification;
0N/Aimport javax.management.NotificationBroadcasterSupport;
0N/Aimport javax.management.ObjectName;
0N/A
0N/A/**
0N/A * <p>Superclass of every connector server. A connector server is
0N/A * attached to an MBean server. It listens for client connection
0N/A * requests and creates a connection for each one.</p>
0N/A *
0N/A * <p>A connector server is associated with an MBean server either by
0N/A * registering it in that MBean server, or by passing the MBean server
0N/A * to its constructor.</p>
0N/A *
0N/A * <p>A connector server is inactive when created. It only starts
0N/A * listening for client connections when the {@link #start() start}
0N/A * method is called. A connector server stops listening for client
0N/A * connections when the {@link #stop() stop} method is called or when
0N/A * the connector server is unregistered from its MBean server.</p>
0N/A *
0N/A * <p>Stopping a connector server does not unregister it from its
0N/A * MBean server. A connector server once stopped cannot be
0N/A * restarted.</p>
0N/A *
0N/A * <p>Each time a client connection is made or broken, a notification
0N/A * of class {@link JMXConnectionNotification} is emitted.</p>
0N/A *
0N/A * @since 1.5
0N/A */
0N/Apublic abstract class JMXConnectorServer
0N/A extends NotificationBroadcasterSupport
0N/A implements JMXConnectorServerMBean, MBeanRegistration, JMXAddressable {
0N/A
0N/A /**
0N/A * <p>Name of the attribute that specifies the authenticator for a
0N/A * connector server. The value associated with this attribute, if
0N/A * any, must be an object that implements the interface {@link
0N/A * JMXAuthenticator}.</p>
0N/A */
0N/A public static final String AUTHENTICATOR =
0N/A "jmx.remote.authenticator";
0N/A
0N/A /**
0N/A * <p>Constructs a connector server that will be registered as an
0N/A * MBean in the MBean server it is attached to. This constructor
0N/A * is typically called by one of the <code>createMBean</code>
0N/A * methods when creating, within an MBean server, a connector
0N/A * server that makes it available remotely.</p>
0N/A */
0N/A public JMXConnectorServer() {
0N/A this(null);
0N/A }
0N/A
0N/A /**
0N/A * <p>Constructs a connector server that is attached to the given
0N/A * MBean server. A connector server that is created in this way
469N/A * can be registered in a different MBean server, or not registered
469N/A * in any MBean server.</p>
0N/A *
0N/A * @param mbeanServer the MBean server that this connector server
0N/A * is attached to. Null if this connector server will be attached
0N/A * to an MBean server by being registered in it.
0N/A */
0N/A public JMXConnectorServer(MBeanServer mbeanServer) {
1790N/A this.mbeanServer = mbeanServer;
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns the MBean server that this connector server is
1790N/A * attached to.</p>
0N/A *
0N/A * @return the MBean server that this connector server is attached
0N/A * to, or null if it is not yet attached to an MBean server.
0N/A */
0N/A public synchronized MBeanServer getMBeanServer() {
1790N/A return mbeanServer;
469N/A }
469N/A
1790N/A public synchronized void setMBeanServerForwarder(MBeanServerForwarder mbsf)
1790N/A {
469N/A if (mbsf == null)
469N/A throw new IllegalArgumentException("Invalid null argument: mbsf");
469N/A
1790N/A if (mbeanServer != null) mbsf.setMBeanServer(mbeanServer);
1790N/A mbeanServer = mbsf;
0N/A }
0N/A
0N/A public String[] getConnectionIds() {
0N/A synchronized (connectionIds) {
0N/A return connectionIds.toArray(new String[connectionIds.size()]);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns a client stub for this connector server. A client
0N/A * stub is a serializable object whose {@link
0N/A * JMXConnector#connect(Map) connect} method can be used to make
0N/A * one new connection to this connector server.</p>
0N/A *
0N/A * <p>A given connector need not support the generation of client
0N/A * stubs. However, the connectors specified by the JMX Remote API do
0N/A * (JMXMP Connector and RMI Connector).</p>
0N/A *
0N/A * <p>The default implementation of this method uses {@link
0N/A * #getAddress} and {@link JMXConnectorFactory} to generate the
0N/A * stub, with code equivalent to the following:</p>
0N/A *
0N/A * <pre>
0N/A * JMXServiceURL addr = {@link #getAddress() getAddress()};
0N/A * return {@link JMXConnectorFactory#newJMXConnector(JMXServiceURL, Map)
0N/A * JMXConnectorFactory.newJMXConnector(addr, env)};
0N/A * </pre>
0N/A *
0N/A * <p>A connector server for which this is inappropriate must
0N/A * override this method so that it either implements the
0N/A * appropriate logic or throws {@link
0N/A * UnsupportedOperationException}.</p>
0N/A *
0N/A * @param env client connection parameters of the same sort that
0N/A * could be provided to {@link JMXConnector#connect(Map)
0N/A * JMXConnector.connect(Map)}. Can be null, which is equivalent
0N/A * to an empty map.
0N/A *
0N/A * @return a client stub that can be used to make a new connection
0N/A * to this connector server.
0N/A *
0N/A * @exception UnsupportedOperationException if this connector
0N/A * server does not support the generation of client stubs.
0N/A *
0N/A * @exception IllegalStateException if the JMXConnectorServer is
0N/A * not started (see {@link JMXConnectorServerMBean#isActive()}).
0N/A *
0N/A * @exception IOException if a communications problem means that a
0N/A * stub cannot be created.
0N/A **/
0N/A public JMXConnector toJMXConnector(Map<String,?> env)
0N/A throws IOException
0N/A {
0N/A if (!isActive()) throw new
0N/A IllegalStateException("Connector is not active");
0N/A JMXServiceURL addr = getAddress();
0N/A return JMXConnectorFactory.newJMXConnector(addr, env);
0N/A }
0N/A
0N/A /**
0N/A * <p>Returns an array indicating the notifications that this MBean
0N/A * sends. The implementation in <code>JMXConnectorServer</code>
0N/A * returns an array with one element, indicating that it can emit
0N/A * notifications of class {@link JMXConnectionNotification} with
0N/A * the types defined in that class. A subclass that can emit other
0N/A * notifications should return an array that contains this element
0N/A * plus descriptions of the other notifications.</p>
0N/A *
0N/A * @return the array of possible notifications.
0N/A */
699N/A @Override
0N/A public MBeanNotificationInfo[] getNotificationInfo() {
0N/A final String[] types = {
0N/A JMXConnectionNotification.OPENED,
0N/A JMXConnectionNotification.CLOSED,
0N/A JMXConnectionNotification.FAILED,
0N/A };
0N/A final String className = JMXConnectionNotification.class.getName();
0N/A final String description =
0N/A "A client connection has been opened or closed";
0N/A return new MBeanNotificationInfo[] {
0N/A new MBeanNotificationInfo(types, className, description),
0N/A };
0N/A }
0N/A
0N/A /**
0N/A * <p>Called by a subclass when a new client connection is opened.
0N/A * Adds <code>connectionId</code> to the list returned by {@link
0N/A * #getConnectionIds()}, then emits a {@link
0N/A * JMXConnectionNotification} with type {@link
0N/A * JMXConnectionNotification#OPENED}.</p>
0N/A *
0N/A * @param connectionId the ID of the new connection. This must be
0N/A * different from the ID of any connection previously opened by
0N/A * this connector server.
0N/A *
0N/A * @param message the message for the emitted {@link
0N/A * JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getMessage()}.
0N/A *
0N/A * @param userData the <code>userData</code> for the emitted
0N/A * {@link JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getUserData()}.
0N/A *
0N/A * @exception NullPointerException if <code>connectionId</code> is
0N/A * null.
0N/A */
0N/A protected void connectionOpened(String connectionId,
0N/A String message,
0N/A Object userData) {
0N/A
0N/A if (connectionId == null)
0N/A throw new NullPointerException("Illegal null argument");
0N/A
0N/A synchronized (connectionIds) {
0N/A connectionIds.add(connectionId);
0N/A }
0N/A
0N/A sendNotification(JMXConnectionNotification.OPENED, connectionId,
0N/A message, userData);
0N/A }
0N/A
0N/A /**
0N/A * <p>Called by a subclass when a client connection is closed
0N/A * normally. Removes <code>connectionId</code> from the list returned
0N/A * by {@link #getConnectionIds()}, then emits a {@link
0N/A * JMXConnectionNotification} with type {@link
0N/A * JMXConnectionNotification#CLOSED}.</p>
0N/A *
0N/A * @param connectionId the ID of the closed connection.
0N/A *
0N/A * @param message the message for the emitted {@link
0N/A * JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getMessage()}.
0N/A *
0N/A * @param userData the <code>userData</code> for the emitted
0N/A * {@link JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getUserData()}.
0N/A *
0N/A * @exception NullPointerException if <code>connectionId</code>
0N/A * is null.
0N/A */
0N/A protected void connectionClosed(String connectionId,
0N/A String message,
0N/A Object userData) {
0N/A
0N/A if (connectionId == null)
0N/A throw new NullPointerException("Illegal null argument");
0N/A
0N/A synchronized (connectionIds) {
0N/A connectionIds.remove(connectionId);
0N/A }
0N/A
0N/A sendNotification(JMXConnectionNotification.CLOSED, connectionId,
0N/A message, userData);
0N/A }
0N/A
0N/A /**
0N/A * <p>Called by a subclass when a client connection fails.
0N/A * Removes <code>connectionId</code> from the list returned by
0N/A * {@link #getConnectionIds()}, then emits a {@link
0N/A * JMXConnectionNotification} with type {@link
0N/A * JMXConnectionNotification#FAILED}.</p>
0N/A *
0N/A * @param connectionId the ID of the failed connection.
0N/A *
0N/A * @param message the message for the emitted {@link
0N/A * JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getMessage()}.
0N/A *
0N/A * @param userData the <code>userData</code> for the emitted
0N/A * {@link JMXConnectionNotification}. Can be null. See {@link
0N/A * Notification#getUserData()}.
0N/A *
0N/A * @exception NullPointerException if <code>connectionId</code> is
0N/A * null.
0N/A */
0N/A protected void connectionFailed(String connectionId,
0N/A String message,
0N/A Object userData) {
0N/A
0N/A if (connectionId == null)
0N/A throw new NullPointerException("Illegal null argument");
0N/A
0N/A synchronized (connectionIds) {
0N/A connectionIds.remove(connectionId);
0N/A }
0N/A
0N/A sendNotification(JMXConnectionNotification.FAILED, connectionId,
0N/A message, userData);
0N/A }
0N/A
0N/A private void sendNotification(String type, String connectionId,
0N/A String message, Object userData) {
0N/A Notification notif =
0N/A new JMXConnectionNotification(type,
0N/A getNotificationSource(),
0N/A connectionId,
0N/A nextSequenceNumber(),
0N/A message,
0N/A userData);
0N/A sendNotification(notif);
0N/A }
0N/A
0N/A private synchronized Object getNotificationSource() {
0N/A if (myName != null)
0N/A return myName;
0N/A else
0N/A return this;
0N/A }
0N/A
0N/A private static long nextSequenceNumber() {
0N/A synchronized (sequenceNumberLock) {
0N/A return sequenceNumber++;
0N/A }
0N/A }
0N/A
0N/A // implements MBeanRegistration
0N/A /**
0N/A * <p>Called by an MBean server when this connector server is
0N/A * registered in that MBean server. This connector server becomes
0N/A * attached to the MBean server and its {@link #getMBeanServer()}
0N/A * method will return <code>mbs</code>.</p>
0N/A *
0N/A * <p>If this connector server is already attached to an MBean
0N/A * server, this method has no effect. The MBean server it is
0N/A * attached to is not necessarily the one it is being registered
0N/A * in.</p>
0N/A *
0N/A * @param mbs the MBean server in which this connection server is
0N/A * being registered.
0N/A *
0N/A * @param name The object name of the MBean.
0N/A *
0N/A * @return The name under which the MBean is to be registered.
0N/A *
0N/A * @exception NullPointerException if <code>mbs</code> or
0N/A * <code>name</code> is null.
0N/A */
0N/A public synchronized ObjectName preRegister(MBeanServer mbs,
0N/A ObjectName name) {
0N/A if (mbs == null || name == null)
0N/A throw new NullPointerException("Null MBeanServer or ObjectName");
1790N/A if (mbeanServer == null) {
1790N/A mbeanServer = mbs;
0N/A myName = name;
0N/A }
0N/A return name;
0N/A }
0N/A
0N/A public void postRegister(Boolean registrationDone) {
0N/A // do nothing
0N/A }
0N/A
0N/A /**
0N/A * <p>Called by an MBean server when this connector server is
0N/A * unregistered from that MBean server. If this connector server
0N/A * was attached to that MBean server by being registered in it,
0N/A * and if the connector server is still active,
0N/A * then unregistering it will call the {@link #stop stop} method.
0N/A * If the <code>stop</code> method throws an exception, the
0N/A * unregistration attempt will fail. It is recommended to call
0N/A * the <code>stop</code> method explicitly before unregistering
0N/A * the MBean.</p>
0N/A *
0N/A * @exception IOException if thrown by the {@link #stop stop} method.
0N/A */
0N/A public synchronized void preDeregister() throws Exception {
0N/A if (myName != null && isActive()) {
0N/A stop();
0N/A myName = null; // just in case stop is buggy and doesn't stop
0N/A }
0N/A }
0N/A
0N/A public void postDeregister() {
0N/A myName = null;
0N/A }
0N/A
1790N/A /**
1790N/A * The MBeanServer used by this server to execute a client request.
0N/A */
1790N/A private MBeanServer mbeanServer = null;
0N/A
0N/A /**
0N/A * The name used to registered this server in an MBeanServer.
0N/A * It is null if the this server is not registered or has been unregistered.
0N/A */
0N/A private ObjectName myName;
0N/A
1790N/A private final List<String> connectionIds = new ArrayList<String>();
0N/A
0N/A private static final int[] sequenceNumberLock = new int[0];
0N/A private static long sequenceNumber;
0N/A}