KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > panoptes > component > jmx > model > MBeanProxyFactory


1 package net.sf.panoptes.component.jmx.model;
2 import java.lang.reflect.Constructor JavaDoc;
3 import java.util.HashMap JavaDoc;
4 import java.util.Map JavaDoc;
5
6 import javassist.CannotCompileException;
7 import javassist.ClassPool;
8 import javassist.CtClass;
9 import javassist.CtMethod;
10 import javassist.Loader;
11 import javassist.NotFoundException;
12
13 import javax.management.MBeanAttributeInfo JavaDoc;
14 import javax.management.MBeanInfo JavaDoc;
15 import javax.management.MBeanOperationInfo JavaDoc;
16 import javax.management.MBeanParameterInfo JavaDoc;
17 import javax.management.MBeanServerConnection JavaDoc;
18 import javax.management.MBeanServerInvocationHandler JavaDoc;
19 import javax.management.ObjectName JavaDoc;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23
24 /**
25  *
26  * Factory for creating concrete MBean proxies that delegate method invocations
27  * to an <code>MBeanServerConnection</code>.
28  *
29  * @author Dag Liodden
30  * @version 0.1
31  */

32 public class MBeanProxyFactory {
33
34     private Log log = LogFactory.getLog(MBeanProxyFactory.class);
35     private Map JavaDoc primitives = new HashMap JavaDoc();
36     private static MBeanProxyFactory instance = new MBeanProxyFactory();
37
38     /**
39      *
40      * Constructs a new factory.
41      *
42      */

43     private MBeanProxyFactory() {
44
45         primitives.put("boolean", "java.lang.Boolean");
46         primitives.put("byte", "java.lang.Byte");
47         primitives.put("char", "java.lang.Character");
48         primitives.put("float", "java.lang.Float");
49         primitives.put("double", "java.lang.Double");
50         primitives.put("int", "java.lang.Integer");
51         primitives.put("long", "java.lang.Long");
52         primitives.put("short", "java.lang.Short");
53
54     }
55
56     public static MBeanProxyFactory getInstance() {
57         return instance;
58     }
59
60     /**
61      * Creates a new proxy using Javassist bytecode engineering. The proxy's
62      * method signatures will be exactly the same as the real MBean except that
63      * primitive parameters will be objects.
64      *
65      * It's possible to implement the
66      * primitives too, but then we need boxing / unboxing in the methods. This could
67      * perhaps be done elegantly by just adding empty methods with the correct
68      * signatures and creating another proxy with <code>java.lang.reflect.Proxy</code>
69      * which would handle boxing / unboxing as well as the actual invocations. This
70      * would also avoid the errorprone java-source-strings in this method, but since
71      * this class probably only will be used for the specific purpose of exposing
72      * MBean operations and attributes to JSTL in Jelly, it won't be necessary as
73      * it works great right now.
74      *
75      * Operations or attributes with type / parameters of locally unknown classes
76      * will be ignored (obviously).
77      *
78      * @param info name of the MBean to proxy
79      * @param serverConnection the connection to invoke methods on
80      * @return a concrete class with all operations and attributes of the MBean
81      * @throws Exception
82      */

83     public Object JavaDoc createProxy(ObjectName JavaDoc objectName, MBeanServerConnection JavaDoc serverConnection) throws Exception JavaDoc {
84         MBeanInfo JavaDoc info = serverConnection.getMBeanInfo(objectName);
85         
86         // Check if we have this class locally. If so, we use the standard delegate
87
try {
88             Class JavaDoc interfaceClass = Class.forName(info.getClassName() + "MBean");
89             log.info("Interface found locally.");
90             return MBeanServerInvocationHandler.newProxyInstance(serverConnection, objectName, interfaceClass, true);
91         } catch (NoClassDefFoundError JavaDoc ce) {
92             log.info("Interface does not exist locally. Generating...");
93         } catch (ClassNotFoundException JavaDoc ce) {
94             log.info("Interface does not exist locally. Generating...");
95         }
96         String JavaDoc proxyClassName = "MBeanProxy" + System.currentTimeMillis();
97
98         ClassPool pool = ClassPool.getDefault();
99         Loader loader = new Loader(pool);
100
101         CtClass proxyClass = pool.makeClass(proxyClassName);
102         proxyClass.setSuperclass(pool.get("net.sf.panoptes.component.jmx.model.MBeanProxyStub"));
103
104         /**
105          * Add getters and setters for attributes
106          */

107         MBeanAttributeInfo JavaDoc[] attributes = info.getAttributes();
108         for (int i = 0; i < attributes.length; i++) {
109             MBeanAttributeInfo JavaDoc att = attributes[i];
110
111             try {
112                 String JavaDoc name = att.getName();
113
114                 if (att.isReadable()) {
115                     CtMethod getMethod =
116                         new CtMethod(
117                             getClassForName(pool, att.getType()),
118                             "get" + name,
119                             new CtClass[0],
120                             proxyClass);
121
122                     String JavaDoc body =
123                         "{ \n"
124                             + "return ("
125                             + getClassForName(pool, att.getType()).getName()
126                             + ") get_panoptes_serverConnection().getAttribute(get_panoptes_objectName(), "
127                             + "\""
128                             + name
129                             + "\") "
130                             + ";\n}";
131
132                     log.debug(
133                         "Adding getter for attribute " + name + " with invoker body:\n" + body);
134
135                     getMethod.setBody(body);
136                     proxyClass.addMethod(getMethod);
137                 }
138
139                 if (att.isWritable()) {
140                     CtMethod setMethod =
141                         new CtMethod(
142                             CtClass.voidType,
143                             "set" + name,
144                             new CtClass[] { getClassForName(pool, att.getType())},
145                             proxyClass);
146
147                     String JavaDoc body =
148                         "{ \n"
149                             + "get_panoptes_serverConnection().setAttribute(get_panoptes_objectName(), "
150                             + "new javax.management.Attribute("
151                             + "\""
152                             + name
153                             + "\""
154                             + ", $1));"
155                             + "; \n}";
156                     log.debug(
157                         "Adding setter for attribute " + name + " with invoker body:\n" + body);
158                     setMethod.setBody(body);
159                     proxyClass.addMethod(setMethod);
160
161                 }
162             } catch (NotFoundException e) {
163                 log.warn(
164                     "Ignoring MBean attribute "
165                         + att.getName()
166                         + " since a remote class "
167                         + att.getType()
168                         + " is missing locally.");
169                 continue;
170
171             }
172
173         }
174
175         /**
176          * Add operations
177          */

178
179         MBeanOperationInfo JavaDoc[] operations = info.getOperations();
180         for (int i = 0; i < operations.length; i++) {
181             MBeanOperationInfo JavaDoc op = operations[i];
182             MBeanParameterInfo JavaDoc[] paramInfo = op.getSignature();
183
184             try {
185
186                 // Constuct parameter info
187
CtClass[] parameters = new CtClass[paramInfo.length];
188                 for (int j = 0; j < parameters.length; j++) {
189                     parameters[j] = pool.get(paramInfo[j].getType());
190                 }
191
192                 CtMethod opMethod =
193                     new CtMethod(
194                         getClassForName(pool, op.getReturnType()),
195                         op.getName(),
196                         parameters,
197                         proxyClass);
198
199                 /**
200                  * Set the body ( new Object[] { } isn't supported by Javassist BTW
201                  */

202                 StringBuffer JavaDoc body = new StringBuffer JavaDoc();
203                 body.append("{\n");
204                 body.append("Object[] parameters = new Object[" + parameters.length + "];\n");
205                 body.append("String[] signature = new String[" + parameters.length + "];\n");
206
207                 for (int j = 0; j < parameters.length; j++) {
208                     body.append("parameters[" + j + "] = $args[" + j + "];\n");
209
210                     String JavaDoc type;
211
212                     body.append("signature[" + j + "] = \"" + paramInfo[j].getType() + "\";\n");
213                 }
214
215                 CtClass returnType = getClassForName(pool, op.getReturnType());
216                 if (returnType.equals(CtClass.voidType)) {
217                     body.append(
218                         "\n get_panoptes_serverConnection().invoke(get_panoptes_objectName(),\""
219                             + op.getName()
220                             + "\", parameters, signature);");
221                 } else {
222                     body.append(
223                         "\nreturn ("
224                             + returnType.getName()
225                             + ") get_panoptes_serverConnection().invoke(get_panoptes_objectName(),\""
226                             + op.getName()
227                             + "\", parameters, signature);");
228                 }
229                 body.append("\n}");
230
231                 log.debug("Operation body: " + body.toString());
232                 try {
233                     opMethod.setBody(body.toString());
234                 } catch (CannotCompileException e) {
235                     e.printStackTrace();
236                 }
237
238                 proxyClass.addMethod(opMethod);
239             } catch (NotFoundException e) {
240                 log.warn(
241                     "Ignoring MBean operation "
242                         + op.getName()
243                         + " since a remote class "
244                         + " is missing locally.");
245                 continue;
246             }
247
248         }
249
250         Class JavaDoc clazz = loader.loadClass(proxyClassName);
251         
252         Constructor JavaDoc constructor = clazz.getConstructor(new Class JavaDoc[] { MBeanServerConnection JavaDoc.class, ObjectName JavaDoc.class });
253         Object JavaDoc stub = constructor.newInstance(new Object JavaDoc[] { serverConnection, objectName });
254                 
255         return stub;
256     }
257
258     /**
259      *
260      * Translates a typename to a <code>CtClass</code>. If it's a primitive, the
261      * corresponding primitive class will be returned. (Strange that Javassist
262      * doesn't have this, or am I missing something?). Anyways, we could use
263      * Object in getters and setters, but this won't cause JSTL to interpret the
264      * data right (I think). E.g when the signature contains Integer, JSTL will convert
265      * parameters to Integer which the MBeanServer will convert back to ints on the
266      * other side. I'm not sure about this, and I'm very tired, so...
267      *
268      * @param pool
269      * @param string
270      * @return
271      */

272     private CtClass getClassForName(ClassPool pool, String JavaDoc className) throws NotFoundException {
273         if (primitives.containsKey(className))
274             return pool.get((String JavaDoc) primitives.get(className));
275         else
276             return pool.get(className);
277     }
278
279 }
280
Popular Tags