11 Replies Latest reply on Jun 24, 2008 10:37 AM by alesj

    Support for @JMX on attributes

    alesj

      Tim raised this question on MC user forum:
      - http://www.jboss.com/index.html?module=bb&op=viewtopic&t=137721

      So I hacked something in this direction - adding annotation plugin for @JMX.

      public abstract class JMXAnnotationPlugin<T extends AnnotatedInfo> extends AbstractAnnotationPlugin<T, JMX>
      {
       protected JMXAnnotationPlugin()
       {
       super(JMX.class);
       }
      
       protected List<? extends MetaDataVisitorNode> internalApplyAnnotation(T info, MetaData metaData, JMX jmx, KernelControllerContext context) throws Throwable
       {
       Class<?> exposedInterface = jmx.exposedInterface();
       if (exposedInterface == null || void.class.equals(exposedInterface))
       exposedInterface = getExposedInterface(info);
       if (exposedInterface == null || exposedInterface.isInterface() == false)
       throw new IllegalArgumentException("Illegal exposed interface: " + exposedInterface);
      
       BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(createObjectName(context, info, jmx), exposedInterface.getName());
       // TODO - uncomment with new MC release; builder.addAnnotation(jmx);
       Object proxy = createProxy(context, info, exposedInterface);
       KernelController controller = (KernelController)context.getController();
       controller.install(builder.getBeanMetaData(), proxy);
      
       // no change directly on context
       return null;
       }
      
       /**
       * Create proxy for attribute.
       *
       * @param context the context
       * @param info the info
       * @param exposedInterface the exposed interface
       * @return attribute's proxy
       * @throws Throwable for any error
       */
       protected Object createProxy(KernelControllerContext context, T info, Class<?> exposedInterface) throws Throwable
       {
       return Proxy.newProxyInstance(
       context.getClassLoader(),
       new Class<?>[]{exposedInterface},
       new AttributeInvocationHandler(context, getName(info))
       );
       }
      
       protected void internalCleanAnnotation(T info, MetaData metaData, JMX jmx, KernelControllerContext context) throws Throwable
       {
       Controller controller = context.getController();
       controller.uninstall(createObjectName(context, info, jmx));
       }
      
       /**
       * Get exposed interface from info.
       *
       * @param info the info
       * @return exposed interface
       */
       protected abstract Class<?> getExposedInterface(T info);
      
       /**
       * Get name from info.
       *
       * @param info the info
       * @return info's name
       */
       protected abstract String getName(T info);
      
       /**
       * Create object name.
       *
       * @param context the context
       * @param info the info
       * @param jmx the annotation
       * @return obejct name
       * @throws Exception for any error
       */
       protected String createObjectName(ControllerContext context, T info, JMX jmx) throws Exception
       {
       if (jmx != null)
       {
       String jmxName = jmx.name();
       if (jmxName != null && jmxName.length() > 0)
       return jmxName;
       }
      
       // try to build one from the bean name and info param
       String name = context.getName().toString();
       String objectName = name;
       if (name.contains(":") == false)
       {
       objectName = "jboss.pojo:name='" + name + "'";
       }
       return objectName + ",property=" + getName(info);
       }
      
       /**
       * Attribute invocation handler.
       */
       protected class AttributeInvocationHandler implements InvocationHandler
       {
       private KernelControllerContext context;
       private String property;
      
       protected AttributeInvocationHandler(KernelControllerContext context, String property)
       {
       this.context = context;
       this.property = property;
       }
      
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
       {
       Object target = context.get(property);
       return method.invoke(target, args);
       }
       }
      }
      


      I'm creating a proxy target around @JMX exposed attribute, installing it to MC, hence leaving all the rest of jmx work to MC.

      Does this look legit?