Dive into connection pooling with J2EE

Manage access to shared, server-side resources for high performance

The Java 2 Enterprise Edition (J2EE) specification provides a distributed services-based architecture for implementing highly scalable, reliable, and available e-business applications. In general, a J2EE application architecture maps to the Model-View-Controller (MVC) framework -- repositories/external system resources support the domain model (Model), JSPs/Servlets manage the presentation (View), and EJBs deal with the business logic (Controller).

A typical e-business application use case would be realized by components in all the three layers on the server side. Given the large number of user interactions (millions for customer-facing applications), the finite server-side resources need to be optimally shared. Such resources may include databases, message queues, directories, enterprise systems (SAP, CICS), and so forth, each of which is accessed by an application using a connection object that represents the resource entry point. Managing access to those shared resources is essential for meeting the high-performance requirements for J2EE applications.

Connection pooling is a technique that was pioneered by database vendors to allow multiple clients to share a cached set of connection objects that provide access to a database resource. In this article, I examine connection pooling in a J2EE environment for server-side resources such as databases, message queues, directories, and enterprise systems.

Why pool resource connections?

Consider the following code example where an EJB accesses a database resource using JDBC 1.0, without connection pooling:

...
import java.sql.*;
import javax.sql.*;
...
public class AccountBean implements EntityBean {
...
public Collection ejbFindByLastName(String lName) {
      try {
            String dbdriver =  new InitialContext().lookup("java:comp/env/DBDRIVER").toString();
            Class.forName(dbdriver).newInstance();
            Connection conn = null;
            conn = DriverManager.getConnection("java:comp/env/DBURL", "userID", "password");
            ...
            conn.close();
      }
...
}

Evidently, the main problem in this example is the opening and closing of connections. Given that entity beans are shared components, for every client request, the database connections are acquired and released several times.

You can see from Figure 1 that acquiring and releasing database connections via the database manager, using JDBC 1.0, will impact the performance on the EJB layer. That impact is due to the overhead in creating and destroying those objects by the database resource manager process. Typically, the application server process takes around one to three seconds to establish a database connection (that includes communicating with the server, authenticating, and so forth), and that needs to be done for every client (EJB) request.

Figure 1. Connection management using JDBC 1.0

Connection pooling using service provider facilities

Now I will look at what connection pooling facilities are currently available for database and nondatabase resource types in the J2EE environment.

JDBC 2.0 Standard Extension API

The JDBC 2.0 Standard Extension API specifies that a database service provider can implement a pooling technique that can allow multiple connection objects from a resource pool to be shared transparently among the requesting clients. In that situation, a J2EE component can use connection objects without causing overheads on the database resource manager, since a pool manager creates the connection objects upfront, at startup. The application service provider implements the pool manager in its memory space and can optimize resource usage by dynamically altering the pool size, based on demand. That is illustrated in Figure 2.

Figure 2. Connection pooling using JDBC 2.0 Standard extension

Using the DataSource interface (JDBC 2.0) or the DriverManager (JDBC 1.0) interface, a J2EE component could get physical database connection objects. To obtain logical (pooled) connections, the J2EE component must use these JDBC 2.0 pooling manager interfaces:

  • A javax.sql.ConnectionPoolDataSource interface that serves as a resource manager connection factory for pooled java.sql.Connection objects. Each database server vendor provides the implementation for that interface (for example, Oracle implements the oracle.jdbc.pool.OracleConnectionPoolDataSource class).
  • A javax.sql.PooledConnection interface that encapsulates the physical connection to a database. Again, the database vendor provides the implementation.

An XA (X/Open specification) equivalent exists for each of those interfaces as well as for XA connections.

The following code example shows how an EJB application might access a database resource by using pooled connection objects (based on JDBC 2.0). The EJB component in this example uses a JNDI lookup to locate the database connection pool resource. The JNDI 1.2 Standard Extension API lets Java applications access objects in disparate directories and naming systems in a common way. Using the JNDI API, an application can look up a directory to locate any type of resource such as database servers, LDAP servers, print servers, message servers, file servers, and so forth. For a good overview of JNDI, refer to "The Java Naming and Directory Interface (JNDI): A More Open and Flexible Model."

Note: The actual code will vary depending on the database vendor implementation classes.

import java.sql.*; 
import javax.sql.*; 
// import here vendor specific JDBC drivers
 
public ProductPK ejbCreate() {
      try {
// initialize JNDI lookup parameters
            Context ctx = new InitialContext(parms);
...
            ConnectionPoolDataSource cpds = (ConnectionPoolDataSource)ctx.lookup(cpsource); 
... 
// Following parms could all come from a JNDI look-up 
            cpds.setDatabaseName("PTDB"); 
            cpds.setUserIF("XYZ"); 
...
            PooledConnection pc = cpds.getPooledConnection(); 
            Connection conn = pc.getConnection(); 
...
// do business logic
            conn.close();
      }
...
}

The key difference between the above code (using JDBC 2.0) and using JDBC 1.0 is that a getConnection() gets an already open connection from the pool, and close() simply releases the connection object back to the pool. JDBC 2.0 drivers are available today from almost every database server vendor such as Oracle, DB2, Sybase, and Informix. And most application server vendors (IBM, BEA, iPlanet, IONA, etc.) today support JDBC 2.0.

I should note that today almost all application servers employ a two-tier connection pooling architecture where the pools are held in the application server memory space (as opposed to a stand-alone connection broker).

JMS 1.02 Standard Extension API

J2EE application components can communicate asynchronously with other enterprise applications using a messaging resource. The JMS 1.02 Standard Extension API provides a vendor-independent way to communicate with messaging service providers. As in the case of a database resource, message queues are accessed using connection objects that can be pooled.

The JMS 1.02 API includes the following interfaces to support resource pooling:

  • A javax.jms.QueueConnectionFactory or javax.jms.TopicConnectionFactory for factory objects
  • A javax.jms.QueueConnection or javax.jms.TopicConnection for connection objects

A JMS service provider implements those interfaces. The following code shows how an EJB component might access a message queue resource, using connection objects.

// Use JNDI to find the connection factory and the destination Context ctx = new InitialContext(); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("java:comp/env/jms/theFactory"); Queue queue = (Queue) ctx.lookup("java:comp/env/jms/theQueue");

// create a connection, session, sender, and the message QueueConnection conn; QueueConnection conn = factory.createQueueConnection("myUserName", "myPassword"); QueueSession session = connection.createQueueSession (false, Session.AUTO_ACKNOWLEDGE); QueueSender sender = session.createSender(queue); ... // start up the connection, send the message connection.start(); sender.send("Message"); connection.stop();

// now close all resources to ensure that native resources are released sender.close(); session.close(); connection.close();

With connection pooling, the JMS factory classes typically have proxies (configured by an administrator) so the open() and close() requests actually go to the proxies that manage a connection pool. Following the JMS API guidelines, a JMS service provider may implement a database to manage the message queues. In that situation, the appropriate JDBC driver renders the connection pooling. If the application is already using a JDBC 2.0 connection pool-enabled database, then all you need to do is configure the JNDI property for the JMS to use that JDBC instance.

JNDI API for LDAP

The javax.naming.LDAP package includes classes that are specific to LDAP (and not included in the generic javax.naming.directory). Unlike the JDBC 2.0 and JMS 1.02 APIs, the JNDI LDAP API does not specify any interfaces for connection pooling. A directory service provider could optionally provide support via SDKs. For example, iPlanet's Netscape Directory Server SDK 4.0 for Java includes the following class for building LDAP clients:

public class netscape.ldap.util.ConnectionPool extends java.lang.Object
methods: Connection(), getConnection(), close(), etc. 

Refer to the "Netscape Directory Server Application Programmer's Guide" for more details.

The J2EE Connector Architecture 1.0

In all of the above examples, the EJB components have to import vendor-specific implementation classes in order to use the connection pooling facilities of the resource. That obviously makes the EJBs less portable, weakening the J2EE promise.

Ideally, one would like a generic connection interface that EJBs can use for any resource type and all connection management functions, including pooling, provided under the hood. That is one of the goals of the upcoming J2EE Connector Architecture 1.0 specification; a draft copy is publicly available at the time of this writing (see Resources).

Figure 3 shows the central concept behind the architecture, the resource adapter. A pluggable component for each resource type supported by the application server, a resource adapter executes within the application server address space. The client API for accessing those adapters could either be the Common Client Interface (CCI) or (for backward compatibility) a resource-specific API such as JDBC 2.0. For instance, the CCI defines javax.resource.cci.ConnectionFactory and javax.resource.cci.Connection as interfaces for a connection factory and a connection respectively -- similar to the JDBC 2.0 interfaces I mentioned in the previous section.

Figure 3. Resource adapter in J2EE Connector Architecture 1.0

Connection pooling in Connector 1.0

The programming model for Connector 1.0 is as follows:

  • An EJB performs a JNDI lookup of a connection factory and then issues a getConnection() request.
  • The connection factory delegates the request to a ConnectionManager.
  • The connection manager looks for an instance of a connection pool in the application server. If no connection pool is available, then the manager uses the ManagedConnectionFactory to create a physical (nonpooled) connection.
  • In that scenario, the resource adapter provider is assumed to implement the interface. However, the connector architecture does not indicate how an application server might implement a connection pool but provides guidelines, such as partitioning a pool based on adapter type, quality-of-service (QoS) requirements, and so forth. For more details, refer to the J2EE Connector Architecture specification.

For example, the iPlanet Unified Integration Framework Toolkit v 6.0, a product version of Sun's connectors to enterprise/legacy systems based on the upcoming EJB 2.0 connector architecture, defines connection pools for each backend system that an EJB layer might access. A thread, executed periodically, monitors the use and longevity of pool objects. For details, refer to iPlanet Unified Integration Framework.

Design considerations for the EJB layer

The fact that you have resource managers that manage your connection pools does not guarantee optimum performance from the EJB layer -- there are some design considerations as well!

First, consider the code example below of an EJB client accessing a LDAP directory that implements a connection pool.

import netscape.ldap.util.*; ... public class NewCustomerBean implements SessionBean { ... private SessionContext context; // Bean Context private LDAPConnection lc; // LDAP Connection object ... public void setSessionContext(SessionContext sc) { this.context = sc;

// initialize JNDI lookup parameters Context ctx = new InitialContext(parms); ... ConnectionPool cp = (ConnectionPool)ctx.lookup(cpsource); // Establish LDAP Connection. try { this.lc = cp.getConnection(); ... }

What is wrong with the above picture? First, the stateful session object (NewCustomerBean) opens up the connection object in the setEntityContext and holds on to it until the end of the use case -- a rather costly implementation if the number of users (sessions) increases rapidly. Second, and more important, since connection objects are not serializable, per the EJB 1.2 specification, the container can discard the bean instance upon passivation (i.e., move the session bean from its active state to a bean instance pool).

One alternative is that resource connections are acquired and released in the ejbActivate() and ejbPassivate() methods of the session bean, respectively. Without connection pooling, that is of course expensive and not recommended. With pooling however, connections can be acquired and released with minimum overhead for the EJB layer, using that technique. The point here is that beyond the facilities offered by the specifications and the implementations, design choices are, as always, key performance determinants.

A second consideration is around the issue of authentication. You might have observed that pooled connections imply shared connections, which then imply that the connections are not tied to a specific authentication credential. For example, in the case of JDBC 2.0 connections, an application server pool manager requests, at startup, a preset number of connections from the DB manager, using a single authentication credential (typically a userid/password) stored in a configuration file. Sometimes that may not satisfy the security policy for the application. The same argument applies for LDAP connections that require binding with a specific credential to a LDAP subtree. In those situations, one alternative might be to use a cached connection that has been established using a specific credential, which can be reused for the same type of credentials. The downside to that is that cached connections are held for long periods of time. Another alternative might be to use generic connections for resources and implement certain application-level security.

Conclusion

In this article, I showed the need for connection pooling resources in a J2EE environment, based on the shared nature of the resources as well as the EJB components that access them. You saw the facilities defined by the JDBC 2.0, JMS 1.02, and the JNDI 1.2 Standard Extension APIs as well as vendor support for the implementation of those API interfaces. Although the vendor-specific solutions are robust, you use them at the cost of EJB portability. The upcoming J2EE Connector Architecture 1.0 addresses that issue and makes resources pluggable, relieving the EJB layer from dealing with vendor-specific libraries. And finally, I explained why your design plays an important role in taking advantage of those pooling techniques for delivering high-performance J2EE applications.

Siva Visveswaran has been working with Java for more than three years and has been smitten by J2EE. Most recently, he has been involved in architecture and development of large and complex J2EE applications for Fortune 100 financial service companies and dot-coms. He has more than 12 years experience in the IT industry and is currently working as a principal consultant at a large management consulting firm, specializing in e-business architecture, infrastructure technologies, and content management solutions. Siva has a master's degree in computer science from Wayne State University in Detroit, Mich.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more