Pooling Web Service Connections in Grails

Using Apache Commons Pool from Groovy and Grails is an easy to use tool to configure an object pool on the JVM, especially for reusing expensive to create JAX-WS Web Service connections..

Jeff Sheets

Apache Commons Pool is a great tool to easily configure an object pool on the JVM. Having a pool of created objects helps when you need to reuse connection objects that are expensive to create (LDAP, Web Service, etc).

While improving the performance of a Grails application, I noticed that 2 to 4 seconds were being consumed simply creating a connection to a specific JAX-WS Java Web Service that we used to retrieve Rules for building data grid columns. The perfect opportunity to install an object pool. Along the way I ran into some issues pooling the JAX-WS Port Proxy stub object, and I’ll show you the simple work around here.

First, install the commons-pool2 jar dependency in BuildConfig.groovy

dependencies {
  compile "org.apache.commons:commons-pool2:2.2"
}

Next create a BasePooledObjectFactory that Apache Commons Pool will use to create an object to be placed in the pool. You’ll need a create() method to build your object, and a wrap() method that wraps your object with a PooledObject implementation for stats and pool maintenance purposes. This code uses a legacy Java RuleServiceClientFactory to build the ruleService JAX-WS Port Proxy stub object, yours should probably inject a factory or service.

import org.apache.commons.pool2.BasePooledObjectFactory
import org.apache.commons.pool2.PooledObject
import org.apache.commons.pool2.impl.DefaultPooledObject
class RuleServiceFactory extends BasePooledObjectFactory<JaxwsPortProxy<RuleServiceWS>> {

  @Override
  public JaxwsPortProxy<RuleServiceWS> create() throws Exception {
    // Used to get JAX-WS Port Proxy WS Stub object
    def ruleService = RuleServiceClientFactory.getRuleService()

    return new JaxwsPortProxy<RuleServiceWS>().wrap(ruleService)
  }

  @Override
  public PooledObject<JaxwsPortProxy<RuleServiceWS>> wrap(JaxwsPortProxy<RuleServiceWS> ruleService) {
    return new DefaultPooledObject<JaxwsPortProxy<RuleServiceWS>>(ruleService);
  }
}

The factory is then wired into a GenericObjectPool in resources.groovy so we can easily inject the ConnectionPool into our Service objects. Here is where you can configure the pool properties.

import org.apache.commons.pool2.impl.GenericObjectPool
import com.sheetsj.pool.RuleServiceFactory
beans = {
  ruleServiceFactory(RuleServiceFactory)

  ruleConnectionPool(GenericObjectPool, ruleServiceFactory) {
    maxTotal = 10
    maxIdle = 10

    //61 seconds to wait for object creation
    maxWaitMillis = 61000

    //10 minutes before an object is evicted for being idle
    minEvictableIdleTimeMillis = 10 * 60 * 1000

    //2 minutes between checks for evictions
    timeBetweenEvictionRunsMillis = 2 * 60 * 1000

    blockWhenExhausted = true
  }
}

See how the ruleConnectionPool is used in this sample GridService. The getGridRules() uses an available pooled WS Connection.

import static com.sheetsj.pool.PoolHelper.withCommonsPool
class GridService {
  /**
  * Improve JAX-WS performance by reusing connections.
  * Pool defined in resources.groovy
  */
  ObjectPool ruleConnectionPool

  /**
  * Gets rules using a free connection from the connection pool
  */
  def getGridRules(String gridName) {
    withCommonsPool(ruleConnectionPool) { ruleWSConn ->
      def request = new RequestWSDTO(gridName: gridName)
      ResponseWSDTO result = ruleWSConn.getGridMetaData(request)

      result.getGridMetaDataWSDTO()
    }
  }
}

The PoolHelper.withCommonsPool is a convenience closure that I use to wrap the handling of the pool. This method handles invalidating and returning objects to the pool, much like how Groovy Sql methods will wrap the closing and transaction handling of a JDBC Connection. It frees up the GridService from knowing the API of Apache Commons Pool.

import org.apache.commons.pool2.ObjectPool
import org.apache.log4j.Logger
class PoolHelper {
  static Logger log = Logger.getLogger(PoolHelper)

  /**
  * Executes a closure using the object from the passed
  * in Commons Pool, invalidating the object if an error is returned,
  * and always returning it to the pool. Similar to how Groovy Sql methods work.
  */
  static def withCommonsPool(ObjectPool pool, Closure closure) {
    def borrowedObject = pool.borrowObject()
    try {
      return closure.call(borrowedObject)
    } catch (Exception e) {
      log.warn "exception caught using pool, invalidating connection", e
      pool.invalidateObject(borrowedObject)
      borrowedObject = null
      throw e
    } finally {
      if (null != borrowedObject) {
        pool.returnObject(borrowedObject)
      }
    }
  }
}

Finally, you may have noticed that the RuleServiceFactory is using a JaxwsPortProxy object to wrap the connection. Apache Pool2 requires each item in the pool to be unique via the equals method, but the JAX-WS port proxy object does not play well with this. So using a simple Groovy Proxy wrapper with UUID’s to id the objects can get around the problem.

import java.util.UUID;
import groovy.util.Proxy
/**
 * Needed so each item in pool is unique via equals method,
 * but Jaxws Port calls use a Proxy that does not behave well for the equals method
 * @see http://stackoverflow.com/questions/22824889/apache-pool-cant-return-object-in-spring-controller-service
 */
class JaxwsPortProxy<T> extends Proxy {
  private final UUID poolId = UUID.randomUUID()

  @Override
  boolean equals(Object o) {
    if (this == o)
      return true
    if (!(o instanceof JaxwsPortProxy))
      return false

    JaxwsPortProxy that = (JaxwsPortProxy) o

    poolId == that.poolId
  }

  @Override
  int hashCode() {
    poolId?.hashCode() ?: 0
  }
}

Hopefully this shows how easy it is to pool web service connections in Groovy. It should also be noted that all of this is pure Groovy besides the simple helpers that the Grails BuildConfig and resources.groovy files provide. So you can use this pattern in any Groovy/Java project even if Grails is not your current framework of choice.

Share this Post

Related Blog Posts

JavaScript

Add Javascript unit tests and run them with grails test-app

August 19th, 2014

With frameworks like Jasmine, Karma, and Grails, we can write Javascript tests and run them with grails test-app.

Igor Shults
JavaScript

Extending Angulars $resource Service for a Consistent API

June 3rd, 2014

Extending Angulars $resource service to make it easy to declare resources and REST APIs. Wrapping the $resource service to normalize the REST calls to make it easier to work with promises and the $q service.

Object Partners
JavaScript

Unit test your server-side JavaScript with Spock

May 29th, 2014

Learn how to use Spock, the powerful Groovy-based specification framework, to unit test your server-side JavaScript with style.

David Norton

About the author

Jeff Sheets

Chief Software Technologist

Jeff has developed Java, Groovy, Grails, and Javascript web apps for industries as varied as Defense, Energy, Weather, Insurance, and Telecom. He is a co-organizer of the Omaha Java Users Group. Jeff has worked on Grails projects since the Grails 1.3.x days, and has experience with production Groovy code as well as Spock tests and Gradle builds. His latest focus has been on AngularJS and Spring Boot applications using JHipster. Jeff also enjoys volunteering at local CoderDojo events to teach programming to our next generation.