001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.tomcat.util.modeler;
019:
020: import java.lang.reflect.Method;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import javax.management.AttributeNotFoundException;
025: import javax.management.DynamicMBean;
026: import javax.management.InstanceNotFoundException;
027: import javax.management.MBeanAttributeInfo;
028: import javax.management.MBeanConstructorInfo;
029: import javax.management.MBeanException;
030: import javax.management.MBeanInfo;
031: import javax.management.MBeanNotificationInfo;
032: import javax.management.MBeanOperationInfo;
033: import javax.management.ReflectionException;
034: import javax.management.RuntimeOperationsException;
035: import javax.management.ServiceNotFoundException;
036:
037: //import javax.management.modelmbean.InvalidTargetObjectTypeException;
038:
039: /**
040: * <p>Internal configuration information for a managed bean (MBean)
041: * descriptor.</p>
042: *
043: * @author Craig R. McClanahan
044: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
045: */
046:
047: public class ManagedBean implements java.io.Serializable {
048: private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean";
049: // ----------------------------------------------------- Instance Variables
050: static final Object[] NO_ARGS_PARAM = new Object[0];
051: static final Class[] NO_ARGS_PARAM_SIG = new Class[0];
052:
053: /**
054: * The <code>ModelMBeanInfo</code> object that corresponds
055: * to this <code>ManagedBean</code> instance.
056: */
057: transient MBeanInfo info = null;
058: // Map<AttributeInfo>
059: private Map attributes = new HashMap();
060: //Map<OperationInfo>
061: private Map operations = new HashMap();
062:
063: protected String className = BASE_MBEAN;
064: //protected ConstructorInfo constructors[] = new ConstructorInfo[0];
065: protected String description = null;
066: protected String domain = null;
067: protected String group = null;
068: protected String name = null;
069:
070: //protected List fields = new ArrayList();
071: protected NotificationInfo notifications[] = new NotificationInfo[0];
072: protected String type = null;
073:
074: /** Constructor. Will add default attributes.
075: *
076: */
077: public ManagedBean() {
078: AttributeInfo ai = new AttributeInfo();
079: ai.setName("modelerType");
080: ai
081: .setDescription("Type of the modeled resource. Can be set only once");
082: ai.setType("java.lang.String");
083: ai.setWriteable(false);
084: addAttribute(ai);
085: }
086:
087: // ------------------------------------------------------------- Properties
088:
089: /**
090: * The collection of attributes for this MBean.
091: */
092: public AttributeInfo[] getAttributes() {
093: AttributeInfo result[] = new AttributeInfo[attributes.size()];
094: attributes.values().toArray(result);
095: return result;
096: }
097:
098: /**
099: * The fully qualified name of the Java class of the MBean
100: * described by this descriptor. If not specified, the standard JMX
101: * class (<code>javax.management.modelmbean.RequiredModeLMBean</code>)
102: * will be utilized.
103: */
104: public String getClassName() {
105: return (this .className);
106: }
107:
108: public void setClassName(String className) {
109: this .className = className;
110: this .info = null;
111: }
112:
113: // /**
114: // * The collection of constructors for this MBean.
115: // */
116: // public ConstructorInfo[] getConstructors() {
117: // return (this.constructors);
118: // }
119:
120: /**
121: * The human-readable description of this MBean.
122: */
123: public String getDescription() {
124: return (this .description);
125: }
126:
127: public void setDescription(String description) {
128: this .description = description;
129: this .info = null;
130: }
131:
132: /**
133: * The (optional) <code>ObjectName</code> domain in which this MBean
134: * should be registered in the MBeanServer.
135: */
136: public String getDomain() {
137: return (this .domain);
138: }
139:
140: public void setDomain(String domain) {
141: this .domain = domain;
142: }
143:
144: /**
145: * <p>Return a <code>List</code> of the {@link FieldInfo} objects for
146: * the name/value pairs that should be
147: * added to the Descriptor created from this metadata.</p>
148: */
149: // public List getFields() {
150: // return (this.fields);
151: // }
152: //
153: /**
154: * The (optional) group to which this MBean belongs.
155: */
156: public String getGroup() {
157: return (this .group);
158: }
159:
160: public void setGroup(String group) {
161: this .group = group;
162: }
163:
164: /**
165: * The name of this managed bean, which must be unique among all
166: * MBeans managed by a particular MBeans server.
167: */
168: public String getName() {
169: return (this .name);
170: }
171:
172: public void setName(String name) {
173: this .name = name;
174: this .info = null;
175: }
176:
177: /**
178: * The collection of notifications for this MBean.
179: */
180: public NotificationInfo[] getNotifications() {
181: return (this .notifications);
182: }
183:
184: /**
185: * The collection of operations for this MBean.
186: */
187: public OperationInfo[] getOperations() {
188: OperationInfo[] result = new OperationInfo[operations.size()];
189: operations.values().toArray(result);
190: return result;
191: }
192:
193: /**
194: * The fully qualified name of the Java class of the resource
195: * implementation class described by the managed bean described
196: * by this descriptor.
197: */
198: public String getType() {
199: return (this .type);
200: }
201:
202: public void setType(String type) {
203: this .type = type;
204: this .info = null;
205: }
206:
207: // --------------------------------------------------------- Public Methods
208:
209: /**
210: * Add a new attribute to the set of attributes for this MBean.
211: *
212: * @param attribute The new attribute descriptor
213: */
214: public void addAttribute(AttributeInfo attribute) {
215: attributes.put(attribute.getName(), attribute);
216: }
217:
218: /**
219: * Add a new constructor to the set of constructors for this MBean.
220: *
221: * @param constructor The new constructor descriptor
222: */
223: // public void addConstructor(ConstructorInfo constructor) {
224: //
225: // synchronized (constructors) {
226: // ConstructorInfo results[] =
227: // new ConstructorInfo[constructors.length + 1];
228: // System.arraycopy(constructors, 0, results, 0, constructors.length);
229: // results[constructors.length] = constructor;
230: // constructors = results;
231: // this.info = null;
232: // }
233: //
234: // }
235:
236: /**
237: * <p>Add a new field to the fields associated with the
238: * Descriptor that will be created from this metadata.</p>
239: *
240: * @param field The field to be added
241: */
242: // public void addField(FieldInfo field) {
243: // fields.add(field);
244: // }
245:
246: /**
247: * Add a new notification to the set of notifications for this MBean.
248: *
249: * @param notification The new notification descriptor
250: */
251: public void addNotification(NotificationInfo notification) {
252:
253: synchronized (notifications) {
254: NotificationInfo results[] = new NotificationInfo[notifications.length + 1];
255: System.arraycopy(notifications, 0, results, 0,
256: notifications.length);
257: results[notifications.length] = notification;
258: notifications = results;
259: this .info = null;
260: }
261:
262: }
263:
264: /**
265: * Add a new operation to the set of operations for this MBean.
266: *
267: * @param operation The new operation descriptor
268: */
269: public void addOperation(OperationInfo operation) {
270: operations.put(operation.getName(), operation);
271: }
272:
273: /**
274: * Create and return a <code>ModelMBean</code> that has been
275: * preconfigured with the <code>ModelMBeanInfo</code> information
276: * for this managed bean, but is not associated with any particular
277: * managed resource. The returned <code>ModelMBean</code> will
278: * <strong>NOT</strong> have been registered with our
279: * <code>MBeanServer</code>.
280: *
281: * @exception InstanceNotFoundException if the managed resource
282: * object cannot be found
283: * @exception InvalidTargetObjectTypeException if our MBean cannot
284: * handle object references (should never happen)
285: * @exception MBeanException if a problem occurs instantiating the
286: * <code>ModelMBean</code> instance
287: * @exception RuntimeOperationsException if a JMX runtime error occurs
288: */
289: public DynamicMBean createMBean() throws InstanceNotFoundException,
290: MBeanException, RuntimeOperationsException {
291:
292: return (createMBean(null));
293:
294: }
295:
296: /**
297: * Create and return a <code>ModelMBean</code> that has been
298: * preconfigured with the <code>ModelMBeanInfo</code> information
299: * for this managed bean, and is associated with the specified
300: * managed object instance. The returned <code>ModelMBean</code>
301: * will <strong>NOT</strong> have been registered with our
302: * <code>MBeanServer</code>.
303: *
304: * @param instance Instanced of the managed object, or <code>null</code>
305: * for no associated instance
306: *
307: * @exception InstanceNotFoundException if the managed resource
308: * object cannot be found
309: * @exception InvalidTargetObjectTypeException if our MBean cannot
310: * handle object references (should never happen)
311: * @exception MBeanException if a problem occurs instantiating the
312: * <code>ModelMBean</code> instance
313: * @exception RuntimeOperationsException if a JMX runtime error occurs
314: */
315: public DynamicMBean createMBean(Object instance)
316: throws InstanceNotFoundException, MBeanException,
317: RuntimeOperationsException {
318:
319: BaseModelMBean mbean = null;
320:
321: // Load the ModelMBean implementation class
322: if (getClassName().equals(BASE_MBEAN)) {
323: // Skip introspection
324: mbean = new BaseModelMBean();
325: } else {
326: Class clazz = null;
327: Exception ex = null;
328: try {
329: clazz = Class.forName(getClassName());
330: } catch (Exception e) {
331: }
332:
333: if (clazz == null) {
334: try {
335: ClassLoader cl = Thread.currentThread()
336: .getContextClassLoader();
337: if (cl != null)
338: clazz = cl.loadClass(getClassName());
339: } catch (Exception e) {
340: ex = e;
341: }
342: }
343:
344: if (clazz == null) {
345: throw new MBeanException(ex,
346: "Cannot load ModelMBean class "
347: + getClassName());
348: }
349: try {
350: // Stupid - this will set the default minfo first....
351: mbean = (BaseModelMBean) clazz.newInstance();
352: } catch (RuntimeOperationsException e) {
353: throw e;
354: } catch (Exception e) {
355: throw new MBeanException(e,
356: "Cannot instantiate ModelMBean of class "
357: + getClassName());
358: }
359: }
360:
361: mbean.setManagedBean(this );
362:
363: // Set the managed resource (if any)
364: try {
365: if (instance != null)
366: mbean.setManagedResource(instance, "ObjectReference");
367: } catch (InstanceNotFoundException e) {
368: throw e;
369: }
370: return (mbean);
371:
372: }
373:
374: /**
375: * Create and return a <code>ModelMBeanInfo</code> object that
376: * describes this entire managed bean.
377: */
378: MBeanInfo getMBeanInfo() {
379:
380: // Return our cached information (if any)
381: if (info != null)
382: return (info);
383:
384: // Create subordinate information descriptors as required
385: AttributeInfo attrs[] = getAttributes();
386: MBeanAttributeInfo attributes[] = new MBeanAttributeInfo[attrs.length];
387: for (int i = 0; i < attrs.length; i++)
388: attributes[i] = attrs[i].createAttributeInfo();
389:
390: OperationInfo opers[] = getOperations();
391: MBeanOperationInfo operations[] = new MBeanOperationInfo[opers.length];
392: for (int i = 0; i < opers.length; i++)
393: operations[i] = opers[i].createOperationInfo();
394:
395: // ConstructorInfo consts[] = getConstructors();
396: // ModelMBeanConstructorInfo constructors[] =
397: // new ModelMBeanConstructorInfo[consts.length];
398: // for (int i = 0; i < consts.length; i++)
399: // constructors[i] = consts[i].createConstructorInfo();
400:
401: NotificationInfo notifs[] = getNotifications();
402: MBeanNotificationInfo notifications[] = new MBeanNotificationInfo[notifs.length];
403: for (int i = 0; i < notifs.length; i++)
404: notifications[i] = notifs[i].createNotificationInfo();
405:
406: // Construct and return a new ModelMBeanInfo object
407: info = new MBeanInfo(getClassName(), getDescription(),
408: attributes, new MBeanConstructorInfo[] {}, operations,
409: notifications);
410: // try {
411: // Descriptor descriptor = info.getMBeanDescriptor();
412: // Iterator fields = getFields().iterator();
413: // while (fields.hasNext()) {
414: // FieldInfo field = (FieldInfo) fields.next();
415: // descriptor.setField(field.getName(), field.getValue());
416: // }
417: // info.setMBeanDescriptor(descriptor);
418: // } catch (MBeanException e) {
419: // ;
420: // }
421:
422: return (info);
423:
424: }
425:
426: /**
427: * Return a string representation of this managed bean.
428: */
429: public String toString() {
430:
431: StringBuffer sb = new StringBuffer("ManagedBean[");
432: sb.append("name=");
433: sb.append(name);
434: sb.append(", className=");
435: sb.append(className);
436: sb.append(", description=");
437: sb.append(description);
438: if (group != null) {
439: sb.append(", group=");
440: sb.append(group);
441: }
442: sb.append(", type=");
443: sb.append(type);
444: sb.append("]");
445: return (sb.toString());
446:
447: }
448:
449: Method getGetter(String aname, BaseModelMBean mbean, Object resource)
450: throws AttributeNotFoundException, MBeanException,
451: ReflectionException {
452: // TODO: do we need caching ? JMX is for management, it's not supposed to require lots of performance.
453: Method m = null; // (Method)getAttMap.get( name );
454:
455: if (m == null) {
456: AttributeInfo attrInfo = (AttributeInfo) attributes
457: .get(aname);
458: // Look up the actual operation to be used
459: if (attrInfo == null)
460: throw new AttributeNotFoundException(
461: " Cannot find attribute " + aname + " for "
462: + resource);
463:
464: String getMethod = attrInfo.getGetMethod();
465: if (getMethod == null)
466: throw new AttributeNotFoundException(
467: "Cannot find attribute " + aname
468: + " get method name");
469:
470: Object object = null;
471: NoSuchMethodException exception = null;
472: try {
473: object = mbean;
474: m = object.getClass().getMethod(getMethod,
475: NO_ARGS_PARAM_SIG);
476: } catch (NoSuchMethodException e) {
477: exception = e;
478: ;
479: }
480: if (m == null && resource != null) {
481: try {
482: object = resource;
483: m = object.getClass().getMethod(getMethod,
484: NO_ARGS_PARAM_SIG);
485: exception = null;
486: } catch (NoSuchMethodException e) {
487: exception = e;
488: }
489: }
490: if (exception != null)
491: throw new ReflectionException(exception,
492: "Cannot find getter method " + getMethod);
493: //getAttMap.put( name, m );
494: }
495:
496: return m;
497: }
498:
499: public Method getSetter(String aname, BaseModelMBean bean,
500: Object resource) throws AttributeNotFoundException,
501: MBeanException, ReflectionException {
502: // Cache may be needed for getters, but it is a really bad idea for setters, this is far
503: // less frequent.
504: Method m = null;//(Method)setAttMap.get( name );
505:
506: if (m == null) {
507: AttributeInfo attrInfo = (AttributeInfo) attributes
508: .get(aname);
509: if (attrInfo == null)
510: throw new AttributeNotFoundException(
511: " Cannot find attribute " + aname);
512:
513: // Look up the actual operation to be used
514: String setMethod = attrInfo.getSetMethod();
515: if (setMethod == null)
516: throw new AttributeNotFoundException(
517: "Cannot find attribute " + aname
518: + " set method name");
519:
520: String argType = attrInfo.getType();
521:
522: Class signature[] = new Class[] { BaseModelMBean
523: .getAttributeClass(argType) };
524:
525: Object object = null;
526: NoSuchMethodException exception = null;
527: try {
528: object = this ;
529: m = object.getClass().getMethod(setMethod, signature);
530: } catch (NoSuchMethodException e) {
531: exception = e;
532: ;
533: }
534: if (m == null && resource != null) {
535: try {
536: object = resource;
537: m = object.getClass().getMethod(setMethod,
538: signature);
539: exception = null;
540: } catch (NoSuchMethodException e) {
541: exception = e;
542: }
543: }
544: if (exception != null)
545: throw new ReflectionException(exception,
546: "Cannot find setter method " + setMethod + " "
547: + resource);
548: //setAttMap.put( name, m );
549: }
550:
551: return m;
552: }
553:
554: public Method getInvoke(String aname, Object[] params,
555: String[] signature, BaseModelMBean bean, Object resource)
556: throws MBeanException, ReflectionException {
557: Method method = null;
558: if (method == null) {
559: if (params == null)
560: params = new Object[0];
561: if (signature == null)
562: signature = new String[0];
563: if (params.length != signature.length)
564: throw new RuntimeOperationsException(
565: new IllegalArgumentException(
566: "Inconsistent arguments and signature"),
567: "Inconsistent arguments and signature");
568:
569: // Acquire the ModelMBeanOperationInfo information for
570: // the requested operation
571: OperationInfo opInfo = (OperationInfo) operations
572: .get(aname);
573: if (opInfo == null)
574: throw new MBeanException(new ServiceNotFoundException(
575: "Cannot find operation " + aname),
576: "Cannot find operation " + aname);
577:
578: // Prepare the signature required by Java reflection APIs
579: // FIXME - should we use the signature from opInfo?
580: Class types[] = new Class[signature.length];
581: for (int i = 0; i < signature.length; i++) {
582: types[i] = BaseModelMBean
583: .getAttributeClass(signature[i]);
584: }
585:
586: // Locate the method to be invoked, either in this MBean itself
587: // or in the corresponding managed resource
588: // FIXME - Accessible methods in superinterfaces?
589: Object object = null;
590: Exception exception = null;
591: try {
592: object = this ;
593: method = object.getClass().getMethod(aname, types);
594: } catch (NoSuchMethodException e) {
595: exception = e;
596: ;
597: }
598: try {
599: if ((method == null) && (resource != null)) {
600: object = resource;
601: method = object.getClass().getMethod(aname, types);
602: }
603: } catch (NoSuchMethodException e) {
604: exception = e;
605: }
606: if (method == null) {
607: throw new ReflectionException(exception,
608: "Cannot find method " + aname
609: + " with this signature");
610: }
611: // invokeAttMap.put(mkey, method);
612: }
613: return method;
614: }
615:
616: }
|