jmx introspector is a small bundle that creates dynamic proxies for remote mbeans. See README.txt for details

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@441807 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jmxintrospector/README.txt b/jmxintrospector/README.txt
new file mode 100644
index 0000000..979b5b3
--- /dev/null
+++ b/jmxintrospector/README.txt
@@ -0,0 +1,27 @@
+JMX introspector is a small library bundle that 

+uses the Javassist library, the reflection API and 

+the metadata provided by JMX on the managed objects 

+to dynamically proxy remote MBeans, without having 

+the classes in your classpath. 

+It can be used to create management consoles that do not

+need to have the remote mbeans classes in its classpath to 

+use dynamic proxies.

+

+It is used by the org.apache.felix.mishell project to create management clients 

+for felix jmood, but it can be used to manage any JMX agent.

+

+It currently uses Javassist version 3.3 for the generation

+of the interface classes, which is part of JBoss and 

+can be downloaded from http://www.jboss.org

+or directly from https://sourceforge.net/project/showfiles.php?group_id=22866&package_id=80766

+Javassist is licensed under the Mozilla Public License and the LGPL. 

+IMPORTANT: 

+You need to install Javassist manually to your local maven repository

+in order to build this bundle, as it is not available at the repositories yet:

+

+mvn install:install-file -Dfile=<path-to-file> -DgroupId=javassist \

+    -DartifactId=javassist -Dversion=3.3 -Dpackaging=jar

+

+//TODO

+

+

diff --git a/jmxintrospector/pom.xml b/jmxintrospector/pom.xml
new file mode 100644
index 0000000..4da175a
--- /dev/null
+++ b/jmxintrospector/pom.xml
@@ -0,0 +1,62 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+ <parent>

+    <groupId>org.apache.felix</groupId>

+    <artifactId>felix</artifactId>

+    <version>0.8.0-SNAPSHOT</version>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <name>JMXIntrospector</name>

+  <packaging>osgi-bundle</packaging>

+  <artifactId>${groupId}.jmxintrospector</artifactId>

+  <dependencies>

+    <dependency>

+      <groupId>junit</groupId>

+      <artifactId>junit</artifactId>

+      <version>3.8.1</version>

+      <scope>test</scope>

+    </dependency>

+     <dependency>

+       <groupId>javassist</groupId>

+       <artifactId>javassist</artifactId>

+       <version>3.3</version>

+     </dependency> 

+  </dependencies>

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.felix.plugins</groupId>

+        <artifactId>maven-osgi-plugin</artifactId>

+        <version>${pom.version}</version>

+        <extensions>true</extensions>

+        <configuration>

+            <inlinedArtifacts>

+        	    <inlinedArtifact>javassist</inlinedArtifact>

+          	</inlinedArtifacts>

+          <osgiManifest>

+            <bundleName>${name}</bundleName>

+            <bundleSymbolicName>${artifactId}</bundleSymbolicName>

+            <exportPackage>

+            org.apache.felix.jmxintrospector

+            </exportPackage>

+          </osgiManifest>

+        </configuration>

+      </plugin>

+        <plugin>

+                <groupId>org.apache.maven.plugins</groupId>

+                <artifactId>maven-compiler-plugin</artifactId>

+                <configuration>

+                    <source>1.6</source><!--should fail if not java6-->

+                    <target>1.6</target>

+                </configuration>

+             </plugin>      

+    <plugin>

+      <groupId>org.apache.maven.plugins</groupId>

+      <artifactId>maven-surefire-plugin</artifactId>

+      <configuration>

+        <skip>true</skip>

+      </configuration>

+    </plugin>

+    </plugins>

+  </build>

+</project>

diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBean.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBean.java
new file mode 100644
index 0000000..f983408
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBean.java
@@ -0,0 +1,31 @@
+/*

+ *   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 javax.management.MBeanInfo;

+import javax.management.MBeanServerConnection;

+

+/**

+ * Proxies returned implement this interface, to ease handling of mbeans (filtering and so on) 

+ *

+ */

+public interface MBean {

+	public String getObjectName();

+	public MBeanServerConnection getMBeanServer();

+	public MBeanInfo getMBeanInfo();

+}

diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyFactory.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyFactory.java
new file mode 100644
index 0000000..753e6e9
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyFactory.java
@@ -0,0 +1,192 @@
+/*

+ *   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.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.MBeanAttributeInfo;

+import javax.management.MBeanInfo;

+import javax.management.MBeanNotificationInfo;

+import javax.management.MBeanOperationInfo;

+import javax.management.MBeanServerConnection;

+import javax.management.MBeanServerInvocationHandler;

+import javax.management.NotificationEmitter;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmxintrospector.classbean.TypeGetterMBean;

+

+public class MBeanProxyFactory {

+	private MBeanServerConnection mbeanServer;

+	

+	public MBeanProxyFactory(){

+	}

+	

+	public MBeanProxyFactory(MBeanServerConnection mbeanServer) {

+		super();

+		this.mbeanServer = mbeanServer;

+		

+	}

+

+	private Class getInterface(String oname)throws Exception{

+		ObjectName objectName=ObjectName.getInstance(oname);

+		

+		String ifaceName=mbeanServer.getObjectInstance(objectName).getClassName().replace('.', '_');

+		CtClass ctIface=null;

+		try{

+			ctIface=javassist.ClassPool.getDefault().get(ifaceName);

+			return this.getClass().getClassLoader().loadClass(ifaceName);

+		}catch (Exception e) {

+			ctIface=javassist.ClassPool.getDefault().makeInterface(ifaceName);

+			for (CtMethod m : addMethods(ctIface, objectName)) {

+				ctIface.addMethod(m);

+			}

+			try {

+			return ctIface.toClass(this.getClass().getClassLoader(), this.getClass().getProtectionDomain());

+			} catch (CannotCompileException cce) {

+				System.out.println(cce.getCause());

+				throw cce;

+			}

+		}

+		

+	}

+	private List<CtMethod> addMethods(CtClass ctIface, ObjectName objectName)throws Exception{

+		ClassPool pool=javassist.ClassPool.getDefault();

+		List<CtMethod> methods=new ArrayList<CtMethod>();

+		MBeanInfo minfo =mbeanServer.getMBeanInfo(objectName);

+		CtMethod m=null;

+		

+		for (MBeanAttributeInfo info : minfo.getAttributes()) {

+			String name=info.getName().substring(0, 1).toUpperCase()+info.getName().substring(1);

+			if(info.isReadable()){

+			if(info.isIs()){

+				m=new CtMethod(CtClass.booleanType, "is"+ name,null, ctIface);

+				methods.add(m);

+			}

+			else{

+//				try {

+				m=new CtMethod(pool.get(info.getType()), "get"+ name,null, ctIface);

+//				}catch (NotFoundException nfe) {

+//					String n=nfe.getMessage();

+//					String notFoundName=n.startsWith("[")?n.substring(1, n.length()):n;

+//					Class notFound=(Class)mbeanServer.invoke(ObjectName.getInstance(TypeGetterMBean.MBEAN_NAME), "getType", new Object[] {notFoundName}, new String[] {String.class.getName()});

+//					

+//					m=new CtMethod(pool.get(info.getType()), "get"+ name,null, ctIface);

+//				}

+				methods.add(m);

+				}

+

+			}

+			

+			if(info.isWritable()){

+				m=new CtMethod(CtClass.voidType, "set"+ name,new CtClass[]{pool.get(info.getType())} , ctIface);

+				methods.add(m);

+			}

+		}

+		for (MBeanOperationInfo info : minfo.getOperations()) {

+			CtClass[] params=new CtClass[info.getSignature().length];

+			for (int i = 0; i < params.length; i++) {

+				params[i]=pool.get(info.getSignature()[i].getType());

+			}

+			m=new CtMethod(pool.get(info.getReturnType()), info.getName(),params, ctIface);

+			methods.add(m);

+

+		}

+		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

+	 * @param oname

+	 * @return

+	 * @throws Exception

+	 */

+	public Object newProxyInstance(String oname)throws Exception{

+		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;

+		Object proxy=MBeanServerInvocationHandler.newProxyInstance(mbeanServer, objectName, iface, isBroadcaster);

+		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};

+		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

+		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

+			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;

+	}

+

+}

diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyManager.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyManager.java
new file mode 100644
index 0000000..1d935f3
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/MBeanProxyManager.java
@@ -0,0 +1,136 @@
+/*

+ *   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.lang.management.ManagementFactory;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+import java.util.Set;

+import java.util.logging.Level;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServerConnection;

+import javax.management.MBeanServerFactory;

+import javax.management.ObjectName;

+import javax.management.remote.JMXConnectorFactory;

+import javax.management.remote.JMXServiceURL;

+

+public class MBeanProxyManager {

+	//FIXME: mixing up Server and MBeanServerConnections is dirty and error-prone

+	private List<Server> servers = new ArrayList<Server>();

+

+	private List<Object> objects = new ArrayList<Object>();

+

+	private Logger logger = Logger.getLogger(this.getClass().getName());

+

+	public void addRMIServer(String host, String path) throws Exception {

+		addRMIServer(host, path, 1099);

+	}

+

+	public void addRMIServer(String host, String path, int port)

+			throws Exception {

+		addRemoteServer("service:jmx:rmi:///jndi/rmi://" + host + ":" + port + path);

+	}

+

+	public void addRemoteServer(String url) throws Exception {

+		JMXServiceURL u = new JMXServiceURL(url);

+		MBeanServerConnection s = JMXConnectorFactory.connect(u)

+				.getMBeanServerConnection();

+		add(url, s);

+	}

+

+	public void addLocalServer() throws Exception {

+			MBeanServerConnection s=ManagementFactory.getPlatformMBeanServer();

+			add(s.getDefaultDomain(), s);

+	}

+

+	private void add(String id, MBeanServerConnection s) throws Exception {

+		Server server=new Server(s,id);

+		servers.add(server);

+		Set<ObjectName> onames = s.queryNames(ObjectName.WILDCARD, null);

+		MBeanProxyFactory introspector = new MBeanProxyFactory(server);

+		for (ObjectName name : onames) {

+			try {

+				objects.add(introspector.newProxyInstance(name

+						.toString()));

+			} catch (javassist.NotFoundException nfe) {

+				

+				logger.warning("ERROR"+nfe);

+				continue;

+			}

+		}

+	}

+

+	public void removeServer(Server server) {

+				servers.remove(server);

+				for (Object o : objects) {

+					if (((MBean)o).getMBeanServer().equals(server)) objects.remove(o);

+				}

+	}

+	///////////

+	//Finders//

+	///////////

+	public List<Object> getObjects() {

+		return objects;

+	}

+	public Object findFirst(String substring){

+		return findFirst(substring, null);

+	}

+	public Object findFirst(String substring, Server server){

+		for (Object o :objects){

+			MBean bean=(MBean)o;

+			if (isTheServer(bean, server)&&bean.getObjectName().contains(substring)){

+				return o;

+			}

+		}

+		return null;

+	}

+	private boolean isTheServer(MBean bean, MBeanServerConnection server){

+		return server==null?true:bean.getMBeanServer().equals(server);

+	}

+	public List<Object> findAll(String substring){

+		return findAll(substring, null);

+	}

+	

+	public List<Object> findAll(String substring, MBeanServerConnection server){

+		List<Object> matches=new ArrayList<Object>();

+		for (Object o :objects){

+			MBean bean=(MBean)o;

+			if (isTheServer(bean, server)&&bean.getObjectName().contains(substring)){

+				matches.add(o);

+			}

+		}

+		return matches;

+	}

+	

+	public List<Object> findMatches(String regex){

+		List<Object> matches=new ArrayList<Object>();

+		for (Object o :objects){

+			if (((MBean)o).getObjectName().matches(regex)){

+				matches.add(o);

+			}

+		}

+		return matches;

+	}

+		

+	public List<Server> getServers() {

+		return servers;

+	}

+}

diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/Server.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/Server.java
new file mode 100644
index 0000000..1d6beb1
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/Server.java
@@ -0,0 +1,110 @@
+package org.apache.felix.jmxintrospector;

+

+import java.io.IOException;

+import java.util.Set;

+

+import javax.management.Attribute;

+import javax.management.AttributeList;

+import javax.management.AttributeNotFoundException;

+import javax.management.InstanceAlreadyExistsException;

+import javax.management.InstanceNotFoundException;

+import javax.management.IntrospectionException;

+import javax.management.InvalidAttributeValueException;

+import javax.management.ListenerNotFoundException;

+import javax.management.MBeanException;

+import javax.management.MBeanInfo;

+import javax.management.MBeanRegistrationException;

+import javax.management.MBeanServerConnection;

+import javax.management.NotCompliantMBeanException;

+import javax.management.NotificationFilter;

+import javax.management.NotificationListener;

+import javax.management.ObjectInstance;

+import javax.management.ObjectName;

+import javax.management.QueryExp;

+import javax.management.ReflectionException;

+

+public class Server implements MBeanServerConnection {

+	private MBeanServerConnection server;

+	private String id;

+	public Server(MBeanServerConnection server, String id){

+	 this.server=server;

+	 this.id=id;

+	}

+	

+	//Delegates

+	public void addNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, IOException {

+		server.addNotificationListener(name, listener, filter, handback);

+	}

+	public void addNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, IOException {

+		server.addNotificationListener(name, listener, filter, handback);

+	}

+	public ObjectInstance createMBean(String className, ObjectName name, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException {

+		return server.createMBean(className, name, params, signature);

+	}

+	public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, Object[] params, String[] signature) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException {

+		return server.createMBean(className, name, loaderName, params, signature);

+	}

+	public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, InstanceNotFoundException, IOException {

+		return server.createMBean(className, name, loaderName);

+	}

+	public ObjectInstance createMBean(String className, ObjectName name) throws ReflectionException, InstanceAlreadyExistsException, MBeanRegistrationException, MBeanException, NotCompliantMBeanException, IOException {

+		return server.createMBean(className, name);

+	}

+	public Object getAttribute(ObjectName name, String attribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, IOException {

+		return server.getAttribute(name, attribute);

+	}

+	public AttributeList getAttributes(ObjectName name, String[] attributes) throws InstanceNotFoundException, ReflectionException, IOException {

+		return server.getAttributes(name, attributes);

+	}

+	public String getDefaultDomain() throws IOException {

+		return server.getDefaultDomain();

+	}

+	public String[] getDomains() throws IOException {

+		return server.getDomains();

+	}

+	public Integer getMBeanCount() throws IOException {

+		return server.getMBeanCount();

+	}

+	public MBeanInfo getMBeanInfo(ObjectName name) throws InstanceNotFoundException, IntrospectionException, ReflectionException, IOException {

+		return server.getMBeanInfo(name);

+	}

+	public ObjectInstance getObjectInstance(ObjectName name) throws InstanceNotFoundException, IOException {

+		return server.getObjectInstance(name);

+	}

+	public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature) throws InstanceNotFoundException, MBeanException, ReflectionException, IOException {

+		return server.invoke(name, operationName, params, signature);

+	}

+	public boolean isInstanceOf(ObjectName name, String className) throws InstanceNotFoundException, IOException {

+		return server.isInstanceOf(name, className);

+	}

+	public boolean isRegistered(ObjectName name) throws IOException {

+		return server.isRegistered(name);

+	}

+	public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) throws IOException {

+		return server.queryMBeans(name, query);

+	}

+	public Set<ObjectName> queryNames(ObjectName name, QueryExp query) throws IOException {

+		return server.queryNames(name, query);

+	}

+	public void removeNotificationListener(ObjectName name, NotificationListener listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, ListenerNotFoundException, IOException {

+		server.removeNotificationListener(name, listener, filter, handback);

+	}

+	public void removeNotificationListener(ObjectName name, NotificationListener listener) throws InstanceNotFoundException, ListenerNotFoundException, IOException {

+		server.removeNotificationListener(name, listener);

+	}

+	public void removeNotificationListener(ObjectName name, ObjectName listener, NotificationFilter filter, Object handback) throws InstanceNotFoundException, ListenerNotFoundException, IOException {

+		server.removeNotificationListener(name, listener, filter, handback);

+	}

+	public void removeNotificationListener(ObjectName name, ObjectName listener) throws InstanceNotFoundException, ListenerNotFoundException, IOException {

+		server.removeNotificationListener(name, listener);

+	}

+	public void setAttribute(ObjectName name, Attribute attribute) throws InstanceNotFoundException, AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException, IOException {

+		server.setAttribute(name, attribute);

+	}

+	public AttributeList setAttributes(ObjectName name, AttributeList attributes) throws InstanceNotFoundException, ReflectionException, IOException {

+		return server.setAttributes(name, attributes);

+	}

+	public void unregisterMBean(ObjectName name) throws InstanceNotFoundException, MBeanRegistrationException, IOException {

+		server.unregisterMBean(name);

+	}

+}
\ No newline at end of file
diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetter.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetter.java
new file mode 100644
index 0000000..e52277d
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetter.java
@@ -0,0 +1,45 @@
+/*

+ *   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.classbean;

+

+import java.util.Collection;

+

+import sun.security.krb5.internal.tools.Klist;

+

+import javassist.ClassPool;

+import javassist.CtClass;

+

+public class TypeGetter implements TypeGetterMBean {

+

+	public Class getType(String name) throws Exception{

+		CtClass cl=ClassPool.getDefault().get(name);

+		Collection classes=cl.getRefClasses();

+		CtClass[] all=ClassPool.getDefault().get((String[])classes.toArray(new String[classes.size()]));

+		for (CtClass klazz : all) {

+			klazz.toBytecode();

+			

+		} 

+		ClassLoader loader=this.getClass().getClassLoader();

+		try {

+			return  loader.loadClass(name);

+		} catch (ClassNotFoundException e) {

+			return null; //FIXME: should we implement an searching mechanism?

+			}

+	}

+	

+}

diff --git a/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetterMBean.java b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetterMBean.java
new file mode 100644
index 0000000..9722e89
--- /dev/null
+++ b/jmxintrospector/src/main/java/org/apache/felix/jmxintrospector/classbean/TypeGetterMBean.java
@@ -0,0 +1,23 @@
+/*

+ *   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.classbean;

+

+public interface TypeGetterMBean {

+	public static final String MBEAN_NAME="org.apache.felix:class=TypeGetterMBean";

+	public Class getType (String name) throws Exception;

+}

diff --git a/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/IntrospectorTestHarness.java b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/IntrospectorTestHarness.java
new file mode 100644
index 0000000..888a360
--- /dev/null
+++ b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/IntrospectorTestHarness.java
@@ -0,0 +1,65 @@
+/*

+ *   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.lang.management.ManagementFactory;

+import java.rmi.registry.LocateRegistry;

+import java.rmi.registry.Registry;

+import java.rmi.server.UnicastRemoteObject;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServer;

+import javax.management.MBeanServerConnection;

+import javax.management.ObjectName;

+import javax.management.remote.JMXConnectorServer;

+import javax.management.remote.JMXConnectorServerFactory;

+import javax.management.remote.JMXServiceURL;

+

+

+

+import junit.framework.TestCase;

+

+public class IntrospectorTestHarness extends TestCase {

+	Logger logger=Logger.getLogger(this.getClass().getName());

+	MBeanServerConnection mbs;

+	MBeanProxyManager proxyManager;

+	JMXConnectorServer jmxServer;

+	Registry registry;

+	ObjectName testName;

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		mbs = ManagementFactory.getPlatformMBeanServer();

+		JMXServiceURL u=new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/server");

+        registry=LocateRegistry.createRegistry(1099);

+		jmxServer=JMXConnectorServerFactory.newJMXConnectorServer(u, null, (MBeanServer)mbs);

+		testName=ObjectName.getInstance("test:name="+this.getClass().getName());

+		((MBeanServer)mbs).registerMBean(jmxServer, testName);

+		jmxServer.start();

+		proxyManager=new MBeanProxyManager();

+		proxyManager.addRemoteServer(u.toString());

+		

+	}

+	@Override

+	protected void tearDown() throws Exception {

+		super.tearDown();

+		jmxServer.stop();

+		((MBeanServer)mbs).unregisterMBean(testName);

+		UnicastRemoteObject.unexportObject(registry, true);

+	}

+}

diff --git a/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/MBeanProxyFactoryTestCase.java b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/MBeanProxyFactoryTestCase.java
new file mode 100644
index 0000000..8bde9fb
--- /dev/null
+++ b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/MBeanProxyFactoryTestCase.java
@@ -0,0 +1,47 @@
+/*

+ *   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.lang.management.ManagementFactory;

+import java.util.Set;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServerConnection;

+import javax.management.ObjectName;

+

+import junit.framework.TestCase;

+

+public class MBeanProxyFactoryTestCase extends IntrospectorTestHarness {

+

+	MBeanProxyFactory factory;

+

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		factory = new MBeanProxyFactory(mbs);

+	}

+

+	public void testNewProxyInstance() throws Exception{

+		Set<ObjectName> onames = mbs.queryNames(ObjectName.WILDCARD, null);

+		for (ObjectName name : onames) {

+				Object mbean=factory.newProxyInstance(name.toString());

+				assertTrue(mbean instanceof MBean);

+				logger.info(((MBean)mbean).getObjectName());

+		}

+	}

+}

diff --git a/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/OutOfProcessTestHarness.java b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/OutOfProcessTestHarness.java
new file mode 100644
index 0000000..14cc269
--- /dev/null
+++ b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/OutOfProcessTestHarness.java
@@ -0,0 +1,54 @@
+/*

+ *   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.lang.management.ManagementFactory;

+import java.rmi.registry.LocateRegistry;

+import java.rmi.registry.Registry;

+import java.rmi.server.UnicastRemoteObject;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServer;

+import javax.management.MBeanServerConnection;

+import javax.management.ObjectName;

+import javax.management.remote.JMXConnectorFactory;

+import javax.management.remote.JMXConnectorServer;

+import javax.management.remote.JMXConnectorServerFactory;

+import javax.management.remote.JMXServiceURL;

+

+import junit.framework.TestCase;

+

+public class OutOfProcessTestHarness extends TestCase {

+	Logger logger=Logger.getLogger(this.getClass().getName());

+	MBeanServerConnection mbs;

+	MBeanProxyManager proxyManager;

+	ObjectName testName;

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		JMXServiceURL u=new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1199/server");

+		mbs=JMXConnectorFactory.connect(u).getMBeanServerConnection();

+		proxyManager=new MBeanProxyManager();

+		proxyManager.addRemoteServer(u.toString());

+		

+	}

+	@Override

+	protected void tearDown() throws Exception {

+		super.tearDown();

+	}

+}

diff --git a/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/RemoteMBeanProxyFactoryTestCase.java b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/RemoteMBeanProxyFactoryTestCase.java
new file mode 100644
index 0000000..c1fb215
--- /dev/null
+++ b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/RemoteMBeanProxyFactoryTestCase.java
@@ -0,0 +1,45 @@
+/*

+ *   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;

+

+/**

+ * @author mili

+ *

+ */

+public class RemoteMBeanProxyFactoryTestCase extends MBeanProxyFactoryTestCase{

+

+	/* (non-Javadoc)

+	 * @see org.apache.felix.jmxintrospector.MBeanProxyFactoryTestCase#setUp()

+	 */

+	@Override

+	protected void setUp() throws Exception {

+		OutOfProcessTestHarness t=new OutOfProcessTestHarness();

+		t.setUp();

+		mbs=t.mbs;

+		factory=new MBeanProxyFactory(mbs);

+		

+	}

+

+	/* (non-Javadoc)

+	 * @see org.apache.felix.jmxintrospector.IntrospectorTestHarness#tearDown()

+	 */

+	@Override

+	protected void tearDown() throws Exception {

+	}

+	

+

+}

diff --git a/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/ScriptTestCase.java b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/ScriptTestCase.java
new file mode 100644
index 0000000..a88ab79
--- /dev/null
+++ b/jmxintrospector/src/test/java/org/apache/felix/jmxintrospector/ScriptTestCase.java
@@ -0,0 +1,63 @@
+/*

+ *   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.lang.management.ManagementFactory;

+import java.util.List;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServerConnection;

+import javax.script.ScriptEngine;

+import javax.script.ScriptEngineManager;

+

+import junit.framework.TestCase;

+

+public class ScriptTestCase extends IntrospectorTestHarness {

+	Logger logger=Logger.getLogger(this.getClass().getName());

+	ScriptEngineManager engineManager;

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		engineManager=new ScriptEngineManager();

+		engineManager.put("manager", proxyManager);

+	}

+	public void testRuby() throws Exception{

+		fail("Not implemented");

+	}

+	public void testJavascript() throws Exception{

+		ScriptEngine js=engineManager.getEngineByName("javascript");

+		//results are the same, but may have different hash

+		List<Object> objectsInJava=proxyManager.getObjects();

+		List<Object> objectsInJS=(List<Object>) js.eval("manager.getObjects()");

+		for (Object objectJS : objectsInJS) {

+			Object javaPeer=null;

+			for (Object objectJava : objectsInJava) {

+				if (((MBean)objectJava).getObjectName().equals(((MBean)objectJS).getObjectName()))

+				javaPeer=objectJava;

+			}

+			assertNotNull(javaPeer);

+			System.out.println(javaPeer+";"+ objectJS);

+			assertEquals(javaPeer.getClass(), objectJS.getClass());

+			assertEquals(javaPeer, objectJS);//BUG in MBeanProxyFactory$JMXInvocationHandler

+

+		}

+		

+		

+	}

+	

+}