6.13.2007
Part 2 – Creating an Advanced JBoss 4.x Service Archive (SAR) Components
In part one of this write up provided an introductory look into JBoss' Service Archive architecture (SAR). Service archives are components that are deployed on JBoss that can be used to extend the capabilities of JBoss or your deployed applications. The SAR architecture is the basis for JBoss’ component-based development and allows the deployment of modules that can easily be reused by other deployed modules.
The previous post included an example of a simple service archive that illustrates the ease with which a service archive component can be created and deployed on JBoss. This write up explores the use of JBoss service API to create more advanced components that can receive life-cycle notifications for a deeper integration with the JBoss container. We will take a look at how to use the JBoss XMBean descriptor file which is used to create rich set of attributes for describing JMX MBeans. All concepts covered here, are reinforced through an example that builds on the previous example in part 1 to create a directory monitoring system deployed as SAR in JBoss.
Click here to read part 1 of this post.
Integrating with JBoss Server
The JBoss service API provides different points for deep integration with the JBoss container. These integration points are event callbacks that are fired during at different stages of the container’s lifecycle.
org.jboss.system.ServiceMBean
The core interface that provides access into the container’s service architecture is the org.jboss.system.ServiceMBean. This interface exposes several lifecycle callback methods. Instead of directly implementing the interface, your SAR component class should extend the convenience class org.jboss.system.ServiceMBeanSupport and override the following methods:
| protected void createService() throws Exception; protected void destroyService() throws Exception; protected void startService() throws Exception; protected void stopService() throws Exception;
|
As the method names imply, you override the methods that correspond to the phase in the service lifecycle you are interested in. The createService() is called when the container’s SAR Deployer is about to initialize your service. Once your service is fully realized, the deployer calls the startService() automatically. The destroyService() is invoked by the deployer when server is stopping or when your service is about to be deregistered from the MBean container.
The ServiceMBeanSupport class also makes available other convenience callback methods that maket it easier for your service to receive a larger set of container events. These methods include:
| public ObjectName preRegister(javax.management.MBeanServer server, javax.management.ObjectName name) throws Exception;
public void postRegister(Boolean registrationDone);
|
The preRegister() method provides access to couple of key JMX objects including the MBean server and reference to the ObjectName for the component being registered. These methods are fired right before and right after the component’s registration into the MBean’s server respectively.
| NOTE: Deep integration with the JBoss container means that your code will introduce dependencies on the JBoss service API. However, that’s should not be a problem if your code follows good OO practices and well-know patterns that lessen architectural dependencies. |
The JBoss XMBean Descriptor File
In part one of this write up, I presented a simple SAR example that was implemented using the JMX API's Standard MBean which relies on a prescribed naming pattern. While this works, it has several drawbacks:
It forces the undesirable burden of naming your classes using a management interface naming pattern which may not fit well in your development.
The Standard MBean does not allow you to control which methods / properties are exposed for management. JBoss will automatically expose all management interface properties as JMX attributes and all methods as management operations.
Lastly, the Standard API has no mechanism to expose descriptive metadata regarding the exposed attributes and operations.
While the simple Standard MBean approach works well for simple cases, it may prove inefficient for complicated domain models and force you to insert JMX management matters into your business object graphs. JBoss alleviates this issue by providing the XMBean Deployment Descriptor XML file. XMBean provides the ability to expose any class (POJO) as a JMX MBean and therefore be exposed as a service archive component.
The XMBean descriptor mechanism also lets you expose your MBeans with richer descriptive metadata. Using the XMBean, one may specify description for all expose attributes, getters, and setters exposed by your MBean component. You can also use the XMBean to specify attributes persistence policy, and security interceptors classes supported by JBoss. For further information, see the JBoss XMBean documentation.
Using the XMBean Descriptor File
Declare your SAR component class in the jboss-service.xml file (same as before). Instead of specifying the attributes and operations in the service file, as before, point the component to an XMBean file using the xmbean-dd attribute. In the code snippet below, the component: points to file timer-xmbean.xml to get its definition:
| <mbean code="service.SimpleTimer" name="service.directory.monitor:service=MonitorTimer" xmbean-dd="META-INF/timer-xmbean.xml"> </mbean>
|
Create the XMBean XML descriptor file (with an arbitrary name) that matches the name specified in step 1. In it, insert any number of XML emlements (see JBoss Admin Guide) to describe attributes, methods, notifications, interceptors, and remote access interfaces. Here's an excerpt of the XMBean file for the class service.SimpleTimer:
| <class>service.SimpleTimer</class>
<constructor> <description>The default constructor</description> <name>SimpleTimer</name> </constructor>
<!-- Attributes --> <attribute access="read-write" getMethod="getPeriod" setMethod="setPeriod"> <description>The timing period for the timer. Defaults to 1000 mill sec (1 sec)</description> <name>Period</name> <type>long</type> </attribute>
<!-- Operations --> <operation> <description> <name>start</name> </operation>
<operation> <description>This operation stops the timer service.</description> <name>stop</name> </operation>
<operation impact="ACTION"> <description> When invoked, it sends a timing notification to registered (connected) services. </description> <name>time</name> </operation> |
The XMBean produces the following in the jmx-console:
XMBean extends the service descriptor file to provide features such as dependency injection and descriptive metadata capabilities for the JBoss JMX container. Additionally, <name/> and <description/> tags can be used to describe their enclosing constructor, operation, or attributes. The text will be exposed to the management console for increased usability during management of the component.
Under the hood, XMBean is JBoss' implementation of the Model MBean. The JBoss API does the heavy lifting to generate the sizeable amount of code required to dynamically create model MBeans. You simply specify a POJO and JBoss handles the rest. This approach lets you create complex domain models independent of any container specific API. In future write up, we will explore how to accomplish integration using Java-style annotations.
The Advanced Directory Monitor Example
This example demonstrates several concepts in developing service archive components including the ability to receive life cycle notifications from the JBoss SAR Deployer. Since the service infrastructure is based on JMX, you will inevitably create additional JMX management API dependencies to fully take advantage of the JBoss infrastructure.
For that reason, great care must be taken to implement management infrastructures in your code that separates management concerns away from your core business concerns.
The Directory Scanner Components
The implementation of the scanner is achieved using three distinct components. The segregation of the code into these components is a purely subjective decision. However, creating loosely-coupled components promotes good OO practices, increases code re-use, and, above all, makes implementation of management concerns easier since they can be separated out of business concerns.
Timer
The Timer component (implemented as SimpleTimer) provides timing service to other interested components. It extends the JMX API class NotificationBroadcasterSupport which allows it notify interested components (registered as listeners). For each time period t, the Timer sends a JMX notification of type "service.SimpleTimer.time" to registered listeners. In our sample code, the component Directory Monitor component will register itself as a listener to the Timer service.
Directory Monitor
This component (implemented as DirectoryMonitor2) scans a specified directory for files with specified extensions. When the files with the extension are found in the scanned directory, the monitor sends a notification to registered Directory Monitor Listener. During a scan sweep, if one or more files with a specified extension is detected in a specified directory, the directory monitor sends a notification of type "service.DirectoryMonitor.scan."
The DirectoryMonitor2 class extends the JBoss API class "org.jboss.system.ServiceMBeanSupport" to receive lifecycle notification from the JBoss container. When the SAR Deployer is deploying this component, it calls methods create(), preRegister(), postRegister, and start() respectively. You can implement any of these methods to take advantage of the callback mechanism to customize the registration sequence. In our example below, the DirectoryMonitor2 uses these callback method create() to register itself as a listener of the Timer component:
| public ObjectName preRegister(MBeanServer svr, ObjectName obj) throws Exception { super.preRegister(svr, obj); this.server = svr; ... }
public void create() throws Exception { super.create(); registerForTimer(); ... }
private void registerForTimer() { if(server != null) { NotificationFilterSupport filter = new NotificationFilterSupport(); filter.enableType(EVENT_TYPE); try { ObjectName timerName = new ObjectName(this.getTimerName()); server.addNotificationListener(timerName, this, filter, null); } catch ( ... ) { ... } } . . . } |
From the code sample, you can see that the create() method is implemented as a callback to programmatically register the DirectoryMonitor as a listener to the timer component. Review the code for details on these classes.
MonitorListener
As a design decision, the logic that handles the notifications from the directory monitor is placed in a separate component. Though not necessary, it makes for a cleaner implementation. The MonitorLister handles notifications broadcasted from the Monitor components of type "service.DirectoryMonitor.scan." One advantage of this separation is that the directory monitor code is separated from the code that provides logic on handling the scanned directory resources from the monitor.
| Running the Sample Code
Log into your jmx-console and you should see the following components deployed You can also validate the deployment of your component by seeing output in the console similar to the console image shown below.
|
Conclusion
In this post, I looked at how to create SAR components with deep integration with the JBoss container. SAR’s are JBoss components based on the JBoss container service architecture which itself is based on JMX technology. In a previous post, we have seen how to create simple SAR components using the JMX standard MBeans. In this post, we have seen how to create a more advanced example where the SAR components can be deeply integrated with the JBoss container.
Using the service management interfaces provided by the JBoss service architecture, we’ve seen how you can create SAR components that can listen to container generated lifecycle events including when the components is being created, registered into the container, and destroyed. By overriding methods in class org.jboss.system.ServiceMBeanSupport, we have seen how to implement methods that take advantage of the different lifecycle callbacks invoked during the instantiation sequence of the SAR component. You can download the sample code discussed here using the link found in the resource section.
In future post, we will explore JBoss’s support for annotated class to easily create SAR components using POJO’s.
Resources
1) JBoss Server Documentation - http://docs.jboss.com/jbossas/guides/installguide/r1/en/html_single/
2) JMX - http://en.wikipedia.org/wiki/JMX
3) Download Example – http://vladimirvivien.com/download/demos/jboss-service.zip
Subscribe to Posts [Atom]