1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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
18 using System
.Threading
;
19 using System
.Collections
;
20 using System
.Runtime
.CompilerServices
;
22 using Iesi
.Collections
;
27 using Castle
.ActiveRecord
.Framework
.Scopes
;
30 /// Default implementation of <seealso cref="ISessionFactoryHolder"/>
33 /// This class is thread safe
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
;
43 /// Raised when a root type is registered.
45 public event RootTypeHandler OnRootTypeRegistered
;
48 /// Associates a Configuration object to a root type
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
);
63 /// Requests the Configuration associated to the type.
65 public Configuration
GetConfiguration(Type type
)
67 return type2Conf
[type
] as Configuration
;
73 public Configuration
[] GetAllConfigurations()
75 HashedSet
set = new HashedSet(type2Conf
.Values
);
77 Configuration
[] confs
= new Configuration
[set.Count
];
85 /// Optimized with reader/writer lock.
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)
115 LockCookie lc
= readerWriterLock
.UpgradeToWriterLock(-1);
119 Configuration cfg
= GetConfiguration(normalizedtype
);
121 sessFactory
= cfg
.BuildSessionFactory();
123 type2SessFactory
[normalizedtype
] = sessFactory
;
129 readerWriterLock
.DowngradeFromWriterLock(ref lc
);
134 readerWriterLock
.ReleaseReaderLock();
139 /// Creates a session for the associated type
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
);
157 /// Gets the type of the root.
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
;
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
;
183 return typeof(ActiveRecordBase
);
186 private static ISession
OpenSession(ISessionFactory sessionFactory
)
190 return sessionFactory
.OpenSession(InterceptorFacotry
.Create());
194 private static ISession
OpenSessionWithScope(ISessionScope scope
, ISessionFactory sessionFactory
)
198 return scope
.OpenSession(sessionFactory
, InterceptorFacotry
.Create());
203 /// Releases the specified session
205 /// <param name="session"></param>
206 public void ReleaseSession(ISession session
)
208 if (threadScopeInfo
.HasInitializedScope
)
210 ReleaseScopedSession(session
);
220 /// Gets or sets the implementation of <see cref="IThreadScopeInfo"/>
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
);
238 System
.Diagnostics
.Debug
.Assert( scope
!= null );
239 System
.Diagnostics
.Debug
.Assert( sessionFactory
!= null );
241 if (scope
.IsKeyKnown(sessionFactory
))
243 return scope
.GetSession(sessionFactory
);
249 if (scope
.WantsToCreateTheSession
)
251 session
= OpenSessionWithScope(scope
, sessionFactory
);
255 session
= OpenSession(sessionFactory
);
258 System
.Diagnostics
.Debug
.Assert( session
!= null );
260 scope
.RegisterSession(sessionFactory
, session
);
266 private void ReleaseScopedSession(ISession session
)