Tuesday, June 22, 2010

Enabling JMX Monitoring for Spring-JPA-Hibernate Application

Requirement: Be sure that the application correctly utilizing second level caching by using ehcache. And what is the cache utilization level for the application?
Technologies that is used in the appilcation: JPA/Hibernate, Spring 2.5, JSF+Richfaces.
After some googling I understood that the only way to get caching utilization is to monitor it by JMX.  My collegue Ray McDermott came to the resque and sent me the article:
which I inspired form.
I assume that you have already a similar application. So I will not go through the how you can create such kind of project. If you want to create an application from scratch please read the article above.
To enable caching statistics in your Spring-JPA/Hibernate application first set the hibernate parameters in persistence.xml  like:
<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletonEhCacheProvider"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.jdbc.wrap_result_sets" value="true"/>
<property name="hibernate.cache.use_minimal_puts" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_structured_entries" value="true" />
<property name="hibernate.generate_statistics" value="true" />
Second, we need configure JMX Monitoring aspects:
Simply we need to create two aspects:
  • JMX MBean - which can represent a device, an application, or any resource that needs to be managed.
  • JMX Agent - which is an application that registers MBean(s) with a MBeanServer, e.g. the platform MBeanServer.

In this case we do not need to create JMX Mbean since it will be provided by Hibernate.
We need a JMX Agent:
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.persistence.EntityManagerFactory;

import net.sf.ehcache.CacheManager;
import net.sf.ehcache.management.ManagementService;

import org.hibernate.SessionFactory;
import org.hibernate.ejb.HibernateEntityManagerFactory;
import org.hibernate.jmx.StatisticsService;

public class JmxAgent {

      private EntityManagerFactory entityManagerFactory;
      private MBeanServer mbs;

      public void init() throws Exception {

            SessionFactory sf = ((HibernateEntityManagerFactory) entityManagerFactory)
                        .getSessionFactory();

            ObjectName on = new ObjectName(
                        "Hibernate:type=statistics,application=flrs-web");

            StatisticsService statsMBean = new StatisticsService();
            statsMBean.setSessionFactory(sf);
            statsMBean.setStatisticsEnabled(true);
            mbs.registerMBean(statsMBean, on);

            CacheManager cacheMgr = CacheManager.getInstance();
            ManagementService.registerMBeans(cacheMgr, mbs, true, true, true, true);
      }

      public MBeanServer getMBeanServer() {
            return mbs;
      }

      public void setEntityManagerFactory(
                  EntityManagerFactory entityManagerFactory) {
            this.entityManagerFactory = entityManagerFactory;
      }

      public void setMbs(MBeanServer mbs) {
            this.mbs = mbs;
      }

}
JMXAgent is Spring aware bean and init() is the initializing method for that bean.  JMXAgent has two properties:
MbeanServer ‘mbs’ and EntityManagerFactory  ‘entityManagerFactory’ which are injected by the spring during appilcation context creation.
Here is the Spring configuration of JMXAgent:
<bean id="mbeanServer" class="java.lang.management.ManagementFactory"
      factory-method="getPlatformMBeanServer" />
     
<bean id="jmxAgent" class="com.xxx.flrs.view.utility.JmxAgent" init-method="init">
      <property name="entityManagerFactory" ref="entityManagerFactory"/>
      <property name="mbs" ref="mbeanServer"/>
bean>
That’s all you need to do in the application.
After you complete the application modification, deploy the JMX enabled version in your application server. I tried in Glassfish v2.1.1. But no matter which application server you used. Just be sure that if JMX is enabled for your application server.
And finally here is the funniest part, Monitor hibernate statistics:
To do that first open Jconsole. If %JAVA_HOME% /bin folder is in you path, just open command prompt and type jconsole. You will be asked for a connection:

Find the Advanced tab and type the JMX Url of your application server. Username and Password is the same pair that you login administration console for Glassfish.
I tried other Local and Remote connection ways but i was not sucessfull.
If everything goes right, you should see the window:

Find the Mbeans tab and here is the Hibernate Statistics:





Thank You

Create Custom JNDI URL Resource Provider for Glassfish

Again very simple requirement, again Glassfish and again it cannot be satisfied by default. May be my requirement is not a part of reference implementation :))

Anyway, one of my collegue requested that "put the application properties file outside of the application and look up the property file from JNDI". First I thought that it should be very easy since we define JDBC Datasource zillion times and how can it be different?
Answer is; it is totally different in Glassfish!

Bad New: You need to develop your own ObjectFactory implemantation for URL resources.
Good New: It is so simple to do.

Let me summarize how you can do that:

  1. Create a java project in your favorite IDE. Name can be GlassfishUrlFactory
  2. Create the package that you will put the "javax.naming.spi.ObjectFactory" implementation. Suggestion com.xxx.glassfish.jndi.resource 
  3. Create the ObjectFactory implementation class. Source code looks like:
package com.xxx.glassfish.urlfactory;
import java.net.URL;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;

public class GlassfishUrlFactory implements ObjectFactory {

    
    
    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
            Hashtable environment) throws Exception {

        Reference ref = (Reference) obj;
        String propertyFileUrl=null;
       
        if(ref!=null){
            propertyFileUrl=ref.get("fileUrl").getContent().toString();
        }else{
            throw new Exception("Please Add 'fileUrl' property to JNDI Resource Definition!!");
        }
       
        URL url = new URL(propertyFileUrl);
        return url;
    }
    
    
}

    
Reference is something similar to java.util.Map. It is used to get the parameters that you pass when you define JNDI Resource in your application server. For example imagine that you defined a JDBC datasource and set the username property from the admin console. JDBC Factory class will get it like 

username=ref.get("username").getContent().toString();



       4. Export the project as JAR file. 

       5. Put the JAR file under Glassfish lib folder.
      6. Define a Custom JNDI Resource in Glassfish

       7. Restart the Application Server.

     Here is a sample code how can you look up properties file from Spring:


Tuesday, February 16, 2010

Integrate Glassfish v2.1.1 with Active MQ 5.X

My requirement was very simple and common. What i want to do is; i want to configure a ConnectionFactory JNDI Object in Glassfish to manage Active MQ connections that is used by applications which have messaging features.

Of course i googled couple of hours. And i run into very few articles. I was surprised because there is not enough documentation for such kind of common requirement. I tried all tutorials, i did every each step that is stated in those articles but i could not succeed. It is probably because the versions that want to integrate is different from the versions that is mentioned in those articles.

Anyway lets start with downloading components. (I know it is silly to start this article with giving download links because you probably already have one Glassfish and one Active MQ working. That's why you are looking for integration of these two :)))

Glassfish v2.1.1: https://glassfish.dev.java.net/downloads/v2.1.1-final.html

Active MQ 5.0.3 :http://activemq.apache.org/activemq-530-release.html

The links above also includes installation guidelines. I assume that you have Glassfish AS and Active MQ installed and working in your environment. Let's start with defining JNDI Resource to Glassfish:

Go to Active MQ installation root and copy the Resource Adapter into Glassfish Resource Adapters folder: copy %ActiveMQ_ROOT%/lib/optional/activemq-rar-5.3.0.rar into %GLASSFISH_ROOT%/lib/addons/resourceadapters/genericjmsra/ and rename rar file as activemq.rar

Open command prompt and type:



#>cd GLASSFISH_ROOT/bin #/GLASSFISH_ROOT/bin>asadmin create-resource-adapter-config --property SupportsXA=false:RMPolicy=OnePerPhysicalConnection:ProviderIntegrationMode=javabean:ConnectionFactoryClassName=org.apache.activemq.ActiveMQConnectionFactory:QueueConnectionFactoryClassName=org.apache.activemq.ActiveMQConnectionFactory:TopicConnectionFactoryClassName=org.apache.activemq.ActiveMQConnectionFactory:XAConnectionFactoryClassName=org.apache.activemq.ActiveMQXAConnectionFactory:XAQueueConnectionFactoryClassName=org.apache.activemq.ActiveMQXAConnectionFactory:XATopicConnectionFactoryClassName=org.apache.activemq.ActiveMQXAConnectionFactory:UnifiedDestinationClassName=org.apache.activemq.command.ActiveMQDestination:QueueClassName=org.apache.activemq.command.ActiveMQQueue:TopicClassName=org.apache.activemq.command.ActiveMQTopic:ConnectionFactoryProperties=brokerURL\=tcp\://tkvwasp02\:61616:ServerUrl\=tcp\://hostname\:61616:LogLevel=FINE activemq

This command will help you to create and configure a resource adapter. Please be careful that the above command is one single line. And do not delete any '\' char. And be sure that your application server up and running. Now it is time deploy the Active MQ resource adapter that rar file we copied into Glassfish in step1.

Execute the following command: #/GLASSFISH_ROOT/bin>asadmin deploy ../lib/addons/resourceadapters/genericjmsra/activemq.rar

From now on you can do each action by using Glassfish Admin Console. But i think using CLI commands is much faster.

So lets create JNDI Resouces

1-Create Connection Pool : Be careful all command must be a single line.

#/GLASSFISH_ROOT/bin>asadmin create-connector-connection-pool --raname activemq --connectiondefinition javax.jms.QueueConnectionFactory --transactionsupport LocalTransaction MyConnectionFactoryPool

2- Create Connection Factory: Again be careful all command must be a single line.

#/GLASSFISH_ROOT/bin>asadmin create-connector-resource --poolname MyConnectionFactoryPool jms/MyConnectionFactory

3- Finally create Message Destination: Must be single line!!!

#/GLASSFISH_ROOT/bin>asadmin create-admin-object --raname activemq --restype javax.jms.Queue --property PhysicalName\=SampleQueue jms/MyQueue

So THAT IS IT!! Now, to feel safe, restart the application server. For testing purposes write a simple MessageListener if JNDI Resources that you defined above is working.
Cheers.