This is an automated email from the ASF dual-hosted git repository.

cbrisson pushed a commit to branch VELOCITY-943
in repository https://gitbox.apache.org/repos/asf/velocity-engine.git


The following commit(s) were added to refs/heads/VELOCITY-943 by this push:
     new 977b3881 Proposed conditional patch to address VELOCITY-943 (#51)
977b3881 is described below

commit 977b3881ac7e716adeaa40039ed23c9042bbf4cb
Author: Scott Cantor <[email protected]>
AuthorDate: Sat Sep 7 05:25:02 2024 -0400

    Proposed conditional patch to address VELOCITY-943 (#51)
    
    * Cleaning up log statements and some null checks.
    
    * Clean up logging statements.
    
    * Spring loader should not replace any existing loaders.
    
    * VELOCITY-943 - File vs. classpath issues with Spring
    VelocityEngineFactory
    
    Add conditional enhanced processing of classpaths.
    
    * Replace tabs.
    
    * Remove conditional from logic, unilaterally fix behavior.
---
 .../velocity/spring/SpringResourceLoader.java      |  16 +-
 .../velocity/spring/VelocityEngineFactory.java     | 250 ++++++++++++---------
 2 files changed, 154 insertions(+), 112 deletions(-)

diff --git 
a/spring-velocity-support/src/main/java/org/apache/velocity/spring/SpringResourceLoader.java
 
b/spring-velocity-support/src/main/java/org/apache/velocity/spring/SpringResourceLoader.java
index 62ab8aa0..83691ad7 100644
--- 
a/spring-velocity-support/src/main/java/org/apache/velocity/spring/SpringResourceLoader.java
+++ 
b/spring-velocity-support/src/main/java/org/apache/velocity/spring/SpringResourceLoader.java
@@ -91,8 +91,8 @@ public class SpringResourceLoader extends ResourceLoader {
                }
        }
        if (logger.isInfoEnabled()) {
-               logger.info("SpringResourceLoader for Velocity: using resource 
loader [" + this.resourceLoader +
-                               "] and resource loader paths " + 
Arrays.asList(this.resourceLoaderPaths));
+               logger.info("SpringResourceLoader for Velocity: using resource 
loader [{}] and resource loader paths {}",
+                       resourceLoader, 
Arrays.asList(this.resourceLoaderPaths));
        }
     }
 
@@ -108,19 +108,17 @@ public class SpringResourceLoader extends ResourceLoader {
      */
     @Override
     public Reader getResourceReader(String source, String encoding) throws 
ResourceNotFoundException {
-       if (logger.isDebugEnabled()) {
-               logger.debug("Looking for Velocity resource with name [" + 
source + "]");
-       }
+               logger.debug("Looking for Velocity resource with name [{}]", 
source);
        for (String resourceLoaderPath : this.resourceLoaderPaths) {
                org.springframework.core.io.Resource resource =
                                
this.resourceLoader.getResource(resourceLoaderPath + source);
                try {
-                       return new InputStreamReader(resource.getInputStream(), 
encoding);
+                   if (resource != null) {
+                       return new InputStreamReader(resource.getInputStream(), 
encoding);
+                   }
                }
                catch (IOException ex) {
-                       if (logger.isDebugEnabled()) {
-                               logger.debug("Could not find Velocity resource: 
" + resource);
-                       }
+                               logger.debug("Could not find Velocity resource: 
{}", resource);
                }
        }
        throw new ResourceNotFoundException(
diff --git 
a/spring-velocity-support/src/main/java/org/apache/velocity/spring/VelocityEngineFactory.java
 
b/spring-velocity-support/src/main/java/org/apache/velocity/spring/VelocityEngineFactory.java
index c38590b0..6a042527 100644
--- 
a/spring-velocity-support/src/main/java/org/apache/velocity/spring/VelocityEngineFactory.java
+++ 
b/spring-velocity-support/src/main/java/org/apache/velocity/spring/VelocityEngineFactory.java
@@ -18,7 +18,9 @@ package org.apache.velocity.spring;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
@@ -80,44 +82,52 @@ public class VelocityEngineFactory {
 
     private boolean preferFileSystemAccess = true;
 
-    private boolean overrideLogging = true;
-
 
     /**
      * Set the location of the Velocity config file.
      * Alternatively, you can specify all properties locally.
+     * 
+     * @param configLocation config resource
+     * 
      * @see #setVelocityProperties
      * @see #setResourceLoaderPath
      */
     public void setConfigLocation(Resource configLocation) {
-       this.configLocation = configLocation;
+        this.configLocation = configLocation;
     }
 
     /**
      * Set Velocity properties, like "file.resource.loader.path".
      * Can be used to override values in a Velocity config file,
      * or to specify all necessary properties locally.
+     * 
      * <p>Note that the Velocity resource loader path also be set to any
      * Spring resource location via the "resourceLoaderPath" property.
      * Setting it here is just necessary when using a non-file-based
-     * resource loader.
+     * resource loader.</p>
+     * 
+     * @param velocityProperties engine properties to include
+     *  
      * @see #setVelocityPropertiesMap
      * @see #setConfigLocation
      * @see #setResourceLoaderPath
      */
     public void setVelocityProperties(Properties velocityProperties) {
-       CollectionUtils.mergePropertiesIntoMap(velocityProperties, 
this.velocityProperties);
+        CollectionUtils.mergePropertiesIntoMap(velocityProperties, 
this.velocityProperties);
     }
 
     /**
      * Set Velocity properties as Map, to allow for non-String values
      * like "ds.resource.loader.instance".
+     * 
+     * @param velocityPropertiesMap engine properties to include
+     *  
      * @see #setVelocityProperties
      */
     public void setVelocityPropertiesMap(Map<String, Object> 
velocityPropertiesMap) {
-       if (velocityPropertiesMap != null) {
-               this.velocityProperties.putAll(velocityPropertiesMap);
-       }
+        if (velocityPropertiesMap != null) {
+            this.velocityProperties.putAll(velocityPropertiesMap);
+        }
     }
 
     /**
@@ -126,21 +136,27 @@ public class VelocityEngineFactory {
      * <p>When populated via a String, standard URLs like "file:" and 
"classpath:"
      * pseudo URLs are supported, as understood by ResourceLoader. Allows for
      * relative paths when running in an ApplicationContext.
+     * 
      * <p>Will define a path for the default Velocity resource loader with the 
name
      * "file". If the specified resource cannot be resolved to a {@code 
java.io.File},
      * a generic SpringResourceLoader will be used under the name "spring", 
without
-     * modification detection.
+     * modification detection.</p>
+     * 
      * <p>Note 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).
+     * forever (for example for class path resources).</p>
+     * 
      * <p>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.
      * <p>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 javadoc for details.</p>
+     * 
+     * @param resourceLoaderPath comma-separated resource paths
+     *  
      * @see #setResourceLoader
      * @see #setVelocityProperties
      * @see #setPreferFileSystemAccess
@@ -148,48 +164,61 @@ public class VelocityEngineFactory {
      * @see org.apache.velocity.runtime.resource.loader.FileResourceLoader
      */
     public void setResourceLoaderPath(String resourceLoaderPath) {
-       this.resourceLoaderPath = resourceLoaderPath;
+        this.resourceLoaderPath = resourceLoaderPath;
     }
 
     /**
      * 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.
+     * 
+     * <p>The default is DefaultResourceLoader. Will get overridden by the
+     * ApplicationContext if running in a context.</p>
+     * 
+     * @param resourceLoader Spring resource loader to ue 
+     * 
      * @see org.springframework.core.io.DefaultResourceLoader
      * @see org.springframework.context.ApplicationContext
      */
     public void setResourceLoader(ResourceLoader resourceLoader) {
-       this.resourceLoader = resourceLoader;
+        this.resourceLoader = resourceLoader;
     }
 
     /**
      * Return the Spring ResourceLoader to use for loading Velocity template 
files.
+     * 
+     * @return Spring resource loader to use 
      */
     protected ResourceLoader getResourceLoader() {
-       return this.resourceLoader;
+        return this.resourceLoader;
     }
 
     /**
      * Set whether to prefer file system access for template loading.
      * File system access enables hot detection of template changes.
+     * 
      * <p>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).
+     * specified "resourceLoaderPath" as file system resources, but only when
+     * non-classpath resource paths are included.</p>
+     * 
      * <p>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.
+     * directory while others reside in jar files.</p>
+     * 
+     * @param preferFileSystemAccess whether to rely on file-based loading 
when possible
+     * 
      * @see #setResourceLoaderPath
      */
     public void setPreferFileSystemAccess(boolean preferFileSystemAccess) {
-       this.preferFileSystemAccess = preferFileSystemAccess;
+        this.preferFileSystemAccess = preferFileSystemAccess;
     }
 
     /**
      * Return whether to prefer file system access for template loading.
+     * 
+     * @return  whether to prefer file system access for template loading
      */
     protected boolean isPreferFileSystemAccess() {
-       return this.preferFileSystemAccess;
+        return this.preferFileSystemAccess;
     }
 
     /**
@@ -199,38 +228,36 @@ public class VelocityEngineFactory {
      * @throws VelocityException on Velocity initialization failure
      */
     public VelocityEngine createVelocityEngine() throws IOException, 
VelocityException {
-       VelocityEngine velocityEngine = newVelocityEngine();
-       Map<String, Object> props = new HashMap<String, Object>();
-
-       // Load config file if set.
-       if (this.configLocation != null) {
-               if (logger.isInfoEnabled()) {
-                       logger.info("Loading Velocity config from [" + 
this.configLocation + "]");
-               }
-               
CollectionUtils.mergePropertiesIntoMap(PropertiesLoaderUtils.loadProperties(this.configLocation),
 props);
-       }
-
-       // Merge local properties if set.
-       if (!this.velocityProperties.isEmpty()) {
-               props.putAll(this.velocityProperties);
-       }
-
-       // Set a resource loader path, if required.
-       if (this.resourceLoaderPath != null) {
-               initVelocityResourceLoader(velocityEngine, 
this.resourceLoaderPath);
-       }
-
-       // Apply properties to VelocityEngine.
-       for (Map.Entry<String, Object> entry : props.entrySet()) {
-               velocityEngine.setProperty(entry.getKey(), entry.getValue());
-       }
-
-       postProcessVelocityEngine(velocityEngine);
-
-       // Perform actual initialization.
-       velocityEngine.init();
-
-       return velocityEngine;
+        VelocityEngine velocityEngine = newVelocityEngine();
+        Map<String, Object> props = new HashMap<String, Object>();
+
+        // Load config file if set.
+        if (this.configLocation != null) {
+            logger.info("Loading Velocity config from [{}]", 
this.configLocation);
+            
CollectionUtils.mergePropertiesIntoMap(PropertiesLoaderUtils.loadProperties(this.configLocation),
 props);
+        }
+
+        // Merge local properties if set.
+        if (!this.velocityProperties.isEmpty()) {
+            props.putAll(this.velocityProperties);
+        }
+
+        // Set a resource loader path, if required.
+        if (this.resourceLoaderPath != null) {
+            initVelocityResourceLoader(velocityEngine, 
this.resourceLoaderPath);
+        }
+
+        // Apply properties to VelocityEngine.
+        for (Map.Entry<String, Object> entry : props.entrySet()) {
+            velocityEngine.setProperty(entry.getKey(), entry.getValue());
+        }
+
+        postProcessVelocityEngine(velocityEngine);
+
+        // Perform actual initialization.
+        velocityEngine.init();
+
+        return velocityEngine;
     }
 
     /**
@@ -243,7 +270,7 @@ public class VelocityEngineFactory {
      * @see #createVelocityEngine()
      */
     protected VelocityEngine newVelocityEngine() throws IOException, 
VelocityException {
-       return new VelocityEngine();
+        return new VelocityEngine();
     }
 
     /**
@@ -258,44 +285,61 @@ public class VelocityEngineFactory {
      * @see #createVelocityEngine()
      */
     protected void initVelocityResourceLoader(VelocityEngine velocityEngine, 
String resourceLoaderPath) {
-       if (isPreferFileSystemAccess()) {
-               // 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 = 
StringUtils.commaDelimitedListToStringArray(resourceLoaderPath);
-                       for (int i = 0; i < paths.length; i++) {
-                               String path = paths[i];
-                               Resource resource = 
getResourceLoader().getResource(path);
-                               File file = resource.getFile();  // will fail 
if not resolvable in the file system
-                               if (logger.isDebugEnabled()) {
-                                       logger.debug("Resource loader path [" + 
path + "] resolved to file [" + file.getAbsolutePath() + "]");
-                               }
-                               resolvedPath.append(file.getAbsolutePath());
-                               if (i < paths.length - 1) {
-                                       resolvedPath.append(',');
-                               }
-                       }
-                       
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADERS, "file");
-                       
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
-                       
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, 
resolvedPath.toString());
-               }
-               catch (IOException ex) {
-                       if (logger.isDebugEnabled()) {
-                               logger.debug("Cannot resolve resource loader 
path [" + resourceLoaderPath +
-                                               "] to [java.io.File]: using 
SpringResourceLoader", ex);
-                       }
-                       initSpringResourceLoader(velocityEngine, 
resourceLoaderPath);
-               }
-       }
-       else {
-               // Always load via SpringResourceLoader
-               // (without hot detection of template changes).
-               if (logger.isDebugEnabled()) {
-                       logger.debug("File system access not preferred: using 
SpringResourceLoader");
-               }
-               initSpringResourceLoader(velocityEngine, resourceLoaderPath);
-       }
+        
+        final ResourceLoader loader = getResourceLoader();
+        if (loader != null && isPreferFileSystemAccess()) {
+
+            // Try to load via the file system, fall back to 
SpringResourceLoader
+            // (for hot detection of template changes, if possible).
+            
+            final List<String> filePaths = new ArrayList<>();
+            final List<String> nonFilePaths = new ArrayList<>();
+
+            String[] paths = 
StringUtils.commaDelimitedListToStringArray(resourceLoaderPath);
+
+            // Try to load via the file system, fall back to 
SpringResourceLoader
+            // (for hot detection of template changes, if possible).
+            for (int i = 0; i < paths.length; i++) {
+                String path = paths[i];
+                
+                // Don't check classpath: locations for existence, they're not 
file-based.
+                // Some containers will expand jars and trigger false 
positives.
+                if (path.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX)) {
+                    logger.debug("Using SpringResourceLoader for '{}'", path);
+                    nonFilePaths.add(path);
+                    continue;
+                }
+
+                try {
+                    Resource resource = loader.getResource(path);
+                    File file = resource.getFile();  // will fail if not 
resolvable in the file system
+                    
+                    logger.debug("Resource loader path [{}] resolved to file 
[{}]", path, file.getAbsolutePath());
+                    filePaths.add(file.getAbsolutePath());
+                }
+                catch (IOException ex) {
+                    logger.debug("Cannot resolve resource loader path '{}' to 
filesystem, will use SpringResourceLoader", path, ex);
+                    nonFilePaths.add(path);
+                }
+            }
+
+            if (!filePaths.isEmpty()) {
+                velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADERS, 
"file");
+                
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
+                
velocityEngine.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH,
+                        
StringUtils.collectionToCommaDelimitedString(filePaths));
+            }
+            
+            if (!nonFilePaths.isEmpty()) {
+                initSpringResourceLoader(velocityEngine, 
StringUtils.collectionToCommaDelimitedString(nonFilePaths));
+            }
+        }
+        else {
+            // Always load via SpringResourceLoader
+            // (without hot detection of template changes).
+            logger.debug("File system access not preferred: using 
SpringResourceLoader");
+            initSpringResourceLoader(velocityEngine, resourceLoaderPath);
+        }
     }
 
     /**
@@ -307,16 +351,16 @@ public class VelocityEngineFactory {
      * @see #initVelocityResourceLoader
      */
     protected void initSpringResourceLoader(VelocityEngine velocityEngine, 
String resourceLoaderPath) {
-       velocityEngine.setProperty(
-                       RuntimeConstants.RESOURCE_LOADERS, 
SpringResourceLoader.NAME);
-       velocityEngine.setProperty(
-                       SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, 
SpringResourceLoader.class.getName());
-       velocityEngine.setProperty(
-                       SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, 
"true");
-       velocityEngine.setApplicationAttribute(
-                       SpringResourceLoader.SPRING_RESOURCE_LOADER, 
getResourceLoader());
-       velocityEngine.setApplicationAttribute(
-                       SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, 
resourceLoaderPath);
+        velocityEngine.addProperty(
+                RuntimeConstants.RESOURCE_LOADERS, SpringResourceLoader.NAME);
+        velocityEngine.setProperty(
+                SpringResourceLoader.SPRING_RESOURCE_LOADER_CLASS, 
SpringResourceLoader.class.getName());
+        velocityEngine.setProperty(
+                SpringResourceLoader.SPRING_RESOURCE_LOADER_CACHE, "true");
+        velocityEngine.setApplicationAttribute(
+                SpringResourceLoader.SPRING_RESOURCE_LOADER, 
getResourceLoader());
+        velocityEngine.setApplicationAttribute(
+                SpringResourceLoader.SPRING_RESOURCE_LOADER_PATH, 
resourceLoaderPath);
     }
 
     /**
@@ -331,7 +375,7 @@ public class VelocityEngineFactory {
      * @see org.apache.velocity.app.VelocityEngine#init
      */
     protected void postProcessVelocityEngine(VelocityEngine velocityEngine)
-               throws IOException, VelocityException {
+            throws IOException, VelocityException {
     }
 
 }

Reply via email to