Package javax.management.remote.generic

Source Code of javax.management.remote.generic.GenericConnectorServer$Receiver

/*
* @(#)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;

/**
* <p>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.</p>
*
* <p>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.</p>
*
* <p>The specific connector protocol to be used by an instance of
* this class is specified by attributes in the <code>Map</code>
* 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.</p>
*/
public class GenericConnectorServer extends JMXConnectorServer {

    /**
     * <p>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}.</p>
     */
    public static final String OBJECT_WRAPPING =
  "jmx.remote.object.wrapping";

    /**
     * <p>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}.</p>
     */
    public static final String MESSAGE_CONNECTION_SERVER =
  "jmx.remote.message.connection.server";

// constructors

    /**
     * <p>Constructs a <code>GenericConnectorServer</code> attached to
     * the given MBean server.</p>
     *
     * @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 <var>env</var> 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);
    }


    /**
     * <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
     * {@link IOException}.</p>
     *
     * @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);
}
TOP

Related Classes of javax.management.remote.generic.GenericConnectorServer$Receiver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.