X

Learn Tips and Best Practices from the Oracle JDBC Development

  • September 17, 2015

Using Universal Connection Pooling (UCP) with JBoss AS

Using Universal Connection Pooling (UCP) with JBoss AS

Even though WebLogic with Active GridlLink is Oracle's suggested approach to deploy Java applications that use Oracle Real Applications Clusters (RAC), there might be scenarios in which you can't make that choice (e.g.: certification issues, licensing, library dependency, etc.). Application servers and their database connection pool mechanisms might end up being a bottleneck in the architecture of your applications and a critical component to provide performance, scalability and high-availability.

UCP, besides providing connection pooling and all its intrinsic benefits, leverages features specific from RAC.
These features are:

  • Runtime Connection Load Balancing (RCLB)
  • Fast Connection Failover (FCF)
  • Transaction Affinity
  • Built-in support for Database Resident Connection Pooling (DRCP) and Application Continuity (AC)

You won't be able to exploit this features by using out of the box JBoss' connection pools.

In this simple example we will show you how to configure UCP to be used in a JBoss deployed application, wrapping UCP around a Singleton Enterprise Java Bean (EJB) and using a Servlet as client to the wrapper. We will also show you how to monitor and administer UCP using JBoss JMX-Console without needing extra configuration, coding or deployment.

In an ideal scenario the application server would provide us the possibility to set a custom implementation of a connection pooling (by implementing an interface, for example), but that is not the case with JBoss. In JBoss you can configure all the necessary information to create a connection (driver, url, user, password, etc) and some configuration for the pool (minimum size, maximum size, etc), but you can't configure the class that is going to provide the implementation for connection pooling. There's a workaround for that in this article: https://blogs.oracle.com/dev2dev/entry/how_to_use_oracle_universal1 , which explains how to set a UCP data-source using Spring). But for both scenarios you're declaring beans, or wrappers, to contain the UCP configuration.

1. Download and start JBoss AS:

You can download it from this site: http://jbossas.jboss.org/downloads/.
For this sample we used “JBoss AS 6.1.0.Final”: http://download.jboss.org/jbossas/6.1/jboss-as-distribution-6.1.0.Final.zip.
After unzipping the file you should set your JAVA_HOME env variable to an existing JDK directory (jdk7, it won't work with jdk8).
To start the app server you go to the unzipped directory /bin and run standalone.sh or standalone.bat, depending on your OS (you can skip this step if you install JBoss Developer Studio.
You can check successful start-up by opening a browser to http://localhost:8080/

2. Download and install JBoss Developer Studio:

This is also an optional step, you can download JBoss Developer Studio from http://www.jboss.org/products/devstudio/download/ after unzipping you start it by running jbdevstudio executable.
This is an extension of Eclipse with JBoss specific plugins installed.

3. Configure JBoss AS in JBoss Developer Studio:

In “servers” view choose “new” / “server”, select “JBoss Community, JBoss AS 6.x”, select “Home Directory” to the previously downloaded JBoss AS and leave default values.
After this step you can start/stop application server from JBoss Developer Studio and deploy / un-deploy applications by selecting “Add and Remove..” in Server's contextual menu.

4. Add ucp.jar and ojdbc.jar both to Jboss's runtime:

Add both jars in (JBOSS_HOME/common/lib) and in project's build path (project / properties / Java Build Path / libraries). You could also deploy this jars as specifics for the app, off course.

5. Create the Singleton Wrapper for UCP as this:

    @Startup
   
@Singleton(name = "UcpDemoSingletonWrapper")
   
public class UcpDemoSingletonWrapper {

        @Resource
(name = "connectionFactoryClassName")
       
String connectionFactoryClassName;

            @Resource(name = "url")
        String
url;

        @Resource(name = "user")
        String
user;

        @Resource(name = "password")
        String
password;

        @Resource(name = "initialPoolSize")
        Integer
initialPoolSize;

        /**
        * Initialize method for the Singleton. This wrapper could also implement
        * JMX APIs to be able to be managed through the JMX Console (or any other
        * JMX
-compliant Tool)
        */

        @PostConstruct
       
void init() {
           
try {
               
// Retrieve values from bean's configuration
               
pds.setConnectionFactoryClassName(connectionFactoryClassName);
               
pds.setURL(url);
               
pds.setUser(user);
               
pds.setPassword(password);

                // Override example's desired pool properties
               
// Will be showed through JMX-Console for this example

                pds.setInitialPoolSize(initialPoolSize);
               
pds.setConnectionPoolName(this.getClass().getName());

            } catch (Exception e) {
               
e.printStackTrace();
            }
        }

        // Wrapped pool
       
private PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();

        /**
        * Retrieves connections using wrapped pool
        *
@return a pooled connection
        *
@throws SQLException
        */

              public Connection getConnection() throws SQLException {
   

            /**
            * Trivial implementation to retrieve connections. Logic intrinsic to
            * the pool could be set here.
            */

            return pds.getConnection();
       
}
    }

6. Create EJB configuration file (WEB-INF/ejb-jar.xml) with this values:

    <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.1" metadata-complete="false">
   
<enterprise-beans>
        <session>
           
<ejb-name>UcpDemoSingletonWrapper</ejb-name>
           
<env-entry>
               
<env-entry-name>connectionFactoryClassName</env-entry-name>
               
<env-entry-type>java.lang.String</env-entry-type>
               
<env-entry-value>oracle.jdbc.pool.OracleDataSource</env-entry-value>
           
</env-entry>
           
<env-entry>
               
<env-entry-name>url</env-entry-name>
               
<env-entry-type>java.lang.String</env-entry-type>
               
<env-entry-value>jdbc:oracle:thin:@//localhost:1521/cdb1</env-entry-value>
           
</env-entry>
           
<env-entry>
           
    <env-entry-name>user</env-entry-name>
               
<env-entry-type>java.lang.String</env-entry-type>
               
<env-entry-value>c##psilberk</env-entry-value>
           
</env-entry>
           
<env-entry>
               
<env-entry-name>password</env-entry-name>
               
<env-entry-type>java.lang.String</env-entry-type>
               
<env-entry-value>oracle</env-entry-value>
           
</env-entry>
           
<env-entry>
               
<env-entry-name>initialPoolSize</env-entry-name>
               
<env-entry-type>java.lang.Integer</env-entry-type>
               
<env-entry-value>5</env-entry-value>
           
</env-entry>
            </session>
   
</enterprise-beans>
   
</ejb-jar>

7. Create the client as this sample servlet:

    /**
    * Simple client to show how to use wrapped ucp's EJB
   
*
   
*/

    @WebServlet
("/UcpDemoServletClient")
   
public class UcpDemoServletClient extends HttpServlet {
       
        private
static final long serialVersionUID = 1L;

       
@EJB UcpDemoSingletonWrapper ucpWrapper;

            protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
           
doPost(request, response);
        }

            protected void doPost(HttpServletRequest request,
            HttpServletResponse
response) throws ServletException, IOException {

            try (
               
// Get connection from pool, for this trivial example we avoid ORM

                Connection connection = ucpWrapper.getConnection();
                Statement
statement = connection.createStatement();
                ResultSet
resultSet = statement
                    .executeQuery(
"select * from test_table")) {

                // Send output to response

                PrintWriter printWriter = response.getWriter();

                while (resultSet.next()) {
                   
printWriter.println(resultSet.getString(1));
               
}

            } catch (SQLException sqlException) {
               
throw new ServletException(sqlException);
           
}
        }
    }

8. From Servers's view execute “Publish” and “Start” (or just execute from project's context menu “run in server”).

JBoss deploy

9. Administer EJB from JMX-Console:

Login to http://localhost:8080/jmx-console/

Look for UCP's MBEANs:
oracle.ucp.admin.UniversalConnectionPoolManagerMBean
oracle.ucp.admin.UniversalConnectionPoolMBean
 

Invoke getConnectionPoolName (you will get what was setted on the EJB, “ucp_demo.UcpDemoSingletonWrapper").
Go through oracle.ucp.admin.UniversalConnectionPoolMBean and look for availableConnectionsCount.

10. Invoke servlet:

Typing in a browser http://localhost:8080/ucp_jboss_demo_web_project/UcpDemoServletClient

Check that after several executions the amount of available connections remains constant.
Do the same but not closing the connections in the wrapper (remove from the try with resources block, avoiding connection.close())
Or just execute Connection connection = ucpWrapper.getConnection(); without closing the connection.
You will check that available connections decreases until exception is thrown.
Use JMX-console to administer life-cycle of UCP (start / stop / purge connection pool, etc.).
A full-fledged test would include modifications in the RAC (shutting down/up nodes, checking load balance between them, validating transaction affinity, etc.), in these scenarios UCP would show all its capacities and features (as described at the beginning of this article).

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.