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
.MonoRail
.Framework
18 using System
.Collections
;
19 using System
.Collections
.Specialized
;
20 using System
.ComponentModel
;
21 using System
.Configuration
;
24 using Castle
.Components
.Validator
;
26 using Castle
.MonoRail
.Framework
.Configuration
;
27 using Castle
.MonoRail
.Framework
.Internal
;
28 using Castle
.MonoRail
.Framework
.Services
;
29 using Castle
.MonoRail
.Framework
.Services
.AjaxProxyGenerator
;
32 /// Parent Service container for the MonoRail framework
34 public class MonoRailServiceContainer
: AbstractServiceContainer
36 /// <summary>The only one Extension Manager</summary>
37 protected internal ExtensionManager extensionManager
;
39 /// <summary>Prevents GC from collecting the extensions</summary>
40 private IList extensions
= new ArrayList();
42 /// <summary>Keeps only one copy of the config</summary>
43 private MonoRailConfiguration config
;
45 /// <summary></summary>
46 private IDictionary extension2handler
;
49 /// Initializes a new instance of the <see cref="MonoRailServiceContainer"/> class.
51 public MonoRailServiceContainer()
53 extension2handler
= new HybridDictionary(true);
57 /// Initializes a new instance of the <see cref="MonoRailServiceContainer"/> class.
59 /// <param name="config">The config.</param>
60 public MonoRailServiceContainer(MonoRailConfiguration config
) : this()
66 /// Allows registration without the configuration
68 public void RegisterBaseService(Type service
, object instance
)
70 InvokeServiceEnabled(instance
);
71 InvokeInitialize(instance
);
73 AddService(service
, instance
);
77 /// Initializes the container state and its services
81 DiscoverHttpHandlerExtensions();
85 MonoRailConfiguration config
= ObtainConfiguration();
87 InitExtensions(config
);
92 /// Checks whether the specified URL is to be handled by MonoRail
94 /// <param name="url">The URL.</param>
96 /// <see langword="true"/> if it is a MonoRail request; otherwise, <see langword="false"/>.
98 public bool IsMonoRailRequest(String url
)
100 String extension
= Path
.GetExtension(url
);
102 return extension2handler
.Contains(extension
);
105 private void DiscoverHttpHandlerExtensions()
107 XmlDocument webConfig
= new XmlDocument();
108 webConfig
.Load(Path
.Combine(AppDomain
.CurrentDomain
.BaseDirectory
, "web.config"));
110 XmlNodeList addNodes
= webConfig
.DocumentElement
.SelectNodes(
111 "/configuration/system.web/httpHandlers/add");
113 if (addNodes
.Count
== 0)
115 // Possibly the web.config configuration node is using a namespace declaration
117 XmlElement systemWebElem
= webConfig
.DocumentElement
["system.web"];
118 XmlElement handlers
= systemWebElem
["httpHandlers"];
119 addNodes
= handlers
.ChildNodes
;
124 foreach(XmlNode addNode
in addNodes
)
126 if (addNode
.NodeType
!= XmlNodeType
.Element
)
131 XmlElement addElem
= (XmlElement
) addNode
;
133 String type
= addElem
.GetAttribute("type");
135 if (type
.StartsWith("Castle.MonoRail.Framework.MonoRailHttpHandlerFactory"))
137 String extension
= addElem
.GetAttribute("path").Substring(1);
138 extension2handler
.Add(extension
, String
.Empty
);
145 throw new RailsException("We inspected the web.config httpHandlers section and " +
146 "couldn't find an extension that mapped to MonoRailHttpHandlerFactory. " +
147 "Is your configuration right to use MonoRail?");
152 /// Reads the configuration and initializes
153 /// registered extensions.
155 /// <param name="config">The configuration object</param>
156 private void InitExtensions(MonoRailConfiguration config
)
158 extensionManager
= new ExtensionManager(this);
160 foreach(ExtensionEntry entry
in config
.ExtensionEntries
)
162 AssertImplementsService(typeof(IMonoRailExtension
), entry
.ExtensionType
);
164 IMonoRailExtension extension
= (IMonoRailExtension
) ActivateService(entry
.ExtensionType
);
166 extension
.SetExtensionConfigNode(entry
.ExtensionNode
);
168 extensions
.Add(extension
);
173 /// Coordinates the instantiation, registering and initialization (lifecycle-wise)
174 /// of the services used by MonoRail.
176 /// <param name="config">The configuration object</param>
177 private void InitServices(MonoRailConfiguration config
)
179 AddService(typeof(ExtensionManager
), extensionManager
);
180 AddService(typeof(MonoRailConfiguration
), config
);
182 IList services
= InstantiateAndRegisterServices(config
.ServiceEntries
);
184 LifecycleService(services
);
185 LifecycleService(extensions
);
187 LifecycleInitialize(services
);
188 LifecycleInitialize(extensions
);
192 /// Checks for services that implements <see cref="IInitializable"/>
193 /// or <see cref="ISupportInitialize"/> and initialize them through the interface
195 /// <param name="services">List of MonoRail's services</param>
196 private void LifecycleInitialize(IList services
)
198 foreach(object instance
in services
)
200 InvokeInitialize(instance
);
205 /// Checks for services that implements <see cref="IServiceEnabledComponent"/>
206 /// and invoke <see cref="IServiceEnabledComponent.Service"/> on them
208 /// <param name="services">List of MonoRail's services</param>
209 private void LifecycleService(IList services
)
211 foreach(object instance
in services
)
213 InvokeServiceEnabled(instance
);
218 /// Instantiates and registers the services used by MonoRail.
220 /// <param name="services">The service's registry</param>
221 /// <returns>List of service's instances</returns>
222 private IList
InstantiateAndRegisterServices(ServiceEntryCollection services
)
224 IList instances
= new ArrayList();
228 foreach(DictionaryEntry entry
in services
.ServiceImplMap
)
230 Type service
= (Type
) entry
.Key
;
231 Type impl
= (Type
) entry
.Value
;
233 AssertImplementsService(service
, impl
);
235 object instance
= ActivateService(impl
);
237 AddService(service
, instance
);
239 instances
.Add(instance
);
244 foreach(Type type
in services
.CustomServices
)
246 object instance
= ActivateService(type
);
248 AddService(type
, instance
);
250 instances
.Add(instance
);
257 /// Registers the default implementation of services, if
258 /// they are not registered
260 private void InitConfiguration()
262 config
= ObtainConfiguration();
264 RegisterMissingServices(config
);
268 /// Checks whether non-optional services were supplied
269 /// through the configuration, and if not, register the
270 /// default implementation.
272 /// <param name="config">The configuration object</param>
273 private void RegisterMissingServices(MonoRailConfiguration config
)
275 ServiceEntryCollection services
= config
.ServiceEntries
;
277 services
.RegisterService(ServiceIdentification
.ViewEngineManager
,
278 typeof(DefaultViewEngineManager
));
281 if (!services
.HasService(ServiceIdentification
.ViewSourceLoader
))
283 services
.RegisterService(ServiceIdentification
.ViewSourceLoader
,
284 typeof(FileAssemblyViewSourceLoader
));
286 if (!services
.HasService(ServiceIdentification
.ScaffoldingSupport
))
288 Type defaultScaffoldingType
=
289 TypeLoadUtil
.GetType(
290 TypeLoadUtil
.GetEffectiveTypeName(
291 "Castle.MonoRail.ActiveRecordScaffold.ScaffoldingSupport, Castle.MonoRail.ActiveRecordScaffold"), true);
293 if (defaultScaffoldingType
!= null)
295 services
.RegisterService(ServiceIdentification
.ScaffoldingSupport
, defaultScaffoldingType
);
298 if (!services
.HasService(ServiceIdentification
.ControllerFactory
))
300 if (config
.ControllersConfig
.CustomControllerFactory
!= null)
302 services
.RegisterService(ServiceIdentification
.ControllerFactory
,
303 config
.ControllersConfig
.CustomControllerFactory
);
307 services
.RegisterService(ServiceIdentification
.ControllerFactory
,
308 typeof(DefaultControllerFactory
));
311 if (!services
.HasService(ServiceIdentification
.ViewComponentFactory
))
313 if (config
.ViewComponentsConfig
.CustomViewComponentFactory
!= null)
315 services
.RegisterService(ServiceIdentification
.ViewComponentFactory
,
316 config
.ViewComponentsConfig
.CustomViewComponentFactory
);
320 services
.RegisterService(ServiceIdentification
.ViewComponentFactory
,
321 typeof(DefaultViewComponentFactory
));
324 if (!services
.HasService(ServiceIdentification
.FilterFactory
))
326 if (config
.CustomFilterFactory
!= null)
328 services
.RegisterService(ServiceIdentification
.FilterFactory
,
329 config
.CustomFilterFactory
);
333 services
.RegisterService(ServiceIdentification
.FilterFactory
,
334 typeof(DefaultFilterFactory
));
337 if (!services
.HasService(ServiceIdentification
.ResourceFactory
))
339 services
.RegisterService(ServiceIdentification
.ResourceFactory
, typeof(DefaultResourceFactory
));
341 if (!services
.HasService(ServiceIdentification
.EmailSender
))
343 services
.RegisterService(ServiceIdentification
.EmailSender
, typeof(MonoRailSmtpSender
));
345 if (!services
.HasService(ServiceIdentification
.ControllerDescriptorProvider
))
347 services
.RegisterService(ServiceIdentification
.ControllerDescriptorProvider
,
348 typeof(DefaultControllerDescriptorProvider
));
350 if (!services
.HasService(ServiceIdentification
.ResourceDescriptorProvider
))
352 services
.RegisterService(ServiceIdentification
.ResourceDescriptorProvider
, typeof(DefaultResourceDescriptorProvider
));
354 if (!services
.HasService(ServiceIdentification
.RescueDescriptorProvider
))
356 services
.RegisterService(ServiceIdentification
.RescueDescriptorProvider
, typeof(DefaultRescueDescriptorProvider
));
358 if (!services
.HasService(ServiceIdentification
.LayoutDescriptorProvider
))
360 services
.RegisterService(ServiceIdentification
.LayoutDescriptorProvider
, typeof(DefaultLayoutDescriptorProvider
));
362 if (!services
.HasService(ServiceIdentification
.HelperDescriptorProvider
))
364 services
.RegisterService(ServiceIdentification
.HelperDescriptorProvider
, typeof(DefaultHelperDescriptorProvider
));
366 if (!services
.HasService(ServiceIdentification
.FilterDescriptorProvider
))
368 services
.RegisterService(ServiceIdentification
.FilterDescriptorProvider
, typeof(DefaultFilterDescriptorProvider
));
370 if (!services
.HasService(ServiceIdentification
.EmailTemplateService
))
372 services
.RegisterService(ServiceIdentification
.EmailTemplateService
, typeof(EmailTemplateService
));
374 if (!services
.HasService(ServiceIdentification
.ControllerTree
))
376 services
.RegisterService(ServiceIdentification
.ControllerTree
, typeof(DefaultControllerTree
));
378 if (!services
.HasService(ServiceIdentification
.CacheProvider
))
380 services
.RegisterService(ServiceIdentification
.CacheProvider
, typeof(DefaultCacheProvider
));
382 if (!services
.HasService(ServiceIdentification
.ExecutorFactory
))
384 services
.RegisterService(ServiceIdentification
.ExecutorFactory
, typeof(DefaultControllerLifecycleExecutorFactory
));
386 if (!services
.HasService(ServiceIdentification
.TransformationFilterFactory
))
388 services
.RegisterService(ServiceIdentification
.TransformationFilterFactory
, typeof(DefaultTransformFilterFactory
));
390 if (!services
.HasService(ServiceIdentification
.TransformFilterDescriptorProvider
))
392 services
.RegisterService(ServiceIdentification
.TransformFilterDescriptorProvider
,
393 typeof(DefaultTransformFilterDescriptorProvider
));
396 if (!services
.HasService(ServiceIdentification
.UrlBuilder
))
398 services
.RegisterService(ServiceIdentification
.UrlBuilder
, typeof(DefaultUrlBuilder
));
400 if (!services
.HasService(ServiceIdentification
.UrlTokenizer
))
402 services
.RegisterService(ServiceIdentification
.UrlTokenizer
, typeof(DefaultUrlTokenizer
));
404 if (!services
.HasService(ServiceIdentification
.ValidatorRegistry
))
406 services
.RegisterService(ServiceIdentification
.ValidatorRegistry
, typeof(CachedValidationRegistry
));
409 if (!services
.HasService(ServiceIdentification
.AjaxProxyGenerator
))
411 services
.RegisterService(ServiceIdentification
.AjaxProxyGenerator
, typeof(PrototypeAjaxProxyGenerator
));
415 private object ActivateService(Type type
)
419 return Activator
.CreateInstance(type
);
423 String message
= String
.Format("Initialization Exception: " +
424 "Could not instantiate {0}", type
.FullName
);
425 throw new ConfigurationErrorsException(message
, ex
);
429 private void InvokeInitialize(object instance
)
431 IInitializable initializable
= instance
as IInitializable
;
433 if (initializable
!= null)
435 initializable
.Initialize();
438 ISupportInitialize suppInitialize
= instance
as ISupportInitialize
;
440 if (suppInitialize
!= null)
442 suppInitialize
.BeginInit();
443 suppInitialize
.EndInit();
447 private void InvokeServiceEnabled(object instance
)
449 IServiceEnabledComponent serviceEnabled
= instance
as IServiceEnabledComponent
;
451 if (serviceEnabled
!= null)
453 serviceEnabled
.Service(this);
457 private MonoRailConfiguration
ObtainConfiguration()
461 config
= MonoRailConfiguration
.GetConfig();
467 private void AssertImplementsService(Type service
, Type impl
)
469 if (!service
.IsAssignableFrom(impl
))
471 String message
= String
.Format("Initialization Exception: " +
472 "Service {0} does not implement or extend {1}", impl
.FullName
, service
.FullName
);
473 throw new ConfigurationErrorsException(message
);