Leaked object in FileResourceLoader#templatePaths
-------------------------------------------------

                 Key: VELOCITY-715
                 URL: https://issues.apache.org/jira/browse/VELOCITY-715
             Project: Velocity
          Issue Type: Bug
          Components: Engine
         Environment: Sun JRE 6 Update 13
            Reporter: Atsushi Isobe
            Priority: Minor


 org.apache.velocity.runtime.resource.loader.FileResourceLoader#templatePaths 
has stored templatename and real file path permanently.So if 
VelocityEngine#getTemplate(String) has called by too many files, #templatePaths 
have been enlarged. 

Below my patch and test class.
---------------------------------------------------------------------------
--- 
./src/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java  
    (revision 772904)
+++ 
./src/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java  
    (working copy)
@@ -30,6 +30,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
 
 import org.apache.commons.collections.ExtendedProperties;
 import org.apache.velocity.exception.ResourceNotFoundException;
@@ -61,7 +62,7 @@
      * times of the files. This is synchronizedMap
      * instance.
      */
-    private Map templatePaths = Collections.synchronizedMap(new HashMap());
+    private Map templatePaths = Collections.synchronizedMap(new WeakHashMap());
 
     /** Shall we inspect unicode files to see what encoding they contain?. */
     private boolean unicode = false;
@@ -330,8 +331,8 @@
                 currentFile = testFile;
             }
         }
-        File file = getFile(path, fileName);
-        if (currentFile == null || !file.exists())
+        File file = path != null ? getFile(path, fileName) : null;
+        if (currentFile == null || file == null || !file.exists())
         {
             /*
              * noop: if the file is missing now (either the cached
@@ -365,6 +366,10 @@
     public long getLastModified(Resource resource)
     {
         String path = (String) templatePaths.get(resource.getName());
+        if (path == null)
+        {
+               return 0;
+        }
         File file = getFile(path, resource.getName());
 
         if (file.canRead())


---------------------------------------------------------------------------


import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.text.DecimalFormat;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;

public class FileResourceLoaderLeakedObjectTest {
        private static final String TEMPLATE_ENCODING = "UTF-8";
        private static final File TEMPLATE_DIRECTORY = new File("./");
        private static final String TEMPLATE_PREFIX = "testTemplate";
        private static final String TEMPLATE_SUFFIX = ".vm";
        private static final String TEMPLATE_STRING = "foobar";

        private static final Log log = 
LogFactory.getLog(FileResourceLoaderLeakedObjectTest.class);

        public static void main(String[] args) throws Exception {
                VelocityEngine ve = new VelocityEngine();
                Properties properties = new Properties();
        properties.put(Velocity.FILE_RESOURCE_LOADER_PATH, 
TEMPLATE_DIRECTORY.getPath());

                ve.init(properties);
                VelocityContext context = new VelocityContext();

                DecimalFormat countFormat = new DecimalFormat("000,000");
                DecimalFormat totalFormat = new DecimalFormat("000,000,000");
                
                StringWriter writer = new StringWriter();
                File tmp = null;

                for (int i = 0; i < 0x100000; i++) {
                        try {
                                tmp = File.createTempFile(TEMPLATE_PREFIX, 
TEMPLATE_SUFFIX, TEMPLATE_DIRECTORY);
                                FileUtils.writeStringToFile(tmp, 
TEMPLATE_STRING, TEMPLATE_ENCODING);
                                Template template = 
ve.getTemplate(tmp.getPath(), TEMPLATE_ENCODING);
                                template.merge(context, writer);

                                if ((i & 0xFFFF) == 0) {
                                        System.gc();
                                        Runtime runtime = Runtime.getRuntime();
                                        log.info(new StringBuilder("count: 
").append(countFormat.format(i)).append(" total: 
").append(totalFormat.format(runtime.totalMemory() - runtime.freeMemory())));
                                }
                        } catch (ResourceNotFoundException e) {
                                log.warn("", e);
                        } catch (ParseErrorException e) {
                                log.warn("", e);
                        } catch (MethodInvocationException e) {
                                log.warn("", e);
                        } catch (IOException e) {
                                log.warn("", e);
                        } catch (Exception e) {
                                log.warn("", e);
                        } finally {
                                if (tmp != null && tmp.exists()) {
                                        tmp.delete();
                                }
                        }
                }
        }
}

---------------------------------------------------------------------------


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to