/*
 * 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 freemarker.cache;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;

import freemarker.template.Configuration;

This is an abstract template loader that can load templates whose location can be described by an URL. This superclass only works for cases where merely getting the URL immediately tells if the resource exists, not for cases where for example you had to check response headers to know that. The subclasses only need to override the getURL(String) method.
/** * This is an abstract template loader that can load templates whose location can be described by an URL. This * superclass only works for cases where merely getting the URL immediately tells if the resource exists, not for cases * where for example you had to check response headers to know that. The subclasses only need to override the * {@link #getURL(String)} method. */
public abstract class URLTemplateLoader implements TemplateLoader { private Boolean urlConnectionUsesCaches; public Object findTemplateSource(String name) throws IOException { URL url = getURL(name); return url == null ? null : new URLTemplateSource(url, getURLConnectionUsesCaches()); } public long getLastModified(Object templateSource) { return ((URLTemplateSource) templateSource).lastModified(); } public Reader getReader(Object templateSource, String encoding) throws IOException { return new InputStreamReader( ((URLTemplateSource) templateSource).getInputStream(), encoding); } public void closeTemplateSource(Object templateSource) throws IOException { ((URLTemplateSource) templateSource).close(); }
Since:2.3.21
/** * Getter pair of {@link #setURLConnectionUsesCaches(Boolean)}. * * @since 2.3.21 */
public Boolean getURLConnectionUsesCaches() { return urlConnectionUsesCaches; }
Sets if URLConnection.setUseCaches(boolean) will be called, and with what value. By default this is null; see the behavior then below. The recommended value is false, so that FreeMarker can always reliably detect when a template was changed. The default is null only for backward compatibility, and certainly will be changed to false in 2.4.0. As FreeMarker has its own template cache with its own update delay setting (Configuration.setTemplateUpdateDelay(int)), setting this to false shouldn't cause performance problems.

Regarding null value: By default then URLConnection.setUseCaches(boolean) won't be called, and so the default of the URLConnection subclass will be in effect (usually true). That's the 2.3.0-compatible mode. However, if Configuration.getIncompatibleImprovements() is at least 2.3.21, then when Configuration.getTemplate is used, null will mean false. Note that this 2.3.21 trick only works if the template is loaded through Configuration.getTemplate (or TemplateCache).

Since:2.3.21
/** * Sets if {@link URLConnection#setUseCaches(boolean)} will be called, and with what value. By default this is * {@code null}; see the behavior then below. The recommended value is {@code false}, so that FreeMarker can always * reliably detect when a template was changed. The default is {@code null} only for backward compatibility, * and certainly will be changed to {@code false} in 2.4.0. As FreeMarker has its own template cache with its * own update delay setting ({@link Configuration#setTemplateUpdateDelay(int)}), setting this to {@code false} * shouldn't cause performance problems. * * <p>Regarding {@code null} value: By default then {@link URLConnection#setUseCaches(boolean)} won't be called, * and so the default of the {@link URLConnection} subclass will be in effect (usually {@code true}). That's the * 2.3.0-compatible mode. However, if {@link Configuration#getIncompatibleImprovements()} is at least 2.3.21, then * when {@code Configuration.getTemplate} is used, {@code null} will mean {@code false}. Note that this 2.3.21 trick * only works if the template is loaded through {@code Configuration.getTemplate} (or {@link TemplateCache}). * * @since 2.3.21 */
public void setURLConnectionUsesCaches(Boolean urlConnectionUsesCaches) { this.urlConnectionUsesCaches = urlConnectionUsesCaches; }
Given a template name (plus potential locale decorations) retrieves an URL that points the template source.
Params:
  • name – the name of the sought template, including the locale decorations.
Returns:an URL that points to the template source, or null if the template does not exist.
/** * Given a template name (plus potential locale decorations) retrieves * an URL that points the template source. * @param name the name of the sought template, including the locale * decorations. * @return an URL that points to the template source, or {@code null} if the template does not exist. */
protected abstract URL getURL(String name);
Can be used by subclasses to canonicalize URL path prefixes.
Params:
  • prefix – the path prefix to canonicalize
Returns:the canonicalized prefix. All backslashes are replaced with forward slashes, and a trailing slash is appended if the original prefix wasn't empty and didn't already end with a slash.
/** * Can be used by subclasses to canonicalize URL path prefixes. * @param prefix the path prefix to canonicalize * @return the canonicalized prefix. All backslashes are replaced with * forward slashes, and a trailing slash is appended if the original * prefix wasn't empty and didn't already end with a slash. */
protected static String canonicalizePrefix(String prefix) { // make it foolproof prefix = prefix.replace('\\', '/'); // ensure there's a trailing slash if (prefix.length() > 0 && !prefix.endsWith("/")) { prefix += "/"; } return prefix; } }