Package org.apache.felix.jmxintrospector

Source Code of org.apache.felix.jmxintrospector.MBeanProxyFactory$JMXInvocationHandler

/*
*   Copyright 2005 The Apache Software Foundation
*
*   Licensed under the Apache License, Version 2.0 (the "License");
*   you may not use this file except in compliance with the License.
*   You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*   Unless required by applicable law or agreed to in writing, software
*   distributed under the License is distributed on an "AS IS" BASIS,
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*   See the License for the specific language governing permissions and
*   limitations under the License.
*
*/

package org.apache.felix.jmxintrospector;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/*import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
*/
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.NotificationEmitter;
import javax.management.ObjectName;
import javax.management.ReflectionException;

import net.sf.cglib.core.NamingPolicy;
import net.sf.cglib.core.Predicate;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.InterfaceMaker;

import org.objectweb.asm.Type;

/**
*
* The MBeanProxyFactory is the central element of the jmxintrospector library. The main method is the {@link MBeanProxyFactory#newProxyInstance(String)}
* method, that accepts an objectname in String form and returns a proxy for that mbean.
* Internally, it uses the cglib library, although it be made to work with other bytecode libraries. More specifically,prior versions used the Javassist library  
*/

public class MBeanProxyFactory {
  private MBeanServerConnection mbeanServer;
 
  public MBeanProxyFactory(){
  }
 
  public MBeanProxyFactory(MBeanServerConnection mbeanServer) {
    super();
    this.mbeanServer = mbeanServer;
  }

  /**
   * Internal method for generating the Class object for the dynamically-generated interface for the mbean.
   * The name given to the class is based on the actual classname of the mbean, although some extensions are added
   * to it by the cglib library to avoid namespace clashes.
   * @param oname
   * @return
   * @throws IOException
   * @throws InstanceNotFoundException
   * @throws ClassNotFoundException
   * @throws ReflectionException
   * @throws IntrospectionException
   * @throws 
   * @throws MalformedObjectNameException
   * @throws Exception
   */
  private Class getInterface(String oname) throws MalformedObjectNameException, InstanceNotFoundException, IOException, IntrospectionException, ReflectionException {
    ObjectName objectName=ObjectName.getInstance(oname);
    String ifaceName=mbeanServer.getObjectInstance(objectName).getClassName();
    //uses the ifaceName as the prefix for the class name
    InterfaceMaker maker=new MBeanInterfaceMaker(ifaceName);
      for (Signature s : getSignatures(objectName)) {
        //add each method
        maker.add(s, null);
      }
        return maker.create();
    }
  private Type getType(String type) throws ClassNotFoundException{
    return JmxAsmHelper.getAsmType(type);
  }
  /**
   * Internal method for generating the signatures of the mbeans.
   * @param objectName
   * @return
   * @throws IOException
   * @throws ReflectionException
   * @throws IntrospectionException
   * @throws InstanceNotFoundException
   */
  private List<Signature> getSignatures(ObjectName objectName)throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException{
    List<Signature> methods=new ArrayList<Signature>();
    MBeanInfo minfo;
    MBeanAttributeInfo[] attributes=null;
      minfo = mbeanServer.getMBeanInfo(objectName);
      attributes=minfo.getAttributes();
   
    for (MBeanAttributeInfo info : attributes) {
      String name=info.getName().substring(0, 1).toUpperCase()+info.getName().substring(1);
      if(info.isReadable()){
        //For each readable attribute, we generate a getter method (following the isXX for booleans
        //when it is being used on the remote side)
      if(info.isIs()){
        methods.add(new Signature("is"+name, Type.BOOLEAN_TYPE, new Type[0]));
      }
      else{
        try{
        methods.add(new Signature("get"+name, getType(info.getType()), new Type[0]));
        }catch(ClassNotFoundException cnfe){
          System.out.println("JMXINTROSPECTOR WARNING: "+info.getType()+" could not be found. Attribute will not be added to proxy.");
          continue;
       
        }
      }
      //Same with each writable att, but with setters.
      if(info.isWritable()){
        try{
        Type [] params=new Type[]{getType(info.getType())};
        Signature s=new Signature("set"+name, Type.VOID_TYPE, params);
        methods.add(s);
        }catch(ClassNotFoundException cnfe){
          System.out.println("JMXINTROSPECTOR WARNING: "+info.getType()+" could not be found. Attribute will not be added to proxy.");
          continue;
       
      }
    }
    //same for each operation
    for (MBeanOperationInfo info : minfo.getOperations()) {
      try{
      Type[] params=new Type[info.getSignature().length];
      for (int i = 0; i < params.length; i++) {
        params[i]=getType(info.getSignature()[i].getType());
      }
     
      Signature s=new Signature(info.getName(), getType(info.getReturnType()), params);
      methods.add(s);
      }catch(ClassNotFoundException cnfe){
        System.out.println("JMXINTROSPECTOR WARNING: "+info.toString()+" could not be created. Operation will not be added to proxy.");
        continue;
       
      }

    }
    return methods;
  }
  /**
   * Returns a proxy object for the MBean specified by the object name oname in the
   *  mbean server associated with this factory. This proxy object implements the generated interface plus
   *  the MBean interface. It will also be a notification broadcaster if the underlying mbean broadcasts notifications.
   * @param oname
   * @return
   * @throws IOException
   * @throws ReflectionException
   * @throws IntrospectionException
   * @throws InstanceNotFoundException
   * @throws 
   * @throws MalformedObjectNameException
   * @throws Exception
   */
  public Object newProxyInstance(String oname) throws MalformedObjectNameException, InstanceNotFoundException, IntrospectionException, ReflectionException, IOException{
    ObjectName objectName=ObjectName.getInstance(oname);
    Class iface=getInterface(oname);
    MBeanInfo info=mbeanServer.getMBeanInfo(objectName);
    boolean isBroadcaster=false;
    MBeanNotificationInfo[] notifs=info.getNotifications();
    if (notifs!=null && notifs.length!=0) isBroadcaster=true;
    //We first create the proxy for the remote mbean. If broadcasting supported, then it adds the broadcasting interface
    Object proxy=MBeanServerInvocationHandler.newProxyInstance(mbeanServer, objectName, iface, isBroadcaster);
    //We get the underlying invocation handler, needed for the wrapper handler. The wrapper adds the mbean interface functionality
    //and integrates JMX invocation handler.
    InvocationHandler h=Proxy.getInvocationHandler(proxy);
    InvocationHandler wrapper=new JMXInvocationHandler(oname,mbeanServer, mbeanServer.getMBeanInfo(objectName), h);
    Class[] ifaces;
    if (isBroadcaster) {
      ifaces=new Class[]{iface, NotificationEmitter.class, MBean.class};
    }else ifaces=new Class[]{iface, MBean.class};
    //finally, we create the proxy with the appropriate classloader, the interfaces and the invocation handler
    Object mbeanProxy=Proxy.newProxyInstance(proxy.getClass().getClassLoader(), ifaces, wrapper);
    return mbeanProxy;
  }
  private class JMXInvocationHandler implements InvocationHandler, MBean{
    private String objectName;
    private MBeanServerConnection mBeanServer;
    private InvocationHandler mbeanHandler;
    private MBeanInfo mbeanInfo;
   
    public JMXInvocationHandler(String objectName, MBeanServerConnection mbeanServer, MBeanInfo mBeanInfo, InvocationHandler mbeanHandler) {
      super();
      this.objectName = objectName;
      this.mBeanServer = mbeanServer;
      this.mbeanHandler = mbeanHandler;
      this.mbeanInfo =mBeanInfo;
     
    }
   
    //FIXME: hashCode() and equals do not work if not exposed in management interface. I have not thought of a workaround for that yet.
    //note that this is needed for hashmaps and comparisons.
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //decide wether to invoke the JMXInvocationHandler we have implemented
      //or use the one that was created by the MBeanServerInvocationHandler
      if(method.getDeclaringClass().equals(MBean.class)){
        return this.getClass().getMethod(method.getName(), null).invoke(this, args);
      }
      else return mbeanHandler.invoke(proxy, method, args);
    }

    public MBeanServerConnection getMBeanServer() {
      return mBeanServer;
    }

    public String getObjectName() {
      return objectName;
    }

    public MBeanInfo getMBeanInfo() {
      return mbeanInfo;
    }


   
  }

  public MBeanServerConnection getMbeanServer() {
    return mbeanServer;
  }

  public void setMbeanServer(MBeanServerConnection mbs) {
    this.mbeanServer = mbs;
  }
  /**
   * This class is used to be able to modify the super class,
   * because setNamePrefix and setAttemptLoad are protected methods
   *
   */
  private class MBeanInterfaceMaker extends InterfaceMaker{
    public MBeanInterfaceMaker(String namePrefix) {
      super();
      super.setNamePrefix(namePrefix);
      super.setAttemptLoad(true);
    }
  }

}
TOP

Related Classes of org.apache.felix.jmxintrospector.MBeanProxyFactory$JMXInvocationHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.