/**
   * Define an attribute. Explicit definition of an attribute. Reflection is used to locate the
   * actual getter and setter methods.
   *
   * @param attrInfo ModelMBeanAttributeInfo.
   */
  public synchronized void defineAttribute(ModelMBeanAttributeInfo attrInfo) {
    if (_object == null) throw new IllegalStateException("No Object");

    _dirty = true;

    String name = attrInfo.getName();
    String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
    Class oClass = _object.getClass();

    try {
      Class type = TypeUtil.fromName(attrInfo.getType());
      if (type == null)
        type = Thread.currentThread().getContextClassLoader().loadClass(attrInfo.getType());

      Method getter = null;
      Method setter = null;

      if (attrInfo.isReadable())
        getter =
            oClass.getMethod((attrInfo.isIs() ? "is" : "get") + uName, (java.lang.Class[]) null);

      if (attrInfo.isWritable()) setter = oClass.getMethod("set" + uName, new Class[] {type});

      _getter.put(name, getter);
      _setter.put(name, setter);
      _attributes.add(attrInfo);
    } catch (Exception e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new IllegalArgumentException(e.toString());
    }
  }
  /* ------------------------------------------------------------ */
  public synchronized ObjectName uniqueObjectName(
      MBeanServer server, Object object, String objectName) {
    if (!objectName.endsWith("=")) {
      String className = object.getClass().getName();
      if (className.indexOf(".") > 0)
        className = className.substring(className.lastIndexOf(".") + 1);
      if (className.endsWith("MBean")) className = className.substring(0, className.length() - 5);
      if (!objectName.endsWith(":")) objectName += ",";
      objectName += className + "=";
    }

    ObjectName oName = null;
    try {
      while (true) {
        Integer id = (Integer) __objectId.get(objectName);
        if (id == null) id = new Integer(0);
        oName = new ObjectName(objectName + id);
        id = new Integer(id.intValue() + 1);
        __objectId.put(objectName, id);

        // If no server, this must be unique
        if (server == null) break;

        // Otherwise let's check it is unique
        // if not found then it is unique
        if (!server.isRegistered(oName)) break;
      }
    } catch (Exception e) {
      log.warn(LogSupport.EXCEPTION, e);
    }

    return oName;
  }
  /**
   * Define an attribute on the managed object. The meta data is defined by looking for standard
   * getter and setter methods. Descriptions are obtained with a call to findDescription with the
   * attribute name.
   *
   * @param name The name of the attribute. Normal java bean capitlization is enforced on this name.
   * @param writable If false, do not look for a setter.
   * @param onMBean .
   */
  public synchronized void defineAttribute(String name, boolean writable, boolean onMBean) {
    _dirty = true;

    String uName = name.substring(0, 1).toUpperCase() + name.substring(1);
    name = java.beans.Introspector.decapitalize(name);
    Class oClass = onMBean ? this.getClass() : _object.getClass();

    Class type = null;
    Method getter = null;
    Method setter = null;
    Method[] methods = oClass.getMethods();
    for (int m = 0; m < methods.length; m++) {
      if ((methods[m].getModifiers() & Modifier.PUBLIC) == 0) continue;

      // Look for a getter
      if (methods[m].getName().equals("get" + uName)
          && methods[m].getParameterTypes().length == 0) {
        if (getter != null) throw new IllegalArgumentException("Multiple getters for attr " + name);
        getter = methods[m];
        if (type != null && !type.equals(methods[m].getReturnType()))
          throw new IllegalArgumentException("Type conflict for attr " + name);
        type = methods[m].getReturnType();
      }

      // Look for an is getter
      if (methods[m].getName().equals("is" + uName) && methods[m].getParameterTypes().length == 0) {
        if (getter != null) throw new IllegalArgumentException("Multiple getters for attr " + name);
        getter = methods[m];
        if (type != null && !type.equals(methods[m].getReturnType()))
          throw new IllegalArgumentException("Type conflict for attr " + name);
        type = methods[m].getReturnType();
      }

      // look for a setter
      if (writable
          && methods[m].getName().equals("set" + uName)
          && methods[m].getParameterTypes().length == 1) {
        if (setter != null) throw new IllegalArgumentException("Multiple setters for attr " + name);
        setter = methods[m];
        if (type != null && !type.equals(methods[m].getParameterTypes()[0]))
          throw new IllegalArgumentException("Type conflict for attr " + name);
        type = methods[m].getParameterTypes()[0];
      }
    }

    if (getter == null && setter == null)
      throw new IllegalArgumentException("No getter or setters found for " + name);

    try {
      // Remember the methods
      _getter.put(name, getter);
      _setter.put(name, setter);
      // create and add the info
      _attributes.add(new ModelMBeanAttributeInfo(name, findDescription(name), getter, setter));
    } catch (Exception e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new IllegalArgumentException(e.toString());
    }
  }
  /* ------------------------------------------------------------ */
  public Object invoke(String name, Object[] params, String[] signature)
      throws MBeanException, ReflectionException {
    if (log.isDebugEnabled()) log.debug("invoke " + name);

    String methodKey = name + "(";
    if (signature != null)
      for (int i = 0; i < signature.length; i++) methodKey += (i > 0 ? "," : "") + signature[i];
    methodKey += ")";

    try {
      Method method = (Method) _method.get(methodKey);
      if (method == null) throw new NoSuchMethodException(methodKey);

      Object o = _object;
      if (method.getDeclaringClass().isInstance(this)) o = this;
      return method.invoke(o, params);
    } catch (NoSuchMethodException e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new ReflectionException(e);
    } catch (IllegalAccessException e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new MBeanException(e);
    } catch (InvocationTargetException e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new ReflectionException((Exception) e.getTargetException());
    }
  }
  /**
   * Define an operation. Explicit definition of an operation. Reflection is used to locate method
   * called.
   *
   * @param opInfo
   */
  public synchronized void defineOperation(ModelMBeanOperationInfo opInfo) {
    _dirty = true;
    Class oClass = _object.getClass();

    try {
      MBeanParameterInfo[] pInfo = opInfo.getSignature();

      Class[] types = new Class[pInfo.length];
      String method = opInfo.getName() + "(";
      for (int i = 0; i < pInfo.length; i++) {
        Class type = TypeUtil.fromName(pInfo[i].getType());
        if (type == null)
          type = Thread.currentThread().getContextClassLoader().loadClass(pInfo[i].getType());
        types[i] = type;
        method += (i > 0 ? "," : "") + pInfo[i].getType();
      }
      method += ")";

      _method.put(method, oClass.getMethod(opInfo.getName(), types));
      _operations.add(opInfo);
    } catch (Exception e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new IllegalArgumentException(e.toString());
    }
  }
 /** Post Deregister. This implementation destroys this MBean and it cannot be used again. */
 public void postDeregister() {
   _beanInfo = null;
   _mBeanServer = null;
   _object = null;
   _objectName = null;
   if (_getter != null) _getter.clear();
   _getter = null;
   if (_setter != null) _setter.clear();
   _setter = null;
   if (_method != null) _method.clear();
   _method = null;
   if (_attributes != null) _attributes.clear();
   _attributes = null;
   if (_operations != null) _operations.clear();
   _operations = null;
   if (_notifications != null) _notifications.clear();
   _notifications = null;
 }
  /**
   * Define an operation on the managed object. Defines an operation with parameters. Refection is
   * used to determine find the method and it's return type. The description of the method is found
   * with a call to findDescription on "name(signature)". The name and description of each parameter
   * is found with a call to findDescription with "name(partialSignature", the returned description
   * is for the last parameter of the partial signature and is assumed to start with the parameter
   * name, followed by a colon.
   *
   * @param name The name of the method call.
   * @param signature The types of the operation parameters.
   * @param impact Impact as defined in MBeanOperationInfo
   * @param onMBean true if the operation is defined on the mbean
   */
  public synchronized void defineOperation(
      String name, String[] signature, int impact, boolean onMBean) {
    _dirty = true;
    Class oClass = onMBean ? this.getClass() : _object.getClass();
    if (signature == null) signature = new String[0];

    try {
      Class[] types = new Class[signature.length];
      MBeanParameterInfo[] pInfo = new MBeanParameterInfo[signature.length];

      // Check types and build methodKey
      String methodKey = name + "(";
      for (int i = 0; i < signature.length; i++) {
        Class type = TypeUtil.fromName(signature[i]);
        if (type == null)
          type = Thread.currentThread().getContextClassLoader().loadClass(signature[i]);
        types[i] = type;
        signature[i] = type.isPrimitive() ? TypeUtil.toName(type) : signature[i];
        methodKey += (i > 0 ? "," : "") + signature[i];
      }
      methodKey += ")";

      // Build param infos
      for (int i = 0; i < signature.length; i++) {
        String description = findDescription(methodKey + "[" + i + "]");
        int colon = description.indexOf(":");
        if (colon < 0) {
          description = "param" + i + ":" + description;
          colon = description.indexOf(":");
        }
        pInfo[i] =
            new MBeanParameterInfo(
                description.substring(0, colon).trim(),
                signature[i],
                description.substring(colon + 1).trim());
      }

      // build the operation info
      Method method = oClass.getMethod(name, types);
      Class returnClass = method.getReturnType();
      _method.put(methodKey, method);
      _operations.add(
          new ModelMBeanOperationInfo(
              name,
              findDescription(methodKey),
              pInfo,
              returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()),
              impact));
    } catch (Exception e) {
      log.warn("operation " + name, e);
      throw new IllegalArgumentException(e.toString());
    }
  }
 /* ------------------------------------------------------------ */
 public Object getAttribute(String name)
     throws AttributeNotFoundException, MBeanException, ReflectionException {
   if (log.isDebugEnabled()) log.debug("getAttribute " + name);
   Method getter = (Method) _getter.get(name);
   if (getter == null) throw new AttributeNotFoundException(name);
   try {
     Object o = _object;
     if (getter.getDeclaringClass().isInstance(this)) o = this;
     return getter.invoke(o, (java.lang.Object[]) null);
   } catch (IllegalAccessException e) {
     log.warn(LogSupport.EXCEPTION, e);
     throw new AttributeNotFoundException(e.toString());
   } catch (InvocationTargetException e) {
     log.warn(LogSupport.EXCEPTION, e);
     throw new ReflectionException((Exception) e.getTargetException());
   }
 }
  /* ------------------------------------------------------------ */
  public void setAttribute(Attribute attr)
      throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException,
          ReflectionException {
    if (attr == null) return;

    if (log.isDebugEnabled()) log.debug("setAttribute " + attr.getName() + "=" + attr.getValue());
    Method setter = (Method) _setter.get(attr.getName());
    if (setter == null) throw new AttributeNotFoundException(attr.getName());
    try {
      Object o = _object;
      if (setter.getDeclaringClass().isInstance(this)) o = this;
      setter.invoke(o, new Object[] {attr.getValue()});
    } catch (IllegalAccessException e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new AttributeNotFoundException(e.toString());
    } catch (InvocationTargetException e) {
      log.warn(LogSupport.EXCEPTION, e);
      throw new ReflectionException((Exception) e.getTargetException());
    }
  }