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:17 UTC

[19/50] [abbrv] incubator-freemarker git commit: TemplateNameFormat internal API clarifications (terminology, JavaDocs)

TemplateNameFormat internal API clarifications (terminology, JavaDocs)


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

Branch: refs/heads/2.3
Commit: 3c0f1903a9b39153588fcdf5b3ba73dccc159784
Parents: 272008e
Author: ddekany <dd...@apache.org>
Authored: Sun Feb 12 12:55:30 2017 +0100
Committer: ddekany <dd...@apache.org>
Committed: Sun Feb 12 16:22:40 2017 +0100

----------------------------------------------------------------------
 .../java/freemarker/cache/TemplateCache.java    |   4 +-
 .../freemarker/cache/TemplateNameFormat.java    |  54 +++++---
 src/main/java/freemarker/cache/_CacheAPI.java   |   8 +-
 src/main/java/freemarker/core/Environment.java  |  12 +-
 .../cache/TemplateNameFormatTest.java           | 128 +++++++++----------
 5 files changed, 112 insertions(+), 94 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3c0f1903/src/main/java/freemarker/cache/TemplateCache.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/cache/TemplateCache.java b/src/main/java/freemarker/cache/TemplateCache.java
index ba37c57..6980cb5 100644
--- a/src/main/java/freemarker/cache/TemplateCache.java
+++ b/src/main/java/freemarker/cache/TemplateCache.java
@@ -275,7 +275,7 @@ public class TemplateCache {
         NullArgumentException.check("encoding", encoding);
         
         try {
-            name = templateNameFormat.normalizeAbsoluteName(name);
+            name = templateNameFormat.normalizeRootBasedName(name);
         } catch (MalformedTemplateNameException e) {
             // If we don't have to emulate backward compatible behavior, then just rethrow it: 
             if (templateNameFormat != TemplateNameFormat.DEFAULT_2_3_0
@@ -687,7 +687,7 @@ public class TemplateCache {
         if (encoding == null) {
             throw new IllegalArgumentException("Argument \"encoding\" can't be null");
         }
-        name = templateNameFormat.normalizeAbsoluteName(name);
+        name = templateNameFormat.normalizeRootBasedName(name);
         if (name != null && templateLoader != null) {
             boolean debug = LOG.isDebugEnabled();
             String debugName = debug

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3c0f1903/src/main/java/freemarker/cache/TemplateNameFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/cache/TemplateNameFormat.java b/src/main/java/freemarker/cache/TemplateNameFormat.java
index 2e06795..34782c5 100644
--- a/src/main/java/freemarker/cache/TemplateNameFormat.java
+++ b/src/main/java/freemarker/cache/TemplateNameFormat.java
@@ -100,24 +100,46 @@ public abstract class TemplateNameFormat {
     public static final TemplateNameFormat DEFAULT_2_4_0 = new Default020400();
     
     /**
-     * @param baseName Maybe {@code null}, maybe a "file" name instead of a "directory" name.
-     * @param targetName No {@code null}. Maybe relative, maybe absolute.
+     * Converts a name to a template root directory based name, so that it can be used to find a template without
+     * knowing what (like which template) has referred to it. The rules depend on the name format, but a typical example
+     * is converting "t.ftl" with base "sub/contex.ftl" to "sub/t.ftl".
+     * 
+     * @param baseName
+     *            Maybe a file name, maybe a directory name. The meaning of file name VS directory name depends on the
+     *            name format, but typically, something like "foo/bar/" is a directory name, and something like
+     *            "foo/bar" is a file name, and thus in the last case the effective base is "foo/" (i.e., the directory
+     *            that contains the file). Not {@code null}.
+     * @param targetName
+     *            The name to convert. This usually comes from a template that refers to another template by name. It
+     *            can be a relative name, or an absolute name. (In typical name formats absolute names start with
+     *            {@code "/"} or maybe with an URL scheme, and all others are relative). Not {@code null}.
+     * 
+     * @return The path in template root directory relative format, or even an absolute name (where the root directory
+     *         is not the real root directory of the file system, but the imaginary directory that exists to store the
+     *         templates). The standard implementations shipped with FreeMarker always return a root relative path
+     *         (except if the name starts with an URI schema, in which case a full URI is returned).
      */
-    abstract String toAbsoluteName(String baseName, String targetName) throws MalformedTemplateNameException;
+    abstract String toRootBasedName(String baseName, String targetName) throws MalformedTemplateNameException;
     
     /**
-     * @return For backward compatibility only, {@code null} is allowed and will be treated as if the template doesn't
-     *         exist (despite that a normalizer doesn't access the storage, so it's not its duty to decide that).
+     * Normalizes a template root directory based name (relative to the root or absolute), so that equivalent names
+     * become equivalent according {@link String#equals(Object)} too. The rules depend on the name format, but typical
+     * examples are "sub/../t.ftl" to "t.ftl", "sub/./t.ftl" to "sub/t.ftl" and "/t.ftl" to "t.ftl".
+     * 
+     * <p>The standard implementations shipped with FreeMarker always returns a root relative path
+     * (except if the name starts with an URI schema, in which case a full URI is returned), for example, "/foo.ftl"
+     * becomes to "foo.ftl".
+     * 
+     * @param name
+     *            The root based name. Not {@code null}.
+     * 
+     * @return The normalized root based name. Not {@code null}.
      */
-    abstract String normalizeAbsoluteName(String name) throws MalformedTemplateNameException;
+    abstract String normalizeRootBasedName(String name) throws MalformedTemplateNameException;
 
     private static final class Default020300 extends TemplateNameFormat {
         @Override
-        String toAbsoluteName(String baseName, String targetName) {
-            if (baseName == null) {
-                return targetName;
-            }
-            
+        String toRootBasedName(String baseName, String targetName) {
             if (targetName.indexOf("://") > 0) {
                 return targetName;
             } else if (targetName.startsWith("/")) {
@@ -136,7 +158,7 @@ public abstract class TemplateNameFormat {
         }
     
         @Override
-        String normalizeAbsoluteName(final String name) throws MalformedTemplateNameException {
+        String normalizeRootBasedName(final String name) throws MalformedTemplateNameException {
             // Disallow 0 for security reasons.
             checkNameHasNoNullCharacter(name);
             
@@ -188,11 +210,7 @@ public abstract class TemplateNameFormat {
 
     private static final class Default020400 extends TemplateNameFormat {
         @Override
-        String toAbsoluteName(String baseName, String targetName) {
-            if (baseName == null) {
-                return targetName;
-            }
-            
+        String toRootBasedName(String baseName, String targetName) {
             if (findSchemeSectionEnd(targetName) != 0) {
                 return targetName;
             } else if (targetName.startsWith("/")) {  // targetName is an absolute path
@@ -219,7 +237,7 @@ public abstract class TemplateNameFormat {
         }
     
         @Override
-        String normalizeAbsoluteName(final String name) throws MalformedTemplateNameException {
+        String normalizeRootBasedName(final String name) throws MalformedTemplateNameException {
             // Disallow 0 for security reasons.
             checkNameHasNoNullCharacter(name);
     

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3c0f1903/src/main/java/freemarker/cache/_CacheAPI.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/cache/_CacheAPI.java b/src/main/java/freemarker/cache/_CacheAPI.java
index fee6531..638be92 100644
--- a/src/main/java/freemarker/cache/_CacheAPI.java
+++ b/src/main/java/freemarker/cache/_CacheAPI.java
@@ -32,14 +32,14 @@ public final class _CacheAPI {
         // Not meant to be instantiated
     }
     
-    public static String toAbsoluteName(TemplateNameFormat templateNameFormat, String baseName, String targetName)
+    public static String toRootBasedName(TemplateNameFormat templateNameFormat, String baseName, String targetName)
             throws MalformedTemplateNameException {
-        return templateNameFormat.toAbsoluteName(baseName, targetName);
+        return templateNameFormat.toRootBasedName(baseName, targetName);
     }
 
-    public static String normalizeAbsoluteName(TemplateNameFormat templateNameFormat, String name)
+    public static String normalizeRootBasedName(TemplateNameFormat templateNameFormat, String name)
             throws MalformedTemplateNameException {
-        return templateNameFormat.normalizeAbsoluteName(name);
+        return templateNameFormat.normalizeRootBasedName(name);
     }
     
 }

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3c0f1903/src/main/java/freemarker/core/Environment.java
----------------------------------------------------------------------
diff --git a/src/main/java/freemarker/core/Environment.java b/src/main/java/freemarker/core/Environment.java
index feae500..306cf48 100644
--- a/src/main/java/freemarker/core/Environment.java
+++ b/src/main/java/freemarker/core/Environment.java
@@ -2610,7 +2610,7 @@ public final class Environment extends Configurable {
             // that (at least in 2.3.x) the name used for eager import namespace key isn't the template.sourceName, but
             // the looked up name (template.name), which we can get quickly:
             TemplateNameFormat tnf = getConfiguration().getTemplateNameFormat();
-            templateName = _CacheAPI.normalizeAbsoluteName(tnf, _CacheAPI.toAbsoluteName(tnf, null, templateName));
+            templateName = _CacheAPI.normalizeRootBasedName(tnf, templateName);
         }
         
         if (loadedLibs == null) {
@@ -2667,8 +2667,9 @@ public final class Environment extends Configurable {
      * template refers to another template.
      * 
      * @param baseName
-     *            The name to which relative {@code targetName}-s are relative to. Maybe {@code null}, which usually
-     *            means that the base is the root "directory". Assuming {@link TemplateNameFormat#DEFAULT_2_3_0} or
+     *            The name to which relative {@code targetName}-s are relative to. Maybe {@code null} (happens when
+     *            resolving names in nameless templates), which means that the base is the root "directory", and so the
+     *            {@code targetName} is returned without change. Assuming {@link TemplateNameFormat#DEFAULT_2_3_0} or
      *            {@link TemplateNameFormat#DEFAULT_2_4_0}, the rules are as follows. If you want to specify a base
      *            directory here, it must end with {@code "/"}. If it doesn't end with {@code "/"}, it's parent
      *            directory will be used as the base path. Might starts with a scheme part (like {@code "foo://"}, or
@@ -2687,12 +2688,11 @@ public final class Environment extends Configurable {
      */
     public String toFullTemplateName(String baseName, String targetName)
             throws MalformedTemplateNameException {
-        if (isClassicCompatible()) {
-            // Early FM only had absolute names.
+        if (isClassicCompatible() /* FM1 only had absolute names */ || baseName == null) {
             return targetName;
         }
 
-        return _CacheAPI.toAbsoluteName(configuration.getTemplateNameFormat(), baseName, targetName);
+        return _CacheAPI.toRootBasedName(configuration.getTemplateNameFormat(), baseName, targetName);
     }
 
     String renderElementToString(TemplateElement te) throws IOException, TemplateException {

http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3c0f1903/src/test/java/freemarker/cache/TemplateNameFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/freemarker/cache/TemplateNameFormatTest.java b/src/test/java/freemarker/cache/TemplateNameFormatTest.java
index d001965..77f9274 100644
--- a/src/test/java/freemarker/cache/TemplateNameFormatTest.java
+++ b/src/test/java/freemarker/cache/TemplateNameFormatTest.java
@@ -43,77 +43,77 @@ import freemarker.test.MonitoredTemplateLoader;
 public class TemplateNameFormatTest {
 
     @Test
-    public void testToAbsoluteName() throws MalformedTemplateNameException {
+    public void testToRootBasedName() throws MalformedTemplateNameException {
         // Path that are treated the same both in 2.3 and 2.4 format:
         for (TemplateNameFormat tnf : new TemplateNameFormat[] {
                 TemplateNameFormat.DEFAULT_2_3_0, TemplateNameFormat.DEFAULT_2_4_0 }) {
             // Relative paths:
             // - No scheme:
-            assertEquals("a/b", tnf.toAbsoluteName("a/", "b"));
-            assertEquals("/a/b", tnf.toAbsoluteName("/a/", "b"));
-            assertEquals("a/b", tnf.toAbsoluteName("a/f", "b"));
-            assertEquals("/a/b", tnf.toAbsoluteName("/a/f", "b"));
+            assertEquals("a/b", tnf.toRootBasedName("a/", "b"));
+            assertEquals("/a/b", tnf.toRootBasedName("/a/", "b"));
+            assertEquals("a/b", tnf.toRootBasedName("a/f", "b"));
+            assertEquals("/a/b", tnf.toRootBasedName("/a/f", "b"));
             // - Scheme:
-            assertEquals("s://a/b", tnf.toAbsoluteName("s://a/", "b"));
-            assertEquals("s:///a/b", tnf.toAbsoluteName("s:///a/", "b"));
-            assertEquals("s://a/b", tnf.toAbsoluteName("s://a/f", "b"));
-            assertEquals("s:///a/b", tnf.toAbsoluteName("s:///a/f", "b"));
-            assertEquals("s://b", tnf.toAbsoluteName("s://f", "b"));
-            assertEquals("s:///b", tnf.toAbsoluteName("s:///f", "b"));
+            assertEquals("s://a/b", tnf.toRootBasedName("s://a/", "b"));
+            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/", "b"));
+            assertEquals("s://a/b", tnf.toRootBasedName("s://a/f", "b"));
+            assertEquals("s:///a/b", tnf.toRootBasedName("s:///a/f", "b"));
+            assertEquals("s://b", tnf.toRootBasedName("s://f", "b"));
+            assertEquals("s:///b", tnf.toRootBasedName("s:///f", "b"));
             
             // Absolute paths:
             // - No scheme:
-            assertEquals("b", tnf.toAbsoluteName("a/", "/b"));
-            assertEquals("b", tnf.toAbsoluteName("/a/", "/b"));
-            assertEquals("b", tnf.toAbsoluteName("a/s:/f/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("a/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("/a/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("a/s:/f/", "/b"));
             // - Scheme:
-            assertEquals("s://b", tnf.toAbsoluteName("s://x/", "/b"));
-            assertEquals("s://b", tnf.toAbsoluteName("s:///x/", "/b"));
+            assertEquals("s://b", tnf.toRootBasedName("s://x/", "/b"));
+            assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b"));
             
             // Schemed absolute paths:
-            assertEquals("s://b", tnf.toAbsoluteName("a/", "s://b"));
-            assertEquals("s://b", tnf.toAbsoluteName("i://a/", "s://b"));
+            assertEquals("s://b", tnf.toRootBasedName("a/", "s://b"));
+            assertEquals("s://b", tnf.toRootBasedName("i://a/", "s://b"));
         }
         
         // Scheme names in 2.4 format only:
         {
             final TemplateNameFormat tnf = TemplateNameFormat.DEFAULT_2_4_0;
-            assertEquals("s:b", tnf.toAbsoluteName("s:f", "b"));
-            assertEquals("s:/b", tnf.toAbsoluteName("s:/f", "b"));
-            assertEquals("s:b", tnf.toAbsoluteName("s:f", "/b"));
-            assertEquals("s:b", tnf.toAbsoluteName("s:/f", "/b"));
-            assertEquals("s:f/b", tnf.toAbsoluteName("s:f/", "b"));
-            assertEquals("s:/f/b", tnf.toAbsoluteName("s:/f/", "b"));
-            assertEquals("s:b", tnf.toAbsoluteName("s:f/", "/b"));
-            assertEquals("s:b", tnf.toAbsoluteName("s:/f/", "/b"));
-            assertEquals("s:b", tnf.toAbsoluteName("s:/f/", "/b"));
-            assertEquals("b", tnf.toAbsoluteName("a/s://f/", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:f", "b"));
+            assertEquals("s:/b", tnf.toRootBasedName("s:/f", "b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:f", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f", "/b"));
+            assertEquals("s:f/b", tnf.toRootBasedName("s:f/", "b"));
+            assertEquals("s:/f/b", tnf.toRootBasedName("s:/f/", "b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:f/", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
+            assertEquals("s:b", tnf.toRootBasedName("s:/f/", "/b"));
+            assertEquals("b", tnf.toRootBasedName("a/s://f/", "/b"));
         }
         
         // Scheme names in 2.3 format only:
         {
             final TemplateNameFormat tnf = TemplateNameFormat.DEFAULT_2_3_0;
-            assertEquals("a/s://b", tnf.toAbsoluteName("a/s://f/", "/b"));
+            assertEquals("a/s://b", tnf.toRootBasedName("a/s://f/", "/b"));
         }
     }
 
     @Test
-    public void testNormalizeAbsoluteName() throws MalformedTemplateNameException {
+    public void testNormalizeRootBasedName() throws MalformedTemplateNameException {
         // Normalizations that are the same in legacy and modern format:
         for (TemplateNameFormat tnf : new TemplateNameFormat[] {
                 TemplateNameFormat.DEFAULT_2_3_0, TemplateNameFormat.DEFAULT_2_4_0 }) {
-            assertEquals("", tnf.normalizeAbsoluteName(""));
+            assertEquals("", tnf.normalizeRootBasedName(""));
             for (String lead : new String[] { "", "/" }) {
-                assertEquals("foo", tnf.normalizeAbsoluteName(lead + "foo"));
-                assertEquals("foo", tnf.normalizeAbsoluteName(lead + "./foo"));
-                assertEquals("foo", tnf.normalizeAbsoluteName(lead + "./././foo"));
-                assertEquals("foo", tnf.normalizeAbsoluteName(lead + "bar/../foo"));
-                assertEquals("a/b/", tnf.normalizeAbsoluteName("a/b/"));
-                assertEquals("a/", tnf.normalizeAbsoluteName("a/b/../"));
-                assertEquals("a/c../..d/e*/*f", tnf.normalizeAbsoluteName("a/c../..d/e*/*f"));
-                assertEquals("", tnf.normalizeAbsoluteName(""));
-                assertEquals("foo/bar/*", tnf.normalizeAbsoluteName("foo/bar/*"));
-                assertEquals("schema://", tnf.normalizeAbsoluteName("schema://"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "./././foo"));
+                assertEquals("foo", tnf.normalizeRootBasedName(lead + "bar/../foo"));
+                assertEquals("a/b/", tnf.normalizeRootBasedName("a/b/"));
+                assertEquals("a/", tnf.normalizeRootBasedName("a/b/../"));
+                assertEquals("a/c../..d/e*/*f", tnf.normalizeRootBasedName("a/c../..d/e*/*f"));
+                assertEquals("", tnf.normalizeRootBasedName(""));
+                assertEquals("foo/bar/*", tnf.normalizeRootBasedName("foo/bar/*"));
+                assertEquals("schema://", tnf.normalizeRootBasedName("schema://"));
                 
                 assertThrowsWithBackingOutException(lead + "bar/../../x/foo", tnf);
                 assertThrowsWithBackingOutException(lead + "../x", tnf);
@@ -124,7 +124,7 @@ public class TemplateNameFormatTest {
                 {
                     final String name = lead + "foo\u0000";
                     try {
-                        tnf.normalizeAbsoluteName(name);
+                        tnf.normalizeRootBasedName(name);
                         fail();
                     } catch (MalformedTemplateNameException e) {
                         assertEquals(name, e.getTemplateName());
@@ -139,15 +139,15 @@ public class TemplateNameFormatTest {
         assertEqualsOn23AndOn24("bar/foo", "foo", "bar/./../foo");
         
         // Even number of leading ".."-s bug:
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../foo");
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../../../foo");
         
         // ".." and "*"
         assertEqualsOn23AndOn24("a/b/foo", "a/*/foo", "a/b/*/../foo");
         //
         assertEqualsOn23AndOn24("a/foo", "foo", "a/b/*/../../foo");
         //
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("foo", "a/b/*/../../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "a/b/*/../../../foo");
         //
         assertEqualsOn23AndOn24("a/b/*/foo", "a/*/foo", "a/b/*/*/../foo");
         //
@@ -162,13 +162,13 @@ public class TemplateNameFormatTest {
         assertEqualsOn23AndOn24("*/", "", "a/../*/");
         
         // ".." and "scheme"
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("x:/foo", "x://../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:/foo", "x://../foo");
         //
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x://../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x://../../foo");
         //
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("x:../foo", "x:../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:../foo", "x:../foo");
         //
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x:../../foo");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x:../../foo");
 
         // Tricky cases with terminating "/":
         assertEqualsOn23AndOn24("/", "", "/");
@@ -180,7 +180,7 @@ public class TemplateNameFormatTest {
         // Lonely "."
         assertEqualsOn23AndOn24(".", "", ".");
         // Lonely ".."
-        assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24("..", "..");
+        assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("..", "..");
         // Lonely "*"
         
         // Eliminating redundant "//":
@@ -213,15 +213,15 @@ public class TemplateNameFormatTest {
         
         // New kind of scheme handling:
 
-        assertEquals("s:a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName("s:a/b"));
-        assertEquals("s:a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName("s:/a/b"));
-        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName("s://a/b"));
-        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName("s:///a/b"));
-        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName("s:////a/b"));
+        assertEquals("s:a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName("s:a/b"));
+        assertEquals("s:a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName("s:/a/b"));
+        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName("s://a/b"));
+        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName("s:///a/b"));
+        assertEquals("s://a/b", TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName("s:////a/b"));
         
         // Illegal use a of ":":
-        assertNormAbsNameThrowsColonExceptionOn24("a/b:c/d");
-        assertNormAbsNameThrowsColonExceptionOn24("a/b:/..");
+        assertNormRBNameThrowsColonExceptionOn24("a/b:c/d");
+        assertNormRBNameThrowsColonExceptionOn24("a/b:/..");
     }
     
     @Test
@@ -289,19 +289,19 @@ public class TemplateNameFormatTest {
     
     private void assertEqualsOn23AndOn24(String expected23, String expected24, String name)
             throws MalformedTemplateNameException {
-        assertEquals(expected23, TemplateNameFormat.DEFAULT_2_3_0.normalizeAbsoluteName(name));
-        assertEquals(expected24, TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName(name));
+        assertEquals(expected23, TemplateNameFormat.DEFAULT_2_3_0.normalizeRootBasedName(name));
+        assertEquals(expected24, TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName(name));
     }
 
-    private void assertNormAbsNameEqualsOn23ButThrowsBackOutExcOn24(final String expected23, final String name)
+    private void assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24(final String expected23, final String name)
             throws MalformedTemplateNameException {
-        assertEquals(expected23, TemplateNameFormat.DEFAULT_2_3_0.normalizeAbsoluteName(name));
+        assertEquals(expected23, TemplateNameFormat.DEFAULT_2_3_0.normalizeRootBasedName(name));
         assertThrowsWithBackingOutException(name, TemplateNameFormat.DEFAULT_2_4_0);
     }
 
     private void assertThrowsWithBackingOutException(final String name, final TemplateNameFormat tnf) {
         try {
-            tnf.normalizeAbsoluteName(name);
+            tnf.normalizeRootBasedName(name);
             fail();
         } catch (MalformedTemplateNameException e) {
             assertEquals(name, e.getTemplateName());
@@ -309,9 +309,9 @@ public class TemplateNameFormatTest {
         }
     }
 
-    private void assertNormAbsNameThrowsColonExceptionOn24(final String name) throws MalformedTemplateNameException {
+    private void assertNormRBNameThrowsColonExceptionOn24(final String name) throws MalformedTemplateNameException {
         try {
-            TemplateNameFormat.DEFAULT_2_4_0.normalizeAbsoluteName(name);
+            TemplateNameFormat.DEFAULT_2_4_0.normalizeRootBasedName(name);
             fail();
         } catch (MalformedTemplateNameException e) {
             assertEquals(name, e.getTemplateName());