Sunday, February 7, 2010

Devlop your own console for monitoring Enterprise Java Application

In this article we will have a glimpse on how to develop our own monitoring console, which will monitor our Java Enterprise applications. Advantages of developing our own console includes 1. We can decide on the parameters, we need monitor 2. We can change the application server parameters through the console, than depending on the server administrator to change it. 3. When we integrate a third party cache framework with our application , it can also be monitored and tuned. There are several advantages which you could visualize at the end of this article. Again it involves development effort and time which seems to be a drawback.
For this console, the important ingredient will be the MBean which will be acting as a bridge between our application and the J2EE application server. Please excuse me for explaining this process using JBoss Application server, in this article. JBoss is a open source J2EE application server gaining its popularity in a very fast pace. Also its known as a Mbean server.
First before going in to the approach of developing the console, the prequisite will be to have a knowledge of Java Mbeans, Mbeans are Managed Beans(java objects) , that represent a resource to be managed.More can be gained from http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html.
First Step:
The first step involves in the indentification of parameters that need to be monitored. Here we will take the number of transactions happened in a module (example may be booking transaction,search transaction) over a time period , since server start. To brief we will monitor all the successsfull and failed transactions over a time period.
Developing MBean:
The second step involves the development of MBean. Once your monitoring parameters and requirements are finalized, we need to decide on the number of Mbeans to be developed and deployed based on the size of the Enterprise application and requirements. Normally one MBean will serve all our requirements. Make sure you develop a MBean such that it can be accessed from even remote machine using JNDI look up. So that the console can be deployed in one machine and it can control our Enterprise application running in different box. So to make it remote , you should have the following piece of code in Jboss-service.xml

name=”jboss.jmx:type=adaptor,name=MyServiceInvokeTarget,protocol=jrmp,
service=proxyFactory”>

jboss:service=invoker,type=jrmp

mine:service=MyService

MyServiceInvokeTarget

true

org.jboss.test.MyServiceMBean



org.jboss.proxy.ClientMethodInterceptor
org.jboss.proxy.SecurityInterceptor
org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor

org.jboss.invocation.InvokerInterceptor



The JNDI name which is highlighted in the above piece of code is the attribute specifying the JNDI name, which can be used in the client to lookup. This is a approach were a proxy is created to get the service from our MBean. We can access it by normal lookup. Following piece of code shows a sample mbean,
MBean Interface
public interface ConsoleMBean {

public Integer getSuccessTransactions() ;

public void setSuccessTransactions() ;

public Integer getFailedTransactions() ;

public void setFailedTransactions();

public Integer getTotalTransactions() ;

public void setTotalTransactions(); public void start() throws Exception;

public void stop() throws Exception;
}
Mbean Implementation class
public class Console implements ConsoleMBean{


private Integer SuccessTransactions=0;

private Integer FailedTransactions=0;

private Integer TotalTransactions=0;

public Integer getSuccessTransactions() {return SuccessTransactions;
}

public void setSuccessTransactions() {SuccessTransactions = getSuccessTransactions()+1;
}

public Integer getFailedTransactions() {return FailedTransactions;
}

public void setFailedTransactions() {FailedTransactions = getFailedTransactions()+1;
}

public Integer getTotalTransactions() {return TotalTransactions;
}

public void setTotalTransactions() {TotalTransactions = getTotalTransactions()+1;
public void start() throws Exception{
//Do here
}

public void stop() throws Exception{
//Do here
}
}
}
JBoss-service.xml





name=“jboss.jmx:type=adaptor,name=MyServiceInvokeTarget,
protocol=jrmp,service=proxyFactory”>

jboss:service=invoker,type=jrmp


com.example:service=Console


MonitoringConsole

true

org.jboss.test.MyServiceMBean



org.jboss.proxy.ClientMethodInterceptor
org.jboss.proxy.SecurityInterceptor
org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor

org.jboss.invocation.InvokerInterceptor



So we have created a MBean which will be used to monitor the transactions of a module. We can persist the counts in DB or a flat file each time when a server is shut down or in a scheduled manner using quartz scheduler, and we can read the count from the DB when the server startsup. All this can be done using the start() and stop() methods in the MBean.
Integration with Java Enteprise Application:
Your Java Enterprise application will typically have different layers like Presenattion, Business and Data layers. So it depends on the application architecture and requirements as, where to plugin/integrate. Here we will consider that we are going to monitor business transactions i.e.. the booking transactions, So in EJB in the method for booking when the transactions commits we will invoke the method setSuccessTransactions in the Mbean after committing the transaction, it will increase the transaction count by 1. Similarly after rollback invoking setFailureTransaction will increase the failed transaction count by1.
If your application is using Springs, then you can get the reference of the MBean using injection and can access the MBean methods.
Developing the Console UI:
We have so far written code for the MBean, and code to integrate it with the Aplication. next is we need to have a UI through which we can see the results of the transactions. It totally depends on what is required to be displayed in the UI and in the fashion , how it should be displayed. We can have a Simple web application based on struts or even a simple servlet will do. In the UI part we need to code in such way that , it contacts the MBean and gets the information of transactions, by invoking the get method. Also it’s here were you will code to to do appliation server related opertations by getting the reference of corresponding MBean and invoking the operation.
To plot the success transaction, failure transactions and total transactions against time, you can use charting frameworks like JFreechart which is free of cost comes under GNU-GPL license.
Build and Deployment:
Once we are over with the coding, then we need to build and deploy the applications . A .sar file has to created by placing the MBean classed inside the .sar and jboss-service.xml within the META-INF directory. SAR file is the file format used to deploy the MBeans in JBoss App Server. And these file will be first deployed in the server when server is started. The Java application can be deployed as it was how previously. At last the UI application can be deployed as a .war or .ear file depending the components it contains.

Wednesday, September 24, 2008

Usage of Interceptors and Timer Service in EJB3

Interceptors are used to intercept business method invocations og EJB3 bean class. The interceptors can be defined either class level or method level.
Also the interceptors can be in a seperate class using @Interceptor annotation or a method annotated with @AroundInvoke with signature Object methodname (InvocationContext ic)in the same class.
More than one interceptor classes can also be defined for a bean, using @Interceptor annotation. Interceptors have same life cycle as of that of associated bean and can have dependency injection in the same context.

Invocation Context

InvocationContext allows you to propagate through a chain of interceptors, along with its get/set methods, which even provides reference to the bean. Following are the methods that can be accessed by the handle provided.

Object getBean(): Provides the reference to the bean for which the Interceptor is defined.
Method getMethod():Provides information of about which method in the bean is called
Object[] getParameters():Provides infomation of the parameters passed to the bean.
void setParameters(): Set the parameter values
Map getContextData(): Provides context data that can be shared by the chain.
Object proceed(): Proceeds to the next interceptor in the chain or to the business method of the bean.

A simple example of using the Interceptor is illustrated below

package com.test;


import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TimedObject;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerHandle;
import javax.ejb.TimerService;


@Stateless
@RemoteBinding(jndiBinding="Welcome")
@Remote(UpdateEJB.class)
@Interceptors(TestInterceptor.class)
public class UpdateEJBBean implements UpdateEJB {

private String message;

@Resource
private SessionContext ctx;

@Interceptors(TestInterceptor1.class)
public String sayHello(String name) {
System.out.println("Inside EJB method");
return "Hello " + name + message;
}


@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 3");
return invocationContext.proceed();
}

}
The @RemoteBinding(jndiBinding="Welcome") is used to bind the EJB Bean to the JNDI name which we specify, instead using default JNDI name, provided by appserver vendors
The interceptor class will be like the one shown below.

public class TestInterceptor{

@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 1");
return invocationContext.proceed();
}

}

public class TestInterceptor1{

@AroundInvoke
public Object log(InvocationContext invocationContext) throws Exception {
System.err.println(invocationContext.getMethod().getName() + " called from interceptor 1");
return invocationContext.proceed();
}

}

The order of Interceptor Invocation will be like
1.EJB Bean Class level Interceptor
2.EJB Bean Method level interceptor annotated by @Interceptor above the method
3.The method annotated with @AroundInvoke annotation.

Timer Service


Using EJB3 we can create a timely triggers and method invocations using the TimerService, provided by EJB3. You can either implement TimedObject interface, or you can
annotate method that you need to trigger after each timer expiration using @Timeout annotation.

package com.test;

import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TimedObject;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerHandle;
import javax.ejb.TimerService;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionManagement;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;


@Stateless
@RemoteBinding(jndiBinding="Welcome")
@Remote(UpdateEJB.class)
public class UpdateEJBBean implements UpdateEJB,TimedObject {

private String message;

@Resource
private SessionContext ctx;

public String sayHello(String name) {
ctx.getTimerService().createTimer(6000, "HAI");
ctx.getTimerService().createTimer(6000,6000, "HAI");
return "Hello " + name + message;
}

public void ejbTimeout(Timer handle) {
System.out.println("handle.getTimeRemaining()"+handle.getTimeRemaining());
System.out.println("handle.getNextTimeout()"+handle.getNextTimeout());

}
}

To create the timer ctx.getTimerService().createTimer method is used, the timer timeout can be only once or frequently in a timed manner.
createTimer(6000,6000, "HAI") this says that the timer will expire in a period of 6000ms with initial delay of 6000ms.

The argument, Timer provides the handle to the timer, which has getTimeRemaining and getNextTimeout methods.

Instead of implementing interface you can also use annotation @Timeout above the method that needs to be triggered after each timer expiration.

Hope the article was useful.