- Implemented support for view component caching. Just use the attribute
[castle.git] / MonoRail / Castle.MonoRail.Framework / MonoRailServiceContainer.cs
blob55116fb3aac5be4509700a37322b09406dff8395
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.MonoRail.Framework
17 using System;
18 using System.Collections;
19 using System.ComponentModel;
20 using System.Configuration;
21 using System.IO;
22 using System.Xml;
23 using Castle.Components.Validator;
24 using Castle.Core;
25 using Castle.MonoRail.Framework.Configuration;
26 using Castle.MonoRail.Framework.Internal;
27 using Castle.MonoRail.Framework.Services;
28 using Castle.MonoRail.Framework.Services.AjaxProxyGenerator;
30 /// <summary>
31 /// Parent Service container for the MonoRail framework
32 /// </summary>
33 public class MonoRailServiceContainer : AbstractServiceContainer
35 /// <summary></summary>
36 private static string mrExtension = ".castle";
38 /// <summary>The only one Extension Manager</summary>
39 protected internal ExtensionManager extensionManager;
41 /// <summary>Prevents GC from collecting the extensions</summary>
42 private IList extensions = new ArrayList();
44 /// <summary>Keeps only one copy of the config</summary>
45 private MonoRailConfiguration config;
48 /// <summary>
49 /// Initializes a new instance of the <see cref="MonoRailServiceContainer"/> class.
50 /// </summary>
51 public MonoRailServiceContainer()
55 /// <summary>
56 /// Initializes a new instance of the <see cref="MonoRailServiceContainer"/> class.
57 /// </summary>
58 /// <param name="config">The config.</param>
59 public MonoRailServiceContainer(MonoRailConfiguration config) : this()
61 this.config = config;
64 /// <summary>
65 /// Allows registration without the configuration
66 /// </summary>
67 public void RegisterBaseService(Type service, object instance)
69 InvokeServiceEnabled(instance);
70 InvokeInitialize(instance);
72 AddService(service, instance);
75 /// <summary>
76 /// Initializes the container state and its services
77 /// </summary>
78 public void Start()
80 DiscoverHttpHandlerExtensions();
82 InitConfiguration();
84 MonoRailConfiguration config = ObtainConfiguration();
86 InitExtensions(config);
87 InitServices(config);
90 /// <summary>
91 /// Checks whether the specified URL is to be handled by MonoRail
92 /// </summary>
93 /// <param name="url">The URL.</param>
94 /// <returns>
95 /// <see langword="true"/> if it is a MonoRail request; otherwise, <see langword="false"/>.
96 /// </returns>
97 public bool IsMonoRailRequest(String url)
99 String extension = Path.GetExtension(url);
101 return string.Compare(mrExtension, extension, StringComparison.InvariantCultureIgnoreCase) == 0;
104 /// <summary></summary>
105 public static string MonoRailExtension
107 get { return mrExtension; }
110 private static void DiscoverHttpHandlerExtensions()
112 XmlDocument webConfig = new XmlDocument();
113 webConfig.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config"));
115 XmlNodeList addNodes = webConfig.DocumentElement.SelectNodes(
116 "/configuration/system.web/httpHandlers/add");
118 if (addNodes.Count == 0)
120 // Possibly the web.config configuration node is using a namespace declaration
122 XmlElement systemWebElem = webConfig.DocumentElement["system.web"];
123 XmlElement handlers = systemWebElem["httpHandlers"];
124 addNodes = handlers.ChildNodes;
127 bool found = false;
129 foreach(XmlNode addNode in addNodes)
131 if (addNode.NodeType != XmlNodeType.Element)
133 continue;
136 XmlElement addElem = (XmlElement) addNode;
138 String type = addElem.GetAttribute("type");
140 if (type.StartsWith("Castle.MonoRail.Framework.MonoRailHttpHandlerFactory"))
142 mrExtension = addElem.GetAttribute("path").Substring(1);
143 found = true;
147 if (!found)
149 throw new MonoRailException("We inspected the web.config httpHandlers section and " +
150 "couldn't find an extension that mapped to MonoRailHttpHandlerFactory. " +
151 "Is your configuration right to use MonoRail?");
155 /// <summary>
156 /// Reads the configuration and initializes
157 /// registered extensions.
158 /// </summary>
159 /// <param name="config">The configuration object</param>
160 private void InitExtensions(MonoRailConfiguration config)
162 extensionManager = new ExtensionManager(this);
164 foreach(ExtensionEntry entry in config.ExtensionEntries)
166 AssertImplementsService(typeof(IMonoRailExtension), entry.ExtensionType);
168 IMonoRailExtension extension = (IMonoRailExtension) ActivateService(entry.ExtensionType);
170 extension.SetExtensionConfigNode(entry.ExtensionNode);
172 extensions.Add(extension);
176 /// <summary>
177 /// Coordinates the instantiation, registering and initialization (lifecycle-wise)
178 /// of the services used by MonoRail.
179 /// </summary>
180 /// <param name="config">The configuration object</param>
181 private void InitServices(MonoRailConfiguration config)
183 AddService(typeof(ExtensionManager), extensionManager);
184 AddService(typeof(MonoRailConfiguration), config);
186 IList services = InstantiateAndRegisterServices(config.ServiceEntries);
188 LifecycleService(services);
189 LifecycleService(extensions);
191 LifecycleInitialize(services);
192 LifecycleInitialize(extensions);
195 /// <summary>
196 /// Checks for services that implements <see cref="IInitializable"/>
197 /// or <see cref="ISupportInitialize"/> and initialize them through the interface
198 /// </summary>
199 /// <param name="services">List of MonoRail's services</param>
200 private void LifecycleInitialize(IList services)
202 foreach(object instance in services)
204 InvokeInitialize(instance);
208 /// <summary>
209 /// Checks for services that implements <see cref="IServiceEnabledComponent"/>
210 /// and invoke <see cref="IServiceEnabledComponent.Service"/> on them
211 /// </summary>
212 /// <param name="services">List of MonoRail's services</param>
213 private void LifecycleService(IList services)
215 foreach(object instance in services)
217 InvokeServiceEnabled(instance);
221 /// <summary>
222 /// Instantiates and registers the services used by MonoRail.
223 /// </summary>
224 /// <param name="services">The service's registry</param>
225 /// <returns>List of service's instances</returns>
226 private IList InstantiateAndRegisterServices(ServiceEntryCollection services)
228 IList instances = new ArrayList();
230 // Builtin services
232 foreach(DictionaryEntry entry in services.ServiceImplMap)
234 Type service = (Type) entry.Key;
235 Type impl = (Type) entry.Value;
237 AssertImplementsService(service, impl);
239 object instance = ActivateService(impl);
241 AddService(service, instance);
243 instances.Add(instance);
246 // Custom services
248 foreach(Type type in services.CustomServices)
250 object instance = ActivateService(type);
252 AddService(type, instance);
254 instances.Add(instance);
257 return instances;
260 /// <summary>
261 /// Registers the default implementation of services, if
262 /// they are not registered
263 /// </summary>
264 private void InitConfiguration()
266 config = ObtainConfiguration();
268 RegisterMissingServices(config);
271 /// <summary>
272 /// Checks whether non-optional services were supplied
273 /// through the configuration, and if not, register the
274 /// default implementation.
275 /// </summary>
276 /// <param name="config">The configuration object</param>
277 private static void RegisterMissingServices(MonoRailConfiguration config)
279 ServiceEntryCollection services = config.ServiceEntries;
281 services.RegisterService(ServiceIdentification.ViewEngineManager,
282 typeof(DefaultViewEngineManager));
285 if (!services.HasService(ServiceIdentification.ViewSourceLoader))
287 services.RegisterService(ServiceIdentification.ViewSourceLoader,
288 typeof(FileAssemblyViewSourceLoader));
290 if (!services.HasService(ServiceIdentification.ViewComponentDescriptorProvider))
292 services.RegisterService(ServiceIdentification.ViewComponentDescriptorProvider,
293 typeof(DefaultViewComponentDescriptorProvider));
295 if (!services.HasService(ServiceIdentification.ScaffoldingSupport))
297 Type defaultScaffoldingType =
298 TypeLoadUtil.GetType(
299 TypeLoadUtil.GetEffectiveTypeName(
300 "Castle.MonoRail.ActiveRecordScaffold.ScaffoldingSupport, Castle.MonoRail.ActiveRecordScaffold"), true);
302 if (defaultScaffoldingType != null)
304 services.RegisterService(ServiceIdentification.ScaffoldingSupport, defaultScaffoldingType);
307 if (!services.HasService(ServiceIdentification.ControllerFactory))
309 if (config.ControllersConfig.CustomControllerFactory != null)
311 services.RegisterService(ServiceIdentification.ControllerFactory,
312 config.ControllersConfig.CustomControllerFactory);
314 else
316 services.RegisterService(ServiceIdentification.ControllerFactory,
317 typeof(DefaultControllerFactory));
320 if (!services.HasService(ServiceIdentification.ViewComponentFactory))
322 if (config.ViewComponentsConfig.CustomViewComponentFactory != null)
324 services.RegisterService(ServiceIdentification.ViewComponentFactory,
325 config.ViewComponentsConfig.CustomViewComponentFactory);
327 else
329 services.RegisterService(ServiceIdentification.ViewComponentFactory,
330 typeof(DefaultViewComponentFactory));
333 if (!services.HasService(ServiceIdentification.FilterFactory))
335 if (config.CustomFilterFactory != null)
337 services.RegisterService(ServiceIdentification.FilterFactory,
338 config.CustomFilterFactory);
340 else
342 services.RegisterService(ServiceIdentification.FilterFactory,
343 typeof(DefaultFilterFactory));
346 if (!services.HasService(ServiceIdentification.ResourceFactory))
348 services.RegisterService(ServiceIdentification.ResourceFactory, typeof(DefaultResourceFactory));
350 if (!services.HasService(ServiceIdentification.EmailSender))
352 services.RegisterService(ServiceIdentification.EmailSender, typeof(MonoRailSmtpSender));
354 if (!services.HasService(ServiceIdentification.ControllerDescriptorProvider))
356 services.RegisterService(ServiceIdentification.ControllerDescriptorProvider,
357 typeof(DefaultControllerDescriptorProvider));
359 if (!services.HasService(ServiceIdentification.ResourceDescriptorProvider))
361 services.RegisterService(ServiceIdentification.ResourceDescriptorProvider, typeof(DefaultResourceDescriptorProvider));
363 if (!services.HasService(ServiceIdentification.RescueDescriptorProvider))
365 services.RegisterService(ServiceIdentification.RescueDescriptorProvider, typeof(DefaultRescueDescriptorProvider));
367 if (!services.HasService(ServiceIdentification.LayoutDescriptorProvider))
369 services.RegisterService(ServiceIdentification.LayoutDescriptorProvider, typeof(DefaultLayoutDescriptorProvider));
371 if (!services.HasService(ServiceIdentification.HelperDescriptorProvider))
373 services.RegisterService(ServiceIdentification.HelperDescriptorProvider, typeof(DefaultHelperDescriptorProvider));
375 if (!services.HasService(ServiceIdentification.FilterDescriptorProvider))
377 services.RegisterService(ServiceIdentification.FilterDescriptorProvider, typeof(DefaultFilterDescriptorProvider));
379 if (!services.HasService(ServiceIdentification.EmailTemplateService))
381 services.RegisterService(ServiceIdentification.EmailTemplateService, typeof(EmailTemplateService));
383 if (!services.HasService(ServiceIdentification.ControllerTree))
385 services.RegisterService(ServiceIdentification.ControllerTree, typeof(DefaultControllerTree));
387 if (!services.HasService(ServiceIdentification.CacheProvider))
389 services.RegisterService(ServiceIdentification.CacheProvider, typeof(DefaultCacheProvider));
391 if (!services.HasService(ServiceIdentification.ExecutorFactory))
393 services.RegisterService(ServiceIdentification.ExecutorFactory, typeof(DefaultControllerLifecycleExecutorFactory));
395 if (!services.HasService(ServiceIdentification.TransformationFilterFactory))
397 services.RegisterService(ServiceIdentification.TransformationFilterFactory, typeof(DefaultTransformFilterFactory));
399 if (!services.HasService(ServiceIdentification.TransformFilterDescriptorProvider))
401 services.RegisterService(ServiceIdentification.TransformFilterDescriptorProvider,
402 typeof(DefaultTransformFilterDescriptorProvider));
405 if (!services.HasService(ServiceIdentification.UrlBuilder))
407 services.RegisterService(ServiceIdentification.UrlBuilder, typeof(DefaultUrlBuilder));
409 if (!services.HasService(ServiceIdentification.UrlTokenizer))
411 services.RegisterService(ServiceIdentification.UrlTokenizer, typeof(DefaultUrlTokenizer));
413 if (!services.HasService(ServiceIdentification.ValidatorRegistry))
415 services.RegisterService(ServiceIdentification.ValidatorRegistry, typeof(CachedValidationRegistry));
418 if (!services.HasService(ServiceIdentification.AjaxProxyGenerator))
420 services.RegisterService(ServiceIdentification.AjaxProxyGenerator, typeof(PrototypeAjaxProxyGenerator));
424 private static object ActivateService(Type type)
428 return Activator.CreateInstance(type);
430 catch(Exception ex)
432 String message = String.Format("Initialization Exception: " +
433 "Could not instantiate {0}", type.FullName);
434 throw new ConfigurationErrorsException(message, ex);
438 private static void InvokeInitialize(object instance)
440 IInitializable initializable = instance as IInitializable;
442 if (initializable != null)
444 initializable.Initialize();
447 ISupportInitialize suppInitialize = instance as ISupportInitialize;
449 if (suppInitialize != null)
451 suppInitialize.BeginInit();
452 suppInitialize.EndInit();
456 private void InvokeServiceEnabled(object instance)
458 IServiceEnabledComponent serviceEnabled = instance as IServiceEnabledComponent;
460 if (serviceEnabled != null)
462 serviceEnabled.Service(this);
466 private MonoRailConfiguration ObtainConfiguration()
468 if (config == null)
470 config = MonoRailConfiguration.GetConfig();
473 return config;
476 private static void AssertImplementsService(Type service, Type impl)
478 if (!service.IsAssignableFrom(impl))
480 String message = String.Format("Initialization Exception: " +
481 "Service {0} does not implement or extend {1}", impl.FullName, service.FullName);
482 throw new ConfigurationErrorsException(message);