コード例 #1
0
  /**
   * Creates a connector server at the given address. The resultant server is not started until its
   * {@link JMXConnectorServer#start() start} method is called.
   *
   * @param serviceURL the address of the new connector server. The actual address of the new
   *     connector server, as returned by its {@link JMXConnectorServer#getAddress() getAddress}
   *     method, will not necessarily be exactly the same. For example, it might include a port
   *     number if the original address did not.
   * @param environment a set of attributes to control the new connector server's behavior. This
   *     parameter can be null. Keys in this map must be Strings. The appropriate type of each
   *     associated value depends on the attribute. The contents of <code>environment</code> are not
   *     changed by this call.
   * @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.
   * @return a <code>JMXConnectorServer</code> representing the new connector server. Each
   *     successful call to this method produces a different object.
   * @exception NullPointerException if <code>serviceURL</code> is null.
   * @exception IOException if the connector server cannot be made because of a communication
   *     problem.
   * @exception MalformedURLException if there is no provider for the protocol in <code>serviceURL
   *     </code>.
   * @exception JMXProviderException if there is a provider for the protocol in <code>serviceURL
   *     </code> but it cannot be used for some reason.
   */
  public static JMXConnectorServer newJMXConnectorServer(
      JMXServiceURL serviceURL, Map<String, ?> environment, MBeanServer mbeanServer)
      throws IOException {
    if (environment == null) environment = new HashMap();
    else {
      EnvHelp.checkAttributes(environment);
      environment = new HashMap(environment);
    }

    final Class targetInterface = JMXConnectorServerProvider.class;
    final ClassLoader loader = JMXConnectorFactory.resolveClassLoader(environment);
    final String protocol = serviceURL.getProtocol();
    final String providerClassName = "ServerProvider";

    JMXConnectorServerProvider provider =
        (JMXConnectorServerProvider)
            JMXConnectorFactory.getProvider(
                serviceURL, environment, providerClassName, targetInterface, loader);

    IOException exception = null;
    if (provider == null) {
      // Loader is null when context class loader is set to null
      // and no loader has been provided in map.
      // com.sun.jmx.remote.util.Service class extracted from j2se
      // provider search algorithm doesn't handle well null classloader.
      if (loader != null) {
        try {
          JMXConnectorServer connection =
              getConnectorServerAsService(loader, serviceURL, environment, mbeanServer);
          if (connection != null) return connection;
        } catch (JMXProviderException e) {
          throw e;
        } catch (IOException e) {
          exception = e;
        }
      }
      provider =
          (JMXConnectorServerProvider)
              JMXConnectorFactory.getProvider(
                  protocol,
                  PROTOCOL_PROVIDER_DEFAULT_PACKAGE,
                  JMXConnectorFactory.class.getClassLoader(),
                  providerClassName,
                  targetInterface);
    }

    if (provider == null) {
      MalformedURLException e = new MalformedURLException("Unsupported protocol: " + protocol);
      if (exception == null) {
        throw e;
      } else {
        throw EnvHelp.initCause(e, exception);
      }
    }

    environment = Collections.unmodifiableMap(environment);

    return provider.newJMXConnectorServer(serviceURL, environment, mbeanServer);
  }
コード例 #2
0
 private static JMXConnectorServer getConnectorServerAsService(
     ClassLoader loader, JMXServiceURL url, Map map, MBeanServer mbs) throws IOException {
   Iterator providers =
       JMXConnectorFactory.getProviderIterator(JMXConnectorServerProvider.class, loader);
   JMXConnectorServerProvider provider = null;
   JMXConnectorServer connection = null;
   IOException exception = null;
   while (providers.hasNext()) {
     provider = (JMXConnectorServerProvider) providers.next();
     try {
       connection = provider.newJMXConnectorServer(url, map, mbs);
       return connection;
     } catch (JMXProviderException e) {
       throw e;
     } catch (Exception e) {
       if (logger.traceOn())
         logger.trace(
             "getConnectorAsService", "URL[" + url + "] Service provider exception: " + e);
       if (!(e instanceof MalformedURLException)) {
         if (exception == null) {
           if (exception instanceof IOException) {
             exception = (IOException) e;
           } else {
             exception = EnvHelp.initCause(new IOException(e.getMessage()), e);
           }
         }
       }
       continue;
     }
   }
   if (exception == null) return null;
   else throw exception;
 }
コード例 #3
0
  /*
   * Called when a connector is doing reconnection. Like <code>postReconnection</code>,
   * this method is intended to be called only by a client connector:
   * <code>RMIConnector</code> and <code>ClientIntermediary</code>.
   * Call this method will set the flag beingReconnection to <code>true</code>,
   * and the thread used to fetch notifis will be stopped, a new thread can be
   * created only after the method <code>postReconnection</code> is called.
   *
   * It is caller's responsiblity to not re-call this method before calling
   * <code>postReconnection</code>.
   */
  public synchronized ClientListenerInfo[] preReconnection() throws IOException {
    if (state == TERMINATED || beingReconnected) { // should never
      throw new IOException("Illegal state.");
    }

    final ClientListenerInfo[] tmp = infoList.values().toArray(new ClientListenerInfo[0]);

    beingReconnected = true;

    infoList.clear();

    if (currentFetchThread == Thread.currentThread()) {
      /* we do not need to stop the fetching thread, because this thread is
      used to do restarting and it will not be used to do fetching during
      the re-registering the listeners.*/
      return tmp;
    }

    while (state == STARTING) {
      try {
        wait();
      } catch (InterruptedException ire) {
        IOException ioe = new IOException(ire.toString());
        EnvHelp.initCause(ioe, ire);

        throw ioe;
      }
    }

    if (state == STARTED) {
      setState(STOPPING);
    }

    return tmp;
  }
コード例 #4
0
  public ClientNotifForwarder(ClassLoader defaultClassLoader, Map env) {
    maxNotifications = EnvHelp.getMaxFetchNotifNumber(env);
    timeout = EnvHelp.getFetchTimeout(env);

    /* You can supply an Executor in which the remote call to
    fetchNotifications will be made.  The Executor's execute
    method reschedules another task, so you must not use
    an Executor that executes tasks in the caller's thread.  */
    Executor ex = (Executor) env.get("jmx.remote.x.fetch.notifications.executor");
    if (ex == null) ex = new LinearExecutor();
    else if (logger.traceOn()) logger.trace("ClientNotifForwarder", "executor is " + ex);

    this.defaultClassLoader = defaultClassLoader;
    this.executor = ex;
    this.acc = AccessController.getContext();
  }
コード例 #5
0
  /**
   * Returns the size of a notification buffer for a connector server. The default value is 1000.
   */
  public static int getNotifBufferSize(Map<String, ?> env) {
    int defaultQueueSize = 1000; // default value

    // keep it for the compability for the fix:
    // 6174229: Environment parameter should be notification.buffer.size
    // instead of buffer.size
    final String oldP = "jmx.remote.x.buffer.size";

    // the default value re-specified in the system
    try {
      GetPropertyAction act = new GetPropertyAction(BUFFER_SIZE_PROPERTY);
      String s = AccessController.doPrivileged(act);
      if (s != null) {
        defaultQueueSize = Integer.parseInt(s);
      } else { // try the old one
        act = new GetPropertyAction(oldP);
        s = AccessController.doPrivileged(act);
        if (s != null) {
          defaultQueueSize = Integer.parseInt(s);
        }
      }
    } catch (RuntimeException e) {
      logger.warning(
          "getNotifBufferSize", "Can't use System property " + BUFFER_SIZE_PROPERTY + ": " + e);
      logger.debug("getNotifBufferSize", e);
    }

    int queueSize = defaultQueueSize;

    try {
      if (env.containsKey(BUFFER_SIZE_PROPERTY)) {
        queueSize =
            (int)
                EnvHelp.getIntegerAttribute(
                    env, BUFFER_SIZE_PROPERTY, defaultQueueSize, 0, Integer.MAX_VALUE);
      } else { // try the old one
        queueSize =
            (int) EnvHelp.getIntegerAttribute(env, oldP, defaultQueueSize, 0, Integer.MAX_VALUE);
      }
    } catch (RuntimeException e) {
      logger.warning("getNotifBufferSize", "Can't determine queuesize (using default): " + e);
      logger.debug("getNotifBufferSize", e);
    }

    return queueSize;
  }
コード例 #6
0
 static <T> T valueFrom(Descriptor d, String name, OpenType<T> openType) {
   Object x = d.getFieldValue(name);
   if (x == null) return null;
   try {
     return convertFrom(x, openType);
   } catch (Exception e) {
     final String msg =
         "Cannot convert descriptor field " + name + "  to " + openType.getTypeName();
     throw EnvHelp.initCause(new IllegalArgumentException(msg), e);
   }
 }
コード例 #7
0
    public void run() {
      myThread = Thread.currentThread();

      while (state != TERMINATED && !myThread.isInterrupted()) {
        try {
          Thread.sleep(period);
        } catch (InterruptedException ire) {
          // OK.
          // We will check the state at the following steps
        }

        if (state == TERMINATED || myThread.isInterrupted()) {
          break;
        }

        try {
          checkConnection();
        } catch (Exception e) {
          synchronized (lock) {
            if (state == TERMINATED || myThread.isInterrupted()) {
              break;
            }
          }

          e = (Exception) EnvHelp.getCause(e);

          if (e instanceof IOException && !(e instanceof InterruptedIOException)) {
            try {
              gotIOException((IOException) e);
            } catch (Exception ee) {
              logger.warning("Checker-run", "Failed to check connection: " + e);
              logger.warning("Checker-run", "stopping");
              logger.debug("Checker-run", e);

              break;
            }
          } else {
            logger.warning("Checker-run", "Failed to check the connection: " + e);
            logger.debug("Checker-run", e);

            // XXX stop checking?

            break;
          }
        }
      }

      if (logger.traceOn()) {
        logger.trace("Checker-run", "Finished.");
      }
    }
コード例 #8
0
  /**
   * Called after reconnection is finished. This method is intended to be called only by a client
   * connector: <code>RMIConnector</code> and <code>ClientIntermediary</code>.
   */
  public synchronized void postReconnection(ClientListenerInfo[] listenerInfos) throws IOException {

    if (state == TERMINATED) {
      return;
    }

    while (state == STOPPING) {
      try {
        wait();
      } catch (InterruptedException ire) {
        IOException ioe = new IOException(ire.toString());
        EnvHelp.initCause(ioe, ire);
        throw ioe;
      }
    }

    final boolean trace = logger.traceOn();
    final int len = listenerInfos.length;

    for (int i = 0; i < len; i++) {
      if (trace) {
        logger.trace(
            "addNotificationListeners", "Add a listener at " + listenerInfos[i].getListenerID());
      }

      infoList.put(listenerInfos[i].getListenerID(), listenerInfos[i]);
    }

    beingReconnected = false;
    notifyAll();

    if (currentFetchThread == Thread.currentThread()) {
      // no need to init, simply get the id
      try {
        mbeanRemovedNotifID = addListenerForMBeanRemovedNotif();
      } catch (Exception e) {
        final String msg =
            "Failed to register a listener to the mbean "
                + "server: the client will not do clean when an MBean "
                + "is unregistered";
        if (logger.traceOn()) {
          logger.trace("init", msg, e);
        }
      }
    } else if (listenerInfos.length > 0) { // old listeners re-registered
      init(true);
    } else if (infoList.size() > 0) {
      // but new listeners registered during reconnection
      init(false);
    }
  }
コード例 #9
0
  /**
   * Import: should not remove a listener during reconnection, the reconnection needs to change the
   * listener list and that will possibly make removal fail.
   */
  private synchronized void beforeRemove() throws IOException {
    while (beingReconnected) {
      if (state == TERMINATED) {
        throw new IOException("Terminated.");
      }

      try {
        wait();
      } catch (InterruptedException ire) {
        IOException ioe = new IOException(ire.toString());
        EnvHelp.initCause(ioe, ire);

        throw ioe;
      }
    }

    if (state == TERMINATED) {
      throw new IOException("Terminated.");
    }
  }
コード例 #10
0
  private void restart(IOException ioe) throws IOException {
    // check state
    synchronized (lock) {
      if (state == TERMINATED) {
        throw new IOException("The client has been closed.");
      } else if (state == FAILED) { // already failed to re-start by another thread
        throw ioe;
      } else if (state == RE_CONNECTING) {
        // restart process has been called by another thread
        // we need to wait
        while (state == RE_CONNECTING) {
          try {
            lock.wait();
          } catch (InterruptedException ire) {
            // be asked to give up
            InterruptedIOException iioe = new InterruptedIOException(ire.toString());
            EnvHelp.initCause(iioe, ire);

            throw iioe;
          }
        }

        if (state == TERMINATED) {
          throw new IOException("The client has been closed.");
        } else if (state != CONNECTED) {
          // restarted is failed by another thread
          throw ioe;
        }
        return;
      } else {
        state = RE_CONNECTING;
        lock.notifyAll();
      }
    }

    // re-starting
    try {
      doStart();
      synchronized (lock) {
        if (state == TERMINATED) {
          throw new IOException("The client has been closed.");
        }

        state = CONNECTED;

        lock.notifyAll();
      }

      return;
    } catch (Exception e) {
      logger.warning("restart", "Failed to restart: " + e);
      logger.debug("restart", e);

      synchronized (lock) {
        if (state == TERMINATED) {
          throw new IOException("The client has been closed.");
        }

        state = FAILED;

        lock.notifyAll();
      }

      try {
        doStop();
      } catch (Exception eee) {
        // OK.
        // We know there is a problem.
      }

      terminate();

      throw ioe;
    }
  }
コード例 #11
0
  /*
   * Called to decide whether need to start a thread for fetching notifs.
   * <P>The parameter reconnected will decide whether to initilize the clientSequenceNumber,
   * initilaizing the clientSequenceNumber means to ignore all notifications arrived before.
   * If it is reconnected, we will not initialize in order to get all notifications arrived
   * during the reconnection. It may cause the newly registered listeners to receive some
   * notifications arrived before its registray.
   */
  private synchronized void init(boolean reconnected) throws IOException {
    switch (state) {
      case STARTED:
        return;
      case STARTING:
        return;
      case TERMINATED:
        throw new IOException("The ClientNotifForwarder has been terminated.");
      case STOPPING:
        if (beingReconnected == true) {
          // wait for another thread to do, which is doing reconnection
          return;
        }

        while (state == STOPPING) { // make sure only one fetching thread.
          try {
            wait();
          } catch (InterruptedException ire) {
            IOException ioe = new IOException(ire.toString());
            EnvHelp.initCause(ioe, ire);

            throw ioe;
          }
        }

        // re-call this method to check the state again,
        // the state can be other value like TERMINATED.
        init(reconnected);

        return;
      case STOPPED:
        if (beingReconnected == true) {
          // wait for another thread to do, which is doing reconnection
          return;
        }

        if (logger.traceOn()) {
          logger.trace("init", "Initializing...");
        }

        // init the clientSequenceNumber if not reconnected.
        if (!reconnected) {
          try {
            NotificationResult nr = fetchNotifs(-1, 0, 0);
            clientSequenceNumber = nr.getNextSequenceNumber();
          } catch (ClassNotFoundException e) {
            // can't happen
            logger.warning("init", "Impossible exception: " + e);
            logger.debug("init", e);
          }
        }

        // for cleaning
        try {
          mbeanRemovedNotifID = addListenerForMBeanRemovedNotif();
        } catch (Exception e) {
          final String msg =
              "Failed to register a listener to the mbean "
                  + "server: the client will not do clean when an MBean "
                  + "is unregistered";
          if (logger.traceOn()) {
            logger.trace("init", msg, e);
          }
        }

        setState(STARTING);

        // start fetching
        executor.execute(new NotifFetcher());

        return;
      default:
        // should not
        throw new IOException("Unknown state.");
    }
  }