VelocityEngineFactory.cs :  » Inversion-of-Control-Dependency-Injection » Spring.net » Spring » Template » Velocity » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Inversion of Control Dependency Injection » Spring.net 
Spring.net » Spring » Template » Velocity » VelocityEngineFactory.cs
#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 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;
using Spring.Util;

namespace Spring.Template.Velocity{
    /// <summary>
    /// Factory that configures a VelocityEngine. Can be used standalone,
    /// but typically you will use VelocityEngineFactoryObject 
    /// for preparing a VelocityEngine as bean reference.
    ///
    /// <br/>
    /// 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.
    ///
    /// <br/>
    /// 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.
    ///
    /// <br/>
    /// 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.
    ///
    /// <br/>
    /// The simplest way to use this class is to specify a ResourceLoaderPath 
    /// property. the VelocityEngine typically then does not need any further 
    /// configuration.
    ///
    /// </summary>
    /// <see cref="CommonsLoggingLogSystem" />
    /// <see cref="VelocityEngineFactoryObject" />
    /// <see cref="CommonsLoggingLogSystem" />
    /// <author>Erez Mazor</author>
    public class VelocityEngineFactory {
        private const char DELIMITER = ',';

        /// <summary>
        /// Shared logger instance.
        /// </summary>
        protected static readonly ILog log = LogManager.GetLogger(typeof(VelocityEngineFactory));

        private IResource configLocation;

        private IDictionary<string, object> velocityProperties = new Dictionary<string, object>();

        private IList resourceLoaderPaths = new ArrayList();

        private IResourceLoader resourceLoader = new ConfigurableResourceLoader();

        private bool preferFileSystemAccess = true;

        private bool overrideLogging = true;

        /// <summary>
        ///  Set the location of the Velocity config file. Alternatively, you can specify all properties locally. 
        /// </summary> 
        /// <see cref="VelocityProperties"/>
        /// <see cref="ResourceLoaderPath"/>
        public IResource ConfigLocation {
            set { configLocation = value; }
        }

        /// <summary>
        /// Set local NVelocity properties.
        /// </summary>
        /// <see cref="VelocityProperties"/>
        public IDictionary<string, object> VelocityProperties {
            set { velocityProperties = value; }
        }

        /// <summary>
        /// Single ResourceLoaderPath
        /// </summary>
        /// <see cref="ResourceLoaderPaths"/>
        public string ResourceLoaderPath {
            set { resourceLoaderPaths.Add(value); }
        }

        /// <summary>
        /// Set the Velocity resource loader path via a Spring resource location.
        /// Accepts multiple locations in Velocity's comma-separated path style.
        /// <br/>
        /// 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.
        /// <br/>
        /// 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.
        /// <br/> 
        /// 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 throughout
        /// the life time of the application context (for example for class path resources).
        /// <br/>
        /// 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.
        /// <br/>
        /// 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 documentation for details. 
        /// </summary>
        ///  <see cref="ResourceLoader"/>
        ///  <see cref="VelocityProperties"/>
        ///  <see cref="PreferFileSystemAccess"/>
        ///  <see cref="SpringResourceLoader"/>
        ///  <see cref="FileResourceLoader"/>
        public IList ResourceLoaderPaths {
            set { resourceLoaderPaths = value; }
        }

        /// <summary>
        /// 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.
        /// 
        /// </summary>
        /// <see cref="ConfigurableResourceLoader"/>
        /// <see cref="ContextRegistry"/>
        /// 
        public IResourceLoader ResourceLoader {
            get { return resourceLoader; }
            set { resourceLoader = value; }
        }

        /// <summary>
        /// Set whether to prefer file system access for template loading.
        /// File system access enables hot detection of template changes.
        /// <br/>
        /// If this is enabled, VelocityEngineFactory will try to resolve the
        /// specified "resourceLoaderPath" as file system resource.
        /// <br/>
        /// 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 a directory while
        /// others reside in assembly files.
        /// </summary>
        /// <see cref="ResourceLoaderPath"/>
        public bool PreferFileSystemAccess {
            get { return preferFileSystemAccess; }
            set { preferFileSystemAccess = value; }
        }

        /// <summary>
        /// Set whether Velocity should log via Commons Logging, i.e. whether Velocity's 
        /// log system should be set to CommonsLoggingLogSystem. Default value is true
        /// </summary>
        /// <see cref="CommonsLoggingLogSystem"/>
        public bool OverrideLogging {
            get { return overrideLogging; }
            set { overrideLogging = value; }
        }


        /// <summary>
        ///  Create and initialize the VelocityEngine instance and return it
        /// </summary>
        /// <returns>VelocityEngine</returns>
        /// <exception cref="VelocityException" />
        /// <see cref="FillProperties" />
        /// <see cref="InitVelocityResourceLoader" />
        /// <see cref="PostProcessVelocityEngine" />
        /// <see cref="VelocityEngine.Init()" />
        public VelocityEngine CreateVelocityEngine() {
            ExtendedProperties extendedProperties = new ExtendedProperties();
            VelocityEngine velocityEngine = NewVelocityEngine();

            LoadDefaultProperties(extendedProperties);

            // Load config file if set.
            if (configLocation != null) {
                if (log.IsInfoEnabled) {
                    log.Info(string.Format("Loading Velocity config from [{0}]", configLocation));
                }
                FillProperties(extendedProperties, configLocation, false);
            }

            // merge local properties if set.
            if (velocityProperties.Count > 0) {
                foreach (KeyValuePair<string, object> pair in velocityProperties) {
                    extendedProperties.SetProperty(pair.Key, pair.Value);
                }
            }

            // Set a resource loader path, if required.
            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, extendedProperties, resourceLoaderPaths);
            }

            // Log via Commons Logging?
            if (overrideLogging) {
                velocityEngine.SetProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new CommonsLoggingLogSystem());
            }

            PostProcessVelocityEngine(velocityEngine);

            try {
                velocityEngine.Init(extendedProperties);
            } catch (Exception ex) {
                throw new VelocityException(ex.ToString(), ex);
            }

            return velocityEngine;
        }

        /// <summary>
        /// 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.,:
        /// <br/>
        /// 
        /// Pre-requisites:<br/>
        /// resource.manager.class=NVelocity.Runtime.Resource.ResourceManagerImpl <br/>
        /// directive.manager=NVelocity.Runtime.Directive.DirectiveManager <br/>
        /// runtime.introspector.uberspect=NVelocity.Util.Introspection.UberspectImpl <br/>
        /// </summary>
        private static void LoadDefaultProperties(ExtendedProperties 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, true);
            FillProperties(extendedProperties, defaultRuntimeDirectives, true);
        }

        /// <summary>
        ///  Return a new VelocityEngine. Subclasses can override this for
        /// custom initialization, or for using a mock object for testing. <br/>
        /// Called by CreateVelocityEngine()
        /// </summary>
        /// <returns>VelocityEngine instance (non-configured)</returns>
        /// <see cref="CreateVelocityEngine"/>
        protected static VelocityEngine NewVelocityEngine() {
            return new VelocityEngine();
        }

        /// <summary>
        /// Initialize a Velocity resource loader for the given VelocityEngine:
        /// either a standard Velocity FileResourceLoader or a SpringResourceLoader.
        /// <br/>Called by <code>CreateVelocityEngine()</code>.
        /// </summary>
        /// <param name="velocityEngine">velocityEngine the VelocityEngine to configure</param>
        /// <param name="extendedProperties"></param>
        /// <param name="paths">paths the path list to load Velocity resources from</param>
        /// <see cref="FileResourceLoader"/>
        /// <see cref="SpringResourceLoader"/>
        /// <see cref="InitSpringResourceLoader"/>
        /// <see cref="CreateVelocityEngine"/>
        protected void InitVelocityResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, 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();
                try {
                    foreach (string path in paths) {
                        IResource resource = ResourceLoader.GetResource(path);
                        resolvedPaths.Add(resource.File.FullName);
                    }

                    extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, VelocityConstants.File);
                    extendedProperties.SetProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, 
                        StringUtils.CollectionToCommaDelimitedString(resolvedPaths));
                } catch (IOException ex) {
                    if (log.IsDebugEnabled) {
                        log.Error(string.Format("Cannot resolve resource loader path [{0}] to [File]: using SpringResourceLoader", 
                            StringUtils.CollectionToCommaDelimitedString(resolvedPaths)), ex);
                    }

                    InitSpringResourceLoader(velocityEngine, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths));
                }
            } 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, extendedProperties, StringUtils.CollectionToCommaDelimitedString(paths));
            }
        }

        /// <summary>
        ///  Initialize a SpringResourceLoader for the given VelocityEngine.
        /// <br/>Called by <code>InitVelocityResourceLoader</code>.
        /// 
        /// <b>Important</b>: 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.
        /// </summary>
        /// <param name="velocityEngine">velocityEngine the VelocityEngine to configure</param>
        /// <param name="extendedProperties"></param>
        /// <param name="resourceLoaderPathString">resourceLoaderPath the path to load Velocity resources from</param>
        /// <see cref="SpringResourceLoader"/>
        /// <see cref="InitVelocityResourceLoader"/>
        protected void InitSpringResourceLoader(VelocityEngine velocityEngine, ExtendedProperties extendedProperties, string resourceLoaderPathString) {
            extendedProperties.SetProperty(RuntimeConstants.RESOURCE_LOADER, SpringResourceLoader.NAME);
            Type springResourceLoaderType = typeof(SpringResourceLoader);
            string springResourceLoaderTypeName = springResourceLoaderType.FullName + "; " + springResourceLoaderType.Assembly.GetName().Name;
            extendedProperties.SetProperty(SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, springResourceLoaderTypeName);
            velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER, ResourceLoader);
            velocityEngine.SetApplicationAttribute(SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, resourceLoaderPathString);
        }

        /// <summary>
        /// To be implemented by subclasses that want to to perform custom
        /// post-processing of the VelocityEngine after this FactoryObject
        /// performed its default configuration (but before VelocityEngine.init)
        /// <br/>
        /// Called by CreateVelocityEngine
        /// </summary>
        /// <param name="velocityEngine">velocityEngine the current VelocityEngine</param>
        /// <exception cref="IOException" />
        /// <see cref="CreateVelocityEngine"/>
        /// <see cref="VelocityEngine.Init()"/>
        protected void PostProcessVelocityEngine(VelocityEngine velocityEngine) {
        }

        /// <summary>
        /// Populates the velocity properties from the given resource
        /// </summary>
        /// <param name="extendedProperties">ExtendedProperties instance to populate</param>
        /// <param name="resource">The resource from which to load the properties</param>
        /// <param name="append">A flag indicated weather the properties loaded from the resource should be appended or replaced in the extendedProperties</param>
        private static void FillProperties(ExtendedProperties extendedProperties, IInputStreamSource resource, bool append) {
            try {
                if (append) {
                    extendedProperties.Load(resource.InputStream);
                } else {
                    ExtendedProperties overrides = new ExtendedProperties();
                    overrides.Load(resource.InputStream);
                    foreach (DictionaryEntry entry in overrides) {
                        extendedProperties.SetProperty(Convert.ToString(entry.Key), entry.Value);
                    }
                }
            } finally {
                resource.InputStream.Close();
            }
        }
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.