Performance monitoring of portlet

One of the common requirement that i hear is how do i monitor performance of my portlets and get some useful information when the portlet is misbehaving. I used the concept of Global Filters to create a filter that will monitor all your portlets (render, resource, action and Event phase) and write a message in the log if one of the method takes more than the threshold time. You can download the performance filter code from here

This is how one of the doFilter() method of PerformanceFilter looks like

public void doFilter(RenderRequest request, RenderResponse response,FilterChain filterChain)
throws IOException, PortletException {
long beforeTime = System.currentTimeMillis();
filterChain.doFilter(request, response);
long afterTime = System.currentTimeMillis();
long executionTime = (afterTime - beforeTime)/100;
System.out.println("Time for execution " + executionTime);
if(executionTime > debugThreshold){
Map portletInfoMap = getCurrentPortletInfo(request.getWindowID(),
(ServletRequest)request, (ServletResponse)response);
portletInfoMap.put("PORTLET_METHOD", "render");
portletInfoMap.put("PORTLET_EXECUTIONTIME", Long.toString(executionTime));
printDebugInformation(request, response,portletInfoMap);
}
}


In the doFilter() method i am taking the time before and after i forwarded control up the chain and using that time to calculate execution time. If the execution time is more than threshold then i am printing debug information. In my simple filter i am only printing request parameter, but you can print all the information that you want ex. portlet prefrences, portlet session information...

Since this is a Global Filter i have a plugin.xml file which looks like this

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin id="com.webspherenotes.filter.performancemonitorfilter" name="WS_Server"
provider-name="IBM" version="2.0.0">
<extension point="com.ibm.ws.portletcontainer.portlet-filter-config">
<portlet-filter-config
class-name="com.webspherenotes.portlet.PerformanceMonitorFilter" order="99">
<description> Performance Filter, order = 102 </description>
<lifecycle>RENDER_PHASE</lifecycle>
<lifecycle>RESOURCE_PHASE</lifecycle>
<lifecycle>ACTION_PHASE</lifecycle>
<lifecycle>EVENT_PHASE</lifecycle>
<init-param>
<name>DEBUG_THRESHOLD</name>
<value>1</value>
</init-param>

</portlet-filter-config>
</extension>
</plugin>


I am reading value of DEBUG_THRESHOLD input parameter from plugin.xml and using it to decide when should i generate debug log. In my case if the portlet takes more than 1 second to respond then i am generating log. This is how a sample log looks like



****Problematic portlet found ****
Page -> wps.LoginPorltet Name -> wps.p.Login Method -> render Took 7

Accessing JPA from JAX-RS service directly

I wanted to create a REST service that uses JPA bean and i wanted to see if i can do that without using a EJB and these are my notes about how to do that. You can download the sample application from here. I am using JEE 6 compliant Websphere application Server for testing this code. First i did create the Contact.java which is my JPA entity like this

package com.webspherenotes.jpa;

import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlRootElement;


/**
 * The persistent class for the CONTACT database table.
 * 
 */
@Entity
@XmlRootElement
public class Contact implements Serializable {
  private static final long serialVersionUID = 1L;

  @Id
  private int contactid;

  private String email;

  private String firstname;

  private String lastname;

    public Contact() {
    }

  public int getContactid() {
    return this.contactid;
  }

  public void setContactid(int contactid) {
    this.contactid = contactid;
  }

  public String getEmail() {
    return this.email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public String getFirstname() {
    return this.firstname;
  }

  public void setFirstname(String firstname) {
    this.firstname = firstname;
  }

  public String getLastname() {
    return this.lastname;
  }

  public void setLastname(String lastname) {
    this.lastname = lastname;
  }

}
Next i had to create a persistence.xml file like this in the META-INF folder like this

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="MyJPAJAXRS">
    <jta-data-source>jdbc/demodb</jta-data-source>
    <class>com.webspherenotes.jpa.Contact</class>
  </persistence-unit>
</persistence>
As you can see from my persistence.xml my application has only one entity which is Contact.java. Next declare the persistence-context-ref in the web.xml file like this

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <display-name>MyJPAJAXRS</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <persistence-context-ref>
    <persistence-context-ref-name>
      MyJPAJAXRS
    </persistence-context-ref-name>
    <persistence-unit-name>MyJPAJAXRS</persistence-unit-name>
    <persistence-context-type>Transaction</persistence-context-type>
  </persistence-context-ref>
</web-app>
This is how my REST service looks like, note that you cannot inject EntityManager directly in your REST service class because your creating object of the REST service class in Application object instead of container creating it, so you would have to do some more work to look up the EntityManager in the init method of the REST service class like this

package com.webspherenotes.jpa;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/contact")
public class ContactService {
  
  @PersistenceContext(name="MyJPAJAXRS")
  EntityManager entityManager;
  
  @PostConstruct
  public void init(){
    System.out.println("Entering ContactService.init()");
    try {
      InitialContext context = new InitialContext();
      entityManager = (EntityManager)context.lookup("java:comp/env/MyJPAJAXRS");
      System.out.println("Object of mySessionBeanLocal " + entityManager);
    } catch (NamingException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    System.out.println("Exiting ContactService.init()");
  }

  @GET
  @Produces(MediaType.APPLICATION_XML)
  public List getContactList(){
    System.out.println("Inside ContactService.getContactList() " );
    Query q = entityManager.createQuery("SELECT x from Contact x");
  
    return (List)q.getResultList();
  }

  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  @Produces(MediaType.APPLICATION_XML)
  public Contact insertContact(@FormParam("contactId")int contactId,@FormParam("firstName")
  String firstName,
      @FormParam("lastName")String lastName,@FormParam("email") String email) {
    Contact contact = new Contact();
    contact.setContactid(contactId);
    contact.setFirstname(firstName);
    contact.setLastname(lastName);
    contact.setEmail(email);
    entityManager.persist(contact);
    return contact;
  }
  
  @GET
  @Path("/{contactId}")
  @Produces(MediaType.APPLICATION_XML)
  public Contact getContact(@PathParam("contactId")int contactId) {
    Contact contact = entityManager.find(Contact.class, contactId);
    return contact;
  }

  @PUT
  @Path("/{contactId}")
  @Produces(MediaType.APPLICATION_XML)
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  public Contact updateContact(@PathParam("contactId")int contactId,@FormParam("firstName") 
  String firstName,
      @FormParam("lastName")String lastName,@FormParam("email") String email) {
    Contact contact = new Contact();
    contact.setContactid(contactId);
    contact.setFirstname(firstName);
    contact.setLastname(lastName);
    contact.setEmail(email);
    entityManager.merge(contact);
    return contact;
  }
  @DELETE
  @Path("/{contactId}")
  public void deleteContact(@PathParam("contactId")int contactId) {
    Contact contact = new Contact();
    contact.setContactid(contactId);
    entityManager.remove(contact);
  }
  
  
}

Using JAMON for monitoring REST service

JAMON is very nice and powerful performance monitoring tool. You can use it to monitor performance of java program. I wanted to monitor performance of a REST service so i built this generic purpose filter that any one can use. Once installed it generates performance stats like this. You can download the sample code from here
I followed these steps to create the filter
  1. First download the JAMON binaries from AMON home page
  2. Expand the binaries and copy the jamon.jar file in the shared library of your application server
  3. Next install jamon.war which is web application that ships with jamon binary and provides a UI to look at the stats. The screen shot that you see is taken using jamon.war
  4. I already have a REST service that exposes a CONTACT table as a resource, it provides GET, POST, PUT and DELETE operations on the Contact resource
  5. For the JAMON monitoring part i did create this simple filter
    
    package com.webspherenotes.performance.filter;
    
    import java.io.IOException;
    import javax.servlet.DispatcherType;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    
    import com.jamonapi.Monitor;
    import com.jamonapi.MonitorFactory;
    
    /**
     * Servlet Filter implementation class RESTServiceJAMONFilter
     */
    @WebFilter(dispatcherTypes = {DispatcherType.REQUEST }
              , urlPatterns = { "/*" })
    public class RESTServiceJAMONFilter implements Filter {
    
        public RESTServiceJAMONFilter() {
            // TODO Auto-generated constructor stub
        }
    
      public void destroy() {
        // TODO Auto-generated method stub
      }
    
      /**
       * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
       */
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws IOException, ServletException {
    
        HttpServletRequest httpServletRequest= (HttpServletRequest)request;
        Monitor monitor = MonitorFactory.start(RESTCacheKeyBuilder.buildCacheKey(httpServletRequest));
        chain.doFilter(request, response);
        monitor.stop();
      }
    
      public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
      }
    
    }
    
    Inside the filter i start a monitor before passing control up the filter chain and i stop the JAMON monitor once the request is completed, that's all that you have to do to create and record JAMON monitor. You might notice that while starting filter i am calling RESTCacheKeyBuilder.buildCacheKey(httpServletRequest) , this class takes care of creating the monitor key Ex.GET - /JAMONRESTService/rest/contact/xxx is the key that gets created when you call the service by invoking http://localhost:9080/JAMONRESTService/rest/contact/21 url
  6. This is how my key builder looks like
    
    package com.webspherenotes.performance.filter;
    
    import javax.servlet.http.HttpServletRequest;
    
    public class RESTCacheKeyBuilder {
      
      public static String buildCacheKey(HttpServletRequest request){
        StringBuilder cacheKeyBuilder = new StringBuilder();
        cacheKeyBuilder.append(request.getMethod());
        cacheKeyBuilder.append(" - ");
        cacheKeyBuilder.append(request.getContextPath());
        cacheKeyBuilder.append(request.getServletPath());
        cacheKeyBuilder.append(request.getPathInfo());
        String cacheKey = cacheKeyBuilder.toString();
        System.out.println("Cache Key " + cacheKey);
        cacheKey = cacheKey.replaceAll("[0-9]+", "xxx");
        System.out.println("After replacing digits " + cacheKey);
        return cacheKey;
      }
    }
    
    Its very simple, all it does is adds the HTTP method name for the call and the URL for the call, i am replacing all the numbers with xxx. So that the calls for same resource generates same key. Ex. /JAMONRESTService/rest/contact/xxx key would get generated for http://localhost:9080/JAMONRESTService/rest/contact/22 http://localhost:9080/JAMONRESTService/rest/contact/2 http://localhost:9080/JAMONRESTService/rest/contact/210 and as a result i can see how is my GET call on CONTACT resource doing

Using DynaCache as Cache Implementation in Hibernate

Hibernate makes it very easy for us to use caching framework of our own choice. Now if you know the application that your developing is going to be deployed in WebSphere Application Server, then you might want to use the DynaCache caching framework which ships with IBM WebSphere Application Server. I wanted to try that so i did create this sample application that talks to database using Hibernate and makes use of DynaCache for caching. You can download the sample application from here In order to ask Hibernate to use DynaCache as caching implementation first thing that you will have to do is create a class that implements org.hibernate.cache.CacheProvider interface, this interface gets invoked whenever Hibernate wants to initialize cache for particular region.

package com.webspherenotes.hibernate.cache;

import java.util.Date;
import java.util.Properties;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.CacheProvider;

import com.ibm.websphere.cache.DistributedMap;

public class DynaCacheProvider implements CacheProvider {

  public DynaCacheProvider() throws NamingException {
    System.out.println("Entering DynaCacheProvider() constructor");

  }

  public Cache buildCache(String regionName, Properties properties)
      throws CacheException {
    System.out.println("Inside DynaCacheProvider.buildCache " + regionName);
    
    String cacheInstanceJNDIName =(String) properties.get(regionName);
    
    if(cacheInstanceJNDIName == null){
      cacheInstanceJNDIName = (String) properties.get("dynacache.default.cacheinstancename");
      if(cacheInstanceJNDIName == null){
        cacheInstanceJNDIName = "services/cache/distributedmap";
      }  
    }
    System.out.println("Cache instance JNDI name " + cacheInstanceJNDIName);
    DistributedMap distributedMap;
    DynaCache cache = null;
    try {
      InitialContext ic = new InitialContext();
      distributedMap = (DistributedMap) ic.lookup(cacheInstanceJNDIName);
      System.out.println("DistributedMap found in JNDI " + distributedMap);
      cache = new DynaCache(distributedMap, regionName);
    } catch (NamingException e) {
      e.printStackTrace(System.out);
    }


    return cache;
  }

  public boolean isMinimalPutsEnabledByDefault() {
    return false;
  }

  public long nextTimestamp() {
    return new Date().getTime();
  }

  public void start(Properties properties) throws CacheException {
  }

  public void stop() {
  }

}
,. The buildCache method is responsible for returning object of class implementing org.hibernate.cache.Cache interface that should be used for caching objects for this region. In my case i want to have granular control on which DynaCache instance should be used to store the cached object. The rule goes like this
  1. First check if there is region specific instance, if yes use that
  2. If there is no region specific instance check the value of dynacache.default.cacheinstancename to see if that's set if yes use it.
  3. The last option is to use services/cache/distributedmap which is name of the default cache instance in WAS
Next i had to create DynaCache class that implements org.hibernate.cache.Cache, the object of this class gets control for getting, setting, removing entries from cache. I am actually calling methods on DistributedMap

package com.webspherenotes.hibernate.cache;

import java.util.Map;

import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;

import com.ibm.websphere.cache.DistributedMap;

public class DynaCache implements Cache {

  private DistributedMap map;
  private String regionName;

  public DynaCache(DistributedMap map, String regionName) {
    System.out.println("Creating object of HibernateCache() " + regionName);
    this.map = map;
    this.regionName = regionName;
  }

  public void clear() throws CacheException {
    map.clear();
  }

  public Object get(Object key) throws CacheException {
    System.out.println("Inside HibernateCache.get " + key);
    return map.get(getMapKey(key));
  }

  public String getRegionName() {
    System.out.println("Inside HibernateCache.getRegionName " + regionName);

    return regionName;
  }

  public void put(Object key, Object value) throws CacheException {
    System.out.println("Inside HibernateCache.put " + key + " " + value);
    System.out.println(value.getClass().getName());
    map.put(getMapKey(key), value);
  }

  public Object read(Object key) throws CacheException {
    System.out.println("Inside HibernateCache.read " + key);

    return map.get(getMapKey(key));
  }

  public void remove(Object key) throws CacheException {
    map.remove(getMapKey(key));
  }

  public void update(Object key, Object value) throws CacheException {
    map.put(getMapKey(key), value);
  }

  private String getMapKey(Object key) {
    return regionName + "." + key;
  }

  @Override
  public void destroy() throws CacheException {

  }

  @Override
  public long getElementCountInMemory() {
    return this.map.size();
  }

  @Override
  public long getElementCountOnDisk() {
    return 0;
  }

  @Override
  public long getSizeInMemory() {
    return 0;
  }

  @Override
  public int getTimeout() {
    return 0;
  }

  @Override
  public void lock(Object arg0) throws CacheException {

  }

  @Override
  public long nextTimestamp() {
    return 0;
  }

  @Override
  public Map toMap() {
    return this.map;
  }

  @Override
  public void unlock(Object arg0) throws CacheException {

  }

}
Last thing is to define the com.webspherenotes.hibernate.cache.DynaCacheProvider as cacheProvider in hibernate.cfg.xml this tells the Hibernate framework to use the DynaCacheProvider that we just created.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
        <property name="connection.url">jdbc:derby://localhost:1527/C:/data1/contact</property>
        <property name="connection.username">dbadmin</property>
        <property name="connection.password">dbadmin</property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.DerbyDialect</property>

      
       <property name="cache.provider_class">com.webspherenotes.hibernate.cache.DynaCacheProvider</property>
       <property name="dynacache.default.cacheinstancename">services/cache/distributedmap</property>
       <property name="com.javaworld.memcache.Contact">services/cache/contact</property>
       
       <property name="hibernate.cache.use_second_level_cache">true</property>
       
         <property name="cache.use_query_cache">true</property>
       <property name="">localhost:11211</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup 
        <property name="hbm2ddl.auto">create</property>-->

        <mapping resource="com/javaworld/memcache/Contact.hbm.xml"/>
    <mapping resource="com/javaworld/memcache/Address.hbm.xml"/>
    </session-factory>

</hibernate-configuration>
In this file i am telling hibernate to use service/cache/contact cache instance for caching Contact object but the Address objects would get stored in the default cache. So after deploying the code i did hit the cache few times and this what i see in the cachemonitor