All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.orbroker.Broker.scala Maven / Gradle / Ivy

The newest version!
package org.orbroker

import config.BrokerConfig
import org.orbroker.exception.TransientRetryFailedException
import org.orbroker.adapt.BrokerAdapter
import org.orbroker.callback.ExecutionCallback

import java.sql._

object Broker {
  def apply(config: BrokerConfig) = config.build()
}

/**
 * The broker between database and application code.
 * @see [[org.orbroker.config.BrokerConfig]]
 * @author Nils Kilden-Pedersen
 */
final class Broker private[orbroker] (
    private[orbroker] val callback: ExecutionCallback,
    val dataSource: javax.sql.DataSource,
    private[orbroker] val defaultIsolation: Option[Int],
    private[orbroker] val timeout: Int,
    private[orbroker] val fetchSize: Int,
    private[orbroker] val alwaysPrepare: Boolean,
    private[orbroker] val trimSQL: Boolean,
    usernamePassword: Option[(String, String)],
    catalog: Option[String],
    statements: Map[Symbol, SQLStatement],
    private[orbroker] val adapter: BrokerAdapter,
    private[orbroker] val defaultParms: Map[String, Any]) {

  private final val NoneProvided = Int.MinValue + 1

  private[orbroker] def makeStatement(id: Symbol, sql: String) = {
    val sqlLines = sql.split("[\r\n]").filter(_.trim.length > 0).toSeq
    if (SQLStatement.isProcedureCall(sql)) {
      new StaticStatement(id, sqlLines, trimSQL, callback, adapter) with CallStatement
    } else {
      new StaticStatement(id, sqlLines, trimSQL, callback, adapter) with ModifyStatement with QueryStatement
    }
  }

  private[orbroker] def getStatement(id: Symbol) = statements(id)

  private[orbroker] def newConnection(isolationLevel: Option[Int]) = {
    val conn = usernamePassword match {
      case Some((usr, pwd)) ⇒ this.dataSource.getConnection(usr, pwd)
      case None ⇒ this.dataSource.getConnection
    }

    for (cl ← this.catalog if conn.getCatalog != cl) {
      conn.setCatalog(cl)
    }
    for (il ← isolationLevel if conn.getTransactionIsolation != il) {
      conn.setTransactionIsolation(il)
    }
    if (conn.getAutoCommit) {
      conn.setAutoCommit(false)
    }

    conn
  }

  /**
   * Perform read-only behavior, using the given
   * transaction isolation level, or default if left empty.
   * @param isolationLevel The desired transaction isolation level. Leave empty for default.
   * @param f Read-only query block
   */
  def readOnly[T](isolationLevel: Int = NoneProvided)(f: QuerySession ⇒ T): T = {
    readOnly(f, if (isolationLevel == NoneProvided) defaultIsolation else Some(isolationLevel))
  }

  private def readOnly[T](f: QuerySession ⇒ T, isolationLevel: Option[Int]): T = {
    var hasException = false
    val session = new ReadOnly(isolationLevel, this, None)
    try {
      runSession(session, true, f)
    } catch {
      case th ⇒ hasException = true; throw th
    }
    finally {
      try {
        session.close()
      } catch {
        case th if !hasException ⇒ throw th
        case _ ⇒ // Ignore and allow other exception 
      }
    }

  }

  /**
   * Perform read-only behavior, using an externally
   * managed connection. Connection will not be closed.
   * 

NOTICE: This will not access the data source. * @param conn The external connection * @param f Read-only query block */ def readOnly[T](conn: Connection)(f: QuerySession ⇒ T): T = { val session = new ReadOnly(None, this, Some(conn)) runSession(session, false, f) } /** * Perform transactional behavior, using the given * transaction isolation level, or default if left blank. *

NOTICE: Remember to either commit or rollback the session. * @param isolationLevel The desired transaction isolation level, or empty for default. * @param f Transactional execution block */ def transactional[T](isolationLevel: Int = NoneProvided)(f: Transactional ⇒ T): T = { transactional(f, if (isolationLevel == NoneProvided) defaultIsolation else Some(isolationLevel)) } private def transactional[T](f: Transactional ⇒ T, isolationLevel: Option[Int]): T = { var hasException = false val session = new Transactional(isolationLevel, this) try { runSession(session, true, f) } catch { case th ⇒ hasException = true; throw th } finally { try { session.close() } catch { case th if !hasException ⇒ throw th case _ ⇒ // Ignore and allow other exception } } } /** * Perform transactional behavior, using an externally * managed connection. The connection will not be closed, * nor is `commit` or `rollback` available. *

NOTICE: This will not access the data source. * @param conn The external connection * @param f Transaction execution block */ def transactional[T](conn: Connection)(f: Transaction ⇒ T): T = { val session = new Transaction(None, this, Some(conn)) runSession(session, false, f) } /** * Execute and commit a transaction, using the given * transaction isolation level, or default if left blank. * @param isolationLevel The desired transaction isolation level, or empty for default. * @param f Transactional execution block */ def transaction[T](isolationLevel: Int = NoneProvided)(f: Transaction ⇒ T): T = { transactional(isolationLevel) { session ⇒ val t = f(session) session.commit() t } } private def runSession[T, S <: Session](s: S, retryTransient: Boolean, f: S ⇒ T): T = { try { f(s) } catch { case e: SQLException if retryTransient && adapter.isTransient(e) ⇒ { s.discardConnection() runSession(s, false, f) } case e: SQLException if !retryTransient && adapter.isTransient(e) ⇒ throw new TransientRetryFailedException(e) } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy