Mentawai Web Framework

Connection Pooling

A Connection Pool does not have much to do with a web framework, but it is so important for every web application that Mentawai, following its philosophy of making your life easier, has decided to offer a very simple and straighfoward solution through the org.mentawai.filter.ConnectionFilter filter. Through this filter it is possible for the action to get a connection from the pool straight from its input. Below we list an example:

public class HelloMyPool extends BaseAction {
	
    public String execute() throws Exception {
        
        Connection conn = (Connection) input.getValue("conn");
        PreparedStatement stmt = null;
        ResultSet rset = null;
        try {
            stmt = conn.prepareStatement("select username from profiles limit 1");
            rset = stmt.executeQuery();
            if (rset.next()) {
                output.setValue("username", rset.getString(1));
                return SUCCESS;
            }
        } catch(SQLException e) {
            throw new ActionException(e);
        } finally {
            try { if (rset != null) rset.close(); } catch(Exception e) { }
            try { if (stmt != null) stmt.close(); } catch(Exception e) { }
        }
        return ERROR;
    }
}    
        

Notice that you don't need to worry about returning the connection to the pool once you are done using it. The filter will make sure that happens even if an exception is thrown. You should also notice that the ConnectionFilter implements the org.mentawai.core.AfterConsequenceFilter so that the connection is only returned to the pool after the consequence is executed, in other words, for the case of a forward the connection will remain available while the view is being processed (JSP, velocity, etc.).


Using the Jakarta Commons DBCP

Tomcat already comes with DBCP (Jakarta's Connection Pool) so that in theory you don't have to download any jars. However, if you are using another web container, or even if you have problems with Tomcat, you should go to http://jakarta.apache.org/commons/dbcp to download the jars. You should put the DBCP's jar files inside your /WEB-INF/lib directory of your web application.

The same would apply if you were using the C3P0 connection pool through the C3P0ConnectionHandler. You would need to go to http://sourceforge.net/projects/c3p0 and grab the C3P0's jar files.

Below is how you setup the ConnectionFilter inside your application's ApplicationManager:

public class ApplicationManager extends org.mentawai.core.ApplicationManager {
    
    private ConnectionHandler connHandler = null;
    
    public void init(Context application) {
    
        // assuming you have a mysql database with a "lohis" database with username "lohis" and password "lohis"
        this.connHandler = new DBCPConnectionHandler("com.mysql.jdbc.Driver", 
                                                                  "jdbc:mysql://localhost/lohis?autoReconnect=true", 
                                                                  "lohis", 
                                                                  "lohis");
    }
    
    public void loadAction() {
     
        // Java style
        addGlobalFilter(new ConnectionFilter(connHandler));
        
        // Ruby style
        filter(new ConnectionFilter(connHandler));
        
    }
}        
    

Notice that we are using the MySQL JDBC driver Connector/J (com.mysql.jdbc.Driver). You must go here to download the latest version of Connector/J and place its jar file inside your application's /WEB-INF/lib directory.

Also notice that our ConnectionFilter is a global filter, in other words, it will be executed for all actions (except for those which implement the GlobalFilterFree interface). So does that mean that even those actions that do not need a connection will receive one? No, because the ConnectionFilter, like most of other Mentawai filters, are pull based or on demand.


The ConnectionHandler interface

To create an org.mentawai.filter.ConnectionFilter, you must pass an org.mentawai.db.ConnectionHandler as an argument to the filter constructor. A ConnectionHandler is just an abstraction of a connection provider. The source code of the ConnectionHandler is below:

package org.mentawai.db; // this class comes with mentawai

import java.sql.*;
        
public interface ConnectionHandler {

    public Connection getConnection() throws SQLException;
    public void release(Connection conn);

}        
        

Mentawai comes with four ready-to-use connection handlers:

  • DataSourceConnectionHandler: a connection handler with any javax.sql.DataSource

  • JNDIConnectionHandler: a connection handler from a JNDI context

  • C3P0ConnectionHandler: a connection handler with an underlying C3P0 connection pool

  • DBCPConnectoinHandler: a connection handler with an underlying Commons DBCP connection pool

Nothing holds you from implementing this interface to create/use your own connection pool.



More Control

You may access the underlying DBCP's BasicDataSource to configure the DBCP connection pool. How would you do that with XML?


public class ApplicationManager extends org.mentawai.core.ApplicationManager {
    
    private ConnectionHandler connHandler = null;
    
    public void init(Context application) {
    
        // assuming you have a mysql database with a "lohis" database with username "lohis" and password "lohis"
        this.connHandler = new DBCPConnectionHandler("com.mysql.jdbc.Driver", 
                                                                  "jdbc:mysql://localhost/lohis?autoReconnect=true", 
                                                                  "lohis", 
                                                                  "lohis");
                                                                  
        // access the org.apache.commons.dbcp.BasicDataSource                                                                  
        BasicDataSource ds = (BasicDataSource) ((DBCPConnectionHandler) connHandler).getBasicDataSource();
        ds.setInitialSize(5);
        ds.setMaxIdle(5);
        ds.setMaxActive(20);                                                                  
                                                                  
    }
    
    public void loadAction() {
     
        // Java style
        addGlobalFilter(new ConnectionFilter(connHandler));
        
        // Ruby style
        filter(new ConnectionFilter(connHandler));
        
    }
}