Fixing an issue where setting a custom property on a handler will not propagate it...
[castle.git] / Components / General / TemplateEngine / Castle.Components.Common.TemplateEngine.NVelocityTemplateEngine / NVelocityTemplateEngine.cs
blob67e005d11056d1f59207360534273c0a838e94a8
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.Components.Common.TemplateEngine.NVelocityTemplateEngine
17 using System;
18 using System.Collections;
19 using System.ComponentModel;
20 using System.IO;
21 using System.Web;
23 using Castle.Components.Common.TemplateEngine;
24 using Castle.Core.Logging;
26 using Commons.Collections;
28 using NVelocity;
29 using NVelocity.App;
30 using NVelocity.Context;
31 using NVelocity.Runtime;
33 /// <summary>
34 /// Implementation of <see cref="ITemplateEngine"/>
35 /// that uses NVelocity
36 /// </summary>
37 public class NVelocityTemplateEngine : ITemplateEngine, ISupportInitialize
39 private VelocityEngine vengine;
40 private ILogger log = NullLogger.Instance;
42 private ArrayList assemblies = new ArrayList();
43 private String templateDir = ".";
44 private bool enableCache = true;
46 /// <summary>
47 /// Constructs a NVelocityTemplateEngine instance
48 /// assuming the default values
49 /// </summary>
50 public NVelocityTemplateEngine()
54 /// <summary>
55 /// Constructs a NVelocityTemplateEngine instance
56 /// specifing the template directory
57 /// </summary>
58 /// <param name="templateDir"></param>
59 public NVelocityTemplateEngine(String templateDir)
61 this.TemplateDir = templateDir;
64 /// <summary>
65 /// Gets or sets the assembly name. This
66 /// forces NVelocityTemplateEngine to use an assembly resource loader
67 /// instead of File resource loader (which is the default)
68 /// </summary>
69 /// <remarks>
70 /// The property is obsolete, please use the AddResourceAssembly function.
71 /// </remarks>
72 [Obsolete("Please use the AddResourceAssembly function")]
73 public string AssemblyName;
75 /// <summary>
76 /// Add an assembly to the resource collection.
77 /// </summary>
78 /// <param name="assembly"></param>
79 public void AddResourceAssembly(string assembly)
81 if (assembly == null || assembly == string.Empty)
82 throw new ArgumentException("assembly name can not be null or empty");
84 if (assemblies.Contains(assembly))
85 return;
88 assemblies.Add(assembly);
91 /// <summary>
92 /// Gets or sets the template directory
93 /// </summary>
94 public string TemplateDir
96 get { return templateDir; }
97 set
99 if (vengine != null)
100 throw new InvalidOperationException("Could not change the TemplateDir after Template Engine initialization.");
102 templateDir = value;
106 /// <summary>
107 /// Enable/Disable caching. Default is <c>true</c>
108 /// </summary>
109 public bool EnableCache
111 get { return enableCache; }
112 set { enableCache = value; }
115 public ILogger Log
117 get { return log; }
118 set { log = value; }
121 /// <summary>
122 /// Starts/configure NVelocity based on the properties.
123 /// </summary>
124 public void BeginInit()
126 vengine = new VelocityEngine();
128 ExtendedProperties props = new ExtendedProperties();
130 if (assemblies.Count != 0)
132 log.Info("Initializing NVelocityTemplateEngine component using Assemblies:");
133 foreach(string s in assemblies)
135 log.Info(" - {0}", s);
138 props.SetProperty(RuntimeConstants.RESOURCE_LOADER, "assembly");
139 props.SetProperty("assembly.resource.loader.class", "NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader;NVelocity");
140 props.SetProperty("assembly.resource.loader.cache", EnableCache.ToString().ToLower() );
141 props.SetProperty("assembly.resource.loader.assembly", assemblies);
143 else
145 String expandedTemplateDir = ExpandTemplateDir(templateDir);
146 log.InfoFormat("Initializing NVelocityTemplateEngine component using template directory: {0}", expandedTemplateDir);
148 FileInfo propertiesFile = new FileInfo(Path.Combine(expandedTemplateDir, "nvelocity.properties"));
149 if (propertiesFile.Exists)
151 log.Info("Found 'nvelocity.properties' on template dir, loading as base configuration");
152 using(Stream stream = propertiesFile.OpenRead())
154 props.Load(stream);
158 props.SetProperty(RuntimeConstants.RESOURCE_LOADER, "file");
159 props.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, expandedTemplateDir);
160 props.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, EnableCache.ToString().ToLower() );
163 vengine.Init(props);
166 public void EndInit()
170 /// <summary>
171 /// Returns <c>true</c> only if the
172 /// specified template exists and can be used
173 /// </summary>
174 /// <param name="templateName"></param>
175 /// <returns></returns>
176 public bool HasTemplate(String templateName)
178 if (vengine == null)
179 throw new InvalidOperationException("Template Engine not yet initialized.");
183 vengine.GetTemplate(templateName);
185 return true;
187 catch(Exception)
189 return false;
193 /// <summary>
194 /// Process the template with data from the context.
195 /// </summary>
196 public bool Process(IDictionary context, String templateName, TextWriter output)
198 if (vengine == null)
199 throw new InvalidOperationException("Template Engine not yet initialized.");
201 Template template = vengine.GetTemplate(templateName);
203 template.Merge(CreateContext(context), output);
205 return true;
208 /// <summary>
209 /// Process the input template with data from the context.
210 /// </summary>
211 /// <param name="context">The context.</param>
212 /// <param name="templateName">Name of the template. Used only for information during logging</param>
213 /// <param name="output">The output.</param>
214 /// <param name="inputTemplate">The input template.</param>
215 /// <returns></returns>
216 public bool Process(IDictionary context, string templateName, TextWriter output, string inputTemplate)
218 return Process(context, templateName, output, new StringReader(inputTemplate));
221 /// <summary>
222 /// Process the input template with data from the context.
223 /// </summary>
224 /// <param name="context">The context.</param>
225 /// <param name="templateName">Name of the template. Used only for information during logging</param>
226 /// <param name="output">The output.</param>
227 /// <param name="inputTemplate">The input template.</param>
228 /// <returns></returns>
229 public bool Process(IDictionary context, string templateName, TextWriter output, TextReader inputTemplate)
231 if (vengine == null)
232 throw new InvalidOperationException("Template Engine not yet initialized.");
234 return vengine.Evaluate(CreateContext(context), output, templateName, inputTemplate);
237 private IContext CreateContext(IDictionary context)
239 return new VelocityContext( new Hashtable(context) );
242 private String ExpandTemplateDir(String templateDir)
244 log.DebugFormat("Template directory before expansion: {0}", templateDir);
246 // if nothing to expand, then exit
247 if (templateDir == null)
248 templateDir = String.Empty;
250 // expand web application root
251 if (templateDir.StartsWith("~/"))
253 HttpContext webContext = HttpContext.Current;
254 if (webContext != null && webContext.Request != null)
255 templateDir = webContext.Server.MapPath(templateDir);
258 // normalizes the path (including ".." notation, for parent directories)
259 templateDir = new DirectoryInfo(templateDir).FullName;
261 log.DebugFormat("Template directory after expansion: {0}", templateDir);
262 return templateDir;