private MBeanConstructorInfo[] createMBeanConstructorInfo(
      MBeanMetaData metadata, MBeanDescription descrs) {
    Class mbeanClass = metadata.mbean.getClass();

    Constructor[] ctors = mbeanClass.getConstructors();
    MBeanConstructorInfo[] constructors = new MBeanConstructorInfo[ctors.length];
    for (int i = 0; i < ctors.length; ++i) {
      Constructor constructor = ctors[i];
      String descr = descrs == null ? null : descrs.getConstructorDescription(constructor);
      Class[] params = constructor.getParameterTypes();
      MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[params.length];
      for (int j = 0; j < params.length; ++j) {
        Class param = params[j];
        String paramName =
            descrs == null ? null : descrs.getConstructorParameterName(constructor, j);
        String paramDescr =
            descrs == null ? null : descrs.getConstructorParameterDescription(constructor, j);
        paramsInfo[j] = new MBeanParameterInfo(paramName, param.getName(), paramDescr);
      }

      String ctorName = constructor.getName();
      MBeanConstructorInfo info =
          new MBeanConstructorInfo(
              ctorName.substring(ctorName.lastIndexOf('.') + 1), descr, paramsInfo);
      constructors[i] = info;
    }
    return constructors;
  }
  private MBeanOperationInfo[] createMBeanOperationInfo(
      MBeanMetaData metadata, MBeanDescription description) {
    ArrayList operations = new ArrayList();

    Method[] methods = metadata.management.getMethods();
    for (int j = 0; j < methods.length; ++j) {
      Method method = methods[j];
      if (!Utils.isAttributeGetter(method) && !Utils.isAttributeSetter(method)) {
        String descr = description == null ? null : description.getOperationDescription(method);
        Class[] params = method.getParameterTypes();
        MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[params.length];
        for (int k = 0; k < params.length; ++k) {
          Class param = params[k];
          String paramName =
              description == null ? null : description.getOperationParameterName(method, k);
          String paramDescr =
              description == null ? null : description.getOperationParameterDescription(method, k);
          paramsInfo[k] = new MBeanParameterInfo(paramName, param.getName(), paramDescr);
        }
        MBeanOperationInfo info =
            new MBeanOperationInfo(
                method.getName(),
                descr,
                paramsInfo,
                method.getReturnType().getName(),
                MBeanOperationInfo.UNKNOWN);
        operations.add(info);
      }
    }

    return (MBeanOperationInfo[]) operations.toArray(new MBeanOperationInfo[operations.size()]);
  }
  private MBeanInfo createStandardMBeanInfo(MBeanMetaData metadata) {
    // This is a non-standard extension: description for standard MBeans
    MBeanDescription description = createMBeanDescription(metadata);

    MBeanConstructorInfo[] ctors = createMBeanConstructorInfo(metadata, description);
    if (ctors == null) return null;
    MBeanAttributeInfo[] attrs = createMBeanAttributeInfo(metadata, description);
    if (attrs == null) return null;
    MBeanOperationInfo[] opers = createMBeanOperationInfo(metadata, description);
    if (opers == null) return null;
    MBeanNotificationInfo[] notifs = createMBeanNotificationInfo(metadata);
    if (notifs == null) return null;

    return new MBeanInfo(
        metadata.mbean.getClass().getName(),
        description.getMBeanDescription(),
        attrs,
        ctors,
        opers,
        notifs);
  }
  private MBeanAttributeInfo[] createMBeanAttributeInfo(
      MBeanMetaData metadata, MBeanDescription description) {
    Logger logger = getLogger();

    HashMap attributes = new HashMap();
    HashMap getterNames = new HashMap();

    Method[] methods = metadata.management.getMethods();
    for (int j = 0; j < methods.length; ++j) {
      Method method = methods[j];
      if (Utils.isAttributeGetter(method)) {
        String name = method.getName();
        boolean isIs = name.startsWith("is");

        String attribute = null;
        if (isIs) attribute = name.substring(2);
        else attribute = name.substring(3);

        String descr = description == null ? null : description.getAttributeDescription(attribute);

        MBeanAttributeInfo info = (MBeanAttributeInfo) attributes.get(attribute);

        if (info != null) {
          // JMX spec does not allow overloading attributes.
          // If an attribute with the same name already exists the MBean is not compliant
          if (!info.getType().equals(method.getReturnType().getName())) {
            if (logger.isEnabledFor(Logger.DEBUG))
              logger.debug("MBean is not compliant: has overloaded attribute " + attribute);
            return null;
          } else {
            // They return the same value,
            if (getterNames.get(name) != null) {
              // This is the case of an attribute being present in multiple interfaces
              // Ignore all but the first, since they resolve to the same method anyways
              continue;
            }

            // there is a chance that one is a get-getter and one is a is-getter
            // for a boolean attribute. In this case, the MBean is not compliant.
            if (info.isReadable()) {
              if (logger.isEnabledFor(Logger.DEBUG))
                logger.debug("MBean is not compliant: has overloaded attribute " + attribute);
              return null;
            }

            // MBeanAttributeInfo is already present due to a setter method, just update its
            // readability
            info =
                new MBeanAttributeInfo(
                    attribute,
                    info.getType(),
                    info.getDescription(),
                    true,
                    info.isWritable(),
                    isIs);
          }
        } else {
          info =
              new MBeanAttributeInfo(
                  attribute, method.getReturnType().getName(), descr, true, false, isIs);
        }

        // Replace if exists
        attributes.put(attribute, info);
        getterNames.put(name, method);
      } else if (Utils.isAttributeSetter(method)) {
        String name = method.getName();
        String attribute = name.substring(3);

        String descr = description == null ? null : description.getAttributeDescription(attribute);

        MBeanAttributeInfo info = (MBeanAttributeInfo) attributes.get(attribute);

        if (info != null) {
          // JMX spec does not allow overloading attributes.
          // If an attribute with the same name already exists the MBean is not compliant
          if (!info.getType().equals(method.getParameterTypes()[0].getName())) {
            if (logger.isEnabledFor(Logger.DEBUG))
              logger.debug("MBean is not compliant: has overloaded attribute " + attribute);
            return null;
          } else {
            // MBeanAttributeInfo is already present due to a getter method, just update its
            // writability
            info =
                new MBeanAttributeInfo(
                    info.getName(),
                    info.getType(),
                    info.getDescription(),
                    info.isReadable(),
                    true,
                    info.isIs());
          }
        } else {
          info =
              new MBeanAttributeInfo(
                  attribute, method.getParameterTypes()[0].getName(), descr, false, true, false);
        }

        // Replace if exists
        attributes.put(attribute, info);
      }
    }

    return (MBeanAttributeInfo[])
        attributes.values().toArray(new MBeanAttributeInfo[attributes.size()]);
  }