JBoss.org Community Documentation

Chapter 28. Service POJOs (JBoss extension of EJB3)

Service POJOs allow you to define POJOs as JBoss services. The way you define them is very similar to how you define stateless or stateful session beans. One very important difference is that there will only ever be ONE instance of the service bean. i.e. it is not pooled - the bean instance is a singleton. The singleton bean contains shared state, so data set by one client is accessible by other clients.

Take a look at org.jboss.tutorial.service.bean.ServiceOne.java. It has been annotated with @org.jboss.ejb3.annotation.Service, this defines it as a singleton service in JBoss. It implements org.jboss.tutorial.service.bean.ServiceOneRemote and org.jboss.tutorial.service.bean.ServiceOneLocal just as you would do for a normal stateful/stateless bean.

ServiceOne also implements org.jboss.tutorial.service.bean.ServiceOneManagement. org.jboss.tutorial.service.bean.ServiceOne has been annotated with @org.jboss.ejb3.annotation.Management. JBoss will inspect this interface, and create and install an MBean implementing the attributes and operations defined in the @Management interface. The MBean will work on the same singleton bean instance as the remote and local interfaces.

Lifecycle :

Just as for "normal" MBeans in JBoss, the @Service supports lifecycle management. Lifecycle management consists of two things:

  • Lifecycle methods
  • Dependencies

Lifecycle methods :

org.jboss.tutorial.service.bean.ServiceOneManagement contains the four methods:

				
void create() throws Exception;

void start() throws Exception;

void stop();

void destroy();

				
			

You do not need to include all these methods, you can pick and choose. If present, the service container will call these methods as follows:

  • create : called by the server when the service is created and all the services it depends upon have been created too. At this point the service (and all the services it depends on) is installed in the JMX server, but is not yet fully functional.
  • start : called by the server when the service is started and all the services it depends upon have been started too. At this point the service (and all the services it depends on) is fully functional.
  • stop : called by the server when the service is stopped. At this point the service (and all the services that depend on it) is no longer fully operational.
  • destroy : called by the server when the service is destroyed and removed from the MBean server. At this point the service (and all the services that depend on it) are destroyed.

Depends and custom JMX object name :

Let's take a look at how to define the dependencies between services. Open org.jboss.tutorial.service.bean.ServiceTwo. Again it has been annotated with @Service, and it implements the @Management annotated interface org.jboss.tutorial.service.bean.ServiceTwoManagement.

				
@Service(objectName = ServiceTwo.OBJECT_NAME)
@Management(ServiceTwoManagement.class)
@Depends(ServiceOne.OBJECT_NAME)
public class ServiceTwo implements ServiceTwoManagement
{
...
				
			

The @org.jboss.ejb3.annotation.Depends annotation specifies that this service depends on the service created for ServiceOne. i.e. it cannot be started until the service created for ServiceOne has been started.

Note

You can specify an array of ObjectNames if you depended on more than one service.

You will also notice the use of objectName property of @Service. This is used to install the service under a custom ObjectName instead of the default ObjectName. So in this tutorial, our ServiceTwo will be registered at tutorial:service=ServiceTwo

Depends injection :

Take a look at org.jboss.tutorial.bean.ServiceThree. It has dependencies on other MBeans, but rather than annotating the class with @Depends, the dependencies are specified on fields and setter methods.

				
@Depends(ServiceOne.OBJECT_NAME)
public ObjectName serviceOneName;

private ServiceTwoManagement service2;

@Depends(ServiceTwo.OBJECT_NAME)
public void setServiceTwo(ServiceTwoManagement service2)
{
	this.service2 = service2;
}
				
			

With regard to the lifecycle dependencies, the effect of annotating fields and setters with @Depends is the same as if we annotated the class. So, ServiceThree cannot be started until ServiceOne (tutorial:service=ServiceOne) and ServiceTwo(tutorial:service=ServiceTwo) are started. Annotating the fields and setters with @Depends though, allows you to inject the dependencies. So in this tutorial, the ServiceThree.serviceOneName will be injected with the ObjectName which corresponds to ServiceOne. More interesting is the injection of ServiceTwo. setServiceTwo() takes a parameter, which is the ServiceTwoManagement management interface of ServiceTwo. The server creates a dynamic proxy for the ServiceTwoManagement interface, and injects that. This means that you can call the methods on the service2 field without caring that you are actually invoking methods on another service.

Interceptors :

You can define interceptors for your service beans in the same way as shown in the "interceptors" tutorial. This example defines one in the ServiceThree bean class itself:

				
@AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception
{
   System.out.println("ServiceThree - Interceptor");
   return ctx.proceed();
}
				
			

Defining Management Interface via XML :

You can deploy a Service bean as an XMBean, where the management attributes and operations are defined via xml. Take a look at org.jboss.tutorial.service.bean.XMBeanService. Note the @Service annotation specifies an xmbean property. Also note there is no @Management annotation.

				
@Service(objectName = XMBeanService.OBJECT_NAME, xmbean = "resource:META-INF/service-xmbean.xml")
@Remote(XMBeanServiceRemote.class)
public class XMBeanService implements XMBeanServiceRemote
{
...
				
			

Now take a look at META-INF/service-xmbean.xml. This is the file referenced by the xmbean property and specifies the bean's management attributes and operations. Note the class, constructor, attribute and operation elements.

Building and Running

Note

To build and run the example, make sure you have installed JBoss 5.x. See the Section 1.1, “JBoss Application Server 5.x” for details.

From the command prompt, move to the "service" folder under the Section 1.3, “Set the EJB3_TUTORIAL_HOME”

Ant Users:

Make sure the "default" server configuration of JBossAS-5.x is running

			
$ ant
$ ant run

run:
     [java] invoking remote business interface of ServiceOne...
     [java] Set the attribute value through ServiceOneRemote to 100
     [java] attribute value for (ServiceOne) singleton obtained via JMX is what we set via remote interface: 100
     [java] Invoking ServiceThree via JMX...
     [java] Hello from service One
     [java] ServiceThree - Calling ServiceTwo.sayHello() via MBean proxy
     [java] invoking XMBean (configured through deployment descriptor)...
     [java] Set the attribute value to 50
     [java] Invoking XMBean through JMX
     [java] attribute value for (XMBeanService deployment descriptor configured) singleton obtained via JMX is what we set via remote interface: 50
     [java] Hello from an XMBean

		     
			

Maven Users: Make sure the AS is not running.

$ mvn clean install -PRunSingleTutorial
			

On the server side when the application is deployed, you will notice these logs:

			
16:56:54,036 INFO  [STDOUT] ServiceOne - Created
...
16:56:54,082 INFO  [STDOUT] ServiceOne - Started
...
16:56:54,142 INFO  [STDOUT] ServiceTwo - Started
...
16:56:54,226 INFO  [STDOUT] ServiceThree - Started

			
		

Notice that the order is maintained because of the dependencies we have configured on the @Service.