The ScriptingListener Service
The ScriptingListener service was introduced in JBoss v4.0.3. The idea is that
there can be cases that we want to react to some JMX notification, in a way
this should not be hardcoded. For example we want to receive a notification
and map it to another notification, log the original notification,
apply complex logic to decide if a combination of facts constitutes an alarm,
get an mbean attribute from a 2nd mbean and do something with it,
call an operation onto a 3rd mbean, etc.
Combining the ScriptingListener with a simple JMX Timer (configured through
the TimerService to produce TimerNotification notifications at regular intervals)
you can essentially achieve a polling effect. Your script will be called
periodically to apply arbitrary scripting logic (e.g. perform cleanup tasks,
log stuff, monitor a set of attributes).
The ScriptingListener uses the Bean Scripting Framework
(BSF) library to execute a script in any of the scripting languages that can hook
up to BSF (e.g. Jython, Jacl, Groovy, BeanShell, etc.). The script is executed
whenever a notification is received and it is passed the notification along
with some other context info that includes the following variables:
log, an instance of org.jboss.logging.Logger that can be used
to log messages; this is essentially the ScriptingListener's logger.
server, an instance of javax.management.MBeanServer providing access
to the central MBeanServer used by jboss; it can be used to get/set
attributes and invoke operation on other mbeans.
manager, an instance of org.jboss.monitor.alarm.AlarmManager, essentialy
a helper class that is of interest if you want to generate stateless or
stateful alarms that can be stored in the ActiveAlarmTable.
notification, this holds the notification instance received each time
by the ScriptingListener.
handback, the handback object passed to ScriptingListener
handleNotification() along with the notification.
Since executing a script in the context of the notification broadcaster
thread can take up some time (usually milliseconds, still a lot more time
than a broadcaster would expect) we enqueue the received notification
in memory and process it from a background thread.
You have to be a little careful with this, because it may have some issues
with mbeans that produce mutable notifications. Normally mbeans should
always emit immutable notifications, or copies of mutable ones. However
there are cases where this is not true. For example, notifications emitted
by deployers in jboss carry the original DeploymentInfo object (and not a
copy of it, at the time the notification is created). If you process the
notification in a different thread, from that of the sender, you may find
the data in the DeploymentInfo object to have changed.
Also, at this time there is no mechanism to prevent overflowing the internal
queue with notifications, in case we have very fast producers or very slow
scripts, so this is something that could be improved.
The attributes that can be configured are:
ScriptLanguage, the language in which the provided script is written.
Out of the box, jboss will support beanshell since bsh.jar is already
present in the server/xxx/lib directory. If you want a different language,
you need to make sure the implementation is available in the classpath.
The easiest thing is to just drop the .jar file in the lib directory.
Script, the script inlined in the service descriptor. Since scripts
may contain funny characters it is best to escape the xml content of
this attribute, i.e.
<attribute name="Script"><![CDATA[ ...whatever... \]\]\></attribute>
DynamicSubscriptions, since the ScriptingListener is based on
ListenerServiceMBeanSupport, you can indicate whether this service should
subscribe dynamically for notifications to newly registered mbeans
SubscriptionList, the mbeans/notifications to subscribe for.
There are also some read only attributes:
NotificationsReceived, the number of notifications received (and
therefore enqueued) by the ScriptingListener.
NotificationsProcessed, the number of notifications processed
(dequeued) by the script.
TotalProcessingTime, the total time spent by the script in
processing notifications, in milliseconds.
AverageProcessingTime, the average time spent by the script in
processing every notification, again, in milliseconds. This is a good
indication of how much time the script takes to execute.
In the following example, a JMX Timer is instantiated through the
TimerService wrapper, just to provide us with periodic notifications
that trigger our script every 30 seconds. The ScriptingListener subscribes
for those notifications, as you can see, using the SubscriptionList
A simple script is provided in beanshell that, upon the reception of
each notification, it queries and logs the free system memory and the total
number of threads. The server and log variables are already
setup in the script context by the ScriptingListener.
<server> <mbean code="org.jboss.monitor.services.ScriptingListener" name="jboss.monitor:service=ScriptingListener"> <attribute name="ScriptLanguage">beanshell</attribute> <attribute name="SubscriptionList"> <subscription-list> <mbean name="jboss.monitor:name=MonitorClock,type=Timer"></mbean> </subscription-list> </attribute> <attribute name="Script"> <![CDATA[ import javax.management.ObjectName; /* poll free memory and thread count */ ObjectName target = new ObjectName("jboss.system:type=ServerInfo"); long freeMemory = server.getAttribute(target, "FreeMemory"); long threadCount = server.getAttribute(target, "ActiveThreadCount"); log.info("freeMemory" + freeMemory + ", threadCount" + threadCount); \]\]\> </attribute> </mbean> <mbean code="org.jboss.monitor.services.TimerService" name="jboss.monitor:name=MonitorClock,type=TimerService"> <attribute name="NotificationType">jboss.monitor.clock</attribute> <attribute name="TimerPeriod">30sec</attribute> <depends optional-attribute-name="TimerMBean"> <mbean code="javax.management.timer.Timer" name="jboss.monitor:name=MonitorClock,type=Timer"></mbean> </depends> </mbean> </server>
The output in the console looks similar to:
17:08:52,425 INFO [ScriptingListener] freeMemory103875728, threadCount37 17:09:22,439 INFO [ScriptingListener] freeMemory102232792, threadCount37 17:09:52,442 INFO [ScriptingListener] freeMemory103872032, threadCount37 17:10:22,455 INFO [ScriptingListener] freeMemory102229096, threadCount37 17:10:52,448 INFO [ScriptingListener] freeMemory104121072, threadCount37 17:11:22,451 INFO [ScriptingListener] freeMemory102478136, threadCount37 17:11:52,464 INFO [ScriptingListener] freeMemory104117376, threadCount37 17:12:22,467 INFO [ScriptingListener] freeMemory102474440, threadCount37
Instructions for upgrading BSF and BSH can be found here.