diff --git a/Spring.build b/Spring.build index 006fad5e..7cb025de 100644 --- a/Spring.build +++ b/Spring.build @@ -354,6 +354,8 @@ Build properties that may be set: + + @@ -381,6 +383,7 @@ Build properties that may be set: + + @@ -405,6 +409,7 @@ Build properties that may be set: + @@ -416,6 +421,7 @@ Build properties that may be set: + @@ -427,6 +433,7 @@ Build properties that may be set: + @@ -438,6 +445,7 @@ Build properties that may be set: + @@ -613,6 +621,8 @@ Build properties that may be set: + + @@ -648,6 +658,8 @@ Build properties that may be set: + + @@ -1011,6 +1023,10 @@ Build properties that may be set: + + + + @@ -1369,6 +1385,7 @@ Build properties that may be set: + @@ -1385,6 +1402,7 @@ Build properties that may be set: + diff --git a/build-support/solutions/Spring.Net.Template.2008.sln b/build-support/solutions/Spring.Net.Template.2008.sln new file mode 100644 index 00000000..77472186 --- /dev/null +++ b/build-support/solutions/Spring.Net.Template.2008.sln @@ -0,0 +1,66 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core.2008", "..\..\src\Spring\Spring.Core\Spring.Core.2008.csproj", "{710961A3-0DF4-49E4-A26E-F5B9C044AC84}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core.Tests.2008", "..\..\test\Spring\Spring.Core.Tests\Spring.Core.Tests.2008.csproj", "{44B16BAA-6DF8-447C-9D7F-3AD3D854D904}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Template.Velocity.2008", "..\..\src\Spring\Spring.Template.Velocity\Spring.Template.Velocity.2008.csproj", "{BF3AB954-8375-407C-9E98-4C51D8072784}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Template.Velocity.Tests", "..\..\test\Spring\Spring.Template.Velocity.Tests\Spring.Template.Velocity.Tests.csproj", "{10405837-CB67-40D8-9326-84C9383983E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|.NET = Debug|.NET + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Release|.NET = Release|.NET + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug|.NET.ActiveCfg = Debug|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release|.NET.ActiveCfg = Release|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release|Any CPU.Build.0 = Release|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {710961A3-0DF4-49E4-A26E-F5B9C044AC84}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Debug|.NET.ActiveCfg = Debug|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Release|.NET.ActiveCfg = Release|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Release|Any CPU.Build.0 = Release|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Debug|.NET.ActiveCfg = Debug|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Release|.NET.ActiveCfg = Release|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Release|Any CPU.Build.0 = Release|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {BF3AB954-8375-407C-9E98-4C51D8072784}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Debug|.NET.ActiveCfg = Debug|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Release|.NET.ActiveCfg = Release|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Release|Any CPU.Build.0 = Release|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {10405837-CB67-40D8-9326-84C9383983E2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/build-support/solutions/Spring.Net.Testing.2008.vsmdi b/build-support/solutions/Spring.Net.Testing.2008.vsmdi new file mode 100644 index 00000000..854396aa --- /dev/null +++ b/build-support/solutions/Spring.Net.Testing.2008.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/lib/Net/2.0/NVelocity.dll b/lib/Net/2.0/NVelocity.dll new file mode 100644 index 00000000..9b44dfeb Binary files /dev/null and b/lib/Net/2.0/NVelocity.dll differ diff --git a/lib/Net/2.0/NVelocity.pdb b/lib/Net/2.0/NVelocity.pdb new file mode 100644 index 00000000..6acd7032 Binary files /dev/null and b/lib/Net/2.0/NVelocity.pdb differ diff --git a/src/Spring/Spring.Template.Velocity/Spring.Template.Velocity.2008.csproj b/src/Spring/Spring.Template.Velocity/Spring.Template.Velocity.2008.csproj new file mode 100644 index 00000000..316884ec --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Spring.Template.Velocity.2008.csproj @@ -0,0 +1,110 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {BF3AB954-8375-407C-9E98-4C51D8072784} + Library + Properties + Spring + Spring.Template.Velocity + + + 2.0 + + + http://localhost/Spring.Template.Velocity/ + true + Web + true + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + true + false + true + + + true + full + false + ..\..\..\build\VS.NET.2005\Spring.Template.Velocity\Debug\ + TRACE;DEBUG;NET_2_0 + prompt + 4 + ..\..\..\build\VS.NET.2005\Spring.Template.Velocity\Debug\Spring.Template.Velocity.xml + + + pdbonly + true + ..\..\..\build\VS.NET.2005\Spring.Template.Velocity\Release\ + TRACE;NET_2_0 + prompt + 4 + + + + False + ..\..\..\lib\Net\2.0\Common.Logging.dll + + + False + ..\..\..\lib\Net\2.0\NVelocity.dll + + + + + + {710961A3-0DF4-49E4-A26E-F5B9C044AC84} + Spring.Core.2008 + + + + + + + + + + + + False + .NET Framework Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs new file mode 100644 index 00000000..1cb874d4 --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/CommonsLoggingLogSystem.cs @@ -0,0 +1,65 @@ +#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; +using NVelocity.Runtime; +using NVelocity.Runtime.Log; +using LogLevel=NVelocity.Runtime.Log.LogLevel; +using LogManager=Common.Logging.LogManager; + +namespace Spring.Template.Velocity +{ + /// + /// Velocity LogSystem implementation for Jakarta 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 + /// + /// The runtime services. + public void Init(IRuntimeServices runtimeServices) { + } + + /// + /// Log a velocity message using the commons logging system + /// + /// LogLevel to match + /// Message to log + public void LogVelocityMessage(LogLevel level, string message) { + switch (level) { + case LogLevel.Error: + log.Error(message); + break; + case LogLevel.Warn: + log.Warn(message); + break; + case LogLevel.Info: + log.Info(message); + break; + case LogLevel.Debug: + log.Debug(message); + break; + } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs new file mode 100644 index 00000000..2adead92 --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/SpringResourceLoader.cs @@ -0,0 +1,136 @@ +#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; +using System.IO; +using Common.Logging; +using Commons.Collections; +using NVelocity.Runtime.Resource; +using NVelocity.Runtime.Resource.Loader; +using Spring.Core.IO; + +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. + ///

+ /// + /// + /// + /// Erez Mazor (.NET) + public class SpringResourceLoader : ResourceLoader { + public static readonly string NAME = "spring"; + + public static readonly string SPRING_RESOURCE_LOADER_CLASS = "spring.resource.loader.class"; + + public static readonly string SPRING_RESOURCE_LOADER_CACHE = "spring.resource.loader.cache"; + + public static readonly string SPRING_RESOURCE_LOADER = "spring.resource.loader"; + + public static readonly string SPRING_RESOURCE_LOADER_PATH = "spring.resource.loader.path"; + + protected static readonly ILog log = LogManager.GetLogger(typeof(SpringResourceLoader)); + + private IResourceLoader resourceLoader; + + private string[] resourceLoaderPaths; + + + /// + /// Initialize the template loader with a resources class. + /// + /// The 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) { + throw new ArgumentException("'resourceLoaderPath' application attribute must be present for SpringResourceLoader"); + } + resourceLoaderPaths = resourceLoaderPath.Split(','); + for (int i = 0; i < resourceLoaderPaths.Length; i++) { + string path = resourceLoaderPaths[i]; + if (!path.EndsWith("/")) { + resourceLoaderPaths[i] = path + "/"; + } + } + if (log.IsInfoEnabled) { + log.Info(string.Format("SpringResourceLoader for Velocity: using resource loader [{0}] and resource loader paths {1}", resourceLoader, resourceLoaderPaths)); + } + } + + /// + /// Get the InputStream that the Runtime will parse to create a template. + /// + /// The source. + /// + 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); + try { + return resource.InputStream; + } catch (IOException ex) { + if (log.IsErrorEnabled) { + log.Error(string.Format("Could not find Velocity resource: {0}", resource), ex); + } + } + } + throw new ArgumentException(string.Format("Could not find resource [{0}] in Spring resource loader path", source)); + } + + /// + /// Given a template, check to see if the source of InputStream has been modified. + /// + /// The resource. + /// + /// true if the source of the InputStream has been modified; otherwise, false. + /// + public override bool IsSourceModified(Resource resource) { + return false; + } + + /// + /// Get the last modified time of the InputStream source + /// that was used to create the template. We need the template + /// here because we have to extract the name of the template + /// in order to locate the InputStream source. + /// + /// The resource. + /// + public override long GetLastModified(Resource resource) { + return 0; + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs new file mode 100644 index 00000000..b3912715 --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactory.cs @@ -0,0 +1,332 @@ +#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; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Common.Logging; +using Commons.Collections; +using NVelocity.App; +using NVelocity.Exception; +using NVelocity.Runtime; +using NVelocity.Runtime.Resource.Loader; +using Spring.Context.Support; +using Spring.Core.IO; + +namespace Spring.Template.Velocity{ + /// + /// Factory that configures a VelocityEngine. Can be used standalone, + /// but typically you will either use {@link VelocityEngineFactoryBean} + /// for preparing a VelocityEngine as bean reference. + /// + ///

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 + /// to the Spring application context. + /// + ///

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. + /// + ///

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) + 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 IResourceLoader resourceLoader = new ConfigurableResourceLoader(); + + private bool preferFileSystemAccess = true; + + private bool overrideLogging = true; + + /// + /// Set the location of the Velocity config file. Alternatively, you can specify all properties locally. + /// + /// + /// + public IResource ConfigLocation { + set { configLocation = value; } + } + + /// + /// Set Velocity properties as Map, to allow for non-String values like "ds.resource.loader.instance". + /// + /// + public IDictionary VelocityProperties { + set { velocityProperties = 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 + /// 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, + /// 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 + /// 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 + /// 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 + /// as file system resource in any case, turn off the "preferFileSystemAccess" + /// flag. See the latter's javadoc for details. + ///

+ /// + /// + /// + /// + /// + public string ResourceLoaderPath { + set { resourceLoaderPath = value; } + } + + /// + /// Set the Spring ResourceLoader to use for loading Velocity template files. + /// The default is DefaultResourceLoader. Will get overridden by the + /// ApplicationContext if running in a context. + /// + /// + /// + /// + /// + public IResourceLoader ResourceLoader { + get { return resourceLoader; } + 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 + /// (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. + ///

+ /// + public bool PreferFileSystemAccess { + get { return preferFileSystemAccess; } + set { preferFileSystemAccess = value; } + } + + /// + /// Set whether Velocity should log via Commons Logging, i.e. whether Velocity's + /// log system should be set to CommonsLoggingLogSystem. Default value is true + /// + /// + public bool OverrideLogging { + get { return overrideLogging; } + set { overrideLogging = value; } + } + + + /// + /// Prepare the VelocityEngine instance and return it. + /// + /// VelocityEngine + /// + /// + /// + /// + /// + public VelocityEngine CreateVelocityEngine() { + VelocityEngine velocityEngine = NewVelocityEngine(); + ExtendedProperties props = new ExtendedProperties(); + // Load config file if set. + if (configLocation != null) { + if (log.IsInfoEnabled) { + log.Info(string.Format("Loading Velocity config from [{0}]", configLocation)); + } + FillProperties(props, configLocation); + } + + // Merge local properties if set. + if (velocityProperties.Count > 0) { + foreach (KeyValuePair pair in velocityProperties) { + props.Add(pair.Key, pair.Value); + } + } + + // Set a resource loader path, if required. + if (null != resourceLoaderPath) { + InitVelocityResourceLoader(velocityEngine, resourceLoaderPath); + } + + // Log via Commons Logging? + if (overrideLogging) { + velocityEngine.SetProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLoggingLogSystem()); + } + + PostProcessVelocityEngine(velocityEngine); + + 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); + } + + // Perform actual initialization. + velocityEngine.Init(); + } catch (Exception ex) { + throw new VelocityException(ex.ToString(), ex); + } + + return velocityEngine; + } + + /// + /// Return a new VelocityEngine. Subclasses can override this for* + /// custom initialization, or for using a mock object for testing. *

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

+ /// VelocityEngine + /// + protected static VelocityEngine NewVelocityEngine() { + return new VelocityEngine(); + } + + /// + /// Initialize a Velocity resource loader for the given VelocityEngine:* + /// either a standard Velocity FileResourceLoader or a SpringResourceLoader. + ///

Called by CreateVelocityEngine(). + ///

+ /// velocityEngine the VelocityEngine to configure + /// resourceLoaderPath the path to load Velocity resources from + /// + /// + /// + /// + protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, String resourceLoaderFullPath) { + if (PreferFileSystemAccess) { + // Try to load via the file system, fall back to SpringResourceLoader + // (for hot detection of template changes, if possible). + 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()); + } catch (IOException ex) { + if (log.IsDebugEnabled) { + log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", resourceLoaderFullPath), ex); + } + InitSpringResourceLoader(velocityEngine, resourceLoaderFullPath); + } + } else { + // 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); + } + } + + /// + /// Initialize a SpringResourceLoader for the given VelocityEngine. + ///

Called by InitVelocityResourceLoader. + ///

+ /// 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); + } + + /// + /// To be implemented by subclasses that want to to perform custom + /// post-processing of the VelocityEngine after this FactoryBean + /// performed its default configuration (but before VelocityEngine.init) + ///

Called by CreateVelocityEngine() + ///

+ /// velocityEngine the current VelocityEngine + /// + /// + /// + protected static void PostProcessVelocityEngine(VelocityEngine velocityEngine) { + } + + /// + /// Populates the velocity properties from the given resource + /// + /// ExtendedProperties instance to populate + /// The resource from which to load the properties + private static void FillProperties(ExtendedProperties props, IInputStreamSource resource) { + try { + props.Load(resource.InputStream); + } finally { + resource.InputStream.Close(); + } + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs new file mode 100644 index 00000000..02126c91 --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineFactoryObject.cs @@ -0,0 +1,69 @@ +#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; +using NVelocity.App; +using Spring.Context; +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 + /// application code, e.g. for generating email content. + /// + /// See the base class VelocityEngineFactory for configuration details. + /// + /// + /// Erez Mazor (.NET) + public class VelocityEngineFactoryObject : VelocityEngineFactory, IFactoryObject, IInitializingObject, IResourceLoaderAware { + private VelocityEngine velocityEngine; + /// + /// Get the velocity engine underlying object + /// + /// An instance of a configured VelocityEngine + /// + public object GetObject() { + return velocityEngine; + } + + /// + /// Get the type of the velocity engine + /// + public Type ObjectType { + get { return velocityEngine.GetType(); } + } + + /// + /// Returns true + /// + public bool IsSingleton { + get { return true; } + } + + /// + /// Facilitate the creation of the velocity engine object + /// + public void AfterPropertiesSet() { + velocityEngine = CreateVelocityEngine(); + } + } +} \ No newline at end of file diff --git a/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs new file mode 100644 index 00000000..7ca23a57 --- /dev/null +++ b/src/Spring/Spring.Template.Velocity/Template/Velocity/VelocityEngineUtils.cs @@ -0,0 +1,120 @@ +#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; +using System.Collections; +using System.IO; +using Common.Logging; +using NVelocity; +using NVelocity.App; +using NVelocity.Exception; + +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) + 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. + /// + /// VelocityEngine to work with + /// the location of template, relative to Velocity's resource loader path + /// encoding the encoding of the template file + /// 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 + public static void MergeTemplate( + VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model, TextWriter writer) { + + try { + VelocityContext velocityContext = new VelocityContext(model); + velocityEngine.MergeTemplate(templateLocation, encoding, velocityContext, writer); + } catch (VelocityException) { + throw; + } catch (Exception ex) { + throw new VelocityException(ex.ToString(), ex); + } + } + + + /// + /// 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 Hashtable that contains model names as keys and model objects + /// the result as string + /// thrown if any exception is thrown by the velocity engine + public static string MergeTemplateIntostring( + VelocityEngine velocityEngine, string templateLocation, string encoding, Hashtable model) { + + StringWriter result = new StringWriter(); + MergeTemplate(velocityEngine, templateLocation, encoding, model, result); + return result.ToString(); + } + } +} \ No newline at end of file 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 new file mode 100644 index 00000000..26689329 --- /dev/null +++ b/test/Spring/Spring.Template.Velocity.Tests/Spring.Template.Velocity.Tests.csproj @@ -0,0 +1,80 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {10405837-CB67-40D8-9326-84C9383983E2} + Library + Properties + Spring.Template.Velocity.Tests + Spring.Template.Velocity.Tests + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\..\lib\Net\2.0\nunit.framework.dll + + + False + ..\..\..\lib\Net\2.0\NVelocity.dll + + + + 3.5 + + + + + + + + + + {710961A3-0DF4-49E4-A26E-F5B9C044AC84} + Spring.Core.2008 + + + {BF3AB954-8375-407C-9E98-4C51D8072784} + Spring.Template.Velocity.2008 + + + {44B16BAA-6DF8-447C-9D7F-3AD3D854D904} + Spring.Core.Tests.2008 + + + + + + + + + + + \ 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 new file mode 100644 index 00000000..fe06f7fe --- /dev/null +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.cs @@ -0,0 +1,58 @@ +#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 + +#region Imports + +using NUnit.Framework; +using NVelocity.App; +using Spring.Context.Support; +using Spring.Objects.Factory.Xml; + +#endregion + +namespace Spring.Template.Velocity.Tests.Template.Velocity +{ + /// + /// This class contains tests for VelocityEngineFactoryObject + /// + /// Mark Pollack + [TestFixture] + public class VelocityEngineFactoryObjectTests + { + [SetUp] + public void Setup() + { + } + + [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); + + + + } + } +} \ 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 new file mode 100644 index 00000000..b753bcb4 --- /dev/null +++ b/test/Spring/Spring.Template.Velocity.Tests/Template/Velocity/VelocityEngineFactoryObjectTests.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file