freemarker.cache.ClassTemplateLoader Maven / Gradle / Ivy
Show all versions of freemarker-gae Show documentation
/*
* Copyright 2014 Attila Szegedi, Daniel Dekany, Jonathan Revusky
*
* Licensed 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 freemarker.cache;
import java.net.URL;
import freemarker.template.utility.StringUtil;
/**
* A {@link TemplateLoader} that uses streams reachable through
* {@link Class#getResourceAsStream(String)} as its source of templates.
*/
public class ClassTemplateLoader extends URLTemplateLoader
{
private Class baseClass;
private String packagePath;
/**
* Creates a template loader that will use the {@link Class#getResource(String)}
* method of its own class to load the resources, and "/"
as base path.
* This means that that template paths will be resolved relatvively the root package
* of the class hierarchy, so you hardly ever should use this constructor, rather do
* something like this:
* {@link #ClassTemplateLoader(Class, String)
* new ClassTemplateLoader(com.example.myapplication.SomeClass.class, "templates")}
*
* If you extend this class, then the extending class will be used to load
* the resources.
*
*
Warning: this constructor was malfunctioned prior FreeMarker 2.3.4
* -- please update FreeMarker if needed.
*
* @deprecated confusing constructor, and seldom useful;
* use {@link #ClassTemplateLoader(Class, String)} instead.
*/
public ClassTemplateLoader()
{
setFields(this.getClass(), "/");
}
/**
* Creates a template loader that will use the {@link Class#getResource(String)}
* method of the specified class to load the resources, and ""
as base
* path. This means that template paths will be resolved relatively to the class
* location, that is, relatively to the directory (package) of the class.
*
* @param baseClass the class whose
* {@link Class#getResource(String)} will be used to load the templates.
*
* @deprecated it's confusing that the base path is ""
;
* use {@link #ClassTemplateLoader(Class, String)} instead.
*/
public ClassTemplateLoader(Class baseClass)
{
setFields(baseClass, "");
}
/**
* Creates a template loader that will use the {@link Class#getResource(String)} method
* of the specified class to load the resources, and the specified base path (absolute or relative).
*
*
Examples:
*
* - Relative base path (will load from the
*
com.example.myapplication.templates
package):
* new ClassTemplateLoader(
* com.example.myapplication.SomeClass.class,
* "templates")
* - Absolute base path:
* new ClassTemplateLoader(
* somepackage.SomeClass.class,
* "/com/example/myapplication/templates")
*
*
* @param baseClass the class whose {@link Class#getResource(String)} method will be used
* to load the templates. Be sure that you chose a class whose defining class-loader
* sees the templates. This parameter can't be null
.
* @param packagePath the path to the package that contains the templates.
* A path that doesn't start with a slash (/) is relative to the
* path (package) of the specified class. A path that starts with a slash
* is an absolute path starting from the root of the package hierarchy. Path
* components should be separated by forward slashes independently of the
* separator character used by the underlying operating system.
* This parameter can't be null
.
*/
public ClassTemplateLoader(Class baseClass, String packagePath)
{
setFields(baseClass, packagePath);
}
protected URL getURL(String name)
{
String fullPath = packagePath + name;
// Block java.net.URLClassLoader exploits:
if (packagePath.equals("/") && !isSchemeless(fullPath)) {
return null;
}
return baseClass.getResource(fullPath);
}
private static boolean isSchemeless(String fullPath) {
int i = 0;
int ln = fullPath.length();
// Skip a single initial /, as things like "/file:/..." might work:
if (i < ln && fullPath.charAt(i) == '/') i++;
// Check if there's no ":" earlier than a '/', as the URLClassLoader
// could interpret that as an URL scheme:
while (i < ln) {
char c = fullPath.charAt(i);
if (c == '/') return true;
if (c == ':') return false;
i++;
}
return true;
}
private void setFields(Class baseClass, String packagePath) {
if(baseClass == null)
{
throw new IllegalArgumentException("baseClass == null");
}
if(packagePath == null)
{
throw new IllegalArgumentException("path == null");
}
this.baseClass = baseClass;
this.packagePath = canonicalizePrefix(packagePath);
}
/**
* Show class name and some details that are useful in template-not-found errors.
*
* @since 2.3.21
*/
public String toString() {
return "ClassTemplateLoader(baseClass=" + baseClass.getName()
+ ", packagePath=" + StringUtil.jQuote(packagePath) + ")";
}
}