Adding a way to override the interceptor definition. This is required for cases when...
[castle.git] / ActiveRecord / Castle.ActiveRecord / Framework / SessionFactoryHolder.cs
blob513faa60f7ce1be6f838c59bd70c485887414905
1 // Copyright 2004-2007 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
17 using System;
18 using System.Threading;
19 using System.Collections;
20 using System.Runtime.CompilerServices;
22 using Iesi.Collections;
24 using NHibernate;
25 using NHibernate.Cfg;
27 using Castle.ActiveRecord.Framework.Scopes;
29 /// <summary>
30 /// Default implementation of <seealso cref="ISessionFactoryHolder"/>
31 /// </summary>
32 /// <remarks>
33 /// This class is thread safe
34 /// </remarks>
35 public class SessionFactoryHolder : MarshalByRefObject, ISessionFactoryHolder
37 private Hashtable type2Conf = Hashtable.Synchronized(new Hashtable());
38 private Hashtable type2SessFactory = Hashtable.Synchronized(new Hashtable());
39 private ReaderWriterLock readerWriterLock = new ReaderWriterLock();
40 private IThreadScopeInfo threadScopeInfo;
42 /// <summary>
43 /// Raised when a root type is registered.
44 /// </summary>
45 public event RootTypeHandler OnRootTypeRegistered;
47 /// <summary>
48 /// Associates a Configuration object to a root type
49 /// </summary>
50 /// <param name="rootType"></param>
51 /// <param name="cfg"></param>
52 public void Register(Type rootType, Configuration cfg)
54 type2Conf.Add(rootType, cfg);
56 if (OnRootTypeRegistered != null)
58 OnRootTypeRegistered(this, rootType);
62 /// <summary>
63 /// Requests the Configuration associated to the type.
64 /// </summary>
65 public Configuration GetConfiguration(Type type)
67 return type2Conf[type] as Configuration;
70 /// <summary>
71 /// Pendent
72 /// </summary>
73 public Configuration[] GetAllConfigurations()
75 HashedSet set = new HashedSet(type2Conf.Values);
77 Configuration[] confs = new Configuration[set.Count];
79 set.CopyTo(confs, 0);
81 return confs;
84 /// <summary>
85 /// Optimized with reader/writer lock.
86 /// </summary>
87 /// <param name="type"></param>
88 /// <returns></returns>
89 public ISessionFactory GetSessionFactory(Type type)
91 Type normalizedtype = GetRootType(type);
93 if (normalizedtype == null)
95 throw new ActiveRecordException("No configuration for ActiveRecord found in the type hierarchy -> " + type.FullName);
98 readerWriterLock.AcquireReaderLock(-1);
103 ISessionFactory sessFactory = null;
105 if (type2SessFactory.Contains(normalizedtype))
107 sessFactory = type2SessFactory[normalizedtype] as ISessionFactory;
110 if (sessFactory != null)
112 return sessFactory;
115 LockCookie lc = readerWriterLock.UpgradeToWriterLock(-1);
119 Configuration cfg = GetConfiguration(normalizedtype);
121 sessFactory = cfg.BuildSessionFactory();
123 type2SessFactory[normalizedtype] = sessFactory;
125 return sessFactory;
127 finally
129 readerWriterLock.DowngradeFromWriterLock(ref lc);
132 finally
134 readerWriterLock.ReleaseReaderLock();
138 /// <summary>
139 /// Creates a session for the associated type
140 /// </summary>
141 [MethodImpl(MethodImplOptions.Synchronized)]
142 public ISession CreateSession(Type type)
144 if (threadScopeInfo.HasInitializedScope)
146 return CreateScopeSession(type);
149 ISessionFactory sessionFactory = GetSessionFactory(type);
151 ISession session = OpenSession(sessionFactory);
153 return session;
156 /// <summary>
157 /// Gets the type of the root.
158 /// </summary>
159 /// <param name="type">The type.</param>
160 /// <returns></returns>
161 public Type GetRootType(Type type)
163 while(type != typeof(object))
165 if (type2Conf.ContainsKey(type)) return type;
167 type = type.BaseType;
169 #if DOTNET2
170 //to enable multiple database support for generic types
171 if (type.IsGenericType)
173 Type genericTypeDef = type.GetGenericTypeDefinition();
175 if (type2Conf.ContainsKey(genericTypeDef))
177 return genericTypeDef;
180 #endif
183 return typeof(ActiveRecordBase);
186 private static ISession OpenSession(ISessionFactory sessionFactory)
188 lock(sessionFactory)
190 return sessionFactory.OpenSession(InterceptorFacotry.Create());
194 private static ISession OpenSessionWithScope(ISessionScope scope, ISessionFactory sessionFactory)
196 lock(sessionFactory)
198 return scope.OpenSession(sessionFactory, InterceptorFacotry.Create());
202 /// <summary>
203 /// Releases the specified session
204 /// </summary>
205 /// <param name="session"></param>
206 public void ReleaseSession(ISession session)
208 if (threadScopeInfo.HasInitializedScope)
210 ReleaseScopedSession(session);
212 else
214 session.Flush();
215 session.Dispose();
219 /// <summary>
220 /// Gets or sets the implementation of <see cref="IThreadScopeInfo"/>
221 /// </summary>
222 /// <value></value>
223 public IThreadScopeInfo ThreadScopeInfo
225 get { return threadScopeInfo; }
228 ThreadScopeAccessor.Instance.ScopeInfo = value;
229 threadScopeInfo = value;
233 private ISession CreateScopeSession(Type type)
235 ISessionScope scope = threadScopeInfo.GetRegisteredScope();
236 ISessionFactory sessionFactory = GetSessionFactory(type);
237 #if DEBUG
238 System.Diagnostics.Debug.Assert( scope != null );
239 System.Diagnostics.Debug.Assert( sessionFactory != null );
240 #endif
241 if (scope.IsKeyKnown(sessionFactory))
243 return scope.GetSession(sessionFactory);
245 else
247 ISession session;
249 if (scope.WantsToCreateTheSession)
251 session = OpenSessionWithScope(scope, sessionFactory);
253 else
255 session = OpenSession(sessionFactory);
257 #if DEBUG
258 System.Diagnostics.Debug.Assert( session != null );
259 #endif
260 scope.RegisterSession(sessionFactory, session);
262 return session;
266 private void ReleaseScopedSession(ISession session)