001 /*
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements. See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership. The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied. See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 *
020 */
021 package org.apache.qpid.server.management;
022
023 import java.lang.annotation.Annotation;
024 import java.lang.reflect.Constructor;
025 import java.lang.reflect.Method;
026 import java.util.ArrayList;
027 import java.util.List;
028
029 import javax.management.MBeanAttributeInfo;
030 import javax.management.MBeanConstructorInfo;
031 import javax.management.MBeanOperationInfo;
032 import javax.management.MBeanParameterInfo;
033 import javax.management.NotCompliantMBeanException;
034
035 /**
036 * This class is a utility class to introspect the MBean class and the management
037 * interface class for various purposes.
038 * @author Bhupendra Bhardwaj
039 * @version 0.1
040 */
041 class MBeanIntrospector {
042
043 private static final String _defaultAttributeDescription = "Management attribute";
044 private static final String _defaultOerationDescription = "Management operation";
045 private static final String _defaultConstructorDescription = "MBean constructor";
046 private static final String _defaultMbeanDescription = "Management interface of the MBean";
047
048 /**
049 * Introspects the management interface class for MBean attributes.
050 * @param interfaceClass
051 * @return MBeanAttributeInfo[]
052 * @throws NotCompliantMBeanException
053 */
054 static MBeanAttributeInfo[] getMBeanAttributesInfo(Class interfaceClass)
055 throws NotCompliantMBeanException
056 {
057 List<MBeanAttributeInfo> attributesList = new ArrayList<MBeanAttributeInfo>();
058
059 /**
060 * Using reflection, all methods of the managemetn interface will be analysed,
061 * and MBeanInfo will be created.
062 */
063 for (Method method : interfaceClass.getMethods())
064 {
065 String name = method.getName();
066 Class<?> resultType = method.getReturnType();
067 MBeanAttributeInfo attributeInfo = null;
068
069 if (isAttributeGetterMethod(method))
070 {
071 String desc = getAttributeDescription(method);
072 attributeInfo = new MBeanAttributeInfo(name.substring(3),
073 resultType.getName(),
074 desc,
075 true,
076 false,
077 false);
078 int index = getIndexIfAlreadyExists(attributeInfo, attributesList);
079 if (index == -1)
080 {
081 attributesList.add(attributeInfo);
082 }
083 else
084 {
085 attributeInfo = new MBeanAttributeInfo(name.substring(3),
086 resultType.getName(),
087 desc,
088 true,
089 true,
090 false);
091 attributesList.set(index, attributeInfo);
092 }
093 }
094 else if (isAttributeSetterMethod(method))
095 {
096 String desc = getAttributeDescription(method);
097 attributeInfo = new MBeanAttributeInfo(name.substring(3),
098 method.getParameterTypes()[0].getName(),
099 desc,
100 false,
101 true,
102 false);
103 int index = getIndexIfAlreadyExists(attributeInfo, attributesList);
104 if (index == -1)
105 {
106 attributesList.add(attributeInfo);
107 }
108 else
109 {
110 attributeInfo = new MBeanAttributeInfo(name.substring(3),
111 method.getParameterTypes()[0].getName(),
112 desc,
113 true,
114 true,
115 false);
116 attributesList.set(index, attributeInfo);
117 }
118 }
119 else if (isAttributeBoolean(method))
120 {
121 attributeInfo = new MBeanAttributeInfo(name.substring(2),
122 resultType.getName(),
123 getAttributeDescription(method),
124 true,
125 false,
126 true);
127 attributesList.add(attributeInfo);
128 }
129 }
130
131 return attributesList.toArray(new MBeanAttributeInfo[0]);
132 }
133
134 /**
135 * Introspects the management interface class for management operations.
136 * @param interfaceClass
137 * @return MBeanOperationInfo[]
138 */
139 static MBeanOperationInfo[] getMBeanOperationsInfo(Class interfaceClass)
140 {
141 List<MBeanOperationInfo> operationsList = new ArrayList<MBeanOperationInfo>();
142
143 for (Method method : interfaceClass.getMethods())
144 {
145 if (!isAttributeGetterMethod(method) &&
146 !isAttributeSetterMethod(method) &&
147 !isAttributeBoolean(method))
148 {
149 operationsList.add(getOperationInfo(method));
150 }
151 }
152
153 return operationsList.toArray(new MBeanOperationInfo[0]);
154 }
155
156 /**
157 * Checks if the method is an attribute getter method.
158 * @param method
159 * @return true if the method is an attribute getter method.
160 */
161 private static boolean isAttributeGetterMethod(Method method)
162 {
163 if (!(method.getName().equals("get")) &&
164 method.getName().startsWith("get") &&
165 method.getParameterTypes().length == 0 &&
166 !method.getReturnType().equals(void.class))
167 {
168 return true;
169 }
170
171 return false;
172 }
173
174 /**
175 * Checks if the method is an attribute setter method.
176 * @param method
177 * @return true if the method is an attribute setter method.
178 */
179 private static boolean isAttributeSetterMethod(Method method)
180 {
181 if (!(method.getName().equals("set")) &&
182 method.getName().startsWith("set") &&
183 method.getParameterTypes().length == 1 &&
184 method.getReturnType().equals(void.class))
185 {
186 return true;
187 }
188
189 return false;
190 }
191
192 /**
193 * Checks if the attribute is a boolean and the method is a isX kind og method.
194 * @param method
195 * @return true if the method is an attribute isX type of method
196 */
197 private static boolean isAttributeBoolean(Method method)
198 {
199 if (!(method.getName().equals("is")) &&
200 method.getName().startsWith("is") &&
201 method.getParameterTypes().length == 0 &&
202 method.getReturnType().equals(boolean.class))
203 {
204 return true;
205 }
206
207 return false;
208 }
209
210 /**
211 * Helper method to retrieve the attribute index from the list of attributes.
212 * @param attribute
213 * @param list
214 * @return attribute index no. -1 if attribtue doesn't exist
215 * @throws NotCompliantMBeanException
216 */
217 private static int getIndexIfAlreadyExists(MBeanAttributeInfo attribute,
218 List<MBeanAttributeInfo> list)
219 throws NotCompliantMBeanException
220 {
221 String exceptionMsg = "Conflicting attribute methods for attribute " + attribute.getName();
222
223 for (MBeanAttributeInfo memberAttribute : list)
224 {
225 if (attribute.getName().equals(memberAttribute.getName()))
226 {
227 if (!attribute.getType().equals(memberAttribute.getType()))
228 {
229 throw new NotCompliantMBeanException(exceptionMsg);
230 }
231 if (attribute.isReadable() && memberAttribute.isReadable())
232 {
233 if (attribute.isIs() != memberAttribute.isIs())
234 {
235 throw new NotCompliantMBeanException(exceptionMsg);
236 }
237 }
238
239 return list.indexOf(memberAttribute);
240 }
241 }
242
243 return -1;
244 }
245
246 /**
247 * Retrieves the attribute description from annotation
248 * @param attributeMethod
249 * @return attribute description
250 */
251 private static String getAttributeDescription(Method attributeMethod)
252 {
253 MBeanAttribute anno = attributeMethod.getAnnotation(MBeanAttribute.class);
254 if (anno != null)
255 {
256 return anno.description();
257 }
258 return _defaultAttributeDescription;
259 }
260
261 /**
262 * Introspects the method to retrieve the operation information.
263 * @param operation
264 * @return MBeanOperationInfo
265 */
266 private static MBeanOperationInfo getOperationInfo(Method operation)
267 {
268 MBeanOperationInfo operationInfo = null;
269 Class<?> returnType = operation.getReturnType();
270
271 MBeanParameterInfo[] paramsInfo = getParametersInfo(operation.getParameterAnnotations(),
272 operation.getParameterTypes());
273
274 String operationDesc = _defaultOerationDescription;
275 int impact = MBeanOperationInfo.UNKNOWN;
276
277 if (operation.getAnnotation(MBeanOperation.class) != null)
278 {
279 operationDesc = operation.getAnnotation(MBeanOperation.class).description();
280 impact = operation.getAnnotation(MBeanOperation.class).impact();
281 }
282 operationInfo = new MBeanOperationInfo(operation.getName(),
283 operationDesc,
284 paramsInfo,
285 returnType.getName(),
286 impact);
287
288 return operationInfo;
289 }
290
291 /**
292 * Constructs the parameter info.
293 * @param paramsAnno
294 * @param paramTypes
295 * @return MBeanParameterInfo[]
296 */
297 private static MBeanParameterInfo[] getParametersInfo(Annotation[][] paramsAnno,
298 Class<?>[] paramTypes)
299 {
300 int noOfParams = paramsAnno.length;
301
302 MBeanParameterInfo[] paramsInfo = new MBeanParameterInfo[noOfParams];
303
304 for (int i = 0; i < noOfParams; i++)
305 {
306 MBeanParameterInfo paramInfo = null;
307 String type = paramTypes[i].getName();
308 for (Annotation anno : paramsAnno[i])
309 {
310 String name,desc;
311 if (MBeanOperationParameter.class.isInstance(anno))
312 {
313 name = MBeanOperationParameter.class.cast(anno).name();
314 desc = MBeanOperationParameter.class.cast(anno).description();
315 paramInfo = new MBeanParameterInfo(name, type, desc);
316 }
317 }
318
319
320 if (paramInfo == null)
321 {
322 paramInfo = new MBeanParameterInfo("p " + (i + 1), type, "parameter " + (i + 1));
323 }
324 if (paramInfo != null)
325 paramsInfo[i] = paramInfo;
326 }
327
328 return paramsInfo;
329 }
330
331 /**
332 * Introspects the MBean class for constructors
333 * @param implClass
334 * @return MBeanConstructorInfo[]
335 */
336 static MBeanConstructorInfo[] getMBeanConstructorsInfo(Class implClass)
337 {
338 List<MBeanConstructorInfo> constructors = new ArrayList<MBeanConstructorInfo>();
339
340 for (Constructor cons : implClass.getConstructors())
341 {
342 MBeanConstructorInfo constructorInfo = getMBeanConstructorInfo(cons);
343 //MBeanConstructorInfo constructorInfo = new MBeanConstructorInfo("desc", cons);
344 if (constructorInfo != null)
345 constructors.add(constructorInfo);
346 }
347
348 return constructors.toArray(new MBeanConstructorInfo[0]);
349 }
350
351 /**
352 * Retrieves the constructor info from given constructor.
353 * @param cons
354 * @return MBeanConstructorInfo
355 */
356 private static MBeanConstructorInfo getMBeanConstructorInfo(Constructor cons)
357 {
358 String desc = null;
359 Annotation anno = cons.getAnnotation(MBeanConstructor.class);
360 if (anno != null && MBeanConstructor.class.isInstance(anno))
361 {
362 desc = MBeanConstructor.class.cast(anno).value();
363 }
364
365 //MBeanParameterInfo[] paramsInfo = getParametersInfo(cons.getParameterAnnotations(),
366 // cons.getParameterTypes());
367
368 return new MBeanConstructorInfo(cons.getName(),
369 desc != null ? _defaultConstructorDescription : desc ,
370 null);
371 }
372
373 /**
374 * Retrieves the description from the annotations of given class
375 * @param annotatedClass
376 * @return class description
377 */
378 static String getMBeanDescription(Class annotatedClass)
379 {
380 Annotation anno = annotatedClass.getAnnotation(MBeanDescription.class);
381 if (anno != null && MBeanDescription.class.isInstance(anno))
382 {
383 return MBeanDescription.class.cast(anno).value();
384 }
385 return _defaultMbeanDescription;
386 }
387
388 }
|