Package javax.management.remote.generic

Source Code of javax.management.remote.generic.GenericConnector$RequestHandler

/*
* @(#)file      GenericConnector.java
* @(#)author    Sun Microsystems, Inc.
* @(#)version   1.85
* @(#)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.io.*;
import java.util.*;

import javax.management.*;
import javax.management.remote.NotificationResult;

import javax.management.remote.message.Message;
import javax.management.remote.message.MBeanServerRequestMessage;
import javax.management.remote.message.MBeanServerResponseMessage;
import javax.management.remote.message.NotificationRequestMessage;
import javax.management.remote.message.NotificationResponseMessage;
import javax.management.remote.NotificationResult;
import javax.management.remote.message.CloseMessage;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorProvider; // javadoc
import javax.management.remote.JMXServiceURL; // javadoc

import javax.security.auth.Subject;

import com.sun.jmx.remote.generic.ObjectWrappingImpl;
import com.sun.jmx.remote.generic.DefaultConfig;
import com.sun.jmx.remote.generic.ClientSynchroMessageConnection;
import com.sun.jmx.remote.generic.ClientSynchroMessageConnectionImpl;
import com.sun.jmx.remote.generic.SynchroCallback;

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

import com.sun.jmx.remote.opt.util.ClassLoaderWithRepository;
import com.sun.jmx.remote.opt.util.ClassLogger;
import com.sun.jmx.remote.opt.util.OrderClassLoaders;
import com.sun.jmx.remote.opt.util.EnvHelp;

/**
* <p>A client connection to a remote JMX API server.  This class can
* use a {@link MessageConnection} object to specify the transport for
* communicating with the server.</p>
*
* <p>User code does not usually instantiate this class.  Instead, a
* {@link JMXConnectorProvider} should be added to the {@link
* JMXConnectorFactory} so that users can implicitly instantiate the
* GenericConnector (or a subclass of it) through the {@link
* JMXServiceURL} provided when connecting.</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 or the {@link #connect(Map) connect}
* method.  The attribute {@link #MESSAGE_CONNECTION} is the standard
* way to define the transport.  An implementation can recognize other
* attributes to define the transport differently.</p>
*/
public class GenericConnector implements JMXConnector {
    /**
     * <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 =
  GenericConnectorServer.OBJECT_WRAPPING;

    /**
     * <p>Name of the attribute that specifies how this connector
     * sends messages to its connector server.  The value associated
     * with this attribute, if any, must be an object that implements
     * the interface {@link MessageConnection}.</p>
     */
    public static final String MESSAGE_CONNECTION =
  "jmx.remote.message.connection";

    // constructors

    /**
     * <p>Default no-arg constructor.</p>
     **/
    public GenericConnector() {
  // ------------------------------------------------------------
  //  WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
  // ------------------------------------------------------------
  // This constructor is needed in order for subclasses to be
  // serializable.
  //
  this((Map)null);
    }

    /**
     * <p>Constructor specifying connection attributes.</p>
     *
     * @param env the attributes of the connection.
     **/
    public GenericConnector(Map env) {
  // ------------------------------------------------------------
  //  WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
  // ------------------------------------------------------------
  // Initialize transient variables. All transient variables
  // that need a specific initialization must be initialized here.
  //
  rmbscMap = new WeakHashMap();
  lock     = new int[0];
  state    = CREATED;
  if (env == null) {
      this.env = Collections.EMPTY_MAP;
  } else {
      EnvHelp.checkAttributes(env);
            this.env = Collections.unmodifiableMap(env);
  }
  connectionBroadcaster = new NotificationBroadcasterSupport();
    }

    public void connect() throws IOException {
  connect(null);
    }

    public void connect(Map env) throws IOException {
  final boolean tracing = logger.traceOn();
  final String  idstr   = (tracing?"["+this.toString()+"]":null);

  synchronized(lock) {
      switch (state) {
      case CREATED: break;
      case CONNECTED:
    if (tracing)
        logger.trace("connect",idstr + " already connected.");
    return;
      case CLOSED:
    if (tracing) logger.trace("connect",idstr + " already closed.");
    throw new IOException("Connector already closed.");
      default:
    // should never happen
    if (tracing)
        logger.trace("connect",idstr+" unknown state: "+state);
    throw new IOException("Invalid state ("+state+")");
      }

            final Map tmpEnv =
    new HashMap((this.env==null)?Collections.EMPTY_MAP:this.env);

      if (env != null) {
    EnvHelp.checkAttributes(env);
    tmpEnv.putAll(env);
      }

      MessageConnection conn =
    (MessageConnection) tmpEnv.get(MESSAGE_CONNECTION);
      if (conn == null) {
    connection = DefaultConfig.getClientSynchroMessageConnection(tmpEnv);
    if (connection == null) {
        if (tracing)
      logger.trace("connect",idstr + " No MessageConnection");
        throw new
      IllegalArgumentException("No MessageConnection");
    }
    if (tracing)
        logger.trace("connect", "The connection uses a user "
         +"specific Synchronous message connection.");
      } else {
    requestHandler = new RequestHandler();

    connection = new ClientSynchroMessageConnectionImpl(conn, requestHandler, tmpEnv);
    if (tracing)
        logger.trace("connect", "The connection uses a user "+
         "specific Asynchronous message connection.");
      }
      connection.connect(tmpEnv);
      connectionId = connection.getConnectionId();

      objectWrapping = (ObjectWrapping) tmpEnv.get(OBJECT_WRAPPING);
      if (objectWrapping == null)
    objectWrapping = new ObjectWrappingImpl();
          
      clientMBeanServer = new ClientIntermediary(connection,
        objectWrapping, this, tmpEnv);

      this.env = tmpEnv;

      state = CONNECTED;
      if (tracing) logger.trace("connect",idstr+" "+connectionId+" Connected.");
  }

  notifThread = new ThreadService(0, 1);

  sendNotification(new JMXConnectionNotification(
       JMXConnectionNotification.OPENED,
       this,
       connectionId,
       clientNotifID++,
       null,
       null));
    }

    public String getConnectionId() throws IOException {
  checkState();
  return connection.getConnectionId();
    }

    // implements client interface here
    public MBeanServerConnection getMBeanServerConnection()
  throws IOException {
  return getMBeanServerConnection(null);
    }

    public MBeanServerConnection getMBeanServerConnection(
                 Subject delegationSubject)
  throws IOException {
  checkState();
  if (rmbscMap.containsKey(delegationSubject)) {
      return (MBeanServerConnection) rmbscMap.get(delegationSubject);
  } else {
      RemoteMBeanServerConnection rmbsc =
    new RemoteMBeanServerConnection(clientMBeanServer,
            delegationSubject);
      rmbscMap.put(delegationSubject, rmbsc);
      return rmbsc;
  }
    }

    public void close() throws IOException {
  close(false, "The connection is closed by a user.");
    }

    private void close(boolean local, String msg) throws IOException {
  final boolean tracing = logger.traceOn();
  final boolean debug   = logger.debugOn();
  final String  idstr   = (tracing?"["+this.toString()+"]":null);
  Exception         closeException;

  boolean createdState;
  synchronized(lock) {
      if (state == CLOSED) {
    if (tracing) logger.trace("close",idstr + " already closed.");

    return;
      }

      createdState = (state == CREATED);

      state = CLOSED;
      closeException = null;

      if (tracing) logger.trace("close",idstr + " closing.");

      if (!createdState) {
    // inform the remote side of termination
    if (!local) {
        try {
      synchronized(connection) {
          connection.sendOneWay(new CloseMessage(msg));
          Thread.sleep(100);
      }
        } catch (InterruptedException ire) {
      // OK       
        } catch (Exception e1) {
      // error trace
      closeException = e1;
      if (tracing) logger.trace("close",idstr+
              " failed to send close message: " + e1);
      if (debug) logger.debug("close",e1);
        }
    }

    // close the transport protocol.
    try {
        connection.close();
    } catch (Exception e1) {
        closeException = e1;
        if (tracing) logger.trace("close",idstr+
          " failed to close MessageConnection: " + e1);
        if (debug) logger.debug("close",e1);
    }
      }

      if (clientMBeanServer != null) {
    clientMBeanServer.terminate();
      }

      // Clean up MBeanServerConnection table
      //
      rmbscMap.clear();
  }

  // if not connected, no need to send closed notif
  if (!createdState) {
      sendNotification(new JMXConnectionNotification(
          JMXConnectionNotification.CLOSED,
          this,
          connectionId,
          clientNotifID++,
          "The client has been closed.", null));
  }

  if (closeException != null) {
      if (closeException instanceof RuntimeException)
    throw (RuntimeException) closeException;
      if (closeException instanceof IOException)
    throw (IOException) closeException;
      final IOException x = new IOException("Failed to close: " +
              closeException);
      throw (IOException)EnvHelp.initCause(x,closeException);
    
  }
  if (tracing) logger.trace("close",idstr + " closed.");
    }

    public void
  addConnectionNotificationListener(NotificationListener listener,
            NotificationFilter filter,
            Object handback) {
  if (listener == null)
      throw new NullPointerException("listener");
  connectionBroadcaster.addNotificationListener(listener, filter,
                  handback);
    }

    public void
  removeConnectionNotificationListener(NotificationListener listener)
      throws ListenerNotFoundException {
  if (listener == null)
      throw new NullPointerException("listener");
  connectionBroadcaster.removeNotificationListener(listener);
    }

    public void
  removeConnectionNotificationListener(NotificationListener listener,
               NotificationFilter filter,
               Object handback)
      throws ListenerNotFoundException {
  if (listener == null)
      throw new NullPointerException("listener");
  connectionBroadcaster.removeNotificationListener(listener, filter,
               handback);
    }

    /**
     * <p>Send a notification to the connection listeners.  The
     * notification will be sent to every listener added with {@link
     * #addConnectionNotificationListener
     * addConnectionNotificationListener} that was not subsequently
     * removed by a <code>removeConnectionNotificationListener</code>,
     * provided the corresponding {@link NotificationFilter}
     * matches.</p>
     *
     * @param n the notification to send.  This will usually be a
     * {@link JMXConnectionNotification}, but an implementation can
     * send other notifications as well.
     */
    protected void sendNotification(final Notification n) {
  Runnable job = new Runnable() {
    public void run() {
        try {     
      connectionBroadcaster.sendNotification(n);
        } catch (Exception e) {
      // OK.
      // should never
        }
    }
      };

      notifThread.handoff(job);
    }

//----------------------------------------------
// private classes
//----------------------------------------------

    private static class RemoteMBeanServerConnection
      implements MBeanServerConnection {

        public RemoteMBeanServerConnection(ClientIntermediary ci) {
      this(ci, null);
        }

        public RemoteMBeanServerConnection(ClientIntermediary ci, Subject ds) {
            this.ci = ci;
            this.ds = ds;
        }

        //----------------------------------------------
        // Implementation of MBeanServerConnection
        //----------------------------------------------

        public ObjectInstance createMBean(String className, ObjectName name)
            throws
            ReflectionException,
            InstanceAlreadyExistsException,
            MBeanRegistrationException,
            MBeanException,
            NotCompliantMBeanException,
            IOException {
            return ci.createMBean(className, name, ds);
        }

        public ObjectInstance createMBean(String className,
                                          ObjectName name,
                                          ObjectName loaderName)
            throws
            ReflectionException,
            InstanceAlreadyExistsException,
            MBeanRegistrationException,
            MBeanException,
            NotCompliantMBeanException,
            InstanceNotFoundException,
            IOException {
            return ci.createMBean(className, name, loaderName, ds);
        }

        public ObjectInstance createMBean(String className,
                                          ObjectName name,
                                          Object params[],
                                          String signature[])
            throws
            ReflectionException,
            InstanceAlreadyExistsException,
            MBeanRegistrationException,
            MBeanException,
            NotCompliantMBeanException,
            IOException {
            return ci.createMBean(className, name, params, signature, ds);
        }

        public ObjectInstance createMBean(String className,
                                          ObjectName name,
                                          ObjectName loaderName,
                                          Object params[],
                                          String signature[])
            throws
            ReflectionException,
            InstanceAlreadyExistsException,
            MBeanRegistrationException,
            MBeanException,
            NotCompliantMBeanException,
            InstanceNotFoundException,
            IOException {
            return ci.createMBean(className, name, loaderName,
                                  params, signature, ds);
        }

        public void unregisterMBean(ObjectName name)
            throws
            InstanceNotFoundException,
            MBeanRegistrationException,
            IOException {
            ci.unregisterMBean(name, ds);
        }

        public ObjectInstance getObjectInstance(ObjectName name)
            throws InstanceNotFoundException, IOException {
            return ci.getObjectInstance(name, ds);
        }

        public Set queryMBeans(ObjectName name, QueryExp query)
            throws IOException {
            return ci.queryMBeans(name, query, ds);
        }

        public Set queryNames(ObjectName name, QueryExp query)
            throws IOException {
            return ci.queryNames(name, query, ds);
        }

        public boolean isRegistered(ObjectName name)
            throws IOException {
            return ci.isRegistered(name, ds);
        }

        public Integer getMBeanCount()
            throws IOException {
            return ci.getMBeanCount(ds);
        }

        public Object getAttribute(ObjectName name, String attribute)
            throws
            MBeanException,
            AttributeNotFoundException,
            InstanceNotFoundException,
            ReflectionException,
            IOException {
            return ci.getAttribute(name, attribute, ds);
        }

        public AttributeList getAttributes(ObjectName name, String[] attributes)
            throws InstanceNotFoundException, ReflectionException, IOException {
            return ci.getAttributes(name, attributes, ds);
        }

        public void setAttribute(ObjectName name, Attribute attribute)
            throws
            InstanceNotFoundException,
            AttributeNotFoundException,
            InvalidAttributeValueException,
            MBeanException,
            ReflectionException,
            IOException {
            ci.setAttribute(name, attribute, ds);
        }

        public AttributeList setAttributes(ObjectName name,
                                           AttributeList attributes)
            throws InstanceNotFoundException, ReflectionException, IOException {
            return ci.setAttributes(name, attributes, ds);
        }

        public Object invoke(ObjectName name, String operationName,
                             Object params[], String signature[])
            throws
            InstanceNotFoundException,
            MBeanException,
            ReflectionException,
            IOException {
            return ci.invoke(name, operationName, params, signature, ds);
        }

        public String getDefaultDomain()
            throws IOException {
            return ci.getDefaultDomain(ds);
        }

        public String[] getDomains()
            throws IOException {
            return ci.getDomains(ds);
        }

        public void addNotificationListener(ObjectName name,
                                            NotificationListener listener,
                                            NotificationFilter filter,
                                            Object handback)
            throws InstanceNotFoundException, IOException {
            ci.addNotificationListener(name, listener, filter, handback, ds);
        }

        public void addNotificationListener(ObjectName name,
                                            ObjectName listener,
                                            NotificationFilter filter,
                                            Object handback)
            throws InstanceNotFoundException, IOException {
            ci.addNotificationListener(name, listener, filter, handback, ds);
        }

        public void removeNotificationListener(ObjectName name,
                                               ObjectName listener)
            throws
            InstanceNotFoundException,
            ListenerNotFoundException,
            IOException {
            ci.removeNotificationListener(name, listener, ds);
        }

        public void removeNotificationListener(ObjectName name,
                                               ObjectName listener,
                                               NotificationFilter filter,
                                               Object handback)
            throws
            InstanceNotFoundException,
            ListenerNotFoundException,
            IOException {
            ci.removeNotificationListener(name, listener, filter, handback, ds);
        }

        public void removeNotificationListener(ObjectName name,
                                               NotificationListener listener)
            throws
            InstanceNotFoundException,
            ListenerNotFoundException,
            IOException {
            ci.removeNotificationListener(name, listener, ds);
        }

        public void removeNotificationListener(ObjectName name,
                                               NotificationListener listener,
                                               NotificationFilter filter,
                                               Object handback)
            throws
            InstanceNotFoundException,
            ListenerNotFoundException,
            IOException {
            ci.removeNotificationListener(name, listener, filter, handback, ds);
        }

        public MBeanInfo getMBeanInfo(ObjectName name)
            throws
            InstanceNotFoundException,
            IntrospectionException,
            ReflectionException,
            IOException {
            return ci.getMBeanInfo(name, ds);
        }

        public boolean isInstanceOf(ObjectName name, String className)
            throws InstanceNotFoundException, IOException {
            return ci.isInstanceOf(name, className, ds);
        }

        private ClientIntermediary ci;
        private Subject ds;
    }

    private class RequestHandler implements SynchroCallback {

  public Message execute(Message msg) {     
      if (msg instanceof CloseMessage) {
    if (logger.traceOn())
        logger.trace("RequestHandler-execute",
              "got Message REMOTE_TERMINATION");


    // try to re-connect anyway
    try {
        com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin admin
      = clientMBeanServer.getCommunicatorAdmin();
        admin.gotIOException(new IOException(""));

        return null;
    } catch (IOException ioe) {
        // OK
        // the server has been closed.
    }

    try {
        GenericConnector.this.close(true, null);
    } catch (IOException ie) {
        // OK never
    }
      } else {
    final String errstr =
        ((msg==null)?"null":msg.getClass().getName())
        +": Bad message type.";
   
    logger.warning("RequestHandler-execute",errstr);
   
    try {
        logger.warning("RequestHandler-execute",
           "Closing connector");
        GenericConnector.this.close(false, null);
    } catch (IOException ie) {
        logger.info("RequestHandler-execute", ie);
    }
      }

      return null;
  }

  public void connectionException(Exception e) {
      synchronized(lock) {
    if (state != CONNECTED) {
        return;
    }
      }

      logger.warning("RequestHandler-connectionException", e);

      if (e instanceof IOException) {     
    try {
        com.sun.jmx.remote.opt.internal.ClientCommunicatorAdmin admin
      = clientMBeanServer.getCommunicatorAdmin();
        admin.gotIOException((IOException)e);
       
        return;
    } catch (IOException ioe) {
        // OK.
        // closing at the following steps
    }
      }

      synchronized(lock) {
    if (state == CONNECTED) {
        logger.warning("RequestHandler-connectionException", "Got connection exception: "+e.toString());
        logger.debug("RequestHandler-connectionException", "Got connection exception: "+e.toString(), e);
       
        try {
      GenericConnector.this.close(true, null);
        } catch (IOException ie) {
      logger.info("RequestHandler-execute", ie);
        }
    }
      }
  }
    }

    //
    private static class ResponseMsgWrapper {
  public boolean got = false;
  public Message msg = null;

  public ResponseMsgWrapper() {}

  public void setMsg(Message msg) {
      got = true;
      this.msg = msg;
  }
    }

// -------------------------------------------------
// package methods
// -------------------------------------------------
    /**
     * Called by a ClientIntermediary to reconnect the transport because
     * the server has been closed after its timeout.
     */
    ClientSynchroMessageConnection reconnect() throws IOException {
  synchronized(lock) {
      if (state != CONNECTED) {
    throw new IOException(
       "The connector is not at the connection state.");
      }
  }

  sendNotification(new JMXConnectionNotification(
       JMXConnectionNotification.FAILED,
       this,
       connectionId,
       clientNotifID++,
       "The client has got connection exception.", null));

  connection.connect(env);
  connectionId = connection.getConnectionId();

  sendNotification(new JMXConnectionNotification(
          JMXConnectionNotification.OPENED,
          this,
          connectionId,
          clientNotifID++,
          "The client has succesfully reconnected to the server.", null));

  return connection;
    }

// -------------------------------------------------
// private methods
// -------------------------------------------------
    private void checkState() throws IOException {
  synchronized(lock) {
      if (state == CREATED) {
    throw new IOException("The client has not been connected.");
      } else if (state == CLOSED) {
    throw new IOException("The client has been closed.");
      }
  }
    }

    // private variables

    // -------------------------------------------------------------------
    // WARNING - WARNING - WARNING - WARNING - WARNING - WARNING - WARNING
    // -------------------------------------------------------------------
    //
    // SERIALIZATION ISSUES
    // --------------------
    //
    // All private variables must be defined transient.
    //
    // Do not put any initialization here. If a specific initialization
    // is needed, put it in the empty default constructor.
    //
    // -------------------------------------------------------------------
    private transient ClientSynchroMessageConnection connection;
    private transient ObjectWrapping    objectWrapping;
    private transient Map env;

    private transient ClientIntermediary clientMBeanServer;
    private transient WeakHashMap rmbscMap;
    private transient String connectionId;

    private transient RequestHandler requestHandler;

    private transient final NotificationBroadcasterSupport
  connectionBroadcaster;

    private transient ThreadService notifThread;

    // state
    private static final int CREATED = 1;
    private static final int CONNECTED = 2;
    private static final int CLOSED = 3;

    // default value is 0.
    private transient int state;
    private transient int[] lock;

    private transient long clientNotifID = 0;

    private static final ClassLogger logger =
  new ClassLogger("javax.management.remote.generic", "GenericConenctor");
}
TOP

Related Classes of javax.management.remote.generic.GenericConnector$RequestHandler

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.