Merged branch back to the trunk. Build is passing with no changes.
[castle.git] / MonoRail / Castle.MonoRail.Framework / Views / ViewEngineBase.cs
blob03995b6af2e650df13d9e157efdc11542f4e9aee
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.Generic;
19 using System.Configuration;
20 using System.IO;
21 using Castle.Core;
22 using Castle.Core.Logging;
24 /// <summary>
25 /// Abstract base class for View Engines.
26 /// </summary>
27 public abstract class ViewEngineBase : IViewEngine, IServiceEnabledComponent
29 private bool xhtmlRendering;
30 private IViewSourceLoader viewSourceLoader;
31 private ILogger logger = NullLogger.Instance;
33 /// <summary>
34 /// The service provider instance
35 /// </summary>
36 protected IServiceProvider serviceProvider;
38 #region IServiceEnabledComponent implementation
40 /// <summary>
41 /// Services the specified provider.
42 /// </summary>
43 /// <param name="provider">The provider.</param>
44 public virtual void Service(IServiceProvider provider)
46 serviceProvider = provider;
48 viewSourceLoader = (IViewSourceLoader) provider.GetService(typeof(IViewSourceLoader));
50 if (viewSourceLoader == null)
52 string message = "Could not obtain IViewSourceLoader";
53 throw new ConfigurationErrorsException(message);
56 ILoggerFactory loggerFactory = (ILoggerFactory) provider.GetService(typeof(ILoggerFactory));
58 if (loggerFactory != null)
60 logger = loggerFactory.Create(GetType());
64 #endregion
66 #region IViewEngine implementation
68 /// <summary>
69 /// Gets the view file extension.
70 /// </summary>
71 /// <value>The view file extension.</value>
72 public abstract string ViewFileExtension { get; }
74 /// <summary>
75 /// Gets a value indicating whether the view engine
76 /// support the generation of JS.
77 /// </summary>
78 /// <value>
79 /// <c>true</c> if JS generation is supported; otherwise, <c>false</c>.
80 /// </value>
81 public abstract bool SupportsJSGeneration { get; }
83 /// <summary>
84 /// Gets the JS generator file extension.
85 /// </summary>
86 /// <value>The JS generator file extension.</value>
87 public abstract string JSGeneratorFileExtension { get; }
89 /// <summary>
90 /// Implementors should return a generator instance if
91 /// the view engine supports JS generation.
92 /// </summary>
93 /// <param name="generatorInfo">The generator info.</param>
94 /// <param name="context">The request context.</param>
95 /// <param name="controller">The controller.</param>
96 /// <param name="controllerContext">The controller context.</param>
97 /// <returns>A JS generator instance</returns>
98 public abstract object CreateJSGenerator(JSCodeGeneratorInfo generatorInfo, IEngineContext context, IController controller,
99 IControllerContext controllerContext);
101 /// <summary>
102 /// Processes the js generation view template - using the templateName
103 /// to obtain the correct template, and using the specified <see cref="TextWriter"/>
104 /// to output the result.
105 /// </summary>
106 /// <param name="templateName">Name of the template.</param>
107 /// <param name="output">The output.</param>
108 /// <param name="generatorInfo">The generator info.</param>
109 /// <param name="context">The request context.</param>
110 /// <param name="controller">The controller.</param>
111 /// <param name="controllerContext">The controller context.</param>
112 public abstract void GenerateJS(string templateName, TextWriter output, JSCodeGeneratorInfo generatorInfo,
113 IEngineContext context, IController controller, IControllerContext controllerContext);
115 /// <summary>
116 /// Gets/sets whether rendering should aim
117 /// to be XHTML compliant, obtained from the configuration.
118 /// </summary>
119 public bool XHtmlRendering
121 get { return xhtmlRendering; }
122 set { xhtmlRendering = value; }
125 /// <summary>
126 /// Evaluates whether the specified template exists.
127 /// </summary>
128 /// <returns><c>true</c> if it exists</returns>
129 public virtual bool HasTemplate(String templateName)
131 return
132 ViewSourceLoader.HasSource(ResolveTemplateName(templateName)) ||
133 ViewSourceLoader.HasSource(ResolveJSTemplateName(templateName));
136 /// <summary>
137 /// Evaluates whether the specified template exists.
138 /// </summary>
139 /// <returns><c>true</c> if it exists</returns>
140 public virtual bool HasJsGenerationTemplate(String templateName)
142 return ViewSourceLoader.HasSource(templateName);
145 /// <summary>
146 /// Evaluates whether the specified template can be used to generate js.
147 /// </summary>
148 /// <returns><c>true</c> if it exists and has the correct file extension</returns>
149 public virtual bool IsTemplateForJSGeneration(String templateName)
151 string resolvedTemplateName = ResolveJSTemplateName(templateName);
153 return
154 string.Compare(Path.GetExtension(resolvedTemplateName), JSGeneratorFileExtension, true) == 0 &&
155 HasJsGenerationTemplate(resolvedTemplateName);
158 ///<summary>
159 /// Processes the view - using the templateName
160 /// to obtain the correct template
161 /// and writes the results to the System.IO.TextWriter.
162 /// </summary>
163 public abstract void Process(String templateName, TextWriter output, IEngineContext context, IController controller,
164 IControllerContext controllerContext);
167 /// <summary>
168 /// Processes the view - using the templateName
169 /// to obtain the correct template
170 /// and writes the results to the <see cref="TextWriter"/>.
171 /// </summary>
172 public abstract void Process(string templateName, string layoutName, TextWriter output,
173 IDictionary<string, object> parameters);
175 /// <summary>
176 /// Should process the specified partial. The partial name must contains
177 /// the path relative to the views folder.
178 /// </summary>
179 /// <param name="output">The output.</param>
180 /// <param name="context">The request context.</param>
181 /// <param name="controller">The controller.</param>
182 /// <param name="controllerContext">The controller context.</param>
183 /// <param name="partialName">The partial name.</param>
184 public abstract void ProcessPartial(string partialName, TextWriter output, IEngineContext context,
185 IController controller, IControllerContext controllerContext);
187 /// <summary>
188 /// Wraps the specified content in the layout using the
189 /// context to output the result.
190 /// </summary>
191 public abstract void RenderStaticWithinLayout(String contents, IEngineContext context, IController controller,
192 IControllerContext controllerContext);
194 /// <summary>
195 /// Resolves the template name into a file name with the proper file extension
196 /// </summary>
197 protected virtual string ResolveTemplateName(string templateName)
199 if (Path.HasExtension(templateName))
201 return templateName;
203 else
205 return templateName + ViewFileExtension;
209 /// <summary>
210 /// Resolves the template name into a JS generation file name with the proper file extension
211 /// </summary>
212 protected virtual string ResolveJSTemplateName(string templateName)
214 if (Path.HasExtension(templateName))
216 return templateName;
218 else
220 return templateName + JSGeneratorFileExtension;
224 #endregion
226 #region Pre/Post send view
228 /// <summary>
229 /// Invokes the <see cref="IController.PreSendView"/>
230 /// </summary>
231 /// <param name="controller">The controller.</param>
232 /// <param name="view">The view argument.</param>
233 protected virtual void PreSendView(IController controller, object view)
235 controller.PreSendView(view);
238 /// <summary>
239 /// Invokes the <see cref="IController.PostSendView"/>
240 /// </summary>
241 /// <param name="controller">The controller.</param>
242 /// <param name="view">The view argument.</param>
243 protected virtual void PostSendView(IController controller, object view)
245 controller.PostSendView(view);
248 #endregion
250 #region Useful properties
252 /// <summary>
253 /// Gets or sets the view source loader.
254 /// </summary>
255 /// <value>The view source loader.</value>
256 protected IViewSourceLoader ViewSourceLoader
258 get { return viewSourceLoader; }
259 set { viewSourceLoader = value; }
262 /// <summary>
263 /// Gets the logger.
264 /// </summary>
265 /// <value>The logger.</value>
266 protected ILogger Logger
268 get { return logger; }
271 #endregion
273 #region Render Helpers
275 /// <summary>
276 /// Sets the HTTP Content-Type header appropriately.
277 /// </summary>
278 protected virtual void AdjustContentType(IEngineContext context)
280 if (xhtmlRendering)
282 //Find out what they'll accept
283 String httpAccept = context.Request.AcceptHeader;
285 //TODO: Evaluate the q-values of the Accept header
287 //Do they accept application/xhtml+xml?
288 if (httpAccept != null && httpAccept.IndexOf("application/xhtml+xml") != -1)
290 //Send them the proper content type
291 context.Response.ContentType = "application/xhtml+xml";
293 //TODO: Add the xml prolog for browsers that support it
294 //response.Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
296 else
298 //Fall back to text/html for older folk
299 context.Response.ContentType = "text/html";
302 //Fix up the proxy
303 context.Response.AppendHeader("Vary", "Accept");
305 else if (context.Response.ContentType == null)
307 //Just use HTML
308 context.Response.ContentType = "text/html";
312 /// <summary>
313 /// Sets the HTTP Content-Type header to <c>text/javascript</c>
314 /// </summary>
315 protected void AdjustJavascriptContentType(IEngineContext context)
317 context.Response.ContentType = "text/javascript";
320 #endregion