Uploaded image for project: '[Read Only] - Hippo Site Toolkit 2'
  1. [Read Only] - Hippo Site Toolkit 2
  2. HSTTWO-4292

HstFreemarkerServlet - wrong IOException, breaking the contract of TemplateLoader

    XMLWordPrintable

Details

    • Bug
    • Status: Closed
    • Normal
    • Resolution: Fixed
    • 5.2.0
    • 5.3.0
    • None
    • None

    Description

      FreeMarker's template loading invokes TemplateLoader#findTemplateSource(String) before trying to invoke TemplateLoader#getReader(Object, String).
      Implementation on #findTemplateSource() method must not throw an IOException if the source for the template doesn't exist.
      The reason why it must not throw IOException when the template source is not found, is basically because there are options in FreeMarker to ignoreMissing. See JavaDocs in Configuration#getTemplate(...) or Environment#getTemplate(...).
      Especially, Environment#getTemplateForInclusion(...) explicitly uses true value in ignoreMissing parameter.

      Now the problem in HST code is as follows:

      • In both JcrTemplateLoader#findTemplateSource() and WebFileTemplateLoader#findTemplateSource(), at the moment, it always returns a kind of abstract RepositorySource instance through RepositorySource.notFound(absPath) if the node doesn't exist. See org.hippoecm.hst.freemarker.jcr.TemplateLoadingCache#getRepositoryTemplate(String).
      • As a result, when Freemarker finally invokes TemplateLoader#getTemplate(), that org.hippoecm.hst.freemarker.jcr.AbstractTemplateLoader.getReader(Object, String) has to throw an IOException as the kind of abstract RepositorySource represents a not-found source.

      This breaks the contact. It should have returned null in #findTemplateSource() if the node turned out to be non-existing at the path.
      IOException should have thrown only when there's any javax.jcr.Repository exception for example while trying to read a node instead.

      If a developer uses <#include > directive [1] with ignore_missing option, the whole template execution will be just blown away, instead of ignoring that missing included template.

      Example stack trace:

      Caused by: java.io.IOException: Repository templateSource '/webfiles/site/freemarker/myhippoproject/pagenotfound-main2.ftl' not found
      	at org.hippoecm.hst.freemarker.jcr.AbstractTemplateLoader.getReader(AbstractTemplateLoader.java:54) ~[hst-client-5.2.0.jar:5.2.0]
      	at freemarker.cache.MultiTemplateLoader$MultiSource.getReader(MultiTemplateLoader.java:142) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.cache.MultiTemplateLoader.getReader(MultiTemplateLoader.java:102) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:547) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.cache.TemplateCache.getTemplateInternal(TemplateCache.java:439) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:292) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.template.Configuration.getTemplate(Configuration.java:2720) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.core.Environment.getTemplateForInclusion(Environment.java:2540) [freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	at freemarker.core.GetOptionalTemplateMethod.exec(GetOptionalTemplateMethod.java:138) ~[freemarker-gae-2.3.28-incubating-SNAPSHOT.jar:2.3.27.97]
      	... 110 more
      

      If not found, it shouldn't be IOException.

      In summary,

      • Returning a non-null object from #findTemplateSource() simply violates what the API says:
        (ref: https://freemarker.apache.org/docs/api/freemarker/cache/TemplateLoader.html#findTemplateSource-java.lang.String- )
        Both for the return value and the throw exception it's explicitly noted what to do if the template is missing.
      • By the way, #getReader() must not return null in any case unless there's an system exception like IOException. See the latest the JavaDoc API as well. Returning null will just cause NPE in FreeMarker.
      • Only findTemplate should return null on missing template.

      [1] https://freemarker.apache.org/docs/ref_directive_include.html

      Attachments

        Activity

          People

            Unassigned Unassigned
            wko Woonsan Ko (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: