All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.management.remote.generic.GenericConnectorServer Maven / Gradle / Ivy

Go to download

Java Management Extensions (JMX) technology provides the tools for building distributed, Web-based, modular and dynamic solutions for managing and monitoring devices, applications, and service-driven networks. By design, this standard is suitable for adapting legacy systems, implementing new management and monitoring solutions, and plugging into those of the future.

The newest version!
/*
 * @(#)file      GenericConnectorServer.java
 * @(#)author    Sun Microsystems, Inc.
 * @(#)version   1.87
 * @(#)lastedit  07/03/08
 * @(#)build     @BUILD_TAG_PLACEHOLDER@
 *
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU General
 * Public License Version 2 only ("GPL") or the Common Development and
 * Distribution License("CDDL")(collectively, the "License"). You may not use
 * this file except in compliance with the License. You can obtain a copy of the
 * License at http://opendmk.dev.java.net/legal_notices/licenses.txt or in the 
 * LEGAL_NOTICES folder that accompanied this code. See the License for the 
 * specific language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file found at
 *     http://opendmk.dev.java.net/legal_notices/licenses.txt
 * or in the LEGAL_NOTICES folder that accompanied this code.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.
 * 
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * 
 *       "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding
 * 
 *       "[Contributor] elects to include this software in this distribution
 *        under the [CDDL or GPL Version 2] license."
 * 
 * If you don't indicate a single choice of license, a recipient has the option
 * to distribute your version of this file under either the CDDL or the GPL
 * Version 2, or to extend the choice of license to its licensees as provided
 * above. However, if you add GPL Version 2 code and therefore, elected the
 * GPL Version 2 license, then the option applies only if the new code is made
 * subject to such option by the copyright holder.
 * 
 */ 

package javax.management.remote.generic;

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.SortedMap;
import java.util.Collections;
import java.util.Timer;
import java.util.TimerTask;
import java.io.IOException;
import java.io.ObjectOutputStream; // javadoc
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import javax.security.auth.Subject;

import javax.management.MBeanServer;
import javax.management.MBeanRegistration;
import javax.management.NotificationBroadcasterSupport;
import javax.management.InstanceNotFoundException;

import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXConnectorServerProvider;
import javax.management.remote.MBeanServerForwarder;

import javax.management.remote.message.HandshakeEndMessage; // javadoc
import javax.management.remote.message.HandshakeErrorMessage; // javadoc

import com.sun.jmx.remote.generic.ObjectWrappingImpl;
import com.sun.jmx.remote.generic.DefaultConfig;
import com.sun.jmx.remote.generic.ServerSynchroMessageConnection;
import com.sun.jmx.remote.generic.ServerSynchroMessageConnectionImpl;
import com.sun.jmx.remote.generic.SynchroMessageConnectionServer;
import com.sun.jmx.remote.generic.SynchroMessageConnectionServerImpl;

import com.sun.jmx.remote.opt.util.ThreadService;

import com.sun.jmx.remote.opt.security.MBeanServerFileAccessController;
import com.sun.jmx.remote.opt.util.ClassLogger;
import com.sun.jmx.remote.opt.util.EnvHelp;
import com.sun.jmx.remote.opt.internal.ArrayNotificationBuffer;
import com.sun.jmx.remote.opt.internal.NotificationBuffer;

/**
 * 

A JMX API Connector server that creates connections to remote * clients. This class can use a {@link MessageConnectionServer} object * to specify how connections are made.

* *

User code does not usually instantiate this class. Instead, a * {@link JMXConnectorServerProvider} should be added to the {@link * JMXConnectorServerFactory} so that users can implicitly instantiate * the GenericConnector (or a subclass of it) through the {@link * JMXServiceURL} provided when creating it.

* *

The specific connector protocol to be used by an instance of * this class is specified by attributes in the Map * passed to the constructor. The attribute {@link * #MESSAGE_CONNECTION_SERVER} is the standard way to define the * transport. An implementation can recognize other attributes to * define the transport differently.

*/ public class GenericConnectorServer extends JMXConnectorServer { /** *

Name of the attribute that specifies the object wrapping for * parameters whose deserialization requires special treatment. * The value associated with this attribute, if any, must be an * object that implements the interface {@link ObjectWrapping}.

*/ public static final String OBJECT_WRAPPING = "jmx.remote.object.wrapping"; /** *

Name of the attribute that specifies how connections are * made to this connector server. The value associated with this * attribute, if any, must be an object that implements the * interface {@link MessageConnectionServer}.

*/ public static final String MESSAGE_CONNECTION_SERVER = "jmx.remote.message.connection.server"; // constructors /** *

Constructs a GenericConnectorServer attached to * the given MBean server.

* * @param env a set of attributes for the connector server. Can * be null, which is equivalent to an empty map. * @param mbs the local MBeanServer used to execute a remote * request. Null if the MBean server will be specified by * registering this connector server as an MBean in it. * * @exception IllegalArgumentException if env contains * some invalid values. */ public GenericConnectorServer(Map env, MBeanServer mbs) { super(mbs); if (env == null) this.env = Collections.EMPTY_MAP; else { EnvHelp.checkAttributes(env); this.env = Collections.unmodifiableMap(env); } connectingTimeout = DefaultConfig.getConnectingTimeout(this.env); } // used by a client connection void clientClosing(ServerIntermediary inter, String connectionId, String msg, Object userData) { synchronized(lock) { clientList.remove(inter); } super.connectionClosed(connectionId, msg, userData); } // JMXConnectorServerMBean interface implementation public JMXServiceURL getAddress() { if (!isActive()) return null; return sMsgServer.getAddress(); } public Map getAttributes() { Map map = EnvHelp.filterAttributes(env); return Collections.unmodifiableMap(map); } /** *

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 * {@link IOException}.

* * @exception IllegalStateException if the connector server has * not been attached to an MBean server. * @exception IOException if the connector server cannot be * started. */ public void start() throws IOException { final boolean tracing = logger.traceOn(); synchronized(lock) { if (state == STARTED) { if (tracing) logger.trace("start", "already started"); return; } else if (state == STOPPED) { if (tracing) logger.trace("start", "already stopped"); throw new IOException("The server has been stopped."); } if (tracing) logger.trace("start", "starting..."); if (tracing) logger.trace("start", "setting MBeanServer..."); MBeanServer mbs = getMBeanServer(); if (mbs == 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 (env != null) { // Check if access file property is specified // String accessFile = (String) env.get("jmx.remote.x.access.file"); if (accessFile != null) { // Access file property specified, create an instance // of the MBeanServerFileAccessController class // MBeanServerForwarder mbsf = null; try { mbsf = new MBeanServerFileAccessController(accessFile); } catch (IOException e) { throw (IllegalArgumentException) EnvHelp.initCause( new IllegalArgumentException(e.getMessage()),e); } // Set the MBeanServerForwarder // setMBeanServerForwarder(mbsf); mbs = getMBeanServer(); } } if (tracing) logger.trace("start", "setting default ClassLoader..."); try { defaultClassLoader = EnvHelp.resolveServerClassLoader(env, mbs); } catch (InstanceNotFoundException infc) { if (tracing) logger.debug("start", "ClassLoader not found: " + infc); IllegalArgumentException x = new IllegalArgumentException("ClassLoader not found: "+ infc); throw (IllegalArgumentException)EnvHelp.initCause(x,infc); } if (tracing) logger.trace("start", "setting ObjectWrapping..."); objectWrapping = (ObjectWrapping) env.get(OBJECT_WRAPPING); if (objectWrapping == null) objectWrapping = new ObjectWrappingImpl(); final MessageConnectionServer messageServer = (MessageConnectionServer) env.get(MESSAGE_CONNECTION_SERVER); if (messageServer == null) { sMsgServer = DefaultConfig.getSynchroMessageConnectionServer(env); if (sMsgServer == null) { final String msg = "No message connection server"; throw new IllegalArgumentException(msg); } } else { sMsgServer = new SynchroMessageConnectionServerImpl(messageServer, env); } sMsgServer.start(env); state = STARTED; if (tracing) { logger.trace("start", "Connector Server Address = " + sMsgServer.getAddress()); logger.trace("start", "started."); } // start to receive clients receiver = new Receiver(); receiver.start(); } } public void stop() throws IOException { final boolean tracing = logger.traceOn(); synchronized(lock) { if (state == STOPPED) { if (tracing) logger.trace("stop","already stopped."); return; } else if (state == CREATED) { if (tracing) logger.trace("stop","not started yet."); } state = STOPPED; final boolean debug = logger.debugOn(); if (tracing) logger.trace("stop", "stoping."); Exception re = null; if (tracing) logger.trace("stop", "stop MessageConnectionServer..."); // stop the transport level if (sMsgServer != null) sMsgServer.stop(); if (tracing) logger.trace("stop", "stop clients..."); // stop all existing clients if (tracing) logger.trace("stop",clientList.size() + "client(s) found..."); while(clientList.size() > 0) { try { ServerIntermediary inter = (ServerIntermediary)clientList.remove(0); inter.terminate(); } catch (Exception e) { // Warning should be enough. logger.warning("stop","Failed to stop client: " + e); if (debug) logger.debug("stop",e); } } if(notifBuffer != null) notifBuffer.dispose(); threads.terminate(); } cancelConnecting.cancel(); if (tracing) logger.trace("stop","stopped."); } public boolean isActive() { synchronized(lock) { return state == STARTED; } } // used by ServerIntermediary void failedConnectionNotif(String connectionId, String message, Object userData) { super.connectionFailed(connectionId, message, userData); } // private classes private class Receiver extends Thread { public void run() { if (logger.debugOn()) logger.debug("Receiver.run", "starting receiver."); while(isActive()) { final boolean tracing = logger.traceOn(); ServerSynchroMessageConnection connection = null; final boolean debug = logger.debugOn(); if (tracing) logger.trace("Receiver.run", "waiting for connection."); try { connection = sMsgServer.accept(); } catch (IOException ioe) { if (isActive()) { logger.error("Receiver.run", "Unexpected IOException: "+ioe); if (debug) logger.debug("Receiver.run", ioe); try { logger.error("Receiver.run", "stopping server"); GenericConnectorServer.this.stop(); } catch (IOException ie) { logger.warning("Receiver.run", "Failed to stop server: "+ie); if (debug) logger.debug("Receiver.run",ie); } } else { if (tracing) logger.trace("Receiver.run", "interrupted: "+ioe); } break; } if (!isActive()) { return; } if (tracing) logger.trace("Receiver.run", "received connection request."); // use another thread to do security issue to free // the receiver thread for receiving new clients ClientCreation cc = new ClientCreation(connection); if (connectingTimeout <= 0) { threads.handoff(cc); } else { ConnectingStopper stopper = new ConnectingStopper(cc); cc.setStopper(stopper); threads.handoff(cc); cancelConnecting.schedule(stopper, connectingTimeout); } } if (logger.debugOn()) logger.debug("Receiver.run","receiver terminated"); } } private class ClientCreation implements Runnable { public ClientCreation(ServerSynchroMessageConnection connection) { this.connection = connection; } public void setStopper(ConnectingStopper stopper) { this.stopper = stopper; } public void run() { final boolean tracing = logger.traceOn(); Subject subject = null; boolean failed = false; try { connection.connect(env); if (tracing) logger.trace("ClientCreation.run", "opening connection."); subject = connection.getSubject(); } catch (Throwable e) { failed = true; logger.warning("ClientCreation.run", "Failed to open connection: "+e, e); if (tracing) logger.debug("ClientCreation.run",e); try { if (tracing) logger.debug("ClientCreation.run","cleaning up..."); connection.close(); } catch (Exception ee) { if (logger.debugOn()) logger.debug("ClientCreation.run", "Failed to cleanup: "+ee); if (logger.debugOn()) logger.debug("ClientCreation.run",ee); } } synchronized(this) { if (done) { // set by stopper, timeout failed = true; } else { done = true; if (stopper != null) { stopper.cancel(); } } } if (failed) { return; } if (tracing) logger.trace("ClientCreation.run","connection opened."); final ServerIntermediary inter = new ServerIntermediary(getMBeanServer(), GenericConnectorServer.this, connection, objectWrapping, subject, defaultClassLoader,env); synchronized(lock) { if (state != STARTED) { try { if (logger.debugOn()) logger.debug("ClientCreation.run", "connector already stopped."); if (tracing) logger.trace("ClientCreation.run", "cleaning up..."); inter.terminate(); } catch (Exception e) { if (logger.debugOn()) logger.debug("ClientCreation.run", "Failed to cleanup: "+e); if (logger.debugOn()) logger.debug("ClientCreation.run",e); } return; } else { if (tracing) logger.trace("ClientCreation.run", "adding connection to client list."); clientList.add(inter); } } final String cid = connection.getConnectionId(); connectionOpened(cid, "New client connection " + cid + " has been established", null); inter.start(); } ServerSynchroMessageConnection connection; private boolean done = false; private ConnectingStopper stopper; } private class ConnectingStopper extends TimerTask { public ConnectingStopper(ClientCreation cc) { this.cc = cc; } public void run() { synchronized(cc) { if (cc.done) { return; } // tell "timeout" cc.done = true; } if (logger.traceOn()) { logger.trace("ConnectingStopper.run", "Connecting timeout for: "+cc.connection); } try { cc.connection.close(); } catch (Exception e) { if (logger.debugOn()) { logger.debug("ConnectingStoper.run",e); } } } private final ClientCreation cc; } synchronized NotificationBuffer getNotifBuffer() { //Notification buffer is lazily created when the first client connects if(notifBuffer == null) notifBuffer = ArrayNotificationBuffer.getNotificationBuffer(getMBeanServer(), env); return notifBuffer; } private static final ClassLogger logger = new ClassLogger("javax.management.remote.generic", "GenericConnectorServer"); // private variables private Receiver receiver; private SynchroMessageConnectionServer sMsgServer; private ObjectWrapping objectWrapping; private Map env; private ClassLoader defaultClassLoader = null; private ThreadService threads = new ThreadService(0, 10); private ArrayList clientList = new ArrayList(); private static final int DEFAULT_NOTIF_BUFFER_SIZE = 1000; // state private static final int CREATED = 0; private static final int STARTED = 1; private static final int STOPPED = 2; private int state = CREATED; private int[] lock = new int[0]; // client id private static long clientIDCount = 0; private static final int[] clientIDCountLock = new int[0]; private NotificationBuffer notifBuffer; // client connecting control private final long connectingTimeout; // private final int maxConnecting; private static Timer cancelConnecting = new Timer(true); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy