#region License Information
/* HeuristicLab
* Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.Services.Hive.Interfaces;
using System.Configuration;
using System.Data.Common;
using System.ServiceModel;
using System.Transactions;
namespace HeuristicLab.Services.Hive {
public class ConnectionProvider : IConnectionProvider {
public System.Data.Common.DbConnection GetOpenConnection(string connectionStringName) {
ConnectionStringSettings connSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
DbProviderFactory dbProvFact = DbProviderFactories.GetFactory(connSettings.ProviderName);
return ConnectionUtilsStorage.Current.GetOpenConnection(dbProvFact, connSettings.ConnectionString);
}
public void ReleaseConnection(DbConnection connection) {
ConnectionUtilsStorage.Current.ReleaseConnection(connection);
}
}
///
/// Based on the connection management developed by jheinzelreiter,
/// this class stores transactions + connections, closing connections
/// after a transaction has been closed.
/// A non-transacted connection might be closed by the user by calling
/// ReleaseConnection(connection).
///
class ConnectionUtilsStorage : IExtension {
private readonly IDictionary>
transactedConnections = new Dictionary>();
///
/// Returns an opened DbConnection. If a transaction is present, for
/// each unique connection string the same connection is returned.
///
/// DbProviderFactory, which should be used to create
/// connection
/// connection string of the connection
/// A instance
public DbConnection GetOpenConnection(DbProviderFactory providerFactory, string connectionString) {
DbConnection connection = null;
Transaction currentTransaction = Transaction.Current;
if (currentTransaction == null) {
// no transaction context -> return "ordinary" connection
connection = CreateOpenConnection(providerFactory, connectionString);
}
else {
// transaction present
IDictionary connections = null;
lock (transactedConnections) {
// check if current transaction already has at least one connection assigned
if (!transactedConnections.TryGetValue(currentTransaction, out connections)) {
connections = new Dictionary();
transactedConnections[currentTransaction] = connections;
}
if (!connections.TryGetValue(connectionString, out connection)) {
// no connection for this connection string in the current transaction
connection = CreateOpenConnection(providerFactory, connectionString);
connections[connectionString] = connection;
currentTransaction.TransactionCompleted +=
new TransactionCompletedEventHandler(OnTransactionCompleted);
}
}
}
return connection;
}
///
/// Creates a new, opened DbConnection
///
/// connection string of the connection
/// DbProviderFactory, which should be used to create
/// connection
/// A instance
private DbConnection CreateOpenConnection(DbProviderFactory providerFactory,
string connectionString) {
DbConnection connection = providerFactory.CreateConnection();
connection.ConnectionString = connectionString;
connection.Open();
return connection;
}
///
/// Releases a connection.
/// (Remark: The connection is closed only when not used in a transaction)
///
/// connection to release
public void ReleaseConnection(DbConnection connection) {
if (connection == null)
return;
Transaction currentTransaction = Transaction.Current;
// close connection if no transaction is active
if (currentTransaction == null)
connection.Close();
}
///
/// Determines, if custom connection handling code should close a connection.
/// (Remark: Used for DataReader.CommandBehavior)
///
///
public bool ShouldCloseConnection() {
return Transaction.Current == null;
}
///
/// Eventhandler for TransactionScope.TransactionCompleted.
/// Closes connections and removes transaction from observed connections.
///
/// sender
/// TransactionEventArgs
private void OnTransactionCompleted(object sender, TransactionEventArgs e) {
lock (transactedConnections) {
IDictionary connections = null;
if (transactedConnections.TryGetValue(e.Transaction, out connections)) {
foreach (DbConnection conn in connections.Values)
conn.Close();
transactedConnections.Remove(e.Transaction);
}
}
}
private static object monitor = new object();
private static ConnectionUtilsStorage _context = new ConnectionUtilsStorage();
public static ConnectionUtilsStorage Current {
get {
ConnectionUtilsStorage context;
if (OperationContext.Current != null) {
context = OperationContext.Current.Extensions.Find();
if (context == null) {
lock (monitor) {
context = OperationContext.Current.Extensions.Find();
if (context == null) {
context = new ConnectionUtilsStorage();
OperationContext.Current.Extensions.Add(context);
}
}
}
}
else {
context = _context;
}
return context;
}
}
public void Attach(OperationContext owner) {
}
public void Detach(OperationContext owner) {
}
}
}