Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / ActiveRecord / Castle.ActiveRecord / Framework / Scopes / DifferentDatabaseScope.cs
blob12feb15f5d36555a91ec0651117c6fe12e8be8bd
1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.ActiveRecord.Framework.Scopes
17 using System;
18 using System.Collections.Generic;
19 using System.Data;
21 using NHibernate;
23 /// <summary>
24 /// Still very experimental and it's not bullet proof
25 /// for all situations
26 /// </summary>
27 public class DifferentDatabaseScope : AbstractScope
29 private readonly IDbConnection connection;
30 private readonly SessionScope parentSimpleScope;
31 private readonly TransactionScope parentTransactionScope;
33 /// <summary>
34 /// Initializes a new instance of the <see cref="DifferentDatabaseScope"/> class.
35 /// </summary>
36 /// <param name="connection">The connection.</param>
37 public DifferentDatabaseScope(IDbConnection connection) : this(connection, FlushAction.Auto)
41 /// <summary>
42 /// Initializes a new instance of the <see cref="DifferentDatabaseScope"/> class.
43 /// </summary>
44 /// <param name="connection">The connection.</param>
45 /// <param name="flushAction">The flush action.</param>
46 public DifferentDatabaseScope(IDbConnection connection, FlushAction flushAction) : base(flushAction, SessionScopeType.Custom)
48 if (connection == null) throw new ArgumentNullException("connection");
50 this.connection = connection;
52 ISessionScope parentScope = ScopeUtil.FindPreviousScope(this, true);
54 if (parentScope != null)
56 if (parentScope.ScopeType == SessionScopeType.Simple)
58 parentSimpleScope = (SessionScope) parentScope;
60 else if (parentScope.ScopeType == SessionScopeType.Transactional)
62 parentTransactionScope = (TransactionScope) parentScope;
64 parentTransactionScope.OnTransactionCompleted += OnTransactionCompleted;
66 else
68 // Not supported?
73 /// <summary>
74 /// We want to be in charge of creating the session
75 /// </summary>
76 /// <value></value>
77 public override bool WantsToCreateTheSession
79 get { return true; }
82 /// <summary>
83 /// This method is invoked when no session was available
84 /// at and the <see cref="Castle.ActiveRecord.Framework.ISessionFactoryHolder"/>
85 /// just created one. So it registers the session created
86 /// within this scope using a key. The scope implementation
87 /// shouldn't make any assumption on what the key
88 /// actually is as we reserve the right to change it
89 /// <seealso cref="IsKeyKnown"/>
90 /// </summary>
91 /// <param name="key">an object instance</param>
92 /// <param name="session">An instance of <c>ISession</c></param>
93 public override void RegisterSession(object key, ISession session)
95 if (parentTransactionScope != null)
97 // parentTransactionalScope.EnsureHasTransaction(session);
98 parentTransactionScope.RegisterSession(new KeyHolder(key, connection.ConnectionString), session);
100 else if (parentSimpleScope != null)
102 parentSimpleScope.RegisterSession(new KeyHolder(key, connection.ConnectionString), session);
105 base.RegisterSession(key, session);
108 /// <summary>
109 /// This method is invoked when the
110 /// <see cref="Castle.ActiveRecord.Framework.ISessionFactoryHolder"/>
111 /// instance needs a session instance. Instead of creating one it interrogates
112 /// the active scope for one. The scope implementation must check if it
113 /// has a session registered for the given key.
114 /// <seealso cref="RegisterSession"/>
115 /// </summary>
116 /// <param name="key">an object instance</param>
117 /// <returns>
118 /// <c>true</c> if the key exists within this scope instance
119 /// </returns>
120 public override bool IsKeyKnown(object key)
122 if (parentTransactionScope != null)
124 return parentTransactionScope.IsKeyKnown(new KeyHolder(key, connection.ConnectionString));
127 bool keyKnown = false;
129 if (parentSimpleScope != null)
131 keyKnown = parentSimpleScope.IsKeyKnown(new KeyHolder(key, connection.ConnectionString));
134 return keyKnown ? true : base.IsKeyKnown(key);
137 /// <summary>
138 /// This method should return the session instance associated with the key.
139 /// </summary>
140 /// <param name="key">an object instance</param>
141 /// <returns>
142 /// the session instance or null if none was found
143 /// </returns>
144 public override ISession GetSession(object key)
146 if (parentTransactionScope != null)
148 return parentTransactionScope.GetSession(new KeyHolder(key, connection.ConnectionString));
151 ISession session = null;
153 if (parentSimpleScope != null)
155 session = parentSimpleScope.GetSession(new KeyHolder(key, connection.ConnectionString));
158 session = session ?? base.GetSession(key);
160 return session;
163 /// <summary>
164 /// Performs the disposal.
165 /// </summary>
166 /// <param name="sessions">The sessions.</param>
167 protected override void PerformDisposal(ICollection<ISession> sessions)
169 if (parentTransactionScope == null && parentSimpleScope == null)
171 PerformDisposal(sessions, true, true);
175 /// <summary>
176 /// If the <see cref="WantsToCreateTheSession"/> returned
177 /// <c>true</c> then this method is invoked to allow
178 /// the scope to create a properly configured session
179 /// </summary>
180 /// <param name="sessionFactory">From where to open the session</param>
181 /// <param name="interceptor">the NHibernate interceptor</param>
182 /// <returns>the newly created session</returns>
183 public override ISession OpenSession(ISessionFactory sessionFactory, IInterceptor interceptor)
185 return sessionFactory.OpenSession(connection, interceptor);
188 /// <summary>
189 /// This is called when a session has a failure
190 /// </summary>
191 /// <param name="session">the session</param>
192 public override void FailSession(ISession session)
194 if (parentTransactionScope != null)
196 parentTransactionScope.VoteRollBack();
198 else
200 session.Clear();
204 private void OnTransactionCompleted(object sender, EventArgs e)
206 TransactionScope scope = (sender as TransactionScope);
207 scope.DiscardSessions( GetSessions() );
211 class KeyHolder
213 private readonly object inner;
214 private readonly String connectionString;
216 public KeyHolder(object inner, String connectionString)
218 this.inner = inner;
219 this.connectionString = connectionString;
222 public override bool Equals(object obj)
224 KeyHolder other = obj as KeyHolder;
226 if (other != null)
228 return ReferenceEquals(inner, other.inner) &&
229 connectionString == other.connectionString;
232 return false;
235 public override int GetHashCode()
237 return inner.GetHashCode() ^ connectionString.GetHashCode();