Added non-generic registration interface to IKernel and IWindsor to accommodate dynam...
[castle.git] / MonoRail / Castle.MonoRail.Framework / Services / EmailTemplateService.cs
blobfdfea2746de59dcbb137f566be44b8e079837c12
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.IO;
20 using System.Text;
21 using System.Text.RegularExpressions;
22 using Castle.Components.Common.EmailSender;
23 using Castle.Core;
24 using Castle.Core.Logging;
26 /// <summary>
27 /// Default implementation of <see cref="IEmailTemplateService"/>
28 /// </summary>
29 /// <remarks>
30 /// Will work only during a MonoRail process as it needs a <see cref="IEngineContext"/>
31 /// and a <see cref="Controller"/> instance to execute.
32 /// </remarks>
33 public class EmailTemplateService : IMRServiceEnabled, IEmailTemplateService
35 private static readonly String HeaderPattern = @"[ \t]*(?<header>(to|from|cc|bcc|subject|X-\w+)):[ \t]*(?<value>(.)+)(\r*\n*)?";
36 private static readonly Regex HeaderRegEx = new Regex(HeaderPattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase | RegexOptions.Compiled);
37 private static readonly string EmailTemplatePath = "mail";
39 /// <summary>
40 /// The logger instance
41 /// </summary>
42 private ILogger logger = NullLogger.Instance;
44 private IViewEngineManager viewEngineManager;
46 /// <summary>
47 /// Initializes a new instance of the <see cref="EmailTemplateService"/> class.
48 /// </summary>
49 public EmailTemplateService()
53 /// <summary>
54 /// Initializes a new instance of the <see cref="EmailTemplateService"/> class.
55 /// </summary>
56 /// <param name="viewEngineManager">The view engine manager.</param>
57 public EmailTemplateService(IViewEngineManager viewEngineManager)
59 this.viewEngineManager = viewEngineManager;
62 #region IMRServiceEnabled
64 /// <summary>
65 /// Invoked by the framework in order to give a chance to
66 /// obtain other services
67 /// </summary>
68 /// <param name="serviceProvider">The service proviver</param>
69 public void Service(IMonoRailServices serviceProvider)
71 ILoggerFactory loggerFactory = serviceProvider.GetService<ILoggerFactory>();
73 if (loggerFactory != null)
75 logger = loggerFactory.Create(typeof(EmailTemplateService));
78 viewEngineManager = serviceProvider.ViewEngineManager;
81 #endregion
83 /// <summary>
84 /// Creates an instance of <see cref="Message"/>
85 /// using the specified template for the body
86 /// </summary>
87 /// <param name="templateName">Name of the template to load.
88 /// Will look in <c>Views/mail</c> for that template file.</param>
89 /// <param name="layoutName">Name of the layout.</param>
90 /// <param name="parameters">Dictionary with parameters
91 /// that you can use on the email template</param>
92 /// <returns>An instance of <see cref="Message"/></returns>
93 public Message RenderMailMessage(string templateName, string layoutName, object parameters)
95 return RenderMailMessage(templateName, layoutName, new ReflectionBasedDictionaryAdapter(parameters));
98 /// <summary>
99 /// Creates an instance of <see cref="Message"/>
100 /// using the specified template for the body
101 /// </summary>
102 /// <param name="templateName">Name of the template to load.
103 /// Will look in <c>Views/mail</c> for that template file.</param>
104 /// <param name="layoutName">Name of the layout.</param>
105 /// <param name="parameters">Dictionary with parameters
106 /// that you can use on the email template</param>
107 /// <returns>An instance of <see cref="Message"/></returns>
108 public Message RenderMailMessage(string templateName, string layoutName, IDictionary parameters)
110 if (logger.IsDebugEnabled)
112 logger.DebugFormat("Rendering email message. Template name {0}", templateName);
115 if (!templateName.StartsWith("/"))
117 templateName = Path.Combine(EmailTemplatePath, templateName);
120 // use the template engine to generate the body of the message
121 StringWriter writer = new StringWriter();
123 viewEngineManager.Process(templateName, layoutName, writer, new StringObjectDictionaryAdapter(parameters));
125 return CreateMessage(writer);
128 /// <summary>
129 /// Creates an instance of <see cref="Message"/>
130 /// using the specified template for the body
131 /// </summary>
132 /// <param name="templateName">Name of the template to load.
133 /// Will look in Views/mail for that template file.</param>
134 /// <param name="engineContext">The engine context.</param>
135 /// <param name="controller">Controller instance</param>
136 /// <param name="controllerContext">The controller context.</param>
137 /// <param name="doNotApplyLayout">If <c>true</c>, it will skip the layout</param>
138 /// <returns>An instance of <see cref="Message"/></returns>
139 public Message RenderMailMessage(string templateName, IEngineContext engineContext,
140 IController controller, IControllerContext controllerContext, bool doNotApplyLayout)
142 // use the template engine to generate the body of the message
143 StringWriter writer = new StringWriter();
145 String[] oldLayout = controllerContext.LayoutNames;
147 if (doNotApplyLayout)
149 controllerContext.LayoutNames = null;
152 if (!templateName.StartsWith("/"))
154 templateName = Path.Combine(EmailTemplatePath, templateName);
157 viewEngineManager.Process(templateName, writer, engineContext, controller, controllerContext);
159 controllerContext.LayoutNames = oldLayout;
161 return CreateMessage(writer);
164 private Message CreateMessage(StringWriter writer)
166 // create a message object
167 Message message = new Message();
169 StringReader reader = new StringReader(writer.ToString());
171 bool isInBody = false;
172 StringBuilder body = new StringBuilder();
173 string line;
175 while((line = reader.ReadLine()) != null)
177 string header, value;
178 if (!isInBody && IsLineAHeader(line, out header, out value))
180 switch(header.ToLowerInvariant())
182 case "to":
183 message.To = value;
184 break;
185 case "cc":
186 message.Cc = value;
187 break;
188 case "bcc":
189 message.Bcc = value;
190 break;
191 case "subject":
192 message.Subject = value;
193 break;
194 case "from":
195 message.From = value;
196 break;
197 default:
198 message.Headers[header] = value;
199 break;
202 else
204 isInBody = true;
206 if (line == string.Empty)
208 continue;
211 body.AppendLine(line);
215 message.Body = body.ToString();
217 if (message.Body.ToLowerInvariant().IndexOf("<html>") != -1)
219 message.Format = Format.Html;
222 return message;
225 private static bool IsLineAHeader(string line, out string header, out string value)
227 Match match = HeaderRegEx.Match(line);
229 if (match.Success)
231 header = match.Groups["header"].ToString().ToLower();
232 value = match.Groups["value"].ToString();
233 return true;
235 else
237 header = value = null;
238 return false;