add connection pool to Database object

This commit is contained in:
Rodrigo Lazoti
2015-01-20 12:14:28 -02:00
parent 135e1ef73d
commit 172af307a6
10 changed files with 70 additions and 55 deletions

View File

@@ -49,6 +49,8 @@ object MyBuild extends Build {
"org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container;provided", "org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container;provided",
"org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" artifacts Artifact("javax.servlet", "jar", "jar"), "org.eclipse.jetty.orbit" % "javax.servlet" % "3.0.0.v201112011016" % "container;provided;test" artifacts Artifact("javax.servlet", "jar", "jar"),
"junit" % "junit" % "4.11" % "test", "junit" % "junit" % "4.11" % "test",
"com.mchange" % "c3p0" % "0.9.5",
"com.typesafe" % "config" % "1.2.1",
"com.typesafe.play" %% "twirl-compiler" % "1.0.2" "com.typesafe.play" %% "twirl-compiler" % "1.0.2"
), ),
EclipseKeys.withSource := true, EclipseKeys.withSource := true,

View File

@@ -0,0 +1,6 @@
db {
driver = "org.h2.Driver"
url = "jdbc:h2:${DatabaseHome};MVCC=true"
user = "sa"
password = "sa"
}

View File

@@ -10,7 +10,7 @@ import util.Directory._
import util.ControlUtil._ import util.ControlUtil._
import util.JDBCUtil._ import util.JDBCUtil._
import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.Git
import util.Directory import util.{DatabaseConfig, Directory}
object AutoUpdate { object AutoUpdate {
@@ -208,10 +208,7 @@ class AutoUpdateListener extends ServletContextListener {
} }
org.h2.Driver.load() org.h2.Driver.load()
val context = event.getServletContext defining(getConnection()){ conn =>
context.setInitParameter("db.url", s"jdbc:h2:${DatabaseHome};MVCC=true")
defining(getConnection(event.getServletContext)){ conn =>
logger.debug("Start schema update") logger.debug("Start schema update")
try { try {
defining(getCurrentVersion()){ currentVersion => defining(getCurrentVersion()){ currentVersion =>
@@ -239,16 +236,10 @@ class AutoUpdateListener extends ServletContextListener {
def contextDestroyed(sce: ServletContextEvent): Unit = { def contextDestroyed(sce: ServletContextEvent): Unit = {
} }
private def getConnection(servletContext: ServletContext): Connection = private def getConnection(): Connection =
DriverManager.getConnection( DriverManager.getConnection(
servletContext.getInitParameter("db.url"), DatabaseConfig.url,
servletContext.getInitParameter("db.user"), DatabaseConfig.user,
servletContext.getInitParameter("db.password")) DatabaseConfig.password)
private def getDatabase(servletContext: ServletContext): scala.slick.jdbc.JdbcBackend.Database =
slick.jdbc.JdbcBackend.Database.forURL(
servletContext.getInitParameter("db.url"),
servletContext.getInitParameter("db.user"),
servletContext.getInitParameter("db.password"))
} }

View File

@@ -1,27 +1,29 @@
package servlet package servlet
import javax.servlet._ import javax.servlet._
import org.slf4j.LoggerFactory
import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletRequest
import util.Keys import com.mchange.v2.c3p0.ComboPooledDataSource
import org.slf4j.LoggerFactory
import slick.jdbc.JdbcBackend.{Database => SlickDatabase, Session}
import util.{DatabaseConfig, Keys}
/** /**
* Controls the transaction with the open session in view pattern. * Controls the transaction with the open session in view pattern.
*/ */
class TransactionFilter extends Filter { class TransactionFilter extends Filter {
private val logger = LoggerFactory.getLogger(classOf[TransactionFilter]) private val logger = LoggerFactory.getLogger(classOf[TransactionFilter])
def init(config: FilterConfig) = {} def init(config: FilterConfig) = {}
def destroy(): Unit = {} def destroy(): Unit = {}
def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = { def doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain): Unit = {
if(req.asInstanceOf[HttpServletRequest].getRequestURI().startsWith("/assets/")){ if(req.asInstanceOf[HttpServletRequest].getRequestURI().startsWith("/assets/")){
// assets don't need transaction // assets don't need transaction
chain.doFilter(req, res) chain.doFilter(req, res)
} else { } else {
Database(req.getServletContext) withTransaction { session => Database() withTransaction { session =>
logger.debug("begin transaction") logger.debug("begin transaction")
req.setAttribute(Keys.Request.DBSession, session) req.setAttribute(Keys.Request.DBSession, session)
chain.doFilter(req, res) chain.doFilter(req, res)
@@ -34,12 +36,24 @@ class TransactionFilter extends Filter {
object Database { object Database {
def apply(context: ServletContext): slick.jdbc.JdbcBackend.Database = private val logger = LoggerFactory.getLogger(Database.getClass)
slick.jdbc.JdbcBackend.Database.forURL(context.getInitParameter("db.url"),
context.getInitParameter("db.user"),
context.getInitParameter("db.password"))
def getSession(req: ServletRequest): slick.jdbc.JdbcBackend#Session = private val db: SlickDatabase = {
req.getAttribute(Keys.Request.DBSession).asInstanceOf[slick.jdbc.JdbcBackend#Session] val datasource = new ComboPooledDataSource
datasource.setDriverClass(DatabaseConfig.driver)
datasource.setJdbcUrl(DatabaseConfig.url)
datasource.setUser(DatabaseConfig.user)
datasource.setPassword(DatabaseConfig.password)
logger.debug("load database connection pool")
SlickDatabase.forDataSource(datasource)
}
def apply(): SlickDatabase = db
def getSession(req: ServletRequest): Session =
req.getAttribute(Keys.Request.DBSession).asInstanceOf[Session]
} }

View File

@@ -31,7 +31,7 @@ abstract class GitCommand(val context: ServletContext, val owner: String, val re
private def newTask(user: String): Runnable = new Runnable { private def newTask(user: String): Runnable = new Runnable {
override def run(): Unit = { override def run(): Unit = {
Database(context) withSession { implicit session => Database() withSession { implicit session =>
try { try {
runTask(user) runTask(user)
callback.onExit(0) callback.onExit(0)
@@ -130,4 +130,4 @@ class GitCommandFactory(context: ServletContext, baseUrl: String) extends Comman
case _ => new UnknownCommand(command) case _ => new UnknownCommand(command)
} }
} }
} }

View File

@@ -10,7 +10,7 @@ import javax.servlet.ServletContext
class PublicKeyAuthenticator(context: ServletContext) extends PublickeyAuthenticator with SshKeyService { class PublicKeyAuthenticator(context: ServletContext) extends PublickeyAuthenticator with SshKeyService {
override def authenticate(username: String, key: PublicKey, session: ServerSession): Boolean = { override def authenticate(username: String, key: PublicKey, session: ServerSession): Boolean = {
Database(context) withSession { implicit session => Database() withSession { implicit session =>
getPublicKeys(username).exists { sshKey => getPublicKeys(username).exists { sshKey =>
SshUtil.str2PublicKey(sshKey.publicKey) match { SshUtil.str2PublicKey(sshKey.publicKey) match {
case Some(publicKey) => key.equals(publicKey) case Some(publicKey) => key.equals(publicKey)

View File

@@ -0,0 +1,19 @@
package util
import com.typesafe.config.ConfigFactory
import util.Directory.DatabaseHome
object DatabaseConfig {
private val config = ConfigFactory.load("database")
private val dbUrl = config.getString("db.url")
def url(directory: Option[String]): String =
dbUrl.replace("${DatabaseHome}", directory.getOrElse(DatabaseHome))
val url: String = url(None)
val user: String = config.getString("db.user")
val password: String = config.getString("db.password")
val driver: String = config.getString("db.driver")
}

View File

@@ -27,7 +27,7 @@ trait Notifier extends RepositoryService with AccountService with IssuesService
getComments(issue.userName, issue.repositoryName, issue.issueId).map(_.commentedUserName) getComments(issue.userName, issue.repositoryName, issue.issueId).map(_.commentedUserName)
) )
.distinct .distinct
.withFilter ( _ != context.loginAccount.get.userName ) // the operation in person is excluded .withFilter ( _ != context.loginAccount.get.userName ) // the operation in person is excluded
.foreach ( getAccountByUserName(_) filterNot (_.isGroupAccount) filterNot (LDAPUtil.isDummyMailAddress(_)) foreach (x => notify(x.mailAddress)) ) .foreach ( getAccountByUserName(_) filterNot (_.isGroupAccount) filterNot (LDAPUtil.isDummyMailAddress(_)) foreach (x => notify(x.mailAddress)) )
} }
@@ -67,7 +67,7 @@ class Mailer(private val smtp: Smtp) extends Notifier {
def toNotify(r: RepositoryService.RepositoryInfo, issueId: Int, content: String) def toNotify(r: RepositoryService.RepositoryInfo, issueId: Int, content: String)
(msg: String => String)(implicit context: Context) = { (msg: String => String)(implicit context: Context) = {
val database = Database(context.request.getServletContext) val database = Database()
val f = Future { val f = Future {
database withSession { implicit session => database withSession { implicit session =>
@@ -113,4 +113,4 @@ class Mailer(private val smtp: Smtp) extends Notifier {
class MockMailer extends Notifier { class MockMailer extends Notifier {
def toNotify(r: RepositoryService.RepositoryInfo, issueId: Int, content: String) def toNotify(r: RepositoryService.RepositoryInfo, issueId: Int, content: String)
(msg: String => String)(implicit context: Context): Unit = {} (msg: String => String)(implicit context: Context): Unit = {}
} }

View File

@@ -45,25 +45,7 @@
<servlet-name>GitRepositoryServlet</servlet-name> <servlet-name>GitRepositoryServlet</servlet-name>
<url-pattern>/git/*</url-pattern> <url-pattern>/git/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<!-- ===================================================================== -->
<!-- H2 database configuration -->
<!-- ===================================================================== -->
<context-param>
<param-name>db.user</param-name>
<param-value>sa</param-value>
</context-param>
<context-param>
<param-name>db.password</param-name>
<param-value>sa</param-value>
</context-param>
<context-param>
<param-name>db.tcpServer</param-name>
<param-value>-tcpAllowOthers</param-value>
</context-param>
<!-- ===================================================================== --> <!-- ===================================================================== -->
<!-- H2 console configuration --> <!-- H2 console configuration -->
<!-- ===================================================================== --> <!-- ===================================================================== -->
@@ -105,4 +87,4 @@
</context-param> </context-param>
--> -->
</web-app> </web-app>

View File

@@ -3,6 +3,7 @@ package service
import model.Profile._ import model.Profile._
import profile.simple._ import profile.simple._
import util.ControlUtil._ import util.ControlUtil._
import util.DatabaseConfig
import java.sql.DriverManager import java.sql.DriverManager
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import scala.util.Random import scala.util.Random
@@ -12,7 +13,7 @@ trait ServiceSpecBase {
def withTestDB[A](action: (Session) => A): A = { def withTestDB[A](action: (Session) => A): A = {
util.FileUtil.withTmpDir(new File(FileUtils.getTempDirectory(), Random.alphanumeric.take(10).mkString)){ dir => util.FileUtil.withTmpDir(new File(FileUtils.getTempDirectory(), Random.alphanumeric.take(10).mkString)){ dir =>
val (url, user, pass) = (s"jdbc:h2:${dir}", "sa", "sa") val (url, user, pass) = (DatabaseConfig.url(Some(dir.toString)), DatabaseConfig.user, DatabaseConfig.password)
org.h2.Driver.load() org.h2.Driver.load()
using(DriverManager.getConnection(url, user, pass)){ conn => using(DriverManager.getConnection(url, user, pass)){ conn =>
servlet.AutoUpdate.versions.reverse.foreach(_.update(conn)) servlet.AutoUpdate.versions.reverse.foreach(_.update(conn))