private Object invokeAttribute(PropertyDescriptor pd, MethodInvocation invocation)
      throws JMException, IOException {

    String attributeName = JmxUtils.getAttributeName(pd, this.useStrictCasing);
    MBeanAttributeInfo inf = (MBeanAttributeInfo) this.allowedAttributes.get(attributeName);

    // If no attribute is returned, we know that it is not defined in the
    // management interface.
    if (inf == null) {
      throw new InvalidInvocationException(
          "Attribute '" + pd.getName() + "' is not exposed on the management interface");
    }
    if (invocation.getMethod().equals(pd.getReadMethod())) {
      if (inf.isReadable()) {
        return this.server.getAttribute(this.objectName, attributeName);
      } else {
        throw new InvalidInvocationException("Attribute '" + attributeName + "' is not readable");
      }
    } else if (invocation.getMethod().equals(pd.getWriteMethod())) {
      if (inf.isWritable()) {
        server.setAttribute(
            this.objectName, new Attribute(attributeName, invocation.getArguments()[0]));
        return null;
      } else {
        throw new InvalidInvocationException("Attribute '" + attributeName + "' is not writable");
      }
    } else {
      throw new IllegalStateException(
          "Method [" + invocation.getMethod() + "] is neither a bean property getter nor a setter");
    }
  }
 public void testAnnotatedMXBean() throws Exception {
   if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) {
     return;
   }
   FooX foo = new FooX();
   assertTrue("MXBean annotation not detected correctly", JmxUtils.isMBean(foo.getClass()));
 }
  /**
   * Loads the management interface info for the configured MBean into the caches. This information
   * is used by the proxy when determining whether an invocation matches a valid operation or
   * attribute on the management interface of the managed resource.
   */
  private void retrieveMBeanInfo()
      throws MBeanServerNotFoundException, MBeanInfoRetrievalException {
    try {
      MBeanInfo info = this.server.getMBeanInfo(this.objectName);

      // get attributes
      MBeanAttributeInfo[] attributeInfo = info.getAttributes();
      this.allowedAttributes = new HashMap(attributeInfo.length);

      for (int x = 0; x < attributeInfo.length; x++) {
        this.allowedAttributes.put(attributeInfo[x].getName(), attributeInfo[x]);
      }

      // get operations
      MBeanOperationInfo[] operationInfo = info.getOperations();
      this.allowedOperations = new HashMap(operationInfo.length);

      for (int x = 0; x < operationInfo.length; x++) {
        MBeanOperationInfo opInfo = operationInfo[x];
        this.allowedOperations.put(
            new MethodCacheKey(
                opInfo.getName(), JmxUtils.parameterInfoToTypes(opInfo.getSignature())),
            opInfo);
      }
    } catch (ClassNotFoundException ex) {
      throw new MBeanInfoRetrievalException(
          "Unable to locate class specified in method signature", ex);
    } catch (IntrospectionException ex) {
      throw new MBeanInfoRetrievalException(
          "Unable to obtain MBean info for bean [" + this.objectName + "]", ex);
    } catch (InstanceNotFoundException ex) {
      // if we are this far this shouldn't happen, but...
      throw new MBeanInfoRetrievalException(
          "Unable to obtain MBean info for bean ["
              + this.objectName
              + "]: it is likely that this bean was unregistered during the proxy creation process",
          ex);
    } catch (ReflectionException ex) {
      throw new MBeanInfoRetrievalException(
          "Unable to read MBean info for bean [ " + this.objectName + "]", ex);
    } catch (IOException ex) {
      throw new MBeanInfoRetrievalException(
          "An IOException occurred when communicating with the MBeanServer. "
              + "It is likely that you are communicating with a remote MBeanServer. "
              + "Check the inner exception for exact details.",
          ex);
    }
  }
 /**
  * Connects to the remote <code>MBeanServer</code> using the configured <code>JMXServiceURL</code>
  * .
  *
  * @see #setServiceUrl(String)
  * @see #setConnectOnStartup(boolean)
  */
 private void connect() throws MBeanServerNotFoundException {
   if (this.serviceUrl != null) {
     if (logger.isDebugEnabled()) {
       logger.debug("Connecting to remote MBeanServer at URL [" + this.serviceUrl + "]");
     }
     try {
       this.connector = JMXConnectorFactory.connect(this.serviceUrl);
       this.server = this.connector.getMBeanServerConnection();
     } catch (IOException ex) {
       throw new MBeanServerNotFoundException(
           "Could not connect to remote MBeanServer at URL [" + this.serviceUrl + "]", ex);
     }
   } else {
     logger.debug("Attempting to locate local MBeanServer");
     this.server = JmxUtils.locateMBeanServer();
   }
 }
  /**
   * Routes a method invocation (not a property get/set) to the corresponding operation on the
   * managed resource.
   *
   * @param method the method corresponding to operation on the managed resource.
   * @param args the invocation arguments
   * @return the value returned by the method invocation.
   */
  private Object invokeOperation(Method method, Object[] args) throws JMException, IOException {
    MethodCacheKey key = new MethodCacheKey(method.getName(), method.getParameterTypes());
    MBeanOperationInfo info = (MBeanOperationInfo) this.allowedOperations.get(key);
    if (info == null) {
      throw new InvalidInvocationException(
          "Operation '" + method.getName() + "' is not exposed on the management interface");
    }

    String[] signature = null;
    synchronized (this.signatureCache) {
      signature = (String[]) this.signatureCache.get(method);
      if (signature == null) {
        signature = JmxUtils.getMethodSignature(method);
        this.signatureCache.put(method, signature);
      }
    }
    return this.server.invoke(this.objectName, method.getName(), args, signature);
  }
  /**
   * Registers the component specifying the info that describes it.
   *
   * <p>Certain interfaces are automatically detected. If the component implements {@code
   * Lifecycle}, it will be registered as though using {@link #registerLifecycle(Lifecycle)}. If it
   * implements {@code ServletContextAware}, then it will be registered as though using {@link
   * #registerServletContextAware(ServletContextAware)}. If it implements {@code InitializingBean},
   * then it will be initialized as though using {@link #initialize(InitializingBean)}.
   *
   * <p>If the component implements {@code FactoryBean}, it will be checked for the automatically
   * detected interfaces before the factory is evaluated. The evaluated factory will then be
   * registered, and the resulting object will again be checked for automatically detected
   * interfaces.
   *
   * @param info the component info to register, not null
   * @param instance the component instance to register, not null
   * @throws IllegalArgumentException if unable to register
   */
  public void registerComponent(final ComponentInfo info, Object instance) {
    ArgumentChecker.notNull(info, "info");
    ArgumentChecker.notNull(instance, "instance");
    checkStatus(Status.CREATING);

    final ComponentKey key = info.toComponentKey();
    try {
      // initialize
      initialize0(instance);
      registerInstanceInterfaces0(instance);

      // handle factories
      if (instance instanceof FactoryBean<?>) {
        try {
          instance = ((FactoryBean<?>) instance).getObject();
        } catch (final Exception ex) {
          throw new OpenGammaRuntimeException("FactoryBean threw exception", ex);
        }
        initialize0(instance);
        registerInstanceInterfaces0(instance);
      }

      // register into data structures
      final Object current = _instanceMap.putIfAbsent(key, instance);
      if (current != null) {
        throw new IllegalArgumentException(
            "Component already registered for specified information: " + key);
      }
      _infoMap.putIfAbsent(info.getType(), new ComponentTypeInfo(info.getType()));
      final ComponentTypeInfo typeInfo = getTypeInfo(info.getType());
      typeInfo.getInfoMap().put(info.getClassifier(), info);
      registeredComponent(info, instance);

      // If the component being registered is also an MBean, then register it as such
      if (JmxUtils.isMBean(instance.getClass())) {
        registerMBean(instance);
      }
    } catch (final RuntimeException ex) {
      _status.set(Status.FAILED);
      throw new RuntimeException("Failed during registration: " + key, ex);
    }
  }