Repository: incubator-freemarker Updated Branches: refs/heads/3 4a79ad8a4 -> 05f297590
Changed the default of templateNameFormat (template_name_format) to what's equivalent to FM2 DefaultTemplateNameFormat24. The old (FM2) DefaultTemplateNameFormat was removed, and FM2 DefaultTemplateNameFormat24 was renamed to DefaultTemplateNameFormat. Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/05f29759 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/05f29759 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/05f29759 Branch: refs/heads/3 Commit: 05f2975901e48549757f5a668f98b4ef101a0ecb Parents: 4a79ad8 Author: ddekany <[email protected]> Authored: Tue Jun 13 13:25:55 2017 +0200 Committer: ddekany <[email protected]> Committed: Tue Jun 13 13:25:55 2017 +0200 ---------------------------------------------------------------------- FM3-CHANGE-LOG.txt | 3 + .../freemarker/core/ConfigurationTest.java | 27 +- .../freemarker/core/IncludeAndImportTest.java | 2 +- .../core/TemplateNotFoundMessageTest.java | 2 +- .../TemplateNameFormatTest.java | 308 +++++++------------ .../apache/freemarker/core/Configuration.java | 42 ++- .../org/apache/freemarker/core/Environment.java | 32 +- .../core/MutableProcessingConfiguration.java | 4 +- .../freemarker/core/TopLevelConfiguration.java | 4 +- .../MalformedTemplateNameException.java | 7 +- .../impl/DefaultTemplateNameFormat.java | 77 ++--- .../impl/DefaultTemplateNameFormatFM2.java | 105 ------- .../impl/DefaultTemplateResolver.java | 6 +- 13 files changed, 190 insertions(+), 429 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/FM3-CHANGE-LOG.txt ---------------------------------------------------------------------- diff --git a/FM3-CHANGE-LOG.txt b/FM3-CHANGE-LOG.txt index e73dbad..a63f5ef 100644 --- a/FM3-CHANGE-LOG.txt +++ b/FM3-CHANGE-LOG.txt @@ -270,6 +270,9 @@ the FreeMarer 3 changelog here: TemplateExceptionHandler.RETHROW_HANDLER from DEBUG_HANDLER - Changed the default of sqlDateAndTimeTimeZone (sql_date_and_time_time_zone) to TimeZone.default() from null (where null meant falling back to the timeZone setting value) + - Changed the default of templateNameFormat (template_name_format) to what's equivalent to + FM2 DefaultTemplateNameFormat24. The old DefaultTemplateNameFormat was removed, and + DefaultTemplateNameFormat24 was renamed to DefaultTemplateNameFormat. - Removed the logTemplateExceptions (log_template_exceptions) setting. FreeMarker now behaves as if it was false. When a FreeMarker method throws an exception, the caller is responsible for either logging it or letting it bubble up. \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java index d92ced4..a010828 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/ConfigurationTest.java @@ -64,7 +64,6 @@ import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader; import org.apache.freemarker.core.templateresolver.impl.ClassTemplateLoader; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver; import org.apache.freemarker.core.templateresolver.impl.NullCacheStorage; import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage; @@ -170,16 +169,16 @@ public class ConfigurationTest { } assertFalse(cfgB.isTemplateNameFormatSet()); - assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat()); + assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat()); // - cfgB.setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE); + cfgB.setTemplateNameFormat(null); assertTrue(cfgB.isTemplateNameFormatSet()); - assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat()); + assertNull(cfgB.getTemplateNameFormat()); // for (int i = 0; i < 2; i++) { cfgB.unsetTemplateNameFormat(); assertFalse(cfgB.isTemplateNameFormatSet()); - assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat()); + assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat()); } assertFalse(cfgB.isTemplateCacheStorageSet()); @@ -411,17 +410,6 @@ public class ConfigurationTest { { Configuration cfg = new Builder(VERSION_3_0_0) .templateLoader(tl) - .templateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE) - .build(); - final Template template = cfg.getTemplate("a/./../b.ftl"); - assertEquals("a/b.ftl", template.getLookupName()); - assertEquals("a/b.ftl", template.getSourceName()); - assertEquals("In a/b.ftl", template.toString()); - } - - { - Configuration cfg = new Builder(VERSION_3_0_0) - .templateLoader(tl) .templateNameFormat(DefaultTemplateNameFormat.INSTANCE) .build(); final Template template = cfg.getTemplate("a/./../b.ftl"); @@ -434,12 +422,9 @@ public class ConfigurationTest { @Test public void testTemplateNameFormatSetSetting() throws Exception { Builder cfgB = new Builder(VERSION_3_0_0); - assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat()); - cfgB.setSetting(TEMPLATE_NAME_FORMAT_KEY, "defAult_2_4_0"); assertSame(DefaultTemplateNameFormat.INSTANCE, cfgB.getTemplateNameFormat()); - cfgB.setSetting(TEMPLATE_NAME_FORMAT_KEY, "defaUlt_2_3_0"); - assertSame(DefaultTemplateNameFormatFM2.INSTANCE, cfgB.getTemplateNameFormat()); - assertTrue(cfgB.isTemplateNameFormatSet()); + cfgB.setTemplateNameFormat(null); + assertNull(cfgB.getTemplateNameFormat()); cfgB.setSetting(TEMPLATE_NAME_FORMAT_KEY, "defauLt"); assertFalse(cfgB.isTemplateNameFormatSet()); } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java index c8a0186..ac1b907 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/IncludeAndImportTest.java @@ -121,7 +121,7 @@ public class IncludeAndImportTest extends TemplateTest { // The opposite of the previous, where different names refer to the same template after a lookup: assertOutput( "<#setting locale='en_US'>" - + "<#import '*/lib.ftl' as ns1>" + + "<#import 'x/*/lib.ftl' as ns1>" + "<#import 'lib.ftl' as ns2>" + "<@ns1.m/> <@ns2.m/> ${history}", "en en LEnLEn"); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java index 66331ad..f8d142b 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/TemplateNotFoundMessageTest.java @@ -115,7 +115,7 @@ public class TemplateNotFoundMessageTest { String errMsg = failWith(emptyLoader, "x\\y"); showErrorMessage(errMsg); assertThat(errMsg, - allOf(containsStringIgnoringCase("warning"), containsStringIgnoringCase("backslash"))); + containsStringIgnoringCase("backslash")); } { String errMsg = failWith(emptyLoader, "x/./y"); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java ---------------------------------------------------------------------- diff --git a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java index 3a24bfc..50a4120 100644 --- a/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java +++ b/freemarker-core-test/src/test/java/org/apache/freemarker/core/templateresolver/TemplateNameFormatTest.java @@ -27,252 +27,179 @@ import java.io.IOException; import java.util.Locale; import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.Template; -import org.apache.freemarker.core.TemplateNotFoundException; import org.apache.freemarker.core.templateresolver.impl.ByteArrayTemplateLoader; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; -import org.apache.freemarker.test.MonitoredTemplateLoader; import org.apache.freemarker.test.TestConfigurationBuilder; import org.junit.Test; -import com.google.common.collect.ImmutableList; - public class TemplateNameFormatTest { @Test public void testToRootBasedName() throws MalformedTemplateNameException { - // Path that are treated the same both in 2.3 and 2.4 format: - for (TemplateNameFormat tnf : new TemplateNameFormat[] { - DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) { - // Relative paths: - // - No scheme: - 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.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.toRootBasedName("a/", "/b")); - assertEquals("b", tnf.toRootBasedName("/a/", "/b")); - assertEquals("b", tnf.toRootBasedName("a/s:/f/", "/b")); - // - Scheme: - assertEquals("s://b", tnf.toRootBasedName("s://x/", "/b")); - assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b")); - - // Schemed absolute paths: - 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 = DefaultTemplateNameFormat.INSTANCE; - 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 = DefaultTemplateNameFormatFM2.INSTANCE; - assertEquals("a/s://b", tnf.toRootBasedName("a/s://f/", "/b")); - } + final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE; + + // Relative paths: + // - No scheme: + 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.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")); + 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")); + + // Absolute paths: + // - No scheme: + 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.toRootBasedName("s://x/", "/b")); + assertEquals("s://b", tnf.toRootBasedName("s:///x/", "/b")); + + // Schemed absolute paths: + assertEquals("s://b", tnf.toRootBasedName("a/", "s://b")); + assertEquals("s://b", tnf.toRootBasedName("i://a/", "s://b")); } @Test public void testNormalizeRootBasedName() throws MalformedTemplateNameException { - // Normalizations that are the same in legacy and modern format: - for (TemplateNameFormat tnf : new TemplateNameFormat[] { - DefaultTemplateNameFormatFM2.INSTANCE, DefaultTemplateNameFormat.INSTANCE }) { + final TemplateNameFormat tnf = DefaultTemplateNameFormat.INSTANCE; + + assertEquals("", tnf.normalizeRootBasedName("")); + for (String lead : new String[] { "", "/" }) { + 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("")); - for (String lead : new String[] { "", "/" }) { - 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); - assertThrowsWithBackingOutException(lead + "../../../x", tnf); - assertThrowsWithBackingOutException(lead + "../../../x", tnf); - assertThrowsWithBackingOutException("x://../../../foo", tnf); - - { - final String name = lead + "foo\u0000"; - try { - tnf.normalizeRootBasedName(name); - fail(); - } catch (MalformedTemplateNameException e) { - assertEquals(name, e.getTemplateName()); - - assertThat(e.getMalformednessDescription(), containsStringIgnoringCase("null character")); - } + assertEquals("foo/bar/*", tnf.normalizeRootBasedName("foo/bar/*")); + assertEquals("schema://", tnf.normalizeRootBasedName("schema://")); + + assertThrowsWithBackingOutException(lead + "bar/../../x/foo", tnf); + assertThrowsWithBackingOutException(lead + "../x", tnf); + assertThrowsWithBackingOutException(lead + "../../../x", tnf); + assertThrowsWithBackingOutException(lead + "../../../x", tnf); + assertThrowsWithBackingOutException("x://../../../foo", tnf); + + { + final String name = lead + "foo\u0000"; + try { + tnf.normalizeRootBasedName(name); + fail(); + } catch (MalformedTemplateNameException e) { + assertEquals(name, e.getTemplateName()); + + assertThat(e.getMalformednessDescription(), containsStringIgnoringCase("null character")); } } } - + // ".." and "." - assertEqualsOn23AndOn24("bar/foo", "foo", "bar/./../foo"); + assertEquals("foo", tnf.normalizeRootBasedName("bar/./../foo")); - // Even number of leading ".."-s bug: - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../foo"); - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "../../../../foo"); + assertThrowsWithBackingOutException("../../foo", tnf); + assertThrowsWithBackingOutException("../../../../foo", tnf); // ".." and "*" - assertEqualsOn23AndOn24("a/b/foo", "a/*/foo", "a/b/*/../foo"); + assertEquals("a/*/foo", tnf.normalizeRootBasedName("a/b/*/../foo")); // - assertEqualsOn23AndOn24("a/foo", "foo", "a/b/*/../../foo"); + assertEquals("foo", tnf.normalizeRootBasedName("a/b/*/../../foo")); // - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "a/b/*/../../../foo"); + assertThrowsWithBackingOutException("a/b/*/../../../foo", tnf); // - assertEqualsOn23AndOn24("a/b/*/foo", "a/*/foo", "a/b/*/*/../foo"); + assertEquals("a/*/foo", tnf.normalizeRootBasedName("a/b/*/*/../foo")); // - assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/*/../foo"); + assertEquals("a/b/*/foo", tnf.normalizeRootBasedName("a/b/*/c/*/../foo")); // - assertEqualsOn23AndOn24("a/b/*/c/foo", "a/b/*/foo", "a/b/*/c/d/*/../../foo"); + assertEquals("a/b/*/foo", tnf.normalizeRootBasedName("a/b/*/c/d/*/../../foo")); // - assertEqualsOn23AndOn24("a/*//b/*/c/foo", "a/*/b/*/foo", "a/*//b/*/c/d/*/../../foo"); + assertEquals("a/*/b/*/foo", tnf.normalizeRootBasedName("a/*//b/*/c/d/*/../../foo")); // - assertEqualsOn23AndOn24("*", "", "a/../*"); + assertEquals("", tnf.normalizeRootBasedName("a/../*")); // - assertEqualsOn23AndOn24("*/", "", "a/../*/"); + assertEquals("", tnf.normalizeRootBasedName("a/../*/")); // ".." and "scheme" - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:/foo", "x://../foo"); + assertThrowsWithBackingOutException("x://../foo", tnf); // - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x://../../foo"); + assertThrowsWithBackingOutException("x://../../foo", tnf); // - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("x:../foo", "x:../foo"); + assertThrowsWithBackingOutException("x:../foo", tnf); // - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("foo", "x:../../foo"); + assertThrowsWithBackingOutException("x:../../foo", tnf); // Tricky cases with terminating "/": - assertEqualsOn23AndOn24("/", "", "/"); + assertEquals("", tnf.normalizeRootBasedName("/")); // Terminating "/.." (produces terminating "/"): - assertEqualsOn23AndOn24("foo/bar/..", "foo/", "foo/bar/.."); + assertEquals("foo/", tnf.normalizeRootBasedName("foo/bar/..")); // Terminating "/." (produces terminating "/"): - assertEqualsOn23AndOn24("foo/bar/.", "foo/bar/", "foo/bar/."); + assertEquals("foo/bar/", tnf.normalizeRootBasedName("foo/bar/.")); // Lonely "." - assertEqualsOn23AndOn24(".", "", "."); + assertEquals("", tnf.normalizeRootBasedName(".")); // Lonely ".." - assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24("..", ".."); + assertThrowsWithBackingOutException("..", tnf); // Lonely "*" // Eliminating redundant "//": - assertEqualsOn23AndOn24("foo//bar", "foo/bar", "foo//bar"); + assertEquals("foo/bar", tnf.normalizeRootBasedName("foo//bar")); // - assertEqualsOn23AndOn24("///foo//bar///baaz////wombat", "foo/bar/baaz/wombat", "////foo//bar///baaz////wombat"); + assertEquals("foo/bar/baaz/wombat", tnf.normalizeRootBasedName("////foo//bar///baaz////wombat")); // - assertEqualsOn23AndOn24("scheme://foo", "scheme://foo", "scheme://foo"); + assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme://foo")); // - assertEqualsOn23AndOn24("scheme://foo//x/y", "scheme://foo/x/y", "scheme://foo//x/y"); + assertEquals("scheme://foo/x/y", tnf.normalizeRootBasedName("scheme://foo//x/y")); // - assertEqualsOn23AndOn24("scheme:///foo", "scheme://foo", "scheme:///foo"); + assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme:///foo")); // - assertEqualsOn23AndOn24("scheme:////foo", "scheme://foo", "scheme:////foo"); + assertEquals("scheme://foo", tnf.normalizeRootBasedName("scheme:////foo")); // Eliminating redundant "*"-s: - assertEqualsOn23AndOn24("a/*/*/b", "a/*/b", "a/*/*/b"); + assertEquals("a/*/b", tnf.normalizeRootBasedName("a/*/*/b")); // - assertEqualsOn23AndOn24("a/*/*/*/b", "a/*/b", "a/*/*/*/b"); + assertEquals("a/*/b", tnf.normalizeRootBasedName("a/*/*/*/b")); // - assertEqualsOn23AndOn24("*/*/b", "b", "*/*/b"); + assertEquals("b", tnf.normalizeRootBasedName("*/*/b")); // - assertEqualsOn23AndOn24("*/*/b", "b", "/*/*/b"); + assertEquals("b", tnf.normalizeRootBasedName("/*/*/b")); // - assertEqualsOn23AndOn24("b/*/*", "b/*", "b/*/*"); + assertEquals("b/*", tnf.normalizeRootBasedName("b/*/*")); // - assertEqualsOn23AndOn24("b/*/*/*", "b/*", "b/*/*/*"); + assertEquals("b/*", tnf.normalizeRootBasedName("b/*/*/*")); // - assertEqualsOn23AndOn24("*/a/*/b/*/*/c", "a/*/b/*/c", "*/a/*/b/*/*/c"); + assertEquals("a/*/b/*/c", tnf.normalizeRootBasedName("*/a/*/b/*/*/c")); - // New kind of scheme handling: - - assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:a/b")); - assertEquals("s:a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:/a/b")); - assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s://a/b")); - assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:///a/b")); - assertEquals("s://a/b", DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName("s:////a/b")); + assertEquals("s:a/b", tnf.normalizeRootBasedName("s:a/b")); + assertEquals("s:a/b", tnf.normalizeRootBasedName("s:/a/b")); + assertEquals("s://a/b", tnf.normalizeRootBasedName("s://a/b")); + assertEquals("s://a/b", tnf.normalizeRootBasedName("s:///a/b")); + assertEquals("s://a/b", tnf.normalizeRootBasedName("s:////a/b")); // Illegal use a of ":": - assertNormRBNameThrowsColonExceptionOn24("a/b:c/d"); - assertNormRBNameThrowsColonExceptionOn24("a/b:/.."); + assertNormRBNameThrowsColonException("a/b:c/d", tnf); + assertNormRBNameThrowsColonException("a/b:/..", tnf); } @Test - public void assertBackslashNotSpecialWith23() throws IOException { - MonitoredTemplateLoader tl = new MonitoredTemplateLoader(); - tl.putTextTemplate("foo\\bar.ftl", ""); - - Configuration cfg = new TestConfigurationBuilder().templateLoader(tl).build(); - - { - final String name = "foo\\bar.ftl"; - - Template t = cfg.getTemplate(name, Locale.US); - assertEquals(name, t.getLookupName()); - assertEquals(name, t.getSourceName()); - assertEquals( - ImmutableList.of( - "foo\\bar_en_US.ftl", - "foo\\bar_en.ftl", - name), - tl.getLoadNames()); - tl.clearEvents(); - } - - try { - cfg.getTemplate("foo\\missing.ftl", Locale.US); - fail(); - } catch (TemplateNotFoundException e) { - assertEquals("foo\\missing.ftl", e.getTemplateName()); - assertEquals( - ImmutableList.of( - "foo\\missing_en_US.ftl", - "foo\\missing_en.ftl", - "foo\\missing.ftl"), - tl.getLoadNames()); - tl.clearEvents(); - cfg.clearTemplateCache(); - } - - { - final String name = "foo/bar\\..\\bar.ftl"; - try { - cfg.getTemplate(name, Locale.US); - fail(); - } catch (TemplateNotFoundException e) { - assertEquals(name, e.getTemplateName()); - } - } - - } - - @Test public void assertBackslashNotAllowed() throws IOException { Configuration cfg = new TestConfigurationBuilder() .templateLoader(new ByteArrayTemplateLoader()) @@ -286,18 +213,6 @@ public class TemplateNameFormatTest { } } - - private void assertEqualsOn23AndOn24(String expected23, String expected24, String name) - throws MalformedTemplateNameException { - assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name)); - assertEquals(expected24, DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name)); - } - - private void assertNormRBNameEqualsOn23ButThrowsBackOutExcOn24(final String expected23, final String name) - throws MalformedTemplateNameException { - assertEquals(expected23, DefaultTemplateNameFormatFM2.INSTANCE.normalizeRootBasedName(name)); - assertThrowsWithBackingOutException(name, DefaultTemplateNameFormat.INSTANCE); - } private void assertThrowsWithBackingOutException(final String name, final TemplateNameFormat tnf) { try { @@ -309,9 +224,10 @@ public class TemplateNameFormatTest { } } - private void assertNormRBNameThrowsColonExceptionOn24(final String name) throws MalformedTemplateNameException { + private void assertNormRBNameThrowsColonException(final String name, final TemplateNameFormat tnf) + throws MalformedTemplateNameException { try { - DefaultTemplateNameFormat.INSTANCE.normalizeRootBasedName(name); + tnf.normalizeRootBasedName(name); fail(); } catch (MalformedTemplateNameException e) { assertEquals(name, e.getTemplateName()); http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java index d370479..3ae0567 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Configuration.java @@ -77,7 +77,6 @@ import org.apache.freemarker.core.templateresolver.TemplateNameFormat; import org.apache.freemarker.core.templateresolver.TemplateResolver; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver; import org.apache.freemarker.core.templateresolver.impl.MruCacheStorage; import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage; @@ -1312,23 +1311,24 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc * * @param name * The name or path of the template, which is not a real path, but interpreted inside the current - * {@link TemplateLoader}. Can't be {@code null}. The exact syntax of the name depends on the underlying - * {@link TemplateLoader} (the {@link TemplateResolver} more generally), but the default - * {@link TemplateResolver} has some assumptions. First, the name is expected to be a - * hierarchical path, with path components separated by a slash character (not with backslash!). The path - * (the name) given here must <em>not</em> begin with slash; it's always interpreted relative to the - * "template root directory". Then, the {@code ..} and {@code .} path meta-elements will be resolved. For - * example, if the name is {@code a/../b/./c.ftl}, then it will be simplified to {@code b/c.ftl}. The - * rules regarding this are the same as with conventional UN*X paths. The path must not reach outside the - * template root directory, that is, it can't be something like {@code "../templates/my.ftl"} (not even - * if this path happens to be equivalent with {@code "/my.ftl"}). Furthermore, the path is allowed to - * contain at most one path element whose name is {@code *} (asterisk). This path meta-element triggers - * the <i>acquisition mechanism</i>. If the template is not found in the location described by the - * concatenation of the path left to the asterisk (called base path) and the part to the right of the - * asterisk (called resource path), the {@link TemplateResolver} (at least the default one) will attempt - * to remove the rightmost path component from the base path ("go up one directory") and concatenate - * that with the resource path. The process is repeated until either a template is found, or the base - * path is completely exhausted. + * {@link TemplateLoader}. Can't be {@code null}. The exact syntax of the name depends on the + * underlying {@link TemplateNameFormat} and to an extent on the {@link TemplateLoader} (or on the + * {@link TemplateResolver} more generally), but the default configuration has some assumptions. + * First, the name is expected to be a hierarchical path, with path components separated by a slash + * character (not with backslash!). The path (the name) given here is always interpreted relative to + * the "template root directory" and must <em>not</em> begin with slash. Then, the {@code ..} and + * {@code .} path meta-elements will be resolved. For example, if the name is {@code a/../b/./c.ftl}, + * then it will be simplified to {@code b/c.ftl}. The rules regarding this are the same as with + * conventional UN*X paths. The path must not reach outside the template root directory, that is, it + * can't be something like {@code "../templates/my.ftl"} (not even if this path happens to be + * equivalent with {@code "/my.ftl"}). Furthermore, the path is allowed to contain at most one path + * element whose name is {@code *} (asterisk). This path meta-element triggers the <i>acquisition + * mechanism</i>. If the template is not found in the location described by the concatenation of the + * path left to the asterisk (called base path) and the part to the right of the asterisk (called + * resource path), then the {@link TemplateResolver} (at least the default one) will attempt to remove + * the rightmost path component from the base path (go up one directory) and concatenate that with + * the resource path. The process is repeated until either a template is found, or the base path is + * completely exhausted. * * @param locale * The requested locale of the template. This is what {@link Template#getLocale()} on the resulting @@ -1858,10 +1858,6 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc || TEMPLATE_NAME_FORMAT_KEY_CAMEL_CASE.equals(name)) { if (value.equalsIgnoreCase(DEFAULT_VALUE)) { unsetTemplateNameFormat(); - } else if (value.equalsIgnoreCase("default_2_3_0")) { - setTemplateNameFormat(DefaultTemplateNameFormatFM2.INSTANCE); - } else if (value.equalsIgnoreCase("default_2_4_0")) { - setTemplateNameFormat(DefaultTemplateNameFormat.INSTANCE); } else { throw new InvalidSettingValueException(name, value, "No such predefined template name format"); @@ -2166,7 +2162,7 @@ public final class Configuration implements TopLevelConfiguration, CustomStateSc * the default is hardwired to be {@code null} and this method isn't called). */ protected TemplateNameFormat getDefaultTemplateNameFormat() { - return DefaultTemplateNameFormatFM2.INSTANCE; + return DefaultTemplateNameFormat.INSTANCE; } /** http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java index f0cc5a1..e058da8 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/Environment.java @@ -63,7 +63,6 @@ import org.apache.freemarker.core.model.impl.SimpleHash; import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException; import org.apache.freemarker.core.templateresolver.TemplateResolver; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.util.UndeclaredThrowableException; import org.apache.freemarker.core.util._DateUtil; import org.apache.freemarker.core.util._DateUtil.DateToISO8601CalendarFactory; @@ -2819,24 +2818,25 @@ public final class Environment extends MutableProcessingConfiguration<Environmen * Resolves a reference to a template (like the one used in {@code #include} or {@code #import}), assuming a base * name. This gives a full (that is, absolute), even if non-normalized template name, that could be used for * {@link Configuration#getTemplate(String)}. This is mostly used when a template refers to another template. - * + * * @param baseName * 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 DefaultTemplateNameFormatFM2#INSTANCE} - * or {@link DefaultTemplateNameFormat#INSTANCE}, 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 - * with {@link DefaultTemplateNameFormat#INSTANCE} even just with {@code "foo:"}). + * resolving names in nameless templates), which means that the base is the root "directory", and so + * the {@code targetName} is returned without change. Assuming the + * {@link Configuration#getTemplateNameFormat() templateNameFormat} is + * {@link DefaultTemplateNameFormat#INSTANCE}, 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 treated as + * a file name and so its parent directory will be used as the base path. Might starts with a scheme + * part (like {@code "foo://"}, or even just {@code "foo:"}). * @param targetName - * The name of the template, which is either a relative or absolute name. Assuming - * {@link DefaultTemplateNameFormatFM2#INSTANCE} or {@link DefaultTemplateNameFormat#INSTANCE}, the rules - * are as follows. If it starts with {@code "/"} or contains a scheme part separator ({@code "://"}, - * also, with {@link DefaultTemplateNameFormat#INSTANCE} a {@code ":"} with no {@code "/"} anywhere - * before it) then it's an absolute name, otherwise it's a relative path. Relative paths are interpreted - * relatively to the {@code baseName}. Absolute names are simply returned as is, ignoring the - * {@code baseName}, except, when the {@code baseName} has scheme part while the {@code targetName} - * doesn't have, then the schema of the {@code baseName} is prepended to the {@code targetName}. + * The name of the template, which is either a relative or absolute name. Assuming the + * {@link Configuration#getTemplateNameFormat() templateNameFormat} is + * {@link DefaultTemplateNameFormat#INSTANCE}, the rules are as follows. If it starts with {@code "/"} + * or contains a scheme part separator (a {@code ":"} with no {@code "/"} anywhere before it) + * then it's an absolute name, otherwise it's a relative path. Relative paths are interpreted + * relatively to the {@code baseName}. Absolute names are simply returned as is, ignoring the {@code + * baseName}, except, when the {@code baseName} has scheme part while the {@code targetName} doesn't + * have it, then the schema of the {@code baseName} is prepended to the {@code targetName}. */ public String toFullTemplateName(String baseName, String targetName) throws MalformedTemplateNameException { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java index 2b80ecc..97f0e2c 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/MutableProcessingConfiguration.java @@ -58,7 +58,6 @@ import org.apache.freemarker.core.templateresolver.OrMatcher; import org.apache.freemarker.core.templateresolver.PathGlobMatcher; import org.apache.freemarker.core.templateresolver.PathRegexMatcher; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.util.FTLUtil; import org.apache.freemarker.core.util.GenericParseException; import org.apache.freemarker.core.util.OptInTemplateClassResolver; @@ -1656,8 +1655,7 @@ public abstract class MutableProcessingConfiguration<SelfT extends MutableProces * * <li><p>{@code "template_name_format"}: * See: {@link Configuration#getTemplateNameFormat()}. - * <br>String value: {@code "default"} (case insensitive) for the default, {@code "default_2_3_0"} - * for {@link DefaultTemplateNameFormatFM2#INSTANCE}, {@code "default_2_4_0"} for + * <br>String value: {@code "default"} (case insensitive) for the default, * {@link DefaultTemplateNameFormat#INSTANCE}. * </ul> * http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java b/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java index 1211e51..f6b4fbb 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/TopLevelConfiguration.java @@ -36,7 +36,6 @@ import org.apache.freemarker.core.templateresolver.TemplateNameFormat; import org.apache.freemarker.core.templateresolver.TemplateResolver; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateLookupStrategy; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateResolver; import org.apache.freemarker.core.templateresolver.impl.MultiTemplateLoader; import org.apache.freemarker.core.templateresolver.impl.SoftCacheStorage; @@ -97,8 +96,7 @@ public interface TopLevelConfiguration extends ParsingAndProcessingConfiguration /** * The template name format used; see {@link TemplateNameFormat}. The default is - * {@link DefaultTemplateNameFormatFM2#INSTANCE} (while the recommended value for new projects is - * {@link DefaultTemplateNameFormat#INSTANCE}), except when the {@link #getTemplateResolver() templateResolver} + * {@link DefaultTemplateNameFormat#INSTANCE}, except when the {@link #getTemplateResolver() templateResolver} * doesn't support this setting, in which case it's {@code null}. * * <p>If the the {@link #getTemplateResolver() templateResolver} is a {@link DefaultTemplateResolver} then this http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/MalformedTemplateNameException.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/MalformedTemplateNameException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/MalformedTemplateNameException.java index 211b7ee..49c3b88 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/MalformedTemplateNameException.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/MalformedTemplateNameException.java @@ -23,14 +23,11 @@ import java.io.IOException; import org.apache.freemarker.core.Configuration; import org.apache.freemarker.core.TemplateNotFoundException; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormat; -import org.apache.freemarker.core.templateresolver.impl.DefaultTemplateNameFormatFM2; import org.apache.freemarker.core.util._StringUtil; /** - * Indicates that the template name given was malformed according the {@link TemplateNameFormat} in use. Note that for - * backward compatibility, {@link DefaultTemplateNameFormatFM2} doesn't throw this exception, - * {@link DefaultTemplateNameFormat} does. This exception extends {@link IOException} for backward compatibility. + * Indicates that the template name given was malformed according the {@link TemplateNameFormat} in use. + * This exception extends {@link IOException} for backward compatibility. * * * @see TemplateNotFoundException http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormat.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormat.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormat.java index 69fa390..4144e34 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormat.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormat.java @@ -18,64 +18,41 @@ */ package org.apache.freemarker.core.templateresolver.impl; +import java.io.Serializable; +import java.util.Locale; + import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.TemplateNotFoundException; import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException; import org.apache.freemarker.core.templateresolver.TemplateLoader; import org.apache.freemarker.core.templateresolver.TemplateNameFormat; import org.apache.freemarker.core.util._StringUtil; /** - * The default template name format only when {@link Configuration#getIncompatibleImprovements() - * incompatible_improvements} is set to 2.4.0 (or higher). This is not the out-of-the-box default format of FreeMarker - * 2.4.x, because the default {@code incompatible_improvements} is still 2.3.0 there. - * + * The default {@linkplain Configuration#getTemplateNameFormat()} template name format}. This defines a format where + * directories and file names in a path are separated with {@code "/"} (slash). {@code "\"} (backslash) is not + * allowed and causes {@link MalformedTemplateNameException}. Directory names {@code "."} and {@code ".."} are + * treated specially with the same meaning as in UN*X paths. Directory name {@code "*"} is treated as acquisition + * mark (see {@link Configuration#getTemplate(String, Locale, Serializable, boolean)}). * <p> - * Differences to the {@link DefaultTemplateNameFormatFM2} format: - * - * <ul> - * - * <li>The scheme and the path need not be separated with {@code "://"} anymore, only with {@code ":"}. This makes - * template names like {@code "classpath:foo.ftl"} interpreted as an absolute name with scheme {@code "classpath"} - * and absolute path "foo.ftl". The scheme name before the {@code ":"} can't contain {@code "/"}, or else it's - * treated as a malformed name. The scheme part can be separated either with {@code "://"} or just {@code ":"} from - * the path. Hence, {@code myschme:/x} is normalized to {@code myschme:x}, while {@code myschme:///x} is normalized - * to {@code myschme://x}, but {@code myschme://x} or {@code myschme:/x} aren't changed by normalization. It's up - * the {@link TemplateLoader} to which the normalized names are passed to decide which of these scheme separation - * conventions are valid (maybe both).</li> - * - * <li>{@code ":"} is not allowed in template names, except as the scheme separator (see previous point). - * - * <li>Malformed paths throw {@link MalformedTemplateNameException} instead of acting like if the template wasn't - * found. - * - * <li>{@code "\"} (backslash) is not allowed in template names, and causes {@link MalformedTemplateNameException}. - * With {@link DefaultTemplateNameFormatFM2} you would certainly end up with a {@link TemplateNotFoundException} (or - * worse, it would work, but steps like {@code ".."} wouldn't be normalized by FreeMarker). - * - * <li>Template names might end with {@code /}, like {@code "foo/"}, and the presence or lack of the terminating - * {@code /} is seen as significant. While their actual interpretation is up to the {@link TemplateLoader}, - * operations that manipulate template names assume that the last step refers to a "directory" as opposed to a - * "file" exactly if the terminating {@code /} is present. Except, the empty name is assumed to refer to the root - * "directory" (despite that it doesn't end with {@code /}). - * - * <li>{@code //} is normalized to {@code /}, except of course if it's in the scheme name terminator. Like - * {@code foo//bar///baaz.ftl} is normalized to {@code foo/bar/baaz.ftl}. (In general, 0 long step names aren't - * possible anymore.)</li> - * - * <li>The {@code ".."} bugs of the legacy normalizer are oms: {@code ".."} steps has removed the preceding - * {@code "."} or {@code "*"} or scheme steps, not treating them specially as they should be. Now these work as - * expected. Examples: {@code "a/./../c"} has become to {@code "a/c"}, now it will be {@code "c"}; {@code "a/b/*} - * {@code /../c"} has become to {@code "a/b/c"}, now it will be {@code "a/*}{@code /c"}; {@code "scheme://.."} has - * become to {@code "scheme:/"}, now it will be {@code null} ({@link TemplateNotFoundException}) for backing out of - * the root directory.</li> - * - * <li>As now directory paths has to be handled as well, it recognizes terminating, leading, and lonely {@code ".."} - * and {@code "."} steps. For example, {@code "foo/bar/.."} now becomes to {@code "foo/"}</li> - * - * <li>Multiple consecutive {@code *} steps are normalized to one</li> - * - * </ul> + * The name may starts with scheme part, like in {@code "classpath:com/example/bar.ftl"} (scheme "classpath" and + * absolute path "com/example/bar.ftl") or {@code "cms://example.com/foo.ftl"} (scheme "cms" and absolute path + * "example.com/foo.ftl"). The scheme name before the {@code ":"} (colon) can't contain {@code "/"}, and {@code ":"} + * can only be used for denoting the scheme, or else {@link MalformedTemplateNameException} is thrown. + * The scheme part can be separated either with {@code "://"} or just with {@code ":"} from the path, hence, {@code + * myschme:/x} is normalized to {@code myschme:x}, while {@code myschme:///x} is normalized to {@code myschme://x}, + * but {@code myschme://x} or {@code myschme:/x} aren't changed by normalization. It's up the {@link TemplateLoader} + * (to which the normalized names are passed) to decide which of these scheme separation conventions are accepted. + * <p> + * Template names might end with {@code /}, like {@code "foo/"}, and the presence or lack of the terminating {@code + * "/"} is significant. While their actual interpretation is up to the {@link TemplateLoader}, operations that + * manipulate template names assume that the last step refers to a "directory" as opposed to a "file" exactly if the + * terminating {@code /} is present. Except, the empty name is assumed to refer to the root "directory" (despite that + * it doesn't end with {@code /}). + * <p> + * {@code //} is normalized to {@code /}, except of course if it's in the scheme name terminator. Like {@code + * foo//bar///baaz.ftl} is normalized to {@code foo/bar/baaz.ftl}. Hence 0 length step names aren't possible. + * <p> + * Multiple consecutive {@code "*"} steps are normalized to one */ public final class DefaultTemplateNameFormat extends TemplateNameFormat { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormatFM2.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormatFM2.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormatFM2.java deleted file mode 100644 index c5db8e5..0000000 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateNameFormatFM2.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ -package org.apache.freemarker.core.templateresolver.impl; - -import org.apache.freemarker.core.Configuration; -import org.apache.freemarker.core.templateresolver.MalformedTemplateNameException; -import org.apache.freemarker.core.templateresolver.TemplateNameFormat; - -/** - * The default template name format when {@link Configuration#getIncompatibleImprovements() incompatible_improvements} - * is below 2.4.0. As of FreeMarker 2.4.0, the default {@code incompatible_improvements} is still {@code 2.3.0}, and it - * will certainly remain so for a very long time. In new projects it's highly recommended to use - * {@link DefaultTemplateNameFormat#INSTANCE} instead. - * - * @deprecated [FM3] Remove - */ -@Deprecated -public final class DefaultTemplateNameFormatFM2 extends TemplateNameFormat { - - public static final DefaultTemplateNameFormatFM2 INSTANCE = new DefaultTemplateNameFormatFM2(); - - private DefaultTemplateNameFormatFM2() { - // - } - - @Override - public String toRootBasedName(String baseName, String targetName) { - if (targetName.indexOf("://") > 0) { - return targetName; - } else if (targetName.startsWith("/")) { - int schemeSepIdx = baseName.indexOf("://"); - if (schemeSepIdx > 0) { - return baseName.substring(0, schemeSepIdx + 2) + targetName; - } else { - return targetName.substring(1); - } - } else { - if (!baseName.endsWith("/")) { - baseName = baseName.substring(0, baseName.lastIndexOf("/") + 1); - } - return baseName + targetName; - } - } - - @Override - public String normalizeRootBasedName(final String name) throws MalformedTemplateNameException { - // Disallow 0 for security reasons. - checkNameHasNoNullCharacter(name); - - // The legacy algorithm haven't considered schemes, so the name is in effect a path. - // Also, note that `path` will be repeatedly replaced below, while `name` is final. - String path = name; - - for (; ; ) { - int parentDirPathLoc = path.indexOf("/../"); - if (parentDirPathLoc == 0) { - // If it starts with /../, then it reaches outside the template - // root. - throw newRootLeavingException(name); - } - if (parentDirPathLoc == -1) { - if (path.startsWith("../")) { - throw newRootLeavingException(name); - } - break; - } - int previousSlashLoc = path.lastIndexOf('/', parentDirPathLoc - 1); - path = path.substring(0, previousSlashLoc + 1) + - path.substring(parentDirPathLoc + "/../".length()); - } - for (; ; ) { - int currentDirPathLoc = path.indexOf("/./"); - if (currentDirPathLoc == -1) { - if (path.startsWith("./")) { - path = path.substring("./".length()); - } - break; - } - path = path.substring(0, currentDirPathLoc) + - path.substring(currentDirPathLoc + "/./".length() - 1); - } - // Editing can leave us with a leading slash; strip it. - if (path.length() > 1 && path.charAt(0) == '/') { - path = path.substring(1); - } - return path; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/05f29759/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java ---------------------------------------------------------------------- diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java index 54c830d..3a7f406 100644 --- a/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java +++ b/freemarker-core/src/main/java/org/apache/freemarker/core/templateresolver/impl/DefaultTemplateResolver.java @@ -152,11 +152,7 @@ public class DefaultTemplateResolver extends TemplateResolver { * check that it's missing. * * @throws MalformedTemplateNameException - * If the {@code name} was malformed according the current {@link TemplateNameFormat}. However, if the - * {@link TemplateNameFormat} is {@link DefaultTemplateNameFormatFM2#INSTANCE} and - * {@link Configuration#getIncompatibleImprovements()} is less than 2.4.0, then instead of throwing this - * exception, a {@link GetTemplateResult} will be returned, similarly as if the template were missing - * (the {@link GetTemplateResult#getMissingTemplateReason()} will describe the real error). + * If the {@code name} was malformed according the current {@link TemplateNameFormat}. * * @throws IOException * If reading the template has failed from a reason other than the template is missing. This method
