1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.modeler.modules;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.apache.commons.modeler.AttributeInfo;
23 import org.apache.commons.modeler.ManagedBean;
24 import org.apache.commons.modeler.OperationInfo;
25 import org.apache.commons.modeler.ParameterInfo;
26 import org.apache.commons.modeler.Registry;
27 import org.apache.commons.modeler.ConstructorInfo;
28
29 import javax.management.ObjectName;
30
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Modifier;
33 import java.lang.reflect.Constructor;
34 import java.math.BigDecimal;
35 import java.math.BigInteger;
36 import java.util.ArrayList;
37 import java.util.Enumeration;
38 import java.util.Hashtable;
39 import java.util.List;
40
41 public class MbeansDescriptorsIntrospectionSource extends ModelerSource
42 {
43 private static Log log = LogFactory.getLog(MbeansDescriptorsIntrospectionSource.class);
44
45 Registry registry;
46 String location;
47 String type;
48 Object source;
49 List mbeans=new ArrayList();
50
51 public void setRegistry(Registry reg) {
52 this.registry=reg;
53 }
54
55 public void setLocation( String loc ) {
56 this.location=loc;
57 }
58
59 /*** Used if a single component is loaded
60 *
61 * @param type
62 */
63 public void setType( String type ) {
64 this.type=type;
65 }
66
67 public void setSource( Object source ) {
68 this.source=source;
69 }
70
71 public List loadDescriptors( Registry registry, String location,
72 String type, Object source)
73 throws Exception
74 {
75 setRegistry(registry);
76 setLocation(location);
77 setType(type);
78 setSource(source);
79 execute();
80 return mbeans;
81 }
82
83 public void execute() throws Exception {
84 if( registry==null ) registry=Registry.getRegistry();
85 try {
86 ManagedBean managed=createManagedBean(registry, null, (Class)source, type);
87 if( managed==null ) return;
88 managed.setName( type );
89
90 mbeans.add(managed);
91
92 } catch( Exception ex ) {
93 log.error( "Error reading descriptors ", ex);
94 }
95 }
96
97
98
99
100
101 static Hashtable specialMethods=new Hashtable();
102 static {
103 specialMethods.put( "preDeregister", "");
104 specialMethods.put( "postDeregister", "");
105 }
106
107 private static String strArray[]=new String[0];
108 private static ObjectName objNameArray[]=new ObjectName[0];
109
110
111 private static Class[] supportedTypes = new Class[] {
112 Boolean.class,
113 Boolean.TYPE,
114 Byte.class,
115 Byte.TYPE,
116 Character.class,
117 Character.TYPE,
118 Short.class,
119 Short.TYPE,
120 Integer.class,
121 Integer.TYPE,
122 Long.class,
123 Long.TYPE,
124 Float.class,
125 Float.TYPE,
126 Double.class,
127 Double.TYPE,
128 String.class,
129 strArray.getClass(),
130 BigDecimal.class,
131 BigInteger.class,
132 ObjectName.class,
133 objNameArray.getClass(),
134 java.io.File.class,
135 };
136
137 /***
138 * Check if this class is one of the supported types.
139 * If the class is supported, returns true. Otherwise,
140 * returns false.
141 * @param ret The class to check
142 * @return boolean True if class is supported
143 */
144 private boolean supportedType(Class ret) {
145 for (int i = 0; i < supportedTypes.length; i++) {
146 if (ret == supportedTypes[i]) {
147 return true;
148 }
149 }
150 if (isBeanCompatible(ret)) {
151 return true;
152 }
153 return false;
154 }
155
156 /***
157 * Check if this class conforms to JavaBeans specifications.
158 * If the class is conformant, returns true.
159 *
160 * @param javaType The class to check
161 * @return boolean True if the class is compatible.
162 */
163 protected boolean isBeanCompatible(Class javaType) {
164
165 if (javaType.isArray() || javaType.isPrimitive()) {
166 return false;
167 }
168
169
170
171 if (javaType.getName().startsWith("java.") ||
172 javaType.getName().startsWith("javax.")) {
173 return false;
174 }
175
176 try {
177 javaType.getConstructor(new Class[]{});
178 } catch (java.lang.NoSuchMethodException e) {
179 return false;
180 }
181
182
183 Class superClass = javaType.getSuperclass();
184 if (superClass != null &&
185 superClass != java.lang.Object.class &&
186 superClass != java.lang.Exception.class &&
187 superClass != java.lang.Throwable.class) {
188 if (!isBeanCompatible(superClass)) {
189 return false;
190 }
191 }
192 return true;
193 }
194
195 /***
196 * Process the methods and extract 'attributes', methods, etc
197 *
198 * @param realClass The class to process
199 * @param methods The methods to process
200 * @param attMap The attribute map (complete)
201 * @param getAttMap The readable attributess map
202 * @param setAttMap The settable attributes map
203 * @param invokeAttMap The invokable attributes map
204 */
205 private void initMethods(Class realClass,
206 Method methods[],
207 Hashtable attMap, Hashtable getAttMap,
208 Hashtable setAttMap, Hashtable invokeAttMap)
209 {
210 for (int j = 0; j < methods.length; ++j) {
211 String name=methods[j].getName();
212
213 if( Modifier.isStatic(methods[j].getModifiers()))
214 continue;
215 if( ! Modifier.isPublic( methods[j].getModifiers() ) ) {
216 if( log.isDebugEnabled())
217 log.debug("Not public " + methods[j] );
218 continue;
219 }
220 if( methods[j].getDeclaringClass() == Object.class )
221 continue;
222 Class params[]=methods[j].getParameterTypes();
223
224 if( name.startsWith( "get" ) && params.length==0) {
225 Class ret=methods[j].getReturnType();
226 if( ! supportedType( ret ) ) {
227 if( log.isDebugEnabled() )
228 log.debug("Unsupported type " + methods[j]);
229 continue;
230 }
231 name=unCapitalize( name.substring(3));
232
233 getAttMap.put( name, methods[j] );
234
235 attMap.put( name, methods[j] );
236 } else if( name.startsWith( "is" ) && params.length==0) {
237 Class ret=methods[j].getReturnType();
238 if( Boolean.TYPE != ret ) {
239 if( log.isDebugEnabled() )
240 log.debug("Unsupported type " + methods[j] + " " + ret );
241 continue;
242 }
243 name=unCapitalize( name.substring(2));
244
245 getAttMap.put( name, methods[j] );
246
247 attMap.put( name, methods[j] );
248
249 } else if( name.startsWith( "set" ) && params.length==1) {
250 if( ! supportedType( params[0] ) ) {
251 if( log.isDebugEnabled() )
252 log.debug("Unsupported type " + methods[j] + " " + params[0]);
253 continue;
254 }
255 name=unCapitalize( name.substring(3));
256 setAttMap.put( name, methods[j] );
257 attMap.put( name, methods[j] );
258 } else {
259 if( params.length == 0 ) {
260 if( specialMethods.get( methods[j].getName() ) != null )
261 continue;
262 invokeAttMap.put( name, methods[j]);
263 } else {
264 boolean supported=true;
265 for( int i=0; i<params.length; i++ ) {
266 if( ! supportedType( params[i])) {
267 supported=false;
268 break;
269 }
270 }
271 if( supported )
272 invokeAttMap.put( name, methods[j]);
273 }
274 }
275 }
276 }
277
278 /***
279 * XXX Find if the 'className' is the name of the MBean or
280 * the real class ( I suppose first )
281 * XXX Read (optional) descriptions from a .properties, generated
282 * from source
283 * XXX Deal with constructors
284 *
285 * @param registry The Bean registry (not used)
286 * @param domain The bean domain (not used)
287 * @param realClass The class to analyze
288 * @param type The bean type
289 * @return ManagedBean The create MBean
290 */
291 public ManagedBean createManagedBean(Registry registry, String domain,
292 Class realClass, String type)
293 {
294 ManagedBean mbean= new ManagedBean();
295
296 Method methods[]=null;
297
298 Hashtable attMap=new Hashtable();
299
300 Hashtable getAttMap=new Hashtable();
301
302 Hashtable setAttMap=new Hashtable();
303
304 Hashtable invokeAttMap=new Hashtable();
305
306 methods = realClass.getMethods();
307
308 initMethods(realClass, methods, attMap, getAttMap, setAttMap, invokeAttMap );
309
310 try {
311
312 Enumeration en=attMap.keys();
313 while( en.hasMoreElements() ) {
314 String name=(String)en.nextElement();
315 AttributeInfo ai=new AttributeInfo();
316 ai.setName( name );
317 Method gm=(Method)getAttMap.get(name);
318 if( gm!=null ) {
319
320 ai.setGetMethod( gm.getName());
321 Class t=gm.getReturnType();
322 if( t!=null )
323 ai.setType( t.getName() );
324 }
325 Method sm=(Method)setAttMap.get(name);
326 if( sm!=null ) {
327
328 Class t=sm.getParameterTypes()[0];
329 if( t!=null )
330 ai.setType( t.getName());
331 ai.setSetMethod( sm.getName());
332 }
333 ai.setDescription("Introspected attribute " + name);
334 if( log.isDebugEnabled()) log.debug("Introspected attribute " +
335 name + " " + gm + " " + sm);
336 if( gm==null )
337 ai.setReadable(false);
338 if( sm==null )
339 ai.setWriteable(false);
340 if( sm!=null || gm!=null )
341 mbean.addAttribute(ai);
342 }
343
344 en=invokeAttMap.keys();
345 while( en.hasMoreElements() ) {
346 String name=(String)en.nextElement();
347 Method m=(Method)invokeAttMap.get(name);
348 if( m!=null && name != null ) {
349 OperationInfo op=new OperationInfo();
350 op.setName(name);
351 op.setReturnType(m.getReturnType().getName());
352 op.setDescription("Introspected operation " + name);
353 Class parms[]=m.getParameterTypes();
354 for(int i=0; i<parms.length; i++ ) {
355 ParameterInfo pi=new ParameterInfo();
356 pi.setType(parms[i].getName());
357 pi.setName( "param" + i);
358 pi.setDescription("Introspected parameter param" + i);
359 op.addParameter(pi);
360 }
361 mbean.addOperation(op);
362 } else {
363 log.error("Null arg " + name + " " + m );
364 }
365 }
366
367 Constructor[] constructors = realClass.getConstructors();
368 for(int i=0;i<constructors.length;i++) {
369 ConstructorInfo info = new ConstructorInfo();
370 String className = realClass.getName();
371 int nIndex = -1;
372 if((nIndex = className.lastIndexOf('.'))!=-1) {
373 className = className.substring(nIndex+1);
374 }
375 info.setName(className);
376 info.setDescription(constructors[i].getName());
377 Class classes[] = constructors[i].getParameterTypes();
378 for(int j=0;j<classes.length;j++) {
379 ParameterInfo pi = new ParameterInfo();
380 pi.setType(classes[j].getName());
381 pi.setName("param" + j);
382 pi.setDescription("Introspected parameter param" + j);
383 info.addParameter(pi);
384 }
385 mbean.addConstructor(info);
386 }
387
388 if( log.isDebugEnabled())
389 log.debug("Setting name: " + type );
390 mbean.setName( type );
391
392 return mbean;
393 } catch( Exception ex ) {
394 ex.printStackTrace();
395 return null;
396 }
397 }
398
399
400
401 /***
402 * Converts the first character of the given
403 * String into lower-case.
404 *
405 * @param name The string to convert
406 * @return String
407 */
408 private static String unCapitalize(String name) {
409 if (name == null || name.length() == 0) {
410 return name;
411 }
412 char chars[] = name.toCharArray();
413 chars[0] = Character.toLowerCase(chars[0]);
414 return new String(chars);
415 }
416
417 }
418
419