diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs index 1cb874d4..c235b602 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs @@ -1,21 +1,21 @@ -#region License - -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #endregion using Common.Logging; @@ -27,24 +27,24 @@ using LogManager=Common.Logging.LogManager; namespace Spring.Template.Velocity { /// - /// Velocity LogSystem implementation for Jakarta Commons Logging. + /// NVelocity LogSystem implementation for Commons Logging. /// /// Erez Mazor public class CommonsLoggingLogSystem : ILogSystem { protected static readonly ILog log = LogManager.GetLogger(typeof(CommonsLoggingLogSystem)); /// - /// Inits the specified runtime services. No-op in current implementatin + /// Initializes the specified runtime services. No-op in current implementatin /// - /// The runtime services. + /// the runtime services. public void Init(IRuntimeServices runtimeServices) { } /// - /// Log a velocity message using the commons logging system + /// Log a NVelocity message using the commons logging system /// /// LogLevel to match - /// Message to log + /// message to log public void LogVelocityMessage(LogLevel level, string message) { switch (level) { case LogLevel.Error: diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs index 2adead92..64dbdd0c 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs @@ -1,21 +1,21 @@ -#region License - -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #endregion using System; @@ -26,34 +26,55 @@ using NVelocity.Runtime.Resource; using NVelocity.Runtime.Resource.Loader; using Spring.Core.IO; -namespace Spring.Template.Velocity -{ +namespace Spring.Template.Velocity { /// - /// Velocity ResourceLoader adapter that loads via a Spring IResourceLoader. - /// Used by VelocityEngineFactory for any resource loader path that cannot - /// be resolved to a File - /// - ///

Take notoce that this loader does not allow for modification detection: - /// Use Velocity's default FileResourceLoader for File resources. - /// - ///

Expects "spring.resource.loader" and "spring.resource.loader.path" - /// application attributes in the Velocity runtime: the former of type - /// IResourceLoader, the latter a String. + /// NVelocity's abstract ResourceLoader extension which serves + /// as an adapter that loads templates via a Spring IResourceLoader. + /// + ///
+ /// Used by VelocityEngineFactory for any resource loader path that + /// cannot be resolved to a File or an Assembly or for + /// implementations which rely on spring's IResourceLoader + /// mechanism. + /// + ///
+ /// Important: this loader does not allow for modification detection. + ///
+ /// Expects "spring.resource.loader" (IResourceLoader implementations) + /// and "spring.resource.loader.path" application attributes in the + /// NVelocity runtime. ///

/// /// /// + /// + /// /// Erez Mazor (.NET) public class SpringResourceLoader : ResourceLoader { - public static readonly string NAME = "spring"; + /// + /// Prefix used for the NVelocity Configuration + /// + public const string NAME = "spring"; - public static readonly string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; + /// + /// The IResourceLoader implementation type + /// + public const string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; - public static readonly string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; + /// + /// A flag indicating weather a template cache is used + /// + public const string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; - public static readonly string SPRING_RESOURCE_LOADER = "spring.resource.loader"; + /// + /// Fully qualified name of the IResourceLoader implementation class + /// + public const string SPRING_RESOURCE_LOADER = "spring.resource.loader"; - public static readonly string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; + /// + /// A comma delimited list of paths used by the spring IResourceLoader implementation + /// + public const string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; protected static readonly ILog log = LogManager.GetLogger(typeof(SpringResourceLoader)); @@ -65,14 +86,14 @@ namespace Spring.Template.Velocity /// /// Initialize the template loader with a resources class. /// - /// The configuration. + /// The ExtendedProperties representing the Velocity configuration. public override void Init(ExtendedProperties configuration) { resourceLoader = (IResourceLoader)rsvc.GetApplicationAttribute(SPRING_RESOURCE_LOADER); string resourceLoaderPath = (string)rsvc.GetApplicationAttribute(SPRING_RESOURCE_LOADER_PATH); if (resourceLoader == null) { throw new ArgumentException("'resourceLoader' application attribute must be present for SpringResourceLoader"); } - if (resourceLoaderPath == null) { + if (null == resourceLoaderPath) { throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); } resourceLoaderPaths = resourceLoaderPath.Split(','); @@ -88,17 +109,17 @@ namespace Spring.Template.Velocity } /// - /// Get the InputStream that the Runtime will parse to create a template. + /// Get the System.IO.Stream that the Runtime will parse to create a template. /// - /// The source. - /// + /// the source template name + /// a System.IO.Stream representation of the resource public override Stream GetResourceStream(string source) { if (log.IsDebugEnabled) { log.Debug(string.Format("Looking for Velocity resource with name [{0}]", source)); } - for (int i = 0; i < resourceLoaderPaths.Length; i++) { - IResource resource = - resourceLoader.GetResource(resourceLoaderPaths[i] + source); + + foreach (string resourceLoaderPath in resourceLoaderPaths){ + IResource resource = resourceLoader.GetResource(resourceLoaderPath + source); try { return resource.InputStream; } catch (IOException ex) { diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs index b3912715..6fbe5f91 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs @@ -1,21 +1,21 @@ -#region License - -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #endregion using System; @@ -32,43 +32,48 @@ using NVelocity.Runtime.Resource.Loader; using Spring.Context.Support; using Spring.Core.IO; -namespace Spring.Template.Velocity{ +namespace Spring.Template.Velocity { /// /// Factory that configures a VelocityEngine. Can be used standalone, - /// but typically you will either use {@link VelocityEngineFactoryBean} + /// but typically you will use VelocityEngineFactoryObject /// for preparing a VelocityEngine as bean reference. /// - ///

The optional "ConfigLocation" property sets the location of the Velocity + ///
+ /// The optional "ConfigLocation" property sets the location of the Velocity /// properties file, within the current application. Velocity properties can be /// overridden via "VelocityProperties", or even completely specified locally, /// avoiding the need for an external properties file. /// - ///

The "ResourceLoaderPath" property can be used to specify the Velocity - /// resource loader path via Spring's Resource abstraction, possibly relative + ///
+ /// The "ResourceLoaderPath" property can be used to specify the Velocity + /// resource loader path via Spring's IResource abstraction, possibly relative /// to the Spring application context. /// - ///

If "OverrideLogging" is true (the default), the VelocityEngine will be + ///
+ /// If "OverrideLogging" is true (the default), the VelocityEngine will be /// configured to log via Commons Logging, that is, using the Spring-provided - /// "CommonsLoggingLogSystem" as log system. + /// CommonsLoggingLogSystem as log system. /// - ///

The simplest way to use this class is to specify a ResourceLoaderPath - /// property; the VelocityEngine typically then does not need any further + ///
+ /// The simplest way to use this class is to specify a ResourceLoaderPath + /// property. the VelocityEngine typically then does not need any further /// configuration. /// ///

/// /// /// - /// Erez Mazor (.NET) + /// Erez Mazor public class VelocityEngineFactory { private const char DELIMITER = ','; + protected static readonly ILog log = LogManager.GetLogger(typeof(VelocityEngineFactory)); private IResource configLocation; private IDictionary velocityProperties = new Dictionary(); - private String resourceLoaderPath; + private IList resourceLoaderPaths = new ArrayList(); private IResourceLoader resourceLoader = new ConfigurableResourceLoader(); @@ -86,7 +91,7 @@ namespace Spring.Template.Velocity{ } /// - /// Set Velocity properties as Map, to allow for non-String values like "ds.resource.loader.instance". + /// Set local NVelocity properties. /// /// public IDictionary VelocityProperties { @@ -94,35 +99,47 @@ namespace Spring.Template.Velocity{ } /// - /// + /// Single ResourceLoaderPath + /// + /// + public string ResourceLoaderPath { + set { resourceLoaderPaths.Add(value); } + } + + /// /// Set the Velocity resource loader path via a Spring resource location. /// Accepts multiple locations in Velocity's comma-separated path style. - ///

When populated via a String, standard URLs like "file:" and "assembly:" - /// pseudo URLs are supported, as understood by ResourceLoader. Allows for + ///
+ /// When populated via a String, standard URLs like "file:" and "assembly:" + /// pseudo URLs are supported, as understood by IResourceLoader. Allows for /// relative paths when running in an ApplicationContext. - ///

Will define a path for the default Velocity resource loader with the name - /// "file". If the specified resource cannot be resolved to a java.io.File, + ///
+ /// Will define a path for the default Velocity resource loader with the name + /// "file". If the specified resource cannot be resolved to a File, /// a generic SpringResourceLoader will be used under the name "spring", without /// modification detection. - ///

Take notice that resource caching will be enabled in any case. With the file + ///
+ /// Take notice that resource caching will be enabled in any case. With the file /// resource loader, the last-modified timestamp will be checked on access to - /// detect changes. With SpringResourceLoader, the resource will be cached - /// forever (for example for class path resources). - ///

To specify a modification check interval for files, use Velocity's + /// detect changes. With SpringResourceLoader, the resource will be throughout + /// the life time of the application context (for example for class path resources). + ///
+ /// To specify a modification check interval for files, use Velocity's /// standard "file.resource.loader.modificationCheckInterval" property. By default, /// the file timestamp is checked on every access (which is surprisingly fast). /// Of course, this just applies when loading resources from the file system. - ///

To enforce the use of SpringResourceLoader, i.e. to not resolve a path + ///
+ /// To enforce the use of SpringResourceLoader, i.e. to not resolve a path /// as file system resource in any case, turn off the "preferFileSystemAccess" - /// flag. See the latter's javadoc for details. + /// flag. See the latter's documentation for details. ///

/// /// /// /// /// - public string ResourceLoaderPath { - set { resourceLoaderPath = value; } + public IList ResourceLoaderPaths { + set { resourceLoaderPaths = value; } } /// @@ -139,18 +156,17 @@ namespace Spring.Template.Velocity{ set { resourceLoader = value; } } - - /// /// Set whether to prefer file system access for template loading. /// File system access enables hot detection of template changes. - ///

If this is enabled, VelocityEngineFactory will try to resolve the - /// specified "resourceLoaderPath" as file system resource (which will work - /// for expanded class path resources and ServletContext resources too). - ///

Default is "true". Turn this off to always load via SpringResourceLoader + ///
+ /// If this is enabled, VelocityEngineFactory will try to resolve the + /// specified "resourceLoaderPath" as file system resource. + ///
+ /// Default is "true". Turn this off to always load via SpringResourceLoader /// (i.e. as stream, without hot detection of template changes), which might - /// be necessary if some of your templates reside in an expanded classes - /// directory while others reside in jar files. + /// be necessary if some of your templates reside in a directory while + /// others reside in assembly files. ///

/// public bool PreferFileSystemAccess { @@ -170,7 +186,7 @@ namespace Spring.Template.Velocity{ /// - /// Prepare the VelocityEngine instance and return it. + /// Create and initialize the VelocityEngine instance and return it /// /// VelocityEngine /// @@ -180,25 +196,33 @@ namespace Spring.Template.Velocity{ /// public VelocityEngine CreateVelocityEngine() { VelocityEngine velocityEngine = NewVelocityEngine(); - ExtendedProperties props = new ExtendedProperties(); + ExtendedProperties extendedProperties = new ExtendedProperties(); + + // load defaults - see documentation why this is needed + LoadDefaultProperties(velocityEngine); + // Load config file if set. if (configLocation != null) { if (log.IsInfoEnabled) { log.Info(string.Format("Loading Velocity config from [{0}]", configLocation)); } - FillProperties(props, configLocation); + FillProperties(extendedProperties, configLocation); } - // Merge local properties if set. + // merge local properties if set. if (velocityProperties.Count > 0) { foreach (KeyValuePair pair in velocityProperties) { - props.Add(pair.Key, pair.Value); + extendedProperties.SetProperty(pair.Key, pair.Value); } } // Set a resource loader path, if required. - if (null != resourceLoaderPath) { - InitVelocityResourceLoader(velocityEngine, resourceLoaderPath); + if( !preferFileSystemAccess && resourceLoaderPaths.Count == 0){ + throw new ArgumentException("When using SpringResourceLoader you must provide a path using the ResourceLoaderPath property"); + } + + if (resourceLoaderPaths.Count > 0) { + InitVelocityResourceLoader(velocityEngine, resourceLoaderPaths); } // Log via Commons Logging? @@ -210,11 +234,11 @@ namespace Spring.Template.Velocity{ try { // do not init with extended properties rather set one by one - foreach (DictionaryEntry prop in props) { - velocityEngine.SetProperty(Convert.ToString(prop.Key), prop.Value); + foreach (DictionaryEntry property in extendedProperties) { + velocityEngine.SetProperty(Convert.ToString(property.Key), property.Value); } - // Perform actual initialization. + // velocity engine initialization - required velocityEngine.Init(); } catch (Exception ex) { throw new VelocityException(ex.ToString(), ex); @@ -224,90 +248,128 @@ namespace Spring.Template.Velocity{ } /// - /// Return a new VelocityEngine. Subclasses can override this for* - /// custom initialization, or for using a mock object for testing. *

Called by - /// CreateVelocityEngine() + /// This is to overcome an issue with the current NVelocity library, it seems the + /// default runetime properties/directives (nvelocity.properties and directive.properties + /// files) are not being properly located in the library at load time. A jira should + /// be filed but for now we attempt to do this on our own. Particularly our + /// concern here is with several required properties which I don't want + /// to require users to re-defined. e.g.,: + ///
+ /// + /// Pre-requisites:
+ /// resource.manager.class=NVelocity.Runtime.Resource.ResourceManagerImpl
+ /// directive.manager=NVelocity.Runtime.Directive.DirectiveManager
+ /// runtime.introspector.uberspect=NVelocity.Util.Introspection.UberspectImpl
///

- /// VelocityEngine + /// the instance of the velocity engine unto which we load the default properties + private static void LoadDefaultProperties(VelocityEngine velocityEngine) { + ExtendedProperties extendedProperties = new ExtendedProperties(); + IResource defaultRuntimeProperties = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/nvelocity.properties"); + IResource defaultRuntimeDirectives = new AssemblyResource("assembly://NVelocity/NVelocity.Runtime.Defaults/directive.properties"); + FillProperties(extendedProperties, defaultRuntimeProperties); + FillProperties(extendedProperties, defaultRuntimeDirectives); + foreach (DictionaryEntry property in extendedProperties) { + velocityEngine.SetProperty(Convert.ToString(property.Key), property.Value); + } + } + + /// + /// Return a new VelocityEngine. Subclasses can override this for + /// custom initialization, or for using a mock object for testing.
+ /// Called by CreateVelocityEngine() + ///
+ /// VelocityEngine instance (non-configured) /// protected static VelocityEngine NewVelocityEngine() { return new VelocityEngine(); } /// - /// Initialize a Velocity resource loader for the given VelocityEngine:* + /// Initialize a Velocity resource loader for the given VelocityEngine: /// either a standard Velocity FileResourceLoader or a SpringResourceLoader. - ///

Called by CreateVelocityEngine(). + ///
Called by CreateVelocityEngine(). ///

/// velocityEngine the VelocityEngine to configure - /// resourceLoaderPath the path to load Velocity resources from + /// paths the path list to load Velocity resources from /// /// /// /// - protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, String resourceLoaderFullPath) { + protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, IList paths) { + if (PreferFileSystemAccess) { // Try to load via the file system, fall back to SpringResourceLoader // (for hot detection of template changes, if possible). + IList resolvedPaths = new ArrayList(); + foreach (string path in paths){ + IResource resource = ResourceLoader.GetResource(path); + resolvedPaths.Add(resource.File.FullName); + } try { - StringBuilder resolvedPath = new StringBuilder(); - String[] paths = resourceLoaderFullPath.Split(DELIMITER); - for (int i = 0; i < paths.Length; i++) { - string path = paths[i]; - IResource resource = ResourceLoader.GetResource(path); - if (log.IsDebugEnabled) { - log.Debug(string.Format("Resource loader path [{0}] resolved to file [{1}]", path, resource.File.FullName)); - } - resolvedPath.Append(resource.File.FullName); - if (i < paths.Length - 1) { - resolvedPath.Append(','); - } - } + velocityEngine.SetProperty(RuntimeConstants.RESOURCE_LOADER, "file"); velocityEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true"); - velocityEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, resolvedPath.ToString()); + velocityEngine.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, joinList(resolvedPaths)); } catch (IOException ex) { if (log.IsDebugEnabled) { - log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", resourceLoaderFullPath), ex); + log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", joinList(resolvedPaths)), ex); } - InitSpringResourceLoader(velocityEngine, resourceLoaderFullPath); + + InitSpringResourceLoader(velocityEngine, joinList(paths)); } } else { - // Always load via SpringResourceLoader - // (without hot detection of template changes). + // Always load via SpringResourceLoader (without hot detection of template changes). if (log.IsDebugEnabled) { log.Debug("File system access not preferred: using SpringResourceLoader"); } - InitSpringResourceLoader(velocityEngine, resourceLoaderFullPath); + InitSpringResourceLoader(velocityEngine, joinList(paths)); } } + /// + /// Join the list of strings to a comma delimited string + /// + /// values list of strings to join + /// comma delimited string representation of the list + private static string joinList(IList values) { + StringBuilder result = new StringBuilder(); + foreach (string value in values) { + result.Append(value); + result.Append(DELIMITER); + } + return result.ToString(0, result.Length < 1 ? 0 : result.Length - 1); + } + /// /// Initialize a SpringResourceLoader for the given VelocityEngine. - ///

Called by InitVelocityResourceLoader. + ///
Called by InitVelocityResourceLoader. + /// + /// Important: the NVeloctity ResourceLoaderFactory.getLoader + /// method replaces ';' with ',' when attempting to construct our resource + /// loader. The name on the SPRING_RESOURCE_LOADER_CLASS property + /// has to be in the form of "ClassFullName; AssemblyName" in replacement + /// of the tranditional "ClassFullName, AssemblyName" to work. ///

/// velocityEngine the VelocityEngine to configure /// resourceLoaderPath the path to load Velocity resources from /// /// protected void InitSpringResourceLoader(VelocityEngine velocityEngine, string resourceLoaderPathString) { - velocityEngine.SetProperty( - RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); - velocityEngine.SetProperty( - SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, typeof(SpringResourceLoader).Name); - velocityEngine.SetProperty( - SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true"); - velocityEngine.SetApplicationAttribute( - SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader); - velocityEngine.SetApplicationAttribute( - SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString); + velocityEngine.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME); + Type springResourceLoaderType = typeof(SpringResourceLoader); + string springResourceLoaderTypeName = springResourceLoaderType.FullName + "; " + springResourceLoaderType.Assembly.GetName().Name; + velocityEngine.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName); + velocityEngine.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true"); + velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader); + velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString); } /// /// To be implemented by subclasses that want to to perform custom - /// post-processing of the VelocityEngine after this FactoryBean + /// post-processing of the VelocityEngine after this FactoryObject /// performed its default configuration (but before VelocityEngine.init) - ///

Called by CreateVelocityEngine() + ///
+ /// Called by CreateVelocityEngine ///

/// velocityEngine the current VelocityEngine /// @@ -319,11 +381,11 @@ namespace Spring.Template.Velocity{ /// /// Populates the velocity properties from the given resource /// - /// ExtendedProperties instance to populate + /// ExtendedProperties instance to populate /// The resource from which to load the properties - private static void FillProperties(ExtendedProperties props, IInputStreamSource resource) { + private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource) { try { - props.Load(resource.InputStream); + extendedProperties.Load(resource.InputStream); } finally { resource.InputStream.Close(); } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs index 02126c91..14f62128 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs @@ -1,21 +1,21 @@ -#region License - -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #endregion using System; @@ -26,14 +26,14 @@ using Spring.Objects.Factory; namespace Spring.Template.Velocity { /// - /// FactoryObject implementation that configures a VelocityEngine and provides it as an object - /// reference. This object is intended for any kind of usage of Velocity in + /// FactoryObject implementation that configures a VelocityEngine and provides it + /// as an object reference. This object is intended for any kind of usage of Velocity in /// application code, e.g. for generating email content. /// /// See the base class VelocityEngineFactory for configuration details. /// /// - /// Erez Mazor (.NET) + /// Erez Mazor public class VelocityEngineFactoryObject : VelocityEngineFactory, IFactoryObject, IInitializingObject, IResourceLoaderAware { private VelocityEngine velocityEngine; /// @@ -53,7 +53,7 @@ namespace Spring.Template.Velocity } /// - /// Returns true + /// Singleton /// public bool IsSingleton { get { return true; } diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs index 7ca23a57..fb410a55 100644 --- a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs @@ -1,21 +1,21 @@ -#region License - -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - +#region License + +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #endregion using System; @@ -30,32 +30,11 @@ namespace Spring.Template.Velocity{ /// /// Generalized Utility class for merging velocity templates into a text writer or return the result as a string /// - /// Erez Mazor (.NET) + /// Erez Mazor public class VelocityEngineUtils { protected static readonly ILog log = LogManager.GetLogger(typeof(VelocityEngineUtils)); - /// - /// Merge the specified Velocity template with the given model and write - /// the result to the given Writer. - /// - /// VelocityEngine to work with - /// the location of template, relative to Velocity's resource loader path - /// the Hashtable that contains model names as keys and model objects - /// writer the TextWriter to write the result to - /// thrown if any exception is thrown by the velocity engine - [Obsolete("Use the overload that takes the encoding as parameter")] - public static void MergeTemplate(VelocityEngine velocityEngine, string templateLocation, Hashtable model, TextWriter writer) { - try { - VelocityContext velocityContext = new VelocityContext(model); - velocityEngine.MergeTemplate(templateLocation, velocityContext, writer); - } catch (VelocityException) { - throw; - } catch (Exception ex) { - throw new VelocityException(ex.ToString(), ex); - } - } - /// /// Merge the specified Velocity template with the given model and write /// the result to the given Writer. @@ -79,33 +58,12 @@ namespace Spring.Template.Velocity{ } } - /// /// Merge the specified Velocity template with the given model into a string. - ///

When using this method to prepare a text for a mail to be sent with Spring's - /// mail support, consider wrapping VelocityException in MailPreparationException. - ///

- /// VelocityEngine to work with - /// the location of template, relative to Velocity's resource loader path - /// the Hashtable that contains model names as keys and model objects - /// the result as string - /// thrown if any exception is thrown by the velocity engine - [Obsolete("Use the overload that takes the encoding as parameter")] - public static string MergeTemplateIntostring( - VelocityEngine velocityEngine, string templateLocation, Hashtable model) { - - TextWriter result = new StringWriter(); - MergeTemplate(velocityEngine, templateLocation, model, result); - return result.ToString(); - } - - /// - /// Merge the specified Velocity template with the given model into a string. - ///

When using this method to prepare a text for a mail to be sent with Spring's - /// mail support, consider wrapping VelocityException in MailPreparationException. ///

/// VelocityEngine to work with /// the location of template, relative to Velocity's resource loader path + /// the encoding string to use for the merge /// the Hashtable that contains model names as keys and model objects /// the result as string /// thrown if any exception is thrown by the velocity engine diff --git a/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.build b/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.build index 7fad740e..3992a669 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.build +++ b/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.build @@ -26,17 +26,19 @@ - - - - - - - - - + + + + + + + + + + + diff --git a/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.csproj b/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.csproj index d91cb353..45da71f0 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.csproj +++ b/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.csproj @@ -66,6 +66,16 @@ + + + Always + + + + + Always + + diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/SimpleTemplate.vm b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/SimpleTemplate.vm new file mode 100644 index 00000000..07da26e3 --- /dev/null +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/SimpleTemplate.vm @@ -0,0 +1 @@ +value=${var1} \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs index 1df4490d..ef3a0cf0 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs @@ -20,6 +20,9 @@ #region Imports +using System; +using System.Collections; +using System.Text; using NUnit.Framework; using NVelocity.App; using Spring.Context.Support; @@ -27,29 +30,111 @@ using Spring.Objects.Factory.Xml; #endregion -namespace Spring.Template.Velocity.Tests.Template.Velocity -{ +namespace Spring.Template.Velocity.Tests.Template.Velocity { /// /// This class contains tests for VelocityEngineFactoryObject /// /// Mark Pollack + /// Erez Mazor [TestFixture] - public class VelocityEngineFactoryObjectTests - { + public class VelocityEngineFactoryObjectTests { + private const string TEST_VALUE = "TEST_VALUE"; + private XmlApplicationContext appContext; + private readonly Hashtable model = new Hashtable(); + [SetUp] - public void Setup() - { + public void Setup() { + appContext = new XmlApplicationContext(false, + ReadOnlyXmlTestResource.GetFilePath( + "VelocityEngineFactoryObjectTests.xml", + typeof(VelocityEngineFactoryObjectTests))); + model.Add("var1", TEST_VALUE); } + [TearDown] + public void TearDown() { + appContext.Dispose(); + model.Clear(); + } + + /// + /// Test the assemblyBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml + /// [Test] - public void Test() - { - XmlApplicationContext appContext = new XmlApplicationContext(false, - ReadOnlyXmlTestResource.GetFilePath( - "VelocityEngineFactoryObjectTests.xml", - typeof (VelocityEngineFactoryObjectTests))); - VelocityEngine velocityEngine = appContext.GetObject("velocityEngine") as VelocityEngine; - Assert.IsNotNull(velocityEngine); + public void TestMergeUsingAssembly() { + VelocityEngine velocityEngine = appContext.GetObject("assemblyBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm", Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate); + } + + /// + /// Test the fileBasedVelocityEngine bean configuration from VelocityEngineFactoryObjectTests.xml + /// + [Test] + public void TestMergeUsingFile() { + VelocityEngine velocityEngine = appContext.GetObject("fileBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring( + velocityEngine, "Template/Velocity/SimpleTemplate.vm", Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", TEST_VALUE), mergedTemplate); + } + + /// + /// Test using definition of ResourceLoaderPath (file-based configuration) referencing just the template name + /// + [Test] + public void TestMergeUsingResourceLoaderPath() { + VelocityEngine velocityEngine = + appContext.GetObject("pathBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "SimpleTemplate.vm", + Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate); + } + + /// + /// Test using a custom properties file (assembly-based configuration) + /// + [Test] + public void TestMergeUsingConfigPropertiesFile() { + VelocityEngine velocityEngine = + appContext.GetObject("propertiesFileBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, + "Spring.Template.Velocity.Tests.Template.Velocity.SimpleTemplate.vm", + Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate); + } + + /// + /// Test using spring resource loader + /// + [Test] + public void TestMergeUsingSpringResourceLoader() { + VelocityEngine velocityEngine = + appContext.GetObject("springResourceLoaderBasedVelocityEngine") as VelocityEngine; + Assert.IsNotNull(velocityEngine, "velocityEngine is null"); + string mergedTemplate = VelocityEngineUtils.MergeTemplateIntostring(velocityEngine, "SimpleTemplate.vm", + Encoding.UTF8.WebName, model); + Assert.AreEqual(string.Format("value={0}", "TEST_VALUE"), mergedTemplate); + } + + /// + /// Test using invalid configuration + /// + [Test] + public void TestInvalidConfiguration() { + VelocityEngineFactory velocityEngineFactory = new VelocityEngineFactory(); + velocityEngineFactory.PreferFileSystemAccess = false; + VelocityEngine velocityEngine = null; + try { + velocityEngineFactory.CreateVelocityEngine(); + throw new TestException( + "Should not be able to construct VelocityEngineFactory with SpringResourceLoader and no path"); + } catch (ArgumentException) { + Assert.IsNull(velocityEngine, "velocityEngine should be null"); + } } } } \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml index 4ff4274d..687e4ff8 100644 --- a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml @@ -1,15 +1,43 @@  - + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/config.properties b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/config.properties new file mode 100644 index 00000000..61944bd9 --- /dev/null +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/config.properties @@ -0,0 +1,3 @@ +resource.loader=assembly +assembly.resource.loader.class=NVelocity.Runtime.Resource.Loader.AssemblyResourceLoader +assembly.resource.loader.assembly=Spring.Template.Velocity.Tests \ No newline at end of file