Removed untyped contructor from ComponentRegistration and add a protected setter.
[castle.git] / MonoRail / Castle.MonoRail.Framework / Extensions / ExceptionChaining / ExceptionChainingExtension.cs
blob227ee3026c459311f0ef4c1071f3d27f4450c244
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.MonoRail.Framework.Extensions.ExceptionChaining
17 using System;
18 using System.Configuration;
19 using Castle.Core.Configuration;
20 using Castle.MonoRail.Framework.Configuration;
22 /// <summary>
23 /// This extension allow one to perform one or more steps
24 /// in response to an exception threw by an action.
25 ///
26 /// <seealso cref="IExceptionHandler"/>
27 ///
28 /// </summary>
29 ///
30 /// <remarks>
31 /// To successfully install this extension you must register
32 /// it on the <c>extensions</c> node and the handlers within the <c>exception</c> node:
33 /// <code>
34 /// &lt;monorail&gt;
35 /// &lt;extensions&gt;
36 /// &lt;extension type="Castle.MonoRail.Framework.Extensions.ExceptionChaining.ExceptionChainingExtension, Castle.MonoRail.Framework" /&gt;
37 /// &lt;/extensions&gt;
38 ///
39 /// &lt;exception&gt;
40 /// &lt;exceptionHandler type="Type name that implements IExceptionHandler" /&gt;
41 /// &lt;exceptionHandler type="Type name that implements IExceptionHandler" /&gt;
42 /// &lt;/exception&gt;
43 /// &lt;/monorail&gt;
44 /// </code>
45 /// <para>
46 /// Controllers can request IExceptionProcessor through IServiceProvider
47 /// and invoke the handlers to process an exception
48 /// </para>
49 /// <code>
50 /// <![CDATA[
51 /// public void BuyMercedes()
52 /// {
53 /// try
54 /// {
55 /// ...
56 /// }
57 /// catch(Exception ex)
58 /// {
59 /// IExceptionProcessor exProcessor = ServiceProvider.GetService<IExceptionProcessor>();
60 /// exProcessor.ProcessException(ex);
61 ///
62 /// RenderView("CouldNotBuyMercedes");
63 /// }
64 /// }
65 /// ]]>
66 /// </code>
67 /// </remarks>
68 public class ExceptionChainingExtension : IMonoRailExtension, IExceptionProcessor
70 private IExceptionHandler firstHandler;
72 #region IMonoRailExtension implementation
74 /// <summary>
75 /// Gives to the extension implementor a chance to read
76 /// attributes and child nodes of the extension node
77 /// </summary>
78 /// <param name="node">The node that defines the MonoRail extension</param>
79 public void SetExtensionConfigNode(IConfiguration node)
81 // Ignored
84 #endregion
86 #region IServiceEnabledComponent implementation
88 /// <summary>
89 /// Services the specified provider.
90 /// </summary>
91 /// <param name="serviceProvider">The provider.</param>
92 public void Service(IMonoRailServices serviceProvider)
94 ExtensionManager manager = (ExtensionManager)
95 serviceProvider.GetService(typeof(ExtensionManager));
97 IMonoRailConfiguration config = (IMonoRailConfiguration)
98 serviceProvider.GetService(typeof(IMonoRailConfiguration));
100 manager.ActionException += OnException;
101 manager.UnhandledException += OnException;
103 IConfiguration exceptionNode = config.ConfigurationSection.Children["exception"];
105 foreach(IConfiguration node in exceptionNode.Children)
107 string typeAtt = node.Attributes["type"];
109 if (typeAtt == null)
111 throw new MonoRailException("Configuration error: missing type attribute on exception handler configuration.");
114 InstallExceptionHandler(node, typeAtt);
118 #endregion
120 #region IExceptionProcessor implementation
122 /// <summary>
123 /// Initiates the ExceptionChainingExtension manualy
124 /// </summary>
125 /// <param name="exception">The exception to process</param>
126 /// <param name="engineContext">The engine context.</param>
127 public void ProcessException(Exception exception, IEngineContext engineContext)
129 if (exception == null) return;
131 engineContext.LastException = exception;
133 OnException(engineContext);
136 #endregion
138 /// <summary>
139 /// Called when an exception happens.
140 /// </summary>
141 /// <param name="context">The context.</param>
142 private void OnException(IEngineContext context)
144 const String mrExceptionKey = "MonoRail.ExceptionHandled";
146 if (context.Items.Contains(mrExceptionKey))
148 return;
151 if (firstHandler != null)
153 context.Items.Add(mrExceptionKey, true);
155 firstHandler.Process(context);
159 /// <summary>
160 /// Installs the exception handler.
161 /// </summary>
162 /// <param name="node">The node.</param>
163 /// <param name="typeName">Name of the type.</param>
164 private void InstallExceptionHandler(IConfiguration node, String typeName)
166 IExceptionHandler handler;
168 Type handlerType = TypeLoadUtil.GetType(typeName);
170 if (handlerType == null)
172 String message = "The Type for the custom session could not be loaded. " +
173 typeName;
174 throw new ConfigurationErrorsException(message);
179 handler = (IExceptionHandler) Activator.CreateInstance(handlerType);
181 catch(InvalidCastException)
183 String message = "The Type for the custom session must " +
184 "implement ICustomSessionFactory. " + typeName;
185 throw new ConfigurationErrorsException(message);
188 IConfigurableHandler configurableHandler = handler as IConfigurableHandler;
190 if (configurableHandler != null)
192 configurableHandler.Configure(node);
195 handler.Initialize();
197 if (firstHandler == null)
199 firstHandler = handler;
201 else
203 IExceptionHandler navHandler = firstHandler;
205 while(navHandler != null)
207 if (navHandler.Next == null)
209 navHandler.Next = handler;
210 break;
213 navHandler = navHandler.Next;