Friday, December 31, 2010

Developing custom MBeans for JMX monitoring

Developing custom MBeans for JMX monitoring

In many cases, it might be useful to monitor the metrics of a Software Component. Some cases, we may not find suitable tools to get the required statistics and data. Those situations demand to you write own custom implementing to collect the metrics / statistics. So wrapping the custom implementation as an MBean, is simplest possible way to get the job done. Because any standard JMX based monitoring tool can monitor an MBean running the JVM. Let us examine the required steps to develop a custom MBean to accomplish the below use case.

Use case:
A business component, A Service Manager is responsible to process all the service requests generated in the application. This component invokes the external system's service call as part of business computation. As it is a critical component in the application, we need to monitor the performance statistics of the component described below.
• Number of total requests served.
• Number of failed requests.
• Percentage of success rate.
• Average Response Time
• Maximum Response Time
• Minimum Response Time

Implementation steps:
1. Define a monitor bean interface
2. Implement the monitor bean interface
3. Register the MBean with JVM's MBean Server
4. Expose methods for business component (to feed the data in)

Define a monitor bean interface:
• This interface exposes the MBean implementation to JVM's MBean Server.
• It lists the available methods, can be invoked by the MBean Server. Create AServiceMBean.java as below.
• If any of the attributes are allowed to be set by the monitoring tool, we need to provide the setter method.
• If we want to maintain them as read only values only getter would help, no setters.

package com.sample.mbean;

public interface AServiceMBean {

// read only methods..
public int getTotalServcieCalls();
public long getAverageResponseTime();
public long getMaxResponseTime();
public long getMinResponseTime();
public int getFailedServiceCalls();
public int getSuccessServiceCalls();

// a read-write attribute
public String getName();
public String setName(String name);

}

Implement the monitor bean interface:
• It is a class, implements the the MBean interface.
• This class implements the logic to compute the required statistics on raw data (fed by business component) and makes the computed metrics available for JMX server.
• This class should extends one of the MBean class (StandarMBean, StandardEmitterMBean) to convert the class as an eligible MBean.
• You can even implement DynamicMBean, MBeanRegistration interfaces to override the default behavior (for a specific behavior) of a standard MBean. - will discuss further as we progress....

package com.sample.mbean;

import java.lang.management.ManagementFactory;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.StandardMBean;

public class AServiceMBeanImpl extends StandardMBean implements
AServiceMBean {

private static int totalCalls;
private static long totalResponseTime;
private static int totalFailedCalls;
private static long maxResponseTime;
private static long minResponseTime;
private static long avgResponseTime;

public AServiceMBeanImpl() {
super(AServiceMBean.class, true);
}

public AServiceMBeanImpl(Class mbeanInterface)
throws NotCompliantMBeanException {
super(mbeanInterface);
}

public AServiceMBeanImpl(Class mbeanInterface, boolean isMXBean) {
super(mbeanInterface, isMXBean);
}

public AServiceMBeanImpl(T implementation, Class mbeanInterface,
boolean isMXBean) {
super(implementation, mbeanInterface, isMXBean);
}

public AServiceMBeanImpl(T implementation, Class mbeanInterface)
throws NotCompliantMBeanException {
super(implementation, mbeanInterface);
}

@Override
public int getFailedServiceCalls() {
return totalFailedCalls;
}

@Override
public long getMaxResponseTime() {
return maxResponseTime;
}

@Override
public long getMinResponseTime() {
return minResponseTime;
}

@Override
public String getName() {
return "AService-Component";
}


@Override
public String setName(String name) {
//name = name;
}
@Override
public int getSuccessServiceCalls() {
return totalCalls - totalFailedCalls;
}

@Override
public int getTotalServcieCalls() {
return totalCalls;
}

@Override
public long getAverageResponseTime() {
// return totalResponseTime/(totalCalls-totalFailedCalls);
return avgResponseTime;
}

/**
* methods exposed to business component, via which they can feed the data to MBean.
*
**/
public static void addAServiceCall(boolean result, long responseTime) {
totalCalls ++;

if(result) {

if(responseTime < minResponseTime) minResponseTime = responseTime; if(responseTime > maxResponseTime) maxResponseTime = responseTime;

totalResponseTime = ++ responseTime;

} else {
totalFailedCalls++;
}
}


public static void setMaxTime(long maxResultTimeMilli) {
maxResponseTime = maxResultTimeMilli;

}

public static void setAvgTime(long averageResultTimeMilli) {
avgResponseTime = averageResultTimeMilli;

}

public static void setTotalCount(int thread_count) {
totalCalls = thread_count;

}

public static void setMinTime(long minResultTimeMilli) {
minResponseTime = minResultTimeMilli;

}
}

Register the MBean with JVM's MBean Server
Once an MBean is implemented, it needs to be registered with platform MBean, so the MBean is visible to the internal MBean Server. For simplicity you can have the registering the logic as part of the custom MBean implementation. But I would prefer to isolate the registration logic from business computation logic, into another class solely responsible to register and retrieve the custom MBeans.
• Get instance of MBeanServer using ManagementFactory.getPlatformMBeanServer()
• Create an instance of custom MBean with a name
• Register with the MBeanServer
try {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

AServiceMBeanImpl mbean = new AServiceMBeanImpl();
ObjectName name = new ObjectName(
"com.sample.mbean:type=AServiceMBean");
mbs.registerMBean(mbean, name);

} catch (MalformedObjectNameException e) {
e.printStackTrace();
System.exit(0);
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
System.exit(0);
} catch (MBeanRegistrationException e) {
e.printStackTrace();
System.exit(0);
} catch (NotCompliantMBeanException e) {
e.printStackTrace();
}
Expose methods for business component
It is a method exposed to business component. A business component invokes this method and feeds the component's raw data in. It the custom bean applies the logic on and prepares the metrics ready
public static void addAServiceCall(boolean result, long responseTime) {
totalCalls ++;

if(result) {

if(responseTime < minResponseTime) minResponseTime = responseTime; if(responseTime > maxResponseTime) maxResponseTime = responseTime;

totalResponseTime = ++ responseTime;

} else {
totalFailedCalls++;
}
}

Executing the MBean
Once all the above steps are complete, make sure invoke the register method during application star up. It can be invoked however you want but need to make sure the MBean registered once before trying to access from the JMX monitoring tool.
As and when the business component wants feed the data, invoke the exposed method as below.* It can use any of the exposed to methods.
//Feed the MBean...
AServiceMBeanImpl. addAServiceCall(true, timeinmilli);
AServiceMBeanImpl.setMaxTime(maxResultTimeMilli);
AServiceMBeanImpl.setMinTime(minResultTimeMilli);
AServiceMBeanImpl.setAvgTime(averageResultTimeMilli);
AServiceMBeanImpl.setTotalCount(THREAD_COUNT);

Monitoring the MBean
Using the regular approach connect any JMX based monitoring tool (eg. Visual VM), navigate to MBean section, the custom AServiceMBean Service will be shown with the available data.

Friday, November 19, 2010

Enabling remote JMX monitoring for a Java application

In this, I would like to go through the required configuration to enable an application form remote JMX monitoring. So that it can be monitored using profiling tools like jconsole, Visual VM etc..

To enable a JVM for remote JMX monitoring, we need to provide following JAVA_OPTIONS to while starting the JVM.

Simple Configuration - No authentication
-Dcom.sun.management.jmxremote.port=6969
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

The above parameters enable the JVM to accept the JMX connectivity at port 6969. You can use an unused port number for this.

If an application is using Java Wrapper Service to start the JVM, the JAVA OPTIONS should be added to wrapper.conf file as below,

wrapper.java.additional.XX=-Dcom.sun.management.jmxremote.port=6969
wrapper.java.additional.XX=-Dcom.sun.management.jmxremote.ssl=false
wrapper.java.additional.XX=-Dcom.sun.management.jmxremote.authenticate=false

where XX indicates the sequence of java options in wrapper.conf. They might vary, need to be adjusted.

Configuration with Authentication
Remote JMX connectivity can be configured to enforce the security credentials. Here the credential information is accessed from access and password files for authentication and authorization.

-Dcom.sun.management.jmxremote.authenticate=*true*
-Dcom.sun.management.jmxremote.access.file=jmxremote.access
-Dcom.sun.management.jmxremote.password.file=jmxremote.password 

The default location for these files is JRE_HOME/lib/management. You can keep the files based on your application configuration. I would prefer to under /conf directory.

*jmxremote.access contains*
########## jmxremote.access ######################
normalUser readonly
superUser readwrite

*jmxremote.password contains*
########## jmxremote.password ######################
# The "normalUser " role has password "passwOrd".
normalUser passwOrd
superUser passwOrd

Here the very important note is the jmxremote.password file should be owned and accessible by Owner only. Otherwise you would receive an error message File must be restricted to read access (wording may change).





Security authentication can be implemented using JAAS Callback mechanism, where we need to provide implementation for javax.security.auth.callback.NameCallback, javax.security.auth.callback.PasswordCallback

-Dcom.sun.management.jmxremote.login.config=login.config

Using this option, you can even authentication against a third party tool like LDAP etc..

Configuration with SSL encryption
Provide the following JAVA OPTIONS
-Dcom.sun.management.jmxremote.ssl=true
-Djavax.net.ssl.keyStore=     <>
-Djavax.net.ssl.trustStore=    <>
-Djavax.net.ssl.keyStoreType=     <>
-Djavax.net.ssl.keyStorePassword=     <>
-Djavax.net.ssl.trustStoreType=     <>
-Djavax.net.ssl.trustStorePassword=     <>

It covers the quick and basic configuration required to enable a Java application for remote JMX monitoring. I hope it helps you as well..

Thursday, October 07, 2010

A quick note on VMforce

Spring Source has created new offering called VMforce. It is a joint offering from Spring Source and salesforce.com. It is a combination Spring's cloud computing technology expertise and salesforce.com's well known business applications deployed as clouds.

A development team can develop an application in STS (Spring Tool Suite based on Eclipse) and deploy in VMware's vFabric Could Application Platform. Then application will be up and running in clod :-) so don't need to worry about hardware, server etc..

Your application can be integrated with built in Tools of force.com like dashboards, analytics, reporting, search and visual process management.

Overall seems to be very interesting and moves the application into production with faster pace. However it need to understand more about VMforce the framework..

Saturday, August 28, 2010

A successful project

What is your formula for a successful project and/or architecture/design and/or implementation?

I have worked on multiple successful projects and some of the challenging projects as well.  Most of the times, Functional or Requirement churn hinders the project success because the changes cannot be adaptable easily.  Sometimes it questions the basic architecture / design of the application.

However technical team doesn't have control over the requirement management but I strongly feel below precautions navigates towards the success path. It is not limited to below points but I feel they are worth mentioning.  There is no single phase of the SDLC, influences the success of a project, it all TOGETHER.


  • A Solid Architecture
  • Creates a clear separation among major components.
  • Proper distribution of responsibilities.
  • Loose coupling - Integration using an interface.
  • Considering Extensibility, Availability, Reliability and Performance.

  • A Flexible Design
  • Allows extending the functionality without breaking the existing ones.
  • Use dependency injection (IoC) wherever possible.
  • One single interface definition for a component.
  • Evaluate the suitable design patterns.
  • Evaluate integration options ‘MQ’ based versus ‘API’ calls.
  • Configurability – think other side of the requirement.

  • A Proper implementation
  • Always program to interface.
  • Use available features of programming language such Generics, Annotations.
  • Don’t try to re-implement, try to use proven open source framework wherever possible such as Struts, Apache commons, Hibernate, Spring etc..
  • Avoid compile time dependency, go for run time dependency (Example:  spring remoting).
  • Minimize the objects in session.
  • Conduct Code Reviews.

Saturday, April 17, 2010

Reading browser locale from Java

As part of developing complicated applications, we write much complex logic to address some of the business requirements.  But you know when we need a simple thing, to read the browser locale, unless you already worked on the specific problem ...
hmmmmm......
wonder what you do first thing, google it... rather going through Java API....  okay..
enough explanation here is what we need to do to read it..
most of the time it goes in an intercepting servlet or a web filter...

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


public class ReadBrowserLocaleServlet extends HttpServlet {
                         
    public void doGet (HttpServletRequest req,HttpServletResponse res)
                         throws ServletException, IOException
    {
       doPost(req,res);
    }

    public void doPost (HttpServletRequest req, HttpServletResponse res)
                         throws ServletException, IOException
    {
                        
     String browserLocale=req.getHeader("Accept-Language");
    System.out.println("Browser Locale" + browserLocale);
      
    }   
  } 

Let me know if you like it.... Thanks..

Saturday, March 20, 2010

Offloading SSL encryption

It is very common to use SSL encryption (https - protocol scheme) to secure web application, to transfer the form data in encrypted format. It is also common to have SSL encryption getting off loaded after CSS (Content Services Switch) in non-financial applications because maintaining 'https' in end-end flow requires a complex configuration around an Application Server / Web Server.

SSL Off loading means CSS drops the 's' from https, passes client's request to web server as plain http request and takes care of dropped encryption while processing the response to client.

So 'SSL offloading' is seem less to client & further web requests shows up with 'https' only....... then what is the problem here ? if everything works fine...   of course the problem arises when an application logic tries to  redirect the request by forming an explicit URL unless it addresses the protocol scheme accordingly...

In general what happens when we form a URL for re direct, we read the request parameters as below..

public void redirectURL( HttpServletRequest request,  HttpServletResponse response) {

String scheme = request.getScheme();
String serverName = request.getServerName();
String portNumber = request.getServerPort();

String url = schme + "://" + serverName + portNumber + request.getServletPath();
response.sendRedirect(response.encodeRedirectURL(url));
}


The problem comes at the line String scheme = request.getScheme();
it returns only 'http' because 's' was offloading before even the request came to web server, now we are redirecting with pain 'http' protocol to a secured application. Hence the security component will reject the request shown un authorized page.

To address this issue we need to be careful while redirecting a servlet reqeust to accomdate with 's' in protocol scheme if it is a secured application. Modify the above line as below, leave the port number as it can vary for 'https' versus 'http'.
String url = "https"+ "://" + serverName +  request.getServletPath();

So final application logic looks like...

public void redirectURL( HttpServletRequest request,  HttpServletResponse response) {

String scheme = "https";
String serverName = request.getServerName();
String portNumber = request.getServerPort();

String url = schme + "://" + serverName + request.getServletPath();
response.sendRedirect(response.encodeRedirectURL(url));
}

Sunday, January 31, 2010

Integrating Hibernate with Spring

Introduction

As most of us well aware of Hibernate and Spring frameworks, I am not getting into much of introduction part. However in short,

Hibernate

  • A popular & successful ORM tool
  • Abstracting the underlining JDBC programming
  • Portable to any supported database with minor configuration changes
  • Provides Transaction Management etc….

Spring

  • Implementation Inversion of Control (IOC) design pattern.
  • Abstraction to Aspect Oriented Programming (AOP).
  • Creates the java object beans from an application context xml (spring configuration file)

I would like to walk you through a running example how they both work together… Please take a look at the below xml..

Header part of spring configuration xml includes spring-bean.dtd


Loading Hibernate properties: Hibernate properties can be loaded using Spring’s PropertyPlaceholderConfigurer class. Provide hibernate.properties file location as value. If the file placed under any other directory other than WEB-INF directory, use classpath: expression to let the Spring to look for the file in available classpath.





classpath:/properties/hibernate.properties


Defining a DataSource: Use JndiObjectFactoryBean class to define the data source by providing JNDI binding name.




jdbc/SampleDS

Defining a Session Factory: Hibernate session factory can be defined usingLocalSessionFactoryBean class, provides an integration point to Hibernate from Spring.

Here we need to provide data source information and hibernate mapping files (.hbm.xml).

Transaction factory class, hibernate supports

org.hibernate.transaction.JDBCTransactionFactory – delegates to database (JDBC) transactions (default)

org.hibernate.transaction.JTATransactionFactory – delegates to container-managed transaction if an existing transaction is underway in this context (e.g. EJB session bean method), otherwise a new transaction is started and bean-managed transaction are used.

org.hibernate.transaction.CMTTransactionFactory – delegates to container-managed JTA transactions

Transaction Lookup class: It depends on application server on which the application is running, here I am using WebSphere Application Server related one.

Special columns if there are any column defined CLOBs, those can handled using default implementation provided spring. Here as an example I am using CLOB handler.







com/sample/TableName1.hbm.xml




${hibernate.dialect}
${hibernate.show_sql}
${hibernate.default_schema}

org.hibernate.transaction.JTATransactionFactory

org.hibernate.transaction.WebSphereTransactionManagerLookup
java:comp/UserTransaction
org.hibernate.cache.EhCacheProvider
true
true
false







Defining a Transaction Manager: By providing the above defined session factory, a transaction manager needs to be defined as below.
























PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED,readOnly


It might be a quick, not much detailed enough as I covered only basic configuration. Your comments / inputs are much appreciated... I will try to add some more details…..