context: #region License
  
  //  Copyright 2004-2010 Castle Project - http://www.castleproject.org/
  //  
  //  Licensed under the Apache License, Version 2.0 (the "License");
  //  you may not use this file except in compliance with the License.
  //  You may obtain a copy of the License at
  //  
  //      http://www.apache.org/licenses/LICENSE-2.0
  //  
  //  Unless required by applicable law or agreed to in writing, software
  //  distributed under the License is distributed on an "AS IS" BASIS,
  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  //  See the License for the specific language governing permissions and
  //  limitations under the License.
  // 
  
  #endregion
  
  namespace Castle.Facilities.NHibernateIntegration
  {
  	using System;
  	using System.Collections;
  	using System.Data;
  	using System.Linq.Expressions;
  	using NHibernate;
  	using NHibernate.Stat;
  	using NHibernate.Type;
  
  	/// <summary>
  	/// Proxies an ISession so the user cannot close a session which
  	/// is controlled by a transaction, or, when this is not the case, 
  	/// make sure to remove the session from the storage.
  	/// <seealso cref="ISessionStore"/>
  	/// <seealso cref="ISessionManager"/>
  	/// </summary>
  	[Serializable]
  	public class SessionDelegate : MarshalByRefObject, ISession
  	{
  		private readonly ISession inner;
  		private readonly ISessionStore sessionStore;
  		private readonly bool canClose;
  		private bool disposed;
  		private object cookie;
  
  		/// <summary>
  		/// Initializes a new instance of the <see cref="SessionDelegate"/> class.
  		/// </summary>
  		/// <param name="canClose">if set to <c>true</c> [can close].</param>
  		/// <param name="inner">The inner.</param>
  		/// <param name="sessionStore">The session store.</param>
  		public SessionDelegate(bool canClose, ISession inner, ISessionStore sessionStore)
  		{
  			this.inner = inner;
  			this.sessionStore = sessionStore;
  			this.canClose = canClose;
  		}
  
  		/// <summary>
  		/// Gets the inner session.
  		/// </summary>
  		/// <value>The inner session.</value>
  		public ISession InnerSession
  		{
  			get { return inner; }
  		}
  
  		/// <summary>
  		/// Gets or sets the session store cookie.
  		/// </summary>
  		/// <value>The session store cookie.</value>
  		public object SessionStoreCookie
  		{
  			get { return cookie; }
  			set { cookie = value; }
  		}
  
  		#region ISession delegation
  
  		/// <summary>
  		/// Determines at which points Hibernate automatically flushes the session.
  		/// </summary>
  		/// <value></value>
  		/// <remarks>
  		/// For a readonly session, it is reasonable to set the flush mode to <c>FlushMode.Never</c>
  		/// at the start of the session (in order to achieve some extra performance).
  		/// </remarks>
  		public FlushMode FlushMode
  		{
  			get { return inner.FlushMode; }
  			set { inner.FlushMode = value; }
  		}
  
  		/// <summary>
  		/// Get the <see cref="T:NHibernate.ISessionFactory"/> that created this instance.
  		/// </summary>
  		/// <value></value>
  		public ISessionFactory SessionFactory
  		{
  			get { return inner.SessionFactory; }
  		}
  
  		/// <summary>
  		/// Gets the ADO.NET connection.
  		/// </summary>
  		/// <value></value>
  		/// <remarks>
  		/// Applications are responsible for calling commit/rollback upon the connection before
  		/// closing the <c>ISession</c>.
  		/// </remarks>
  		public IDbConnection Connection
  		{
  			get { return inner.Connection; }
  		}
  
  		/// <summary>
  		/// Is the <c>ISession</c> still open?
  		/// </summary>
  		/// <value></value>
  		public bool IsOpen
  		{
  			get { return inner.IsOpen; }
  		}
  
  		/// <summary>
  		/// Is the <c>ISession</c> currently connected?
  		/// </summary>
  		/// <value></value>
  		public bool IsConnected
  		{
  			get { return inner.IsConnected; }
  		}
  
  	   /// <summary>
  	   /// The read-only status for entities (and proxies) loaded into this Session.
  	   /// </summary>
  	   /// <remarks>
  	   /// <para>
  	   /// When a proxy is initialized, the loaded entity will have the same read-only setting
  	   ///             as the uninitialized proxy, regardless of the session's current setting.
  	   /// </para>
  	   /// <para>
  	   /// To change the read-only setting for a particular entity or proxy that is already in 
  	   ///             this session, see <see cref="M:NHibernate.ISession.SetReadOnly(System.Object,System.Boolean)"/>.
  	   /// </para>
  	   /// <para>
  	   /// To override this session's read-only setting for entities and proxies loaded by a query,
  	   ///             see <see cref="M:NHibernate.IQuery.SetReadOnly(System.Boolean)"/>.
  	   /// </para>
  	   /// <para>
  	   /// This method is a facade for <see cref="P:NHibernate.Engine.IPersistenceContext.DefaultReadOnly"/>.
  	   /// </para>
  	   /// </remarks>
  	   /// <seealso cref="M:NHibernate.ISession.IsReadOnly(System.Object)"/><seealso cref="M:NHibernate.ISession.SetReadOnly(System.Object,System.Boolean)"/>
  	   public bool DefaultReadOnly
  	   {
           get { return inner.DefaultReadOnly; }
           set { inner.DefaultReadOnly = value; }
  	   }
  
  	   /// <summary>
  		/// Get the current Unit of Work and return the associated <c>ITransaction</c> object.
  		/// </summary>
  		/// <value></value>
  		public ITransaction Transaction
  		{
  			get { return inner.Transaction; }
  		}
  
  		/// <summary>
  		/// Cancel execution of the current query.
  		/// </summary>
  		/// <remarks>
  		/// May be called from one thread to stop execution of a query in another thread.
  		/// Use with care!
  		/// </remarks>
  		public void CancelQuery()
  		{
  			inner.CancelQuery();
  		}
  
  		/// <summary>
  		/// Does this <c>ISession</c> contain any changes which must be
  		/// synchronized with the database? Would any SQL be executed if
  		/// we flushed this session?
  		/// </summary>
  		/// <returns></returns>
  		public bool IsDirty()
  		{
  			return inner.IsDirty();
  		}
  
  	   /// <summary>
  	   /// Is the specified entity (or proxy) read-only?
  	   /// </summary>
  	   /// <remarks>
  	   /// Facade for <see cref="M:NHibernate.Engine.IPersistenceContext.IsReadOnly(System.Object)"/>.
  	   /// </remarks>
  	   /// <param name="entityOrProxy">An entity (or <see cref="T:NHibernate.Proxy.INHibernateProxy"/>)</param>
  	   /// <returns>
  	   /// <c>true</c> if the entity (or proxy) is read-only, otherwise <c>false</c>.
  	   /// </returns>
  	   /// <seealso cref="P:NHibernate.ISession.DefaultReadOnly"/><seealso cref="M:NHibernate.ISession.SetReadOnly(System.Object,System.Boolean)"/>
  	   public bool IsReadOnly(object entityOrProxy)
  	   {
           return inner.IsReadOnly(entityOrProxy);
  	   }
  
  	   /// <summary>
  	   /// Change the read-only status of an entity (or proxy).
  	   /// </summary>
  	   /// <remarks>
  	   /// <para>
  	   /// Read-only entities can be modified, but changes are not persisted. They are not dirty-checked 
  	   ///             and snapshots of persistent state are not maintained. 
  	   /// </para>
  	   /// <para>
  	   /// Immutable entities cannot be made read-only.
  	   /// </para>
  	   /// <para>
  	   /// To set the <em>default</em> read-only setting for entities and proxies that are loaded 
  	   ///             into the session, see <see cref="P:NHibernate.ISession.DefaultReadOnly"/>.
  	   /// </para>
  	   /// <para>
  	   /// This method a facade for <see cref="M:NHibernate.Engine.IPersistenceContext.SetReadOnly(System.Object,System.Boolean)"/>.
  	   /// </para>
  	   /// </remarks>
  	   /// <param name="entityOrProxy">An entity (or <see cref="T:NHibernate.Proxy.INHibernateProxy"/>).</param><param name="readOnly">If <c>true</c>, the entity or proxy is made read-only; if <c>false</c>, it is made modifiable.</param><seealso cref="P:NHibernate.ISession.DefaultReadOnly"/><seealso cref="M:NHibernate.ISession.IsReadOnly(System.Object)"/>
  	   public void SetReadOnly(object entityOrProxy, bool readOnly)
  	   {
  	      inner.SetReadOnly(entityOrProxy, readOnly);
  	   }
  
  
  	   /// <summary>
  		/// Force the <c>ISession</c> to flush.
  		/// </summary>
  		/// <remarks>
  		/// Must be called at the end of a unit of work, before commiting the transaction and closing
  		/// the session (<c>Transaction.Commit()</c> calls this method). <i>Flushing</i> if the process
  		/// of synchronising the underlying persistent store with persistable state held in memory.
  		/// </remarks>
  		public void Flush()
  		{
  			inner.Flush();
  		}
  
  		/// <summary>
  		/// Disconnect the <c>ISession</c> from the current ADO.NET connection.
  		/// </summary>
  		/// <returns>
  		/// The connection provided by the application or <see langword="null"/>
  		/// </returns>
  		/// <remarks>
  		/// If the connection was obtained by Hibernate, close it or return it to the connection
  		/// pool. Otherwise return it to the application. This is used by applications which require
  		/// long transactions.
  		/// </remarks>
  		public IDbConnection Disconnect()
  		{
  			return inner.Disconnect();
  		}
  
  		/// <summary>
  		/// Obtain a new ADO.NET connection.
  		/// </summary>
  		/// <remarks>
  		/// This is used by applications which require long transactions
  		/// </remarks>
  		public void Reconnect()
  		{
  			inner.Reconnect();
  		}
  
  		/// <summary>
  		/// Reconnect to the given ADO.NET connection.
  		/// </summary>
  		/// <param name="connection">An ADO.NET connection</param>
  		/// <remarks>This is used by applications which require long transactions</remarks>
  		public void Reconnect(IDbConnection connection)
  		{
  			inner.Reconnect(connection);
  		}
  
  		/// <summary>
  		/// Return the identifier of an entity instance cached by the <c>ISession</c>
  		/// </summary>
  		/// <param name="obj">a persistent instance</param>
  		/// <returns>the identifier</returns>
  		/// <remarks>
  		/// Throws an exception if the instance is transient or associated with a different
  		/// <c>ISession</c>
  		/// </remarks>
  		public object GetIdentifier(object obj)
  		{
  			return inner.GetIdentifier(obj);
  		}
  
  		/// <summary>
  		/// Is this instance associated with this Session?
  		/// </summary>
  		/// <param name="obj">an instance of a persistent class</param>
  		/// <returns>
  		/// true if the given instance is associated with this Session
  		/// </returns>
  		public bool Contains(object obj)
  		{
  			return inner.Contains(obj);
  		}
  
  		/// <summary>
  		/// Remove this instance from the session cache.
  		/// </summary>
  		/// <param name="obj">a persistent instance</param>
  		/// <remarks>
  		/// Changes to the instance will not be synchronized with the database.
  		/// This operation cascades to associated instances if the association is mapped
  		/// with <c>cascade="all"</c> or <c>cascade="all-delete-orphan"</c>.
  		/// </remarks>
  		public void Evict(object obj)
  		{
  			inner.Evict(obj);
  		}
  
  		/// <summary>
  		/// Return the persistent instance of the given entity class with the given identifier,
  		/// obtaining the specified lock mode.
  		/// </summary>
  		/// <param name="theType">A persistent class</param>
  		/// <param name="id">A valid identifier of an existing persistent instance of the class</param>
  		/// <param name="lockMode">The lock level</param>
  		/// <returns>the persistent instance</returns>
  		public object Load(Type theType, object id, LockMode lockMode)
  		{
  			return inner.Load(theType, id, lockMode);
  		}
  
  		/// <summary>
  		/// Return the persistent instance of the given entity class with the given identifier,
  		/// obtaining the specified lock mode.
  		/// </summary>
  		/// <param name="entityName">Name of the entity</param>
  		/// <param name="id">A valid identifier of an existing persistent instance of the class</param>
  		/// <param name="lockMode">The lock level</param>
  		/// <returns>the persistent instance</returns>
  		public object Load(string entityName, object id, LockMode lockMode)
  		{
  			return inner.Load(entityName, id, lockMode);
  		}
  
  		/// <summary>
  		/// Return the persistent instance of the given entity class with the given identifier,
  		/// assuming that the instance exists.
  		/// </summary>
  		/// <param name="theType">A persistent class</param>
  		/// <param name="id">A valid identifier of an existing persistent instance of the class</param>
  		/// <returns>The persistent instance or proxy</returns>
  		/// <remarks>
  		/// You should not use this method to determine if an instance exists (use a query or
  		/// <see cref="M:NHibernate.ISession.Get(System.Type,System.Object)"/> instead). Use this only to retrieve an instance
  		/// that you assume exists, where non-existence would be an actual error.
  		/// </remarks>
  		public object Load(Type theType, object id)
  		{
  			return inner.Load(theType, id);
  		}
  
  		/// <summary>
  		/// Loads the specified id.
  		/// </summary>
  		/// <typeparam name="T"></typeparam>
  		/// <param name="id">The id.</param>
  		/// <param name="lockMode">The lock mode.</param>
  		/// <returns></returns>
  		public T Load<T>(object id, LockMode lockMode)
  		{
  			return inner.Load<T>(id, lockMode);
  		}
  
  		/// <summary>
  		/// Loads the specified id.
  		/// </summary>
  		/// <typeparam name="T"></typeparam>
  		/// <param name="id">The id.</param>
  		/// <returns></returns>
  		public T Load<T>(object id)
  		{
  			return inner.Load<T>(id);
  		}
  
  		/// <summary>
  		/// Loads the specified id.
  		/// </summary>
  		/// <param name="entityName">Name of the entity</param>
  		/// <param name="id">The id.</param>
  		/// <returns></returns>
  		public object Load(string entityName, object id)
  		{
  
gt: 			return inner.Load(entityName, id);