You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/03/01 14:21:08 UTC

[10/50] [abbrv] incubator-freemarker git commit: - Fixed problem in StringTemplateLoader and ByteArrayTemplateLoader, which, in some fairly unlikely setups, could confuse the template cache if you are using multiple template loaders of the same class (vi

- Fixed problem in StringTemplateLoader and ByteArrayTemplateLoader, which, in some fairly unlikely setups, could confuse the template cache if you are using multiple template loaders of the same class (via MultiTemplateLoader) with clashing template names.

- Added missing removeTemplate method to ByteArrayTemplateLoader
- Documented that adding/removing templates is not thread safe in the TemplateLoader-s


Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/547a79fe
Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/547a79fe
Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/547a79fe

Branch: refs/heads/2.3
Commit: 547a79fed471d91e372b81c1db68501296cb38bd
Parents: 2065c57
Author: ddekany <dd...@apache.org>
Authored: Tue Feb 7 19:38:07 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Tue Feb 7 19:38:07 2017 +0100

----------------------------------------------------------------------
 .../cache/ByteArrayTemplateLoader.java          | 80 ++++++++++++--------
 .../freemarker/cache/StringTemplateLoader.java  | 69 ++++++++++++-----
 src/manual/en_US/book.xml                       | 31 +++-----
 3 files changed, 109 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/547a79fe/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java b/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java
index 11b2182..c089a85 100644
--- a/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java
+++ b/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java
@@ -24,8 +24,8 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 import freemarker.template.utility.StringUtil;
 
@@ -36,37 +36,35 @@ import freemarker.template.utility.StringUtil;
  * @since 2.3.24
  */
 public class ByteArrayTemplateLoader implements TemplateLoader {
+
+    private static final AtomicLong INSTANCE_COUNTER = new AtomicLong();
     
+    private final long instanceId = INSTANCE_COUNTER.incrementAndGet();
     private final Map<String, ByteArrayTemplateSource> templates = new HashMap<String, ByteArrayTemplateSource>();
     
     /**
-     * Puts a template into the loader. A call to this method is identical to 
-     * the call to the three-arg {@link #putTemplate(String, byte[], long)} 
-     * passing <tt>System.currentTimeMillis()</tt> as the third argument.
-     * @param name the name of the template.
-     * @param templateSource the source code of the template.
+     * Adds a template to this template loader; see {@link StringTemplateLoader#putTemplate(String, String)} for mpre.
      */
     public void putTemplate(String name, byte[] templateSource) {
         putTemplate(name, templateSource, System.currentTimeMillis());
     }
     
     /**
-     * Puts a template into the loader. The name can contain slashes to denote
-     * logical directory structure, but must not start with a slash. If the 
-     * method is called multiple times for the same name and with different
-     * last modified time, the configuration's template cache will reload the 
-     * template according to its own refresh settings (note that if the refresh 
-     * is disabled in the template cache, the template will not be reloaded).
-     * Also, since the cache uses lastModified to trigger reloads, calling the
-     * method with different source and identical timestamp won't trigger
-     * reloading.
-     * @param name the name of the template.
-     * @param templateSource the source code of the template.
-     * @param lastModified the time of last modification of the template in 
-     * terms of <tt>System.currentTimeMillis()</tt>
+     * Adds a template to this template loader; see {@link StringTemplateLoader#putTemplate(String, String, long)} for
+     * more.
      */
     public void putTemplate(String name, byte[] templateSource, long lastModified) {
-        templates.put(name, new ByteArrayTemplateSource(name, templateSource, lastModified));
+        templates.put(name, new ByteArrayTemplateSource(instanceId, name, templateSource, lastModified));
+    }
+    
+    /**
+     * Removes the template with the specified name if it was added earlier.; see
+     * {@link StringTemplateLoader#removeTemplate(String)} for more details.
+     * 
+     * @since 2.3.26
+     */
+    public boolean removeTemplate(String name) {
+        return templates.remove(name) != null;
     }
     
     public void closeTemplateSource(Object templateSource) {
@@ -87,11 +85,13 @@ public class ByteArrayTemplateLoader implements TemplateLoader {
     }
     
     private static class ByteArrayTemplateSource {
+        private final long instanceId;
         private final String name;
         private final byte[] source;
         private final long lastModified;
         
-        ByteArrayTemplateSource(String name, byte[] source, long lastModified) {
+        ByteArrayTemplateSource(long instanceId, String name, byte[] source, long lastModified) {
+            this.instanceId = instanceId;
             if (name == null) {
                 throw new IllegalArgumentException("name == null");
             }
@@ -105,19 +105,35 @@ public class ByteArrayTemplateLoader implements TemplateLoader {
             this.source = source;
             this.lastModified = lastModified;
         }
-        
+
         @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof ByteArrayTemplateSource) {
-                return name.equals(((ByteArrayTemplateSource) obj).name);
-            }
-            return false;
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (int) (instanceId ^ (instanceId >>> 32));
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            return result;
         }
-        
+
         @Override
-        public int hashCode() {
-            return name.hashCode();
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            ByteArrayTemplateSource other = (ByteArrayTemplateSource) obj;
+            if (instanceId != other.instanceId)
+                return false;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            return true;
         }
+        
     }
     
     /**
@@ -129,7 +145,7 @@ public class ByteArrayTemplateLoader implements TemplateLoader {
         sb.append(TemplateLoaderUtils.getClassNameForToString(this));
         sb.append("(Map { ");
         int cnt = 0;
-        for (Iterator it = templates.keySet().iterator(); it.hasNext(); ) {
+        for (String name : templates.keySet()) {
             cnt++;
             if (cnt != 1) {
                 sb.append(", ");
@@ -138,7 +154,7 @@ public class ByteArrayTemplateLoader implements TemplateLoader {
                 sb.append("...");
                 break;
             }
-            sb.append(StringUtil.jQuote(it.next()));
+            sb.append(StringUtil.jQuote(name));
             sb.append("=...");
         }
         if (cnt != 0) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/547a79fe/src/main/java/freemarker/cache/StringTemplateLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/cache/StringTemplateLoader.java b/src/main/java/freemarker/cache/StringTemplateLoader.java
index 25abd35..3f348b0 100644
--- a/src/main/java/freemarker/cache/StringTemplateLoader.java
+++ b/src/main/java/freemarker/cache/StringTemplateLoader.java
@@ -22,8 +22,8 @@ package freemarker.cache;
 import java.io.Reader;
 import java.io.StringReader;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
 
 import freemarker.template.utility.StringUtil;
 
@@ -31,7 +31,7 @@ import freemarker.template.utility.StringUtil;
  * A {@link TemplateLoader} that uses a {@link Map} with {@link String}-s as its source of 
  * templates.
  *
- * In most case the regular way of loading templates from files will be fine.
+ * <p>In most case the regular way of loading templates from files will be fine.
  * However, there can be situations where you don't want to or can't load a
  * template from a file, e.g. if you have to deploy a single jar for 
  * JavaWebStart or if they are contained within a database.
@@ -42,32 +42,39 @@ import freemarker.template.utility.StringUtil;
  *   Template t = new Template("name", new StringReader(templateStr),
  *               new Configuration());
  * </pre>
- * If, however, you want to create templates from strings which import other 
+ * <p>If, however, you want to create templates from strings which import other 
  * templates this method doesn't work.
  *
- * In that case you can create a StringTemplateLoader and add each template to 
+ * <p>In that case you can create a StringTemplateLoader and add each template to 
  * it:
  * <pre>
  *   StringTemplateLoader stringLoader = new StringTemplateLoader();
  *   stringLoader.putTemplate("greetTemplate", "&lt;#macro greet&gt;Hello&lt;/#macro&gt;");
  *   stringLoader.putTemplate("myTemplate", "&lt;#include \"greetTemplate\"&gt;&lt;@greet/&gt; World!");
  * </pre>
- * Then you tell your Configuration object to use it:
+ * <p>Then you tell your Configuration object to use it:
  * <pre>
  *   cfg.setTemplateLoader(stringLoader);
  * </pre>
- * After that you should be able to use the templates as usual. Often you will
+ * <p>After that you should be able to use the templates as usual. Often you will
  * want to combine a <tt>StringTemplateLoader</tt> with another loader. You can
  * do so using a {@link freemarker.cache.MultiTemplateLoader}.
  */
 public class StringTemplateLoader implements TemplateLoader {
     
+    private static final AtomicLong INSTANCE_COUNTER = new AtomicLong();
+    
+    private final long instanceId = INSTANCE_COUNTER.incrementAndGet();
     private final Map<String, StringTemplateSource> templates = new HashMap<String, StringTemplateSource>();
     
     /**
      * Puts a template into the loader. A call to this method is identical to 
      * the call to the three-arg {@link #putTemplate(String, String, long)} 
      * passing <tt>System.currentTimeMillis()</tt> as the third argument.
+     * 
+     * <p>Note that this method is not thread safe! Don't call it after FreeMarker has started using this template
+     * loader.
+     * 
      * @param name the name of the template.
      * @param templateSource the source code of the template.
      */
@@ -85,18 +92,25 @@ public class StringTemplateLoader implements TemplateLoader {
      * Also, since the cache uses lastModified to trigger reloads, calling the
      * method with different source and identical timestamp won't trigger
      * reloading.
+     * 
+     * <p>Note that this method is not thread safe! Don't call it after FreeMarker has started using this template
+     * loader.
+     * 
      * @param name the name of the template.
      * @param templateSource the source code of the template.
      * @param lastModified the time of last modification of the template in 
      * terms of <tt>System.currentTimeMillis()</tt>
      */
     public void putTemplate(String name, String templateSource, long lastModified) {
-        templates.put(name, new StringTemplateSource(name, templateSource, lastModified));
+        templates.put(name, new StringTemplateSource(instanceId, name, templateSource, lastModified));
     }
     
     /**
      * Removes the template with the specified name if it was added earlier.
      * 
+     * <p>Note that this method is not thread safe! Don't call it after FreeMarker has started using this template
+     * loader.
+     * 
      * @param name Exactly the key with which the template was added.
      * 
      * @return Whether a template was found with the given key (and hence was removed now) 
@@ -123,11 +137,13 @@ public class StringTemplateLoader implements TemplateLoader {
     }
     
     private static class StringTemplateSource {
+        private final long instanceId;
         private final String name;
         private final String source;
         private final long lastModified;
         
-        StringTemplateSource(String name, String source, long lastModified) {
+        StringTemplateSource(long instanceId, String name, String source, long lastModified) {
+            this.instanceId = instanceId;
             if (name == null) {
                 throw new IllegalArgumentException("name == null");
             }
@@ -143,18 +159,33 @@ public class StringTemplateLoader implements TemplateLoader {
         }
         
         @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof StringTemplateSource) {
-                return name.equals(((StringTemplateSource) obj).name);
-            }
-            return false;
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (int) (instanceId ^ (instanceId >>> 32));
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            return result;
         }
-        
+
         @Override
-        public int hashCode() {
-            return name.hashCode();
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            StringTemplateSource other = (StringTemplateSource) obj;
+            if (instanceId != other.instanceId)
+                return false;
+            if (name == null) {
+                if (other.name != null)
+                    return false;
+            } else if (!name.equals(other.name))
+                return false;
+            return true;
         }
-        
+
         @Override
         public String toString() {
             return name;
@@ -173,7 +204,7 @@ public class StringTemplateLoader implements TemplateLoader {
         sb.append(TemplateLoaderUtils.getClassNameForToString(this));
         sb.append("(Map { ");
         int cnt = 0;
-        for (Iterator it = templates.keySet().iterator(); it.hasNext(); ) {
+        for (String name : templates.keySet()) {
             cnt++;
             if (cnt != 1) {
                 sb.append(", ");
@@ -182,7 +213,7 @@ public class StringTemplateLoader implements TemplateLoader {
                 sb.append("...");
                 break;
             }
-            sb.append(StringUtil.jQuote(it.next()));
+            sb.append(StringUtil.jQuote(name));
             sb.append("=...");
         }
         if (cnt != 0) {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/547a79fe/src/manual/en_US/book.xml
----------------------------------------------------------------------
diff --git a/src/manual/en_US/book.xml b/src/manual/en_US/book.xml
index 3f9ccef..1903d0c 100644
--- a/src/manual/en_US/book.xml
+++ b/src/manual/en_US/book.xml
@@ -26873,31 +26873,18 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               <literal>Configuration.setTemplateLoader(null)</literal> is also
               allowed for a while.).</para>
             </listitem>
-          </itemizedlist>
-        </section>
-
-        <section>
-          <title>Other changes</title>
 
-          <itemizedlist>
             <listitem>
-              <para><link
-              xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-17">FREEMARKER-17</link>:
-              Removed the Servlet- and JSP-related <literal>*.dtd</literal>
-              files to simplify licensing. We can operate without them as
-              before, as validation with them was disabled earlier too. At
-              this point, everything in the source code of the FreeMarker
-              engine, and everything in the produced
-              <literal>freemarker.jar</literal> was created inside the
-              FreeMarker project.</para>
+              <para>Fixed problem in <literal>StringTemplateLoader</literal>
+              and <literal>ByteArrayTemplateLoader</literal>, which, in some
+              fairly unlikely setups, could confuse the template cache if you
+              are using multiple template loaders of the same class (via
+              <literal>MultiTemplateLoader</literal>) with clashing template
+              names.</para>
             </listitem>
 
             <listitem>
-              <para><link
-              xlink:href="https://issues.apache.org/jira/browse/FREEMARKER-27">FREEMARKER-27</link>:
-              Moved some content from the <literal>NOTICES</literal> files
-              over to the <literal>LICENSE</literal> file, to follow the
-              Apache Incubator guidelines closer.</para>
+              <para>Various smaller code cleanups.</para>
             </listitem>
           </itemizedlist>
         </section>
@@ -26925,6 +26912,10 @@ TemplateModel x = env.getVariable("x");  // get variable x</programlisting>
               over to the <literal>LICENSE</literal> file, to follow the
               Apache Incubator guidelines closer.</para>
             </listitem>
+
+            <listitem>
+              <para>Various smaller JavaDoc improvements.</para>
+            </listitem>
           </itemizedlist>
         </section>
       </section>