Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / ActiveRecord / Castle.ActiveRecord / Framework / SessionFactoryHolder.cs
blob6a82e16239d45aeac66e2846488ccb7ab5ced59c
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
17 using System;
18 using System.Threading;
19 using System.Collections;
20 using System.Runtime.CompilerServices;
21 using Iesi.Collections;
22 using NHibernate;
23 using NHibernate.Cfg;
24 using Castle.ActiveRecord.Framework.Scopes;
26 /// <summary>
27 /// Default implementation of <seealso cref="ISessionFactoryHolder"/>
28 /// </summary>
29 /// <remarks>
30 /// This class is thread safe
31 /// </remarks>
32 public class SessionFactoryHolder : MarshalByRefObject, ISessionFactoryHolder
34 private readonly Hashtable type2Conf = Hashtable.Synchronized(new Hashtable());
35 private readonly Hashtable type2SessFactory = Hashtable.Synchronized(new Hashtable());
36 private readonly ReaderWriterLock readerWriterLock = new ReaderWriterLock();
37 private IThreadScopeInfo threadScopeInfo;
39 /// <summary>
40 /// Raised when a root type is registered.
41 /// </summary>
42 public event RootTypeHandler OnRootTypeRegistered;
44 /// <summary>
45 /// Associates a Configuration object to a root type
46 /// </summary>
47 /// <param name="rootType"></param>
48 /// <param name="cfg"></param>
49 public void Register(Type rootType, Configuration cfg)
51 type2Conf.Add(rootType, cfg);
53 if (OnRootTypeRegistered != null)
55 OnRootTypeRegistered(this, rootType);
59 /// <summary>
60 /// Requests the Configuration associated to the type.
61 /// </summary>
62 public Configuration GetConfiguration(Type type)
64 return type2Conf[type] as Configuration;
67 /// <summary>
68 /// Pendent
69 /// </summary>
70 public Configuration[] GetAllConfigurations()
72 HashedSet set = new HashedSet(type2Conf.Values);
74 Configuration[] confs = new Configuration[set.Count];
76 set.CopyTo(confs, 0);
78 return confs;
81 /// <summary>
82 /// Optimized with reader/writer lock.
83 /// </summary>
84 /// <param name="type"></param>
85 /// <returns></returns>
86 public ISessionFactory GetSessionFactory(Type type)
88 Type normalizedtype = GetRootType(type);
90 if (normalizedtype == null)
92 throw new ActiveRecordException("No configuration for ActiveRecord found in the type hierarchy -> " + type.FullName);
95 readerWriterLock.AcquireReaderLock(-1);
97 try
99 ISessionFactory sessFactory = type2SessFactory[normalizedtype] as ISessionFactory;
101 if (sessFactory != null)
103 return sessFactory;
106 LockCookie lc = readerWriterLock.UpgradeToWriterLock(-1);
110 sessFactory = type2SessFactory[normalizedtype] as ISessionFactory;
112 if (sessFactory != null)
114 return sessFactory;
116 Configuration cfg = GetConfiguration(normalizedtype);
118 sessFactory = cfg.BuildSessionFactory();
120 type2SessFactory[normalizedtype] = sessFactory;
122 return sessFactory;
124 finally
126 readerWriterLock.DowngradeFromWriterLock(ref lc);
129 finally
131 readerWriterLock.ReleaseReaderLock();
135 ///<summary>
136 /// This method allows direct registration
137 /// of a session factory to a type, bypassing the normal preperation that AR
138 /// usually does.
139 /// The main usage is in testing, so you would be able to switch the session factory
140 /// for each test.
141 /// Note that this will override the current session factory for the baseType.
142 ///</summary>
143 public void RegisterSessionFactory(ISessionFactory sessionFactory, Type baseType)
145 type2SessFactory[baseType] = sessionFactory;
148 /// <summary>
149 /// Creates a session for the associated type
150 /// </summary>
151 [MethodImpl(MethodImplOptions.Synchronized)]
152 public ISession CreateSession(Type type)
154 if (threadScopeInfo.HasInitializedScope)
156 return CreateScopeSession(type);
159 ISessionFactory sessionFactory = GetSessionFactory(type);
161 ISession session = OpenSession(sessionFactory);
163 return session;
166 /// <summary>
167 /// Gets the type of the root.
168 /// </summary>
169 /// <param name="type">The type.</param>
170 /// <returns></returns>
171 public Type GetRootType(Type type)
173 while(type != typeof(object))
175 if (type2Conf.ContainsKey(type))
177 return type;
180 type = type.BaseType;
182 //to enable multiple database support for generic types
183 if (type.IsGenericType)
185 Type genericTypeDef = type.GetGenericTypeDefinition();
187 if (type2Conf.ContainsKey(genericTypeDef))
189 return genericTypeDef;
194 return typeof(ActiveRecordBase);
197 private static ISession OpenSession(ISessionFactory sessionFactory)
199 lock(sessionFactory)
201 return sessionFactory.OpenSession(InterceptorFactory.Create());
205 private static ISession OpenSessionWithScope(ISessionScope scope, ISessionFactory sessionFactory)
207 lock(sessionFactory)
209 return scope.OpenSession(sessionFactory, InterceptorFactory.Create());
213 /// <summary>
214 /// Releases the specified session
215 /// </summary>
216 /// <param name="session"></param>
217 public void ReleaseSession(ISession session)
219 if (!threadScopeInfo.HasInitializedScope)
221 session.Flush();
222 session.Dispose();
226 /// <summary>
227 /// Called if an action on the session fails
228 /// </summary>
229 /// <param name="session"></param>
230 public void FailSession(ISession session)
232 if (threadScopeInfo.HasInitializedScope)
234 ISessionScope scope = threadScopeInfo.GetRegisteredScope();
235 scope.FailSession(session);
237 else
239 session.Clear();
243 /// <summary>
244 /// Gets or sets the implementation of <see cref="IThreadScopeInfo"/>
245 /// </summary>
246 /// <value></value>
247 public IThreadScopeInfo ThreadScopeInfo
249 get { return threadScopeInfo; }
252 ThreadScopeAccessor.Instance.ScopeInfo = value;
253 threadScopeInfo = value;
257 private ISession CreateScopeSession(Type type)
259 ISessionScope scope = threadScopeInfo.GetRegisteredScope();
260 ISessionFactory sessionFactory = GetSessionFactory(type);
261 #if DEBUG
262 System.Diagnostics.Debug.Assert(scope != null);
263 System.Diagnostics.Debug.Assert(sessionFactory != null);
264 #endif
265 if (scope.IsKeyKnown(sessionFactory))
267 return scope.GetSession(sessionFactory);
269 else
271 ISession session;
273 if (scope.WantsToCreateTheSession)
275 session = OpenSessionWithScope(scope, sessionFactory);
277 else
279 session = OpenSession(sessionFactory);
281 #if DEBUG
282 System.Diagnostics.Debug.Assert(session != null);
283 #endif
284 scope.RegisterSession(sessionFactory, session);
286 return session;