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
.Facilities
.ActiveRecordIntegration
18 using System
.Reflection
;
19 using System
.Collections
;
20 using System
.Configuration
;
22 using Castle
.ActiveRecord
;
23 using Castle
.ActiveRecord
.Framework
;
24 using Castle
.ActiveRecord
.Framework
.Config
;
25 using Castle
.MicroKernel
.Facilities
;
27 using Castle
.Core
.Configuration
;
28 using Castle
.Core
.Logging
;
29 using Castle
.Services
.Transaction
;
31 using TransactionMode
= Castle
.Services
.Transaction
.TransactionMode
;
34 /// Provides integration with ActiveRecord framework.
36 public class ActiveRecordFacility
: AbstractFacility
38 private ILogger log
= NullLogger
.Instance
;
39 private int sessionFactoryCount
, sessionFactoryHolderCount
;
41 public ActiveRecordFacility()
45 protected override void Init()
47 if (Kernel
.HasComponent(typeof(ILoggerFactory
)))
49 log
= ((ILoggerFactory
) Kernel
[typeof(ILoggerFactory
)]).Create(GetType());
52 log
.Debug("Initializing AR Facility");
54 if (FacilityConfig
== null)
56 log
.FatalError("Configuration for AR Facility not found.");
57 throw new FacilityException("Sorry, but the ActiveRecord Facility depends on a proper configuration node.");
60 IConfiguration assemblyConfig
= FacilityConfig
.Children
["assemblies"];
62 if (assemblyConfig
== null || assemblyConfig
.Children
.Count
== 0)
64 log
.FatalError("No assembly specified on AR Facility config.");
66 throw new FacilityException("You need to specify at least one assembly that contains " +
67 "the ActiveRecord classes. For example, <assemblies><item>MyAssembly</item></assemblies>");
70 ConfigurationCollection assembliyConfigNodes
= assemblyConfig
.Children
;
72 ArrayList assemblies
= new ArrayList(assembliyConfigNodes
.Count
);
74 foreach(IConfiguration assemblyNode
in assembliyConfigNodes
)
76 assemblies
.Add(ObtainAssembly(assemblyNode
.Value
));
79 Kernel
.ComponentCreated
+= new Castle
.MicroKernel
.ComponentInstanceDelegate(Kernel_ComponentCreated
);
81 SetUpTransactionManager();
83 InitializeFramework(assemblies
);
86 public override void Dispose()
88 log
.Info("AR Facility is being disposed.");
92 private void InitializeFramework(ArrayList assemblies
)
94 log
.Info("Initializing ActiveRecord Framework");
96 ActiveRecordStarter
.ResetInitializationFlag();
97 ActiveRecordStarter
.SessionFactoryHolderCreated
+= new SessionFactoryHolderDelegate(OnSessionFactoryHolderCreated
);
101 ConfigurationSourceAdapter adapter
= new ConfigurationSourceAdapter(FacilityConfig
);
103 if (log
.IsDebugEnabled
)
105 log
.Debug("Is Debug enabled {0}", adapter
.Debug
);
106 log
.Debug("ThreadScopeInfo {0}", adapter
.ThreadScopeInfoImplementation
);
107 log
.Debug("NamingStrategy {0}", adapter
.NamingStrategyImplementation
);
108 log
.Debug("SessionFactoryHolder {0}", adapter
.SessionFactoryHolderImplementation
);
111 ActiveRecordStarter
.Initialize(
112 (Assembly
[]) assemblies
.ToArray(typeof(Assembly
)), adapter
);
116 ActiveRecordStarter
.SessionFactoryHolderCreated
-= new SessionFactoryHolderDelegate(OnSessionFactoryHolderCreated
);
120 private void SetUpTransactionManager()
122 if (!Kernel
.HasComponent(typeof(ITransactionManager
)))
124 log
.Info("No Transaction Manager registered on Kernel, registering AR Transaction Manager");
126 Kernel
.AddComponent("ar.transaction.manager",
127 typeof(ITransactionManager
), typeof(DefaultTransactionManager
));
131 private void OnNewTransaction(ITransaction transaction
, TransactionMode transactionMode
, IsolationMode isolationMode
, bool distributedTransaction
)
133 if (!transaction
.DistributedTransaction
)
135 transaction
.Enlist(new TransactionScopeResourceAdapter(transactionMode
));
139 private Assembly
ObtainAssembly(String assemblyName
)
141 log
.Debug("Loading model assembly '{0}' for AR", assemblyName
);
142 return Assembly
.Load(assemblyName
);
145 private void Kernel_ComponentCreated(ComponentModel model
, object instance
)
147 if (model
.Service
!= null && model
.Service
== typeof(ITransactionManager
))
149 (instance
as ITransactionManager
).TransactionCreated
+= new TransactionCreationInfoDelegate(OnNewTransaction
);
153 private void OnSessionFactoryHolderCreated(Castle
.ActiveRecord
.Framework
.ISessionFactoryHolder holder
)
155 holder
.OnRootTypeRegistered
+= new RootTypeHandler(OnRootTypeRegistered
);
157 string componentName
= "activerecord.sessionfactoryholder";
159 if (Kernel
.HasComponent(componentName
))
161 componentName
+= "." + (++sessionFactoryHolderCount
);
164 while(Kernel
.HasComponent(componentName
))
167 componentName
.Substring(0, componentName
.LastIndexOf('.'))
168 + (++sessionFactoryHolderCount
);
171 log
.Info("Registering SessionFactoryHolder named '{0}': {1}", componentName
, holder
);
172 Kernel
.AddComponentInstance(
173 componentName
, typeof(ISessionFactoryHolder
), holder
);
176 private void OnRootTypeRegistered(object sender
, Type rootType
)
178 string componentName
= "activerecord.sessionfactory";
180 if (Kernel
.HasComponent(componentName
))
182 componentName
+= "." + (++sessionFactoryCount
);
185 while(Kernel
.HasComponent(componentName
))
188 componentName
.Substring(0, componentName
.LastIndexOf('.'))
189 + (++sessionFactoryCount
);
192 log
.Info("Registering SessionFactory named '{0}' for the root type {1}: {2}", componentName
, rootType
, sender
);
193 Kernel
.AddComponentInstance(
195 typeof(NHibernate
.ISessionFactory
),
196 new SessionFactoryDelegate((ISessionFactoryHolder
) sender
, rootType
));
200 internal class ConfigurationSourceAdapter
: InPlaceConfigurationSource
202 public ConfigurationSourceAdapter(IConfiguration facilityConfig
)
204 String isWeb
= facilityConfig
.Attributes
["isWeb"];
205 String threadinfotype
= facilityConfig
.Attributes
["threadinfotype"];
206 string isDebug
= facilityConfig
.Attributes
["isDebug"];
207 string sessionfactoryholdertype
= facilityConfig
.Attributes
["sessionfactoryholdertype"];
208 string isLazyByDefault
= facilityConfig
.Attributes
["default-lazy"];
209 string pluralize
= facilityConfig
.Attributes
["pluralizeTableNames"];
210 string verifyModelsAgainstDBSchema
= facilityConfig
.Attributes
["verifyModelsAgainstDBSchema"];
212 SetUpThreadInfoType(ConvertBool(isWeb
), threadinfotype
);
213 SetDebugFlag(ConvertBool(isDebug
));
214 SetUpSessionFactoryHolderType(sessionfactoryholdertype
);
215 SetIsLazyByDefault(ConvertBool(isLazyByDefault
));
216 PluralizeTableNames
= ConvertBool(pluralize
);
217 VerifyModelsAgainstDBSchema
= ConvertBool(verifyModelsAgainstDBSchema
);
219 foreach(IConfiguration config
in facilityConfig
.Children
)
221 if (!"config".Equals(config
.Name
)) continue;
223 Type type
= typeof(ActiveRecordBase
);
225 String typeAtt
= config
.Attributes
["type"];
229 type
= ObtainType(typeAtt
);
232 Add(type
, AdjustConfiguration(config
));
236 private IConfiguration
AdjustConfiguration(IConfiguration config
)
238 MutableConfiguration newConfig
= new MutableConfiguration("entry");
240 foreach(IConfiguration configNode
in config
.Children
)
242 String key
= configNode
.Attributes
["key"];
243 String
value = configNode
.Attributes
["value"];
245 newConfig
.Children
.Add(new MutableConfiguration(key
, value));
251 private static Type
ObtainType(String typeAtt
)
253 Type type
= Type
.GetType(typeAtt
, false, false);
257 String message
= String
.Format("Could not obtain type from name {0}", typeAtt
);
259 throw new ConfigurationErrorsException(message
);
265 private static bool ConvertBool(string boolString
)
267 return "true".Equals(boolString
, StringComparison
.OrdinalIgnoreCase
);