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 :)
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
}
}
}