001package org.avaje.freemarker.layout;
002
003import java.io.IOException;
004import java.io.Reader;
005
006import javax.servlet.ServletContext;
007
008import org.avaje.freemarker.util.IOUtil;
009
010import freemarker.cache.TemplateLoader;
011import freemarker.cache.WebappTemplateLoader;
012
013/**
014 * Simple layout inheritance wrapper for a TemplateLoader.
015 */
016public final class InheritLayoutTemplateLoader implements TemplateLoader {
017  
018  private final TemplateLoader wrapped;
019
020  private final RawTemplateInherit inheritHandler;
021
022  /**
023   * Create a WebappTemplateLoader loader and wrap it with inheritance layout handling.
024   */
025  public static TemplateLoader createWebappLoader(ServletContext servletContext, String templatePath) {
026    return createWebappLoader(servletContext, templatePath, null);
027  }
028  
029  /**
030   * Create a TemplateLoader additionally specifying a ContentFilter. 
031   */
032  public static TemplateLoader createWebappLoader(ServletContext servletContext, String templatePath, ContentFilter contentFilter) {
033    return wrap(new WebappTemplateLoader(servletContext, templatePath), contentFilter);
034  }
035  
036  /**
037   * Wrap a TemplateLoader with inheritance layout handling.
038   */
039  public static TemplateLoader wrap(TemplateLoader baseLoader, ContentFilter contentFilter) {
040    return new InheritLayoutTemplateLoader(baseLoader, contentFilter);
041  }
042  
043  /**
044   * Create wrapping a TemplateLoader.
045   */
046  public InheritLayoutTemplateLoader(TemplateLoader wrapped, ContentFilter contentFilter) {
047    this.wrapped = wrapped;
048    this.inheritHandler = new RawTemplateInherit(new Source(wrapped), contentFilter);
049  }
050
051  public Object findTemplateSource(String name) throws IOException {
052    Object o = wrapped.findTemplateSource(name);
053    if (o == null) {
054      return null;
055    }
056    return new SourceWrapper(name, o);
057  }
058
059  public long getLastModified(Object templateSource) {
060    return wrapped.getLastModified(((SourceWrapper) templateSource).wrappedSource);
061  }
062
063  public void closeTemplateSource(Object templateSource) throws IOException {
064    wrapped.closeTemplateSource(((SourceWrapper) templateSource).wrappedSource);
065  }
066
067  public Reader getReader(Object templateSource, String encoding) throws IOException {
068
069    return inheritHandler.getReader(((SourceWrapper) templateSource).templateName, encoding);
070  }
071
072  private static final class SourceWrapper {
073    final String templateName;
074    final Object wrappedSource;
075
076    private SourceWrapper(String templateName, Object wrappedSource) {
077      this.templateName = templateName;
078      this.wrappedSource = wrappedSource;
079    }
080  }
081
082  private static class Source implements RawTemplateSource {
083
084    private final TemplateLoader wrapped;
085
086    Source(TemplateLoader wrapped) {
087      this.wrapped = wrapped;
088    }
089    
090    public String getSource(String templateName, String encoding) throws IOException {
091
092      try {
093        Object s = wrapped.findTemplateSource(templateName);
094        Reader reader = wrapped.getReader(s, encoding);
095        return IOUtil.read(reader);
096      } catch (Exception e) {
097        throw new IOException("Error loading source for template: "+templateName, e);
098      }
099    }
100  }
101
102}