Search code examples
c3p0scalatra

Scalatra with c3p0 without any extra libs


Im a newbie scala and scalatra developer. Im trying to integrate c3p0 to get connection pooling in my application.

All the examples on the scalatra page is with squeryl etc, but I dont want orm and dsl. Do anyone have a ok examples with scalatra and c3p0.

Thanks all :)


Solution

  • Note: None of the code below has been compiled or checked, i'm just writing it into my browser. apologies for the inevitable glitches.

    So, I've never used Scalatra. But I wrote c3p0, and have used the Servlets API a lot. A quick look at scalatra's guides suggests something like this would work:

    import org.scalatra._
    import com.mchange.v2.c3p0._
    import javax.sql.DataSource
    import javax.servlet.ServletContext
    
    class ScalatraBootstrap extends LifeCycle {
    
      override def init(context: ServletContext) {
        val cpds = new ConnectionPoolDataSource();
    
        // perform any c3p0 config operations you might 
        // want here, or better yet, externalize all of 
        // that into a c3p0.properties, c3p0-config.xml,
        // or (c3p0 version 0.9.5 only) application.conf
    
        context.setAttribute( "appDataSource", cpds );
      }
    
      override def destroy(context: ServletContext) {
        val cpds = context.getAttribute( "appDataSource" );
        if ( cpds != null ) {
          try {
            cpds.close() 
          } catch {
            case e : Exception => e.printStackTrace(); //consider better logging than this
          }
        }
      }
    }
    

    To get access to the DataSource from a ServletRequest object, you'd call...

    request.getServletContext().getAttribute( "appDataSource" ).asInstanceOf[DataSource]
    

    You might want to use your Scala-fu to pimp ServletRequest and make access to the Connection pool easier and prettier. For example, you could write...

    implicit class ConnectionPoolRequest( request : ServletRequest ) {
       def connectionPool : DataSource = request.getServletContext().getAttribute( "appDataSource" ).asInstanceOf[DataSource]
    }
    

    Put this in a package object or some object you import into your code, and while you handle requests you should be able to write stuff like...

    val conn = request.connectionPool.getConnection();
    // do stuff
    conn.close()
    

    However, the above is crappy, leak-prone code, because the close() isn't in a finally and will be skipped by an Exception. In Java7-style, you'd use try-with-resources to avoid this. In Scala, the naive way is to do this:

    var conn = null;
    try {
      conn = request.connectionPool.getConnection();
      // do stuff
    } finally {
      try { if ( conn != null ) conn.close() } catch {
         case e : Exception => e.printStackTrace() // better logging would be nice
      }
    }
    

    However, a better way in Scala is to define utility methods like this:

    def withConnection[T]( ds : DataSource )( op : (Connection) => T) : T = {
      var con : Connection = null;
    
      try {
        con = ds.getConnection();
        op(con);
      } finally { 
        attemptClose( con ); 
      }
    }
    
    def attemptClose( con : Connection ) {
      if ( con != null ) {
        try { if ( conn != null ) conn.close() } catch {
          case e : Exception => e.printStackTrace() // better logging would be nice
        }
      }
    }
    

    Then you can just write stuff like...

    withConnection( request.connectionPool ) { conn =>
      // do stuff with the Connection
      // don't worry about cleaning up, that's taken care of for you
    }
    

    To really keep JDBC clean in scala, consider writing analogous methods like withStatement and withResultSet as well, so you can do

    withConnection( request.connectionPool ) { conn =>
      withStatement( conn ) { stmt =>
        withResultSet( stmt.executeQuery("SELECT * FROM spacemen") ) { rs =>
          // read stuff from ResultSet
        }
      } 
    }