1 | // jademx - JADE management using JMX |
2 | // Copyright 2005 Caboodle Networks, Inc. |
3 | // |
4 | // This library is free software; you can redistribute it and/or |
5 | // modify it under the terms of the GNU Lesser General Public |
6 | // License as published by the Free Software Foundation; either |
7 | // version 2.1 of the License, or (at your option) any later version. |
8 | // |
9 | // This library is distributed in the hope that it will be useful, |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | // Lesser General Public License for more details. |
13 | // |
14 | // You should have received a copy of the GNU Lesser General Public |
15 | // License along with this library; if not, write to the Free Software |
16 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
17 | |
18 | package jade.jademx.mbean; |
19 | |
20 | import jade.util.Logger; |
21 | |
22 | import java.util.Calendar; |
23 | import java.util.Enumeration; |
24 | import java.util.GregorianCalendar; |
25 | import java.util.HashMap; |
26 | import java.util.Iterator; |
27 | import java.util.LinkedList; |
28 | import java.util.List; |
29 | import java.util.Map; |
30 | import java.util.Properties; |
31 | import java.util.SimpleTimeZone; |
32 | |
33 | import javax.management.Attribute; |
34 | import javax.management.AttributeList; |
35 | import javax.management.AttributeNotFoundException; |
36 | import javax.management.InstanceAlreadyExistsException; |
37 | import javax.management.InstanceNotFoundException; |
38 | import javax.management.InvalidAttributeValueException; |
39 | import javax.management.ListenerNotFoundException; |
40 | import javax.management.MBeanAttributeInfo; |
41 | import javax.management.MBeanConstructorInfo; |
42 | import javax.management.MBeanException; |
43 | import javax.management.MBeanInfo; |
44 | import javax.management.MBeanNotificationInfo; |
45 | import javax.management.MBeanOperationInfo; |
46 | import javax.management.MBeanRegistrationException; |
47 | import javax.management.MBeanServer; |
48 | import javax.management.MalformedObjectNameException; |
49 | import javax.management.NotCompliantMBeanException; |
50 | import javax.management.Notification; |
51 | import javax.management.NotificationFilter; |
52 | import javax.management.NotificationListener; |
53 | import javax.management.ObjectInstance; |
54 | import javax.management.ObjectName; |
55 | import javax.management.ReflectionException; |
56 | |
57 | /** |
58 | * Base MBean class. |
59 | * @author David Bernstein, <a href="http://www.caboodlenetworks.com" |
60 | * >Caboodle Networks, Inc.</a> |
61 | */ |
62 | public abstract class JadeBase |
63 | implements JadeBaseMBean { |
64 | |
65 | |
66 | /** |
67 | * construct a base JADE MBean implementation. |
68 | * @param jadeFactory JADE factory to use |
69 | * @param type MBean type |
70 | * @param name MBean name property |
71 | */ |
72 | public JadeBase( JadeFactory jadeFactory, String type, String name ) { |
73 | this.jadeFactory = jadeFactory; |
74 | this.type = type; |
75 | this.name = name; |
76 | } |
77 | |
78 | /** JADE factory to use */ |
79 | private JadeFactory jadeFactory; |
80 | |
81 | /** JADE MBean type */ |
82 | private String type; |
83 | /** JADE MBean name property */ |
84 | private String name; |
85 | |
86 | /** my logger */ |
87 | private final Logger logger = |
88 | Logger.getMyLogger(JadeBase.class.getName()); |
89 | |
90 | |
91 | // |
92 | // REGISTRATION |
93 | // |
94 | |
95 | ///** my MBeanServer */ //, obtained via <code>preRegister()</code> */ |
96 | //private MBeanServer mBeanServer = null; |
97 | /** my ObjectName, obtained via <code>preRegister()</code> */ |
98 | private ObjectName objectName = null; |
99 | /** whether currently registered with MBeanServer */ |
100 | private volatile boolean registered = false; |
101 | /** parent's ObjectName */ |
102 | private ObjectName parentObjectName = null; |
103 | |
104 | |
105 | // BEGIN javax.management.MBeanRegistration IMPLEMENTATION |
106 | |
107 | /* (non-Javadoc) |
108 | * @see javax.management.MBeanRegistration#postDeregister() |
109 | */ |
110 | public void postDeregister() { |
111 | // intentionally empty for now |
112 | } |
113 | |
114 | /* (non-Javadoc) |
115 | * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean) |
116 | */ |
117 | public void postRegister(Boolean registrationDone) { |
118 | if ( registrationDone.booleanValue() ) { |
119 | registered = true; |
120 | } |
121 | } |
122 | |
123 | /* (non-Javadoc) |
124 | * @see javax.management.MBeanRegistration#preDeregister() |
125 | */ |
126 | public void preDeregister() throws Exception { |
127 | // intentionally empty for now |
128 | } |
129 | |
130 | /** |
131 | * zero pad method for timestamp creation |
132 | * @param i integer to zero-pad |
133 | * @param len desired length |
134 | * @return zero-padded integer string |
135 | */ |
136 | private static String zPad( int i, int len ) { |
137 | String s = Integer.toString( i ); |
138 | int missingZeros = len - s.length(); |
139 | if ( 0 != missingZeros ) { |
140 | StringBuffer sb = new StringBuffer(); |
141 | for ( int z = 0; z < missingZeros; z++ ) { |
142 | sb.append( '0' ); |
143 | } |
144 | sb.append( s ); |
145 | s = sb.toString(); |
146 | } |
147 | return s; |
148 | } |
149 | |
150 | /* (non-Javadoc) |
151 | * @see javax.management.MBeanRegistration#preRegister( |
152 | * javax.management.MBeanServer, javax.management.ObjectName) |
153 | */ |
154 | public ObjectName preRegister( MBeanServer server, ObjectName name ) |
155 | throws Exception { |
156 | //mBeanServer = server; |
157 | objectName = name; |
158 | // from method definition: |
159 | // |
160 | // name - |
161 | // The object name of the MBean. This name is null if the name |
162 | // parameter to one of the createMBean or registerMBean methods in the |
163 | // MBeanServer interface is null. In that case, this method must |
164 | // return a non-null ObjectName for the new MBean. |
165 | // Returns: |
166 | // The name under which the MBean is to be registered. This value must |
167 | // not be null. If the name parameter is not null, it will usually but |
168 | // not necessarily be the returned value. |
169 | if ( null == objectName ) { |
170 | GregorianCalendar gCal = |
171 | new GregorianCalendar( new SimpleTimeZone(0, "UTC") ); |
172 | String isoTimestamp = |
173 | zPad( gCal.get( Calendar.YEAR ), 4 ) + |
174 | zPad( gCal.get( Calendar.MONTH)+1, 2 ) + // months zero-based |
175 | zPad( gCal.get( Calendar.DAY_OF_MONTH), 2 ) + |
176 | "T" + // ISO 8601 delim between date and time |
177 | zPad( gCal.get( Calendar.HOUR_OF_DAY ), 2 ) + |
178 | zPad( gCal.get( Calendar.MINUTE ), 2 ) + |
179 | zPad( gCal.get( Calendar.SECOND ), 2 ) + |
180 | "." + // "," is "preferred" Euro style, but comma is name delim |
181 | zPad( gCal.get( Calendar.MILLISECOND ), 3 ) + |
182 | "Z"; // "Zulu" time |
183 | String myHash = Integer.toString( System.identityHashCode( this ) ); |
184 | mBeanNamePropVal = isoTimestamp + "-" + myHash; |
185 | objectName = new ObjectName( objectNameStr( mBeanNamePropVal, null )); |
186 | } |
187 | return objectName; |
188 | } |
189 | |
190 | // END javax.management.MBeanRegistration IMPLEMENTATION |
191 | |
192 | /** |
193 | * given object name key's value, construct full object name string |
194 | * @param mBeanNameValue object name key's value |
195 | * @param properties any properties in addition to type and name |
196 | * @return full object name string |
197 | */ |
198 | private String objectNameStr( String mBeanNameValue, Properties properties){ |
199 | String extraProps = ""; |
200 | if ( null != properties ) { |
201 | Enumeration e = properties.propertyNames(); |
202 | while ( e.hasMoreElements() ) { |
203 | String name = (String)e.nextElement(); |
204 | String value = properties.getProperty( name ); |
205 | extraProps += "," + name + "=" + value; |
206 | } |
207 | } |
208 | return jadeFactory.getObjectNameDomain() + ":" + |
209 | OBJ_NAME_KEY_TYPE + "=" + type + "," + |
210 | OBJ_NAME_KEY_NAME + "=" + mBeanNameValue + |
211 | extraProps; |
212 | } |
213 | |
214 | |
215 | // |
216 | // NOTIFICATION |
217 | // |
218 | |
219 | /** sequence number for notifications */ |
220 | private long notificationSequenceNumber = 0; |
221 | /** map of notification listeners */ |
222 | private Map notificationListeners = new HashMap(); |
223 | /** notification info */ |
224 | private MBeanNotificationInfo[] mBeanNotificationInfo = |
225 | new MBeanNotificationInfo[0]; |
226 | |
227 | /** class to record information about notification listener */ |
228 | private class NotificationListenerInfo { |
229 | /** listener's filter */ |
230 | NotificationFilter filter; |
231 | /** listener's handback */ |
232 | Object handback; |
233 | /** |
234 | * make an object to record information about notification listener |
235 | * @param filter notification listener's filter |
236 | * @param handback notification listener's handback |
237 | */ |
238 | public NotificationListenerInfo( NotificationFilter filter, |
239 | Object handback ) { |
240 | this.filter = filter; |
241 | this.handback = handback; |
242 | } |
243 | /** |
244 | * get notification listener's filter |
245 | * @return Returns the filter. |
246 | */ |
247 | public NotificationFilter getFilter() { |
248 | return filter; |
249 | } |
250 | /** |
251 | * get notification listener's handback |
252 | * @return Returns the handback. |
253 | */ |
254 | public Object getHandback() { |
255 | return handback; |
256 | } |
257 | } |
258 | |
259 | |
260 | /** |
261 | * find (making if not found) list for given listener |
262 | * @param listener listener whose list to find |
263 | * @return list for given listener |
264 | */ |
265 | private List findListenerList( NotificationListener listener ) { |
266 | List listenerList = null; |
267 | synchronized ( notificationListeners ) { |
268 | if ( notificationListeners.containsKey( listener ) ) { |
269 | listenerList = (List)notificationListeners.get( listener ); |
270 | } |
271 | } |
272 | return listenerList; |
273 | } |
274 | |
275 | /** |
276 | * find (making if not found) list for given listener |
277 | * @param listener listener whose list to find |
278 | * @return list for given listener |
279 | */ |
280 | private List findOrCreateListenerList( NotificationListener listener ) { |
281 | List listenerList; |
282 | synchronized ( notificationListeners ) { |
283 | listenerList = findListenerList( listener ); |
284 | if ( null == listenerList ) { |
285 | listenerList = new LinkedList(); |
286 | notificationListeners.put( listener, listenerList ); |
287 | } |
288 | } |
289 | return listenerList; |
290 | } |
291 | |
292 | /** |
293 | * set notification info for this MBean in one fell swoop. |
294 | * use this or <code>addNotificationInfo()</code>, but not both! |
295 | * needed for notification interfaces. |
296 | * @param notificationInfo all notification info for this MBean |
297 | */ |
298 | protected void setNotificationInfo( |
299 | MBeanNotificationInfo[] notificationInfo ) { |
300 | synchronized ( mBeanNotificationInfo ) { |
301 | mBeanNotificationInfo = ( ( null == notificationInfo ) |
302 | ? new MBeanNotificationInfo[0] |
303 | : notificationInfo ); |
304 | } |
305 | } |
306 | |
307 | /** |
308 | * add one notification info for this MBean. |
309 | * use this or <code>setNotificationInfo()</code>, but not both! |
310 | * this is useful for hierarchy of MBean classes each adding its own. |
311 | * needed for notification interfaces. |
312 | * @param notificationInfo notification info for this MBean |
313 | */ |
314 | protected void addNotificationInfo( |
315 | MBeanNotificationInfo notificationInfo ) { |
316 | synchronized ( mBeanNotificationInfo ) { |
317 | MBeanNotificationInfo[] oldNotInfo = mBeanNotificationInfo; |
318 | int oldSize = oldNotInfo.length; |
319 | mBeanNotificationInfo = new MBeanNotificationInfo[oldSize+1]; |
320 | if ( oldNotInfo.length > 0 ) { |
321 | System.arraycopy( oldNotInfo, |
322 | 0, mBeanNotificationInfo, 0, oldSize ); |
323 | } |
324 | mBeanNotificationInfo[oldSize] = notificationInfo; |
325 | } |
326 | } |
327 | |
328 | /** |
329 | * make new notification object for this mbean. |
330 | * sets source, sequence number, timestamp automatically. |
331 | * public so that corresponding agent can invoke. |
332 | * @param type notification type |
333 | * @param message notification message |
334 | * @param userData user data |
335 | * @return new notification from this MBean |
336 | */ |
337 | public Notification newNotification( |
338 | String type, String message, Object userData ) { |
339 | Notification notification = |
340 | new Notification( type, objectName, notificationSequenceNumber++, |
341 | System.currentTimeMillis(), message ); |
342 | notification.setUserData( userData ); |
343 | return notification; |
344 | } |
345 | |
346 | /** |
347 | * send given notification to interested listeners. |
348 | * public so that corresponding agent can invoke. |
349 | * @param notification notification to send |
350 | */ |
351 | public void notifyListeners( Notification notification ) { |
352 | // for every listener in listener map |
353 | // for every info about the listener |
354 | // if no filter or if filter allows this notification |
355 | // send this listener the notification with the handback |
356 | synchronized ( notificationListeners ) { |
357 | for ( Iterator listenerI = |
358 | notificationListeners.entrySet().iterator(); |
359 | listenerI.hasNext(); |
360 | ) { |
361 | Map.Entry listenerEntry = (Map.Entry)listenerI.next(); |
362 | NotificationListener nl = |
363 | (NotificationListener)listenerEntry.getKey(); |
364 | List listenerInfoList = (List)listenerEntry.getValue(); |
365 | for ( Iterator infoI = listenerInfoList.iterator(); |
366 | infoI.hasNext(); ) { |
367 | NotificationListenerInfo nli = |
368 | (NotificationListenerInfo)infoI.next(); |
369 | NotificationFilter nf = nli.getFilter(); |
370 | if ( ( null == nf ) || |
371 | nf.isNotificationEnabled( notification ) ) { |
372 | nl.handleNotification( notification, nli.getHandback()); |
373 | } |
374 | } |
375 | } |
376 | } |
377 | } |
378 | |
379 | /** |
380 | * notify listeners - message and userData can be null. |
381 | * sets source, sequence number, timestamp automatically. |
382 | * public so that corresponding agent can invoke. |
383 | * @param type notification type |
384 | * @param message notification message |
385 | * @param userData user data |
386 | */ |
387 | public void notifyListeners( |
388 | String type, String message, Object userData ) { |
389 | Notification notification = newNotification( type, message, userData ); |
390 | notifyListeners( notification ); |
391 | } |
392 | |
393 | // BEGIN javax.management.NotificationBroadcaster IMPLEMENTATION |
394 | |
395 | /* (non-Javadoc) |
396 | * @see javax.management.NotificationBroadcaster#addNotificationListener( |
397 | * javax.management.NotificationListener, |
398 | * javax.management.NotificationFilter, |
399 | * java.lang.Object) |
400 | */ |
401 | public void addNotificationListener( |
402 | NotificationListener listener, |
403 | NotificationFilter filter, |
404 | Object handback ) |
405 | throws IllegalArgumentException { |
406 | if ( null == listener ) { |
407 | throw new IllegalArgumentException("null listener"); |
408 | } |
409 | synchronized ( notificationListeners ) { |
410 | List listenerList = findOrCreateListenerList( listener ); |
411 | boolean alreadyInList = false; |
412 | for ( Iterator listI = listenerList.iterator(); |
413 | listI.hasNext() && !alreadyInList; ) { |
414 | NotificationListenerInfo nli = |
415 | (NotificationListenerInfo)listI.next(); |
416 | if ( ( nli.getFilter() == filter ) && |
417 | ( nli.getHandback() == handback ) ) { |
418 | alreadyInList = true; |
419 | } |
420 | } |
421 | if ( !alreadyInList ) { |
422 | NotificationListenerInfo nli = |
423 | new NotificationListenerInfo( filter, handback ); |
424 | listenerList.add( nli ); |
425 | } |
426 | } |
427 | } |
428 | /* (non-Javadoc) |
429 | * @see javax.management.NotificationBroadcaster#getNotificationInfo() |
430 | */ |
431 | public MBeanNotificationInfo[] getNotificationInfo() { |
432 | MBeanNotificationInfo mbni[]; |
433 | synchronized ( mBeanNotificationInfo ) { |
434 | mbni = mBeanNotificationInfo; |
435 | } |
436 | return mbni; |
437 | } |
438 | /* (non-Javadoc) |
439 | * @see javax.management.NotificationBroadcaster#removeNotificationListener( |
440 | * javax.management.NotificationListener) |
441 | */ |
442 | public void removeNotificationListener( NotificationListener listener ) |
443 | throws ListenerNotFoundException { |
444 | synchronized ( notificationListeners ) { |
445 | List listenerList = findListenerList( listener ); |
446 | if ( null == listenerList ) { |
447 | throw new ListenerNotFoundException("no such listener"); |
448 | } |
449 | notificationListeners.remove( listener ); |
450 | } |
451 | } |
452 | |
453 | // END javax.management.NotificationBroadcaster IMPLEMENTATION |
454 | |
455 | // javax.management.NotificationEmitter doesn't exist until JMX 1.2 |
456 | // BEGIN javax.management.NotificationEmitter IMPLEMENTATION |
457 | |
458 | /* (non-Javadoc) |
459 | * @see javax.management.NotificationBroadcaster#removeNotificationListener( |
460 | * javax.management.NotificationListener, |
461 | * javax.management.NotificationFilter, |
462 | * java.lang.Object) |
463 | */ |
464 | public void removeNotificationListener( NotificationListener listener, |
465 | NotificationFilter filter, |
466 | Object handback ) |
467 | throws ListenerNotFoundException { |
468 | synchronized ( notificationListeners ) { |
469 | List listenerList = findListenerList( listener ); |
470 | if ( null == listenerList ) { |
471 | throw new ListenerNotFoundException("no such listener"); |
472 | } |
473 | // copy list so don't get concurrent modification upon removal |
474 | Object nlis[] = listenerList.toArray(); |
475 | int nliCount = nlis.length; |
476 | for ( int i = 0; i < nliCount; i++ ) { |
477 | NotificationListenerInfo nli =(NotificationListenerInfo)nlis[i]; |
478 | if ( ( nli.getFilter() == filter ) && |
479 | ( nli.getHandback() == handback ) ) { |
480 | listenerList.remove( nli ); |
481 | } |
482 | } |
483 | |
484 | // doesn't really matter whether the listener list itself |
485 | // is removed or not when empty since it's the matching of the |
486 | // NotificationListenerInfo that matters when deciding to |
487 | if ( 0 == listenerList.size() ) { |
488 | notificationListeners.remove( listener ); |
489 | } |
490 | } |
491 | } |
492 | |
493 | // END javax.management.NotificationEmitter IMPLEMENTATION |
494 | |
495 | /** the Name property value of the MBean name */ |
496 | private String mBeanNamePropVal = null; |
497 | |
498 | /** |
499 | * get the Name property value of the MBean name |
500 | * @return Returns the mBeanNamePropVal. |
501 | */ |
502 | public String getMBeanNamePropVal() { |
503 | return mBeanNamePropVal; |
504 | } |
505 | |
506 | // BEGIN REGISTRATION AND UNREGISTRATION |
507 | |
508 | /* (non-Javadoc) |
509 | * @see jade.management.mbean.JadeBaseMBean#register(java.lang.String) |
510 | */ |
511 | public String register( String mBeanNameValue, Properties properties ) |
512 | throws MalformedObjectNameException, |
513 | InstanceAlreadyExistsException, |
514 | MBeanRegistrationException, |
515 | NotCompliantMBeanException { |
516 | |
517 | //if ( logger.isLoggable( Logger.FINE ) ) { |
518 | // java.io.StringWriter sw = new java.io.StringWriter(); |
519 | // java.io.PrintWriter pw = new java.io.PrintWriter( sw ); |
520 | // if ( null != properties ) { |
521 | // properties.list( pw ); |
522 | // } |
523 | // logger.log( Logger.FINE, "registering name:"+mBeanNameValue+ |
524 | // ", type:"+type+", properties:"+sw); |
525 | // pw.flush(); |
526 | // if ( logger.isLoggable( Logger.FINEST ) ) { |
527 | // Throwable t = new Throwable(); |
528 | // t.printStackTrace( pw ); |
529 | // logger.log( Logger.FINEST, "registration at "+sw ); |
530 | // pw.flush(); |
531 | // } |
532 | //} |
533 | |
534 | objectName = null; |
535 | if ( null != mBeanNameValue ) { |
536 | mBeanNamePropVal = mBeanNameValue; |
537 | objectName = |
538 | new ObjectName( objectNameStr( mBeanNamePropVal, properties ) ); |
539 | } |
540 | ObjectInstance objectInstance = |
541 | jadeFactory.getJadeMXServer().getMBeanServer(). |
542 | registerMBean( this, objectName ); |
543 | return objectInstance.getObjectName().getCanonicalName(); |
544 | } |
545 | |
546 | |
547 | /* (non-Javadoc) |
548 | * @see jade.jademx.mbean.JadeBaseMBean#unregister() |
549 | */ |
550 | public void unregister() |
551 | throws InstanceNotFoundException, |
552 | MBeanRegistrationException{ |
553 | logger.log( Logger.FINEST, |
554 | "JadeBase.unregister():about to unregister "+this); |
555 | try { |
556 | jadeFactory.getJadeMXServer().getMBeanServer(). |
557 | unregisterMBean( objectName ); |
558 | } |
559 | catch ( InstanceNotFoundException infe ) { |
560 | registered = false; |
561 | throw infe; |
562 | } |
563 | registered = false; |
564 | logger.log( Logger.FINEST, |
565 | "JadeBase.unregister():did unregister "+this); |
566 | } |
567 | |
568 | /** |
569 | * return whether this MBean is currently registered with its MBeanServer |
570 | * @return whether this MBean is currently registered with its MBeanServer |
571 | */ |
572 | public boolean isRegistered() { |
573 | return registered; |
574 | } |
575 | |
576 | // END REGISTRATION AND UNREGISTRATION |
577 | |
578 | /* (non-Javadoc) |
579 | * @see jade.management.mbean.JadeBaseMBean#getType() |
580 | */ |
581 | public String getType() { |
582 | return type; |
583 | } |
584 | |
585 | /* (non-Javadoc) |
586 | * @see jade.jademx.mbean.JadeBaseMBean#getName() |
587 | */ |
588 | public String getName() { |
589 | return name; |
590 | } |
591 | |
592 | /* (non-Javadoc) |
593 | * @see jade.jademx.mbean.JadeBaseMBean#getMBeanName() |
594 | */ |
595 | public String getMBeanName() { |
596 | return objectName.getCanonicalName(); |
597 | } |
598 | |
599 | /* (non-Javadoc) |
600 | * @see jade.jademx.mbean.JadeBaseMBean#getObjectName() |
601 | */ |
602 | public ObjectName getObjectName() { |
603 | return objectName; |
604 | } |
605 | |
606 | |
607 | /* (non-Javadoc) |
608 | * @see jade.jademx.mbean.JadeBaseMBean#getParentObjectName() |
609 | */ |
610 | public ObjectName getParentObjectName() { |
611 | return parentObjectName; |
612 | } |
613 | |
614 | /** |
615 | * set parent ObjectName |
616 | * @param parentObjectName The parentObjectName to set. |
617 | */ |
618 | public void setParentObjectName(ObjectName parentObjectName) { |
619 | this.parentObjectName = parentObjectName; |
620 | } |
621 | |
622 | /** |
623 | * return JadeFactory for this MBean |
624 | * @return Returns the jadeFactory. |
625 | */ |
626 | public JadeFactory getJadeFactory() { |
627 | return jadeFactory; |
628 | } |
629 | |
630 | |
631 | // DYNAMIC MBEAN SUPPORT |
632 | |
633 | |
634 | /** MBean information for base JADE MBean class */ |
635 | private MBeanInfo mBeanInfo = null; |
636 | /** |
637 | * return MBean information for base JADE MBean class |
638 | * @return MBean information for base JADE MBean class |
639 | */ |
640 | public MBeanInfo getMBeanInfo() { |
641 | // lazy evaluation |
642 | if ( null == mBeanInfo ) { |
643 | |
644 | String className = JadeBase.class.getName(); |
645 | |
646 | String description = "base (abstract) JADE MBean"; |
647 | |
648 | // attributes |
649 | MBeanAttributeInfo aI[] = new MBeanAttributeInfo[] { |
650 | new MBeanAttributeInfo( |
651 | ATTR_MBEAN_NAME, String.class.getName(), |
652 | "MBean name", |
653 | true, false, false ), |
654 | new MBeanAttributeInfo( |
655 | ATTR_OBJECT_NAME, ObjectName.class.getName(), |
656 | "MBean ObjectName", |
657 | true, false, false ), |
658 | new MBeanAttributeInfo( |
659 | ATTR_PARENT_OBJECT_NAME, ObjectName.class.getName(), |
660 | "parent MBean ObjectName", |
661 | true, false, false ), |
662 | new MBeanAttributeInfo( |
663 | ATTR_JADE_FACTORY, JadeFactory.class.getName(), |
664 | "MBean JadeFactory", |
665 | true, false, false ), |
666 | new MBeanAttributeInfo( |
667 | ATTR_TYPE, String.class.getName(), |
668 | "MBean type", |
669 | true, false, false ) |
670 | }; |
671 | |
672 | // constructors |
673 | MBeanConstructorInfo cI[] = new MBeanConstructorInfo[0]; |
674 | |
675 | // operations |
676 | // MBeanParameterInfo pI[] = new MBeanParameterInfo[] { |
677 | // new MBeanParameterInfo( "mBeanNameValue", |
678 | // String.class.getName(), |
679 | // "name to register MBean with"), |
680 | // new MBeanParameterInfo( "properties", |
681 | // Properties.class.getName(), |
682 | // "non-default properties to use in MBean name") |
683 | // }; |
684 | // MBeanOperationInfo oI[] = new MBeanOperationInfo[] { |
685 | // new MBeanOperationInfo( OPER_REGISTER, |
686 | // "register this MBean with its server", |
687 | // pI, |
688 | // String.class.getName(), |
689 | // MBeanOperationInfo.ACTION_INFO ) |
690 | // }; |
691 | |
692 | MBeanOperationInfo oI[] = new MBeanOperationInfo[0]; |
693 | |
694 | // notifications |
695 | MBeanNotificationInfo nI[] = new MBeanNotificationInfo[0]; |
696 | |
697 | // finally, MBeanInfo for this level of class hierarchy |
698 | mBeanInfo = new MBeanInfo( className, description, aI, cI, oI, nI ); |
699 | |
700 | } |
701 | return mBeanInfo; |
702 | } |
703 | |
704 | /** |
705 | * get an attribute value |
706 | * @param attribute name of attribute to get |
707 | * @return attribute value |
708 | * @throws AttributeNotFoundException no such attribute |
709 | * @throws MBeanException exception from getter |
710 | * @throws ReflectionException exception invoking getter |
711 | */ |
712 | public Object getAttribute( String attribute ) |
713 | throws AttributeNotFoundException, |
714 | MBeanException, |
715 | ReflectionException { |
716 | Object o; |
717 | if ( ATTR_MBEAN_NAME.equals( attribute ) ) { |
718 | o = getMBeanName(); |
719 | } |
720 | else if ( ATTR_OBJECT_NAME.equals( attribute ) ) { |
721 | o = getObjectName(); |
722 | } |
723 | else if ( ATTR_PARENT_OBJECT_NAME.equals( attribute ) ) { |
724 | o = getParentObjectName(); |
725 | } |
726 | else if ( ATTR_JADE_FACTORY.equals( attribute ) ) { |
727 | o = getJadeFactory(); |
728 | } |
729 | else if ( ATTR_TYPE.equals( attribute ) ) { |
730 | o = getType(); |
731 | } |
732 | else { |
733 | throw new AttributeNotFoundException( |
734 | "no such readable attribute \""+attribute+"\""); |
735 | } |
736 | return o; |
737 | } |
738 | |
739 | /** |
740 | * get multiple attribute values |
741 | * @param attributes attributes to be retrieved |
742 | * @return retrieved attributes |
743 | */ |
744 | public AttributeList getAttributes(String[] attributes) { |
745 | AttributeList aL = null; |
746 | int attrCount = attributes.length; |
747 | if ( attrCount >= 0 ) { |
748 | aL = new AttributeList( attrCount ); |
749 | for ( int i = 0; i < attrCount; i++ ) { |
750 | try { |
751 | aL.add( getAttribute( attributes[i] ) ); |
752 | } |
753 | catch ( Exception e ) { |
754 | throw new RuntimeException( e ); |
755 | } |
756 | } |
757 | } |
758 | return aL; |
759 | } |
760 | |
761 | /** |
762 | * @param attribute |
763 | * @throws AttributeNotFoundException |
764 | * @throws InvalidAttributeValueException |
765 | * @throws MBeanException |
766 | * @throws ReflectionException |
767 | */ |
768 | public void setAttribute( Attribute attribute ) |
769 | throws AttributeNotFoundException, |
770 | InvalidAttributeValueException, |
771 | MBeanException, |
772 | ReflectionException { |
773 | // i have no writable attributes |
774 | throw new AttributeNotFoundException( |
775 | "no such writable attribute"+attribute.getName() ); |
776 | } |
777 | |
778 | /** |
779 | * set multiple attribute values |
780 | * @param attributes attribute values to set |
781 | * @return set attribute values |
782 | */ |
783 | public AttributeList setAttributes(AttributeList attributes) { |
784 | int attrCount = attributes.size(); |
785 | for ( int i = 0; i < attrCount; i++ ) { |
786 | try { |
787 | setAttribute( (Attribute)attributes.get(i) ); |
788 | } |
789 | catch ( RuntimeException re ) { |
790 | throw re; |
791 | } |
792 | catch ( Exception e ) { |
793 | throw new RuntimeException( e ); |
794 | } |
795 | } |
796 | return attributes; |
797 | } |
798 | |
799 | /** |
800 | * invoke an action |
801 | * @param actionName name of action to invoke |
802 | * @param params action parameters |
803 | * @param signature action signature |
804 | * @return object result |
805 | * @exception MBeanException wrap action exception |
806 | * @exception ReflectionException wrap action invocation exception |
807 | */ |
808 | public Object invoke(String actionName, Object params[], String signature[]) |
809 | throws MBeanException, ReflectionException { |
810 | //Object o; |
811 | try { |
812 | //if ( OPER_REGISTER.equals( actionName ) ) { |
813 | // o = register( (String)params[0], (Properties)params[1] ); |
814 | //} |
815 | //else { |
816 | throw new ReflectionException( new RuntimeException(), |
817 | "no action named \""+actionName+"\""); |
818 | //} |
819 | } |
820 | catch ( ArrayIndexOutOfBoundsException aioobe ) { |
821 | throw new ReflectionException( aioobe ); |
822 | } |
823 | catch ( ClassCastException cce ) { |
824 | throw new ReflectionException( cce ); |
825 | } |
826 | catch ( ReflectionException re ) { |
827 | throw re; |
828 | } |
829 | catch ( Exception e ) { |
830 | throw new MBeanException( e ); |
831 | } |
832 | //return o; |
833 | } |
834 | |
835 | |
836 | /** |
837 | * override toString() from Object. |
838 | * if registered with MBeanServer, use server's name for this |
839 | * mbean, else return some descriptive information. |
840 | * @return string representation of this jademx mbean |
841 | */ |
842 | public String toString() { |
843 | String s = ( ( null != objectName ) |
844 | ? objectName.toString() |
845 | : ( "unregistered jademx "+type+" "+name+"("+jadeFactory+")" ) ); |
846 | return s; |
847 | } |
848 | |
849 | |
850 | |
851 | } |