The BarrierController Service
Expressing dependencies between services using the <depends> tag
(see an example here) is a convenient way to make
the lifecycle of one service depend on the lifecycle
of another.
So for example, serviceA <depends> on serviceB means that irrespectively
of the deployment order, the calling sequence will be:
serviceB.create()
serviceA.create()
serviceB.start()
serviceA.start()
The Problem
However, there are cases where services do not conform to the JBoss
lifecycle model, i.e. they don't expose create()/start()/stop()/destroy()
methods). For example, this is true for the jboss.system:type=Server MBean
that represents the JBoss server itself. No lifecycle operations are exposed
so you cannot simply express, +if JBoss is fully started then start my own
service+.
Or, even if they do conform to the JBoss lifecycle model, the completion of
a lifecycle method (e.g. the start() method) may not be what we want.
For example the jboss.web:service=WebServer MBean that wraps the embedded
tomcat server in JBoss does not start the tomcat connectors in the start()
method, until only after the jboss server is fully started. So putting
a dependency on this MBean, if we want to hit a webpage through tomcat,
will do no good.
Resolving such non-trivial dependencies is currently performed using JMX
notifications. For example the jboss.system:type=Server MBean emits
a notification of type org.jboss.system.server.started when it has
completed startup, and a notification of type org.jboss.system.server.stopped
when it shutsdown.
Similarly, jboss.web:service=WebServer
emits a notification of type jboss.tomcat.connectors.started as of
JBoss v4.0.2/3.2.8 (see this JIRA
report).
So you can actually subscribe and react to those notifications in order to
implement more complex dependencies. This technique has been generalized
with the BarrierController service; read on.
The Solution (as of JBoss v4.0.2/3.2.8)
The BarrierController is a relatively simple MBean service that extends
ListenerServiceMBeanSupport and thus can subscribe to receive any
notification in the system. It uses the received notifications to control
the lifecycle of a dynamically created MBean called the Barrier.
The Barrier is instantiated, registered and brought to the CREATE state
when the BarrierController is deployed. After that, the Barrier is started
and stopped when matching notifications are received. Thus, other services
need only depend on the Barrier MBean using the usual
tag,
without having to worry about complex lifecycle issues. They will be started
and stopped in tandem with the Barrier. When the BarrierController is
undeployed the Barrier is destroyed, too.
The notifications of interest are configured in the BarrierController using
the SubscriptionList attribute. In order to identify the starting
and stopping notifications we associate with each subscription a
handback string object. Handback objects, if specified, are passed back
along with the delivered notifications at reception time (i.e. when
handleNotification() is called) to qualify the received notifications,
so that you can identify quickly from which subscription a notification is
originating (because your listener can have many active subscriptions).
So we tag the subscriptions that produce the starting/stopping notifications
of interest using any handback strings, and we configure this same string
to the StartBarrierHandback (and StopBarrierHandback correspondingly)
attribute of the BarrierController. Thus we can have more than one notifications
triggering the starting or stopping of the Barrier.
The Example
The attached example
(which is displayed here, too) is pretty
much self describing. It instantiates a BarrierController that creates
a Barrier called jboss:name=TomcatConnector,type=Barrier.
The Barrier is started when the tomcat connectors are started and stopped
when the server shutsdown. In fact, this is a very common pattern for
services that want to hit a servlet inside tomcat.
The service that depends on the Barrier in the example, is a simple
memory monitor that creates a background thread and monitors the memory
usage, emitting notifications when thresholds get crossed, but it could
be anything. We've used this because it prints out to the console
starting and stopping messages, so we know when the service gets
activated/deactivated.
If you hot-deploy this on a running server the Barrier will be stopped
because by the time the BarrierController is deployed the starting
notification is already seen. (There are ways to overcome this.) However,
if you re-start the server, the Barrier will be started just after the
tomcat connectors get activated.
You can also manually start/stop the Barrier by using the startBarrier() and
stopBarrier() methods on the BarrierController. The attribute
BarrierStateString indicates the status of the Barrier.
See NotificationsEmittedByJBossMBeans for deployment notifications.
Advanced stuff
The DynamicSubscriptions attribute can be used to indidicate whether
to monitor the JMX server for new MBeans registering, and subscribe for
notifications to them, if they much the subscription list pattern.
By default it is set to true.
The BarrierEnabledOnStartup defines the initial state of the Barrier,
started or stopped. It is stopped, by default (false).
Many BarrierControllers can be deployed to express different
notification-based dependencies, as long as their names and the specified
BarrierObjectNames are distinct.
Many MBean services can depend on the same Barrier.
More than one notifications may start or stop the barrier, as long
as they specify the same handback string.
Getting multiple times in a row a starting or stopping notification has no
effect on the Barrier.
You may extend org.jboss.system.BarrierController in order to override
the following method, to help the Controller decide about the initial
state of the Barrier. This is useful when the BarrierController is
hot deployed and so the starting notification is gone by that time.
/** * Override this method to apply complex logic whether * to start the Barrier service upon startup or not. * * This method will be only called once and only if * setBarrierEnabledOnStartup(Boolean) has not been called. * * The default implementation is to return false. */ protected Boolean enableOnStartup() { return Boolean.FALSE; }
JBoss AS-5.x
Some users have mentioned that they had trouble, setting this up in JBoss AS-5.x version. See this thread for more details.
Related:
Referenced by:
Comments