/*
* Copyright 2007 (c) by Texture Media, Inc.
*
* This software is confidential and proprietary to
* Texture Media, Inc. It may not be reproduced,
* published or disclosed to others without company
* authorization.
*/
package org.primeframework.mvc.freemarker;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import org.primeframework.mvc.container.ContainerResolver;
import com.google.inject.Inject;
import freemarker.cache.TemplateLoader;
/**
* This class is a free marker template loader that uses the {@link ContainerResolver} interface and the current context
* ClassLoader to find the templates. This provides override support by looking in the container first and then the
* ClassLoader.
*
* @author Brian Pontarelli
*/
public class OverridingTemplateLoader implements TemplateLoader {
private final ContainerResolver containerResolver;
/**
* Creates a resource template loader that will use the specified container resolver to load the resources as well as
* the current threads context class loader.
*
* @param containerResolver The container resolver to use to find the files.
*/
@Inject
public OverridingTemplateLoader(ContainerResolver containerResolver) {
this.containerResolver = containerResolver;
}
/**
* First looks in the container using the {@link ContainerResolver} to get the real path to a File on the file system.
* If that works, it creates a URL out of the File and returns a new URLTemplateSource from that URL.
* <p/>
* If that fails, it tries getting the resource URL frm the {@link ContainerResolver}. If that works, it creates a
* URLTemplateSource from that URL.
* <p/>
* If that fails, it tries to get the resource from the current threads context classloader. If that works, it creates
* a URLTemplateSource from that URL.
*
* @param name The name of the template.
* @return The template or null if it doesn't exist.
* @throws IOException If the template could not be resolved.
*/
public Object findTemplateSource(String name) throws IOException {
// First try to open as plain file.
try {
String realPath = containerResolver.getRealPath(name);
if (realPath != null) {
File file = new File(realPath);
if (file.isFile() && file.canRead()) {
return new URLTemplateSource(file.toURI().toURL());
}
}
} catch (SecurityException e) {
// This means we couldn't access to the file according to the security manager (not the file system). In this case
// we skip this lookup and move to the classpath and other lookups.
}
// If it fails, try to open it with servletContext.getResource.
URL url = containerResolver.getResource(name);
if (url == null) {
// If that fails, finally try looking it up in the class path
ClassLoader cl = Thread.currentThread().getContextClassLoader();
url = cl.getResource(name);
}
return url == null ? null : new URLTemplateSource(url);
}
/**
* Gets the last modified from the URLTemplateSource.
*
* @param templateSource The URLTemplateSource.
* @return The last modified from the URLConnection inside the URLTemplateSource.
*/
public long getLastModified(Object templateSource) {
return ((URLTemplateSource) templateSource).lastModified();
}
/**
* Returns the InputStream from the URLTemplateSource wrapped in an InputStreamReader.
*
* @param templateSource The URLTemplateSource.
* @param encoding Used to construct the InputStreamReader.
* @return The reader.
* @throws IOException if the Reader couldn't be created.
*/
public Reader getReader(Object templateSource, String encoding) throws IOException {
return new InputStreamReader(((URLTemplateSource) templateSource).getInputStream(), encoding);
}
/**
* Calls close on the URLTemplateSource.
*
* @param templateSource The URLTemplateSource.
* @throws IOException If the close fails.
*/
public void closeTemplateSource(Object templateSource) throws IOException {
((URLTemplateSource) templateSource).close();
}
}