http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLoaderSession.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLoaderSession.java b/src/main/java/freemarker/cache/TemplateLoaderSession.java deleted file mode 100644 index 318fe11..0000000 --- a/src/main/java/freemarker/cache/TemplateLoaderSession.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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.InputStream; -import java.io.Reader; - -/** - * Stores shared state between {@link TemplateLoader} operations that are executed close to each other in the same - * thread. For example, a {@link TemplateLoader} that reads from a database might wants to store the database - * connection in it for reuse. The goal of sessions is mostly to increase performance. However, because a - * {@link TemplateCache#getTemplate(String, java.util.Locale, Object, String, boolean)} call is executed inside a single - * session, sessions can be also be utilized to ensure that the template lookup (see {@link TemplateLookupStrategy}) - * happens on a consistent view (a snapshot) of the backing storage, if the backing storage mechanism supports such - * thing. - * - * <p> - * The {@link TemplateLoaderSession} implementation is (usually) specific to the {@link TemplateLoader} - * implementation. If your {@link TemplateLoader} implementation can't take advantage of sessions, you don't have to - * implement this interface, just return {@code null} for {@link TemplateLoader#createSession()}. - * - * <p> - * {@link TemplateLoaderSession}-s should be lazy, that is, creating an instance should be very fast and should not - * cause I/O. Only when (and if ever) the shared resource stored in the session is needed for the first time should the - * shared resource be initialized. - * - * <p> - * {@link TemplateLoaderSession}-s need not be thread safe. - */ -public interface TemplateLoaderSession { - - /** - * Closes this session, freeing any resources it holds. Further operations involving this session should fail, with - * the exception of {@link #close()} itself, which should be silently ignored. - * - * <p> - * The {@link Reader} or {@link InputStream} contained in the {@link TemplateLoadingResult} must be closed before - * {@link #close()} is called on the session in which the {@link TemplateLoadingResult} was created. Except, if - * closing the {@link Reader} or {@link InputStream} has thrown an exception, the caller should just proceed with - * closing the session regardless. After {@link #close()} was called on the session, the methods of the - * {@link Reader} or {@link InputStream} is allowed to throw an exception, or behave in any other erratic way. - * (Because the caller of this interface is usually FreeMarker (the {@link TemplateCache}), normally you don't have - * to deal with these rules, but it's useful to know the expectations if you implement - * {@link TemplateLoaderSession}.) - * - * <p>The caller of {@link TemplateLoader#createSession()} has to guarantee that {@link #close()} will be called on - * the created session. - */ - public void close() throws IOException; - - /** - * Tells if this session is closed. - */ - public boolean isClosed(); - -}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLoaderUtils.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLoaderUtils.java b/src/main/java/freemarker/cache/TemplateLoaderUtils.java deleted file mode 100644 index 2c98053..0000000 --- a/src/main/java/freemarker/cache/TemplateLoaderUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 freemarker.template.Configuration; - -final class TemplateLoaderUtils { - - private TemplateLoaderUtils() { - // Not meant to be instantiated - } - - public static String getClassNameForToString(TemplateLoader templateLoader) { - final Class<? extends TemplateLoader> tlClass = templateLoader.getClass(); - final Package tlPackage = tlClass.getPackage(); - return tlPackage == Configuration.class.getPackage() || tlPackage == TemplateLoader.class.getPackage() - ? tlClass.getSimpleName() : tlClass.getName(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLoadingResult.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLoadingResult.java b/src/main/java/freemarker/cache/TemplateLoadingResult.java deleted file mode 100644 index 3bc7f8d..0000000 --- a/src/main/java/freemarker/cache/TemplateLoadingResult.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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.BufferedInputStream; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.Reader; -import java.io.Serializable; -import java.util.Date; - -import freemarker.core.TemplateConfiguration; -import freemarker.template.Configuration; -import freemarker.template.utility.NullArgumentException; - -/** - * Return value of {@link TemplateLoader#load(String, TemplateLoadingSource, Serializable, TemplateLoaderSession)} - */ -public final class TemplateLoadingResult { - private final TemplateLoadingResultStatus status; - private final TemplateLoadingSource source; - private final Serializable version; - private final Reader reader; - private final InputStream inputStream; - private final TemplateConfiguration templateConfiguration; - - public static final TemplateLoadingResult NOT_FOUND = new TemplateLoadingResult( - TemplateLoadingResultStatus.NOT_FOUND); - public static final TemplateLoadingResult NOT_MODIFIED = new TemplateLoadingResult( - TemplateLoadingResultStatus.NOT_MODIFIED); - - /** - * Creates an instance with status {@link TemplateLoadingResultStatus#OPENED}, for a storage mechanism that - * naturally returns the template content as sequence of {@code char}-s as opposed to a sequence of {@code byte}-s. - * This is the case for example when you store the template in a database in a varchar or CLOB. Do <em>not</em> use - * this constructor for stores that naturally return binary data instead (like files, class loader resources, - * BLOB-s, etc.), because using this constructor will disable FreeMarker's charset selection mechanism. - * - * @param source - * See {@link #getSource()} - * @param version - * See {@link #getVersion()} for the meaning of this. Can be {@code null}, but use that only if the - * backing storage mechanism doesn't know this information. - * @param reader - * Gives the content of the template. It will be read in few thousand character chunks by FreeMarker, so - * generally it need not be a {@link BufferedReader}. - * @param templateConfiguration - * Usually {@code null}, as usually the backing storage mechanism doesn't store such information; - * see {@link #getTemplateConfiguration()}. - */ - public TemplateLoadingResult(TemplateLoadingSource source, Serializable version, Reader reader, - TemplateConfiguration templateConfiguration) { - NullArgumentException.check("templateSource", source); - NullArgumentException.check("reader", reader); - this.status = TemplateLoadingResultStatus.OPENED; - this.source = source; - this.version = version; - this.reader = reader; - this.inputStream = null; - this.templateConfiguration = templateConfiguration; - } - - /** - * Creates an instance with status {@link TemplateLoadingResultStatus#OPENED}, for a storage mechanism that - * naturally returns the template content as sequence of {@code byte}-s as opposed to a sequence of {@code char}-s. - * This is the case for example when you store the template in a file, classpath resource, or BLOB. Do <em>not</em> - * use this constructor for stores that naturally return text instead (like database varchar and CLOB columns). - * - * @param source - * See {@link #getSource()} - * @param version - * See {@link #getVersion()} for the meaning of this. Can be {@code null}, but use that only if the - * backing storage mechanism doesn't know this information. - * @param inputStream - * Gives the content of the template. It will be read in few thousand byte chunks by FreeMarker, so - * generally it need not be a {@link BufferedInputStream}. - * @param templateConfiguration - * Usually {@code null}, as usually the backing storage mechanism doesn't store such information; see - * {@link #getTemplateConfiguration()}. The most probable application is supplying the charset (encoding) - * used by the {@link InputStream} (via {@link TemplateConfiguration#setEncoding(String)}), but only - * do that if the storage mechanism really knows what the charset is. - */ - public TemplateLoadingResult(TemplateLoadingSource source, Serializable version, InputStream inputStream, - TemplateConfiguration templateConfiguration) { - NullArgumentException.check("templateSource", source); - NullArgumentException.check("inputStream", inputStream); - this.status = TemplateLoadingResultStatus.OPENED; - this.source = source; - this.version = version; - this.reader = null; - this.inputStream = inputStream; - this.templateConfiguration = templateConfiguration; - } - - /** - * Used internally for creating the singleton instances which has a state where all other fields are {@code null}. - */ - private TemplateLoadingResult(TemplateLoadingResultStatus status) { - this.status = status; - this.source = null; - this.version = null; - this.reader = null; - this.inputStream = null; - this.templateConfiguration = null; - } - - /** - * Returns non-{@code null} exactly if {@link #getStatus()} is {@link TemplateLoadingResultStatus#OPENED} and the - * backing store mechanism returns content as {@code byte}-s, as opposed to as {@code chars}-s. See also - * {@link #TemplateLoadingResult(TemplateLoadingSource, Serializable, InputStream, TemplateConfiguration)}. It's the - * responsibility of the caller (which is {@link TemplateCache} usually) to {@code close()} the {@link InputStream}. - * The return value is always the same instance, no mater when and how many times this method is called. - * - * <p> - * The returned {@code InputStream} will be read in few kilobyte chunks by FreeMarker, so generally it need not - * be a {@link BufferedInputStream}. - * - * @return {@code null} or a {@code InputStream} to read the template content; see method description for more. - */ - public InputStream getInputStream() { - return inputStream; - } - - /** - * Tells what kind of result this is; see the documentation of {@link TemplateLoadingResultStatus}. - */ - public TemplateLoadingResultStatus getStatus() { - return status; - } - - /** - * Identifies the source on the level of the storage mechanism; stored in the cache together with the version - * ({@link #getVersion()}). When checking if a cache entry is up to date, the sources are compared, and only if they - * are equal are the versions compared. See more at {@link TemplateLoadingSource}. - */ - public TemplateLoadingSource getSource() { - return source; - } - - /** - * If the result status is {@link TemplateLoadingResultStatus#OPENED} and the backing storage stores such - * information, the version (usually the last modification time) of the loaded template, otherwise {@code null}. The - * version is some kind of value which changes when the template in the backing storage is updated. Usually, it's - * the last modification time (a {@link Date} or {@link Long}), though that can be problematic if the template can - * change twice within the granularity of the clock used by the storage. Thus some storages may use a revision - * number instead that's always increased when the template is updated, or the cryptographic hash of the template - * content as the version. Version objects are compared with each other with their {@link Object#equals(Object)} - * method, to see if a cache entry is outdated (though only when the source objects ({@link #getSource()}) are - * equal). Thus, the version object must have proper {@link Object#equals(Object)} and {@link Object#hashCode()} - * methods. - */ - public Serializable getVersion() { - return version; - } - - /** - * Returns non-{@code null} exactly if {@link #getStatus()} is {@link TemplateLoadingResultStatus#OPENED} and the - * backing store mechanism returns content as {@code char}-s, as opposed to as {@code byte}-s. See also - * {@link #TemplateLoadingResult(TemplateLoadingSource, Serializable, Reader, TemplateConfiguration)}. It's the - * responsibility of the caller (which is {@link TemplateCache} usually) to {@code close()} the {@link Reader}. The - * return value is always the same instance, no mater when and how many times this method is called. - * - * <p> - * The returned {@code Reader} will be read in few thousand character chunks by FreeMarker, so generally it need not - * be a {@link BufferedReader}. - * - * @return {@code null} or a {@code Reader} to read the template content; see method description for more. - */ - public Reader getReader() { - return reader; - } - - /** - * If {@link #getStatus()} is {@link TemplateLoadingResultStatus#OPENED}, and the template loader stores such - * information (which is rare) then it returns the {@link TemplateConfiguration} applicable to the template, - * otherwise it returns {@code null}. If {@link #getStatus()} is not {@link TemplateLoadingResultStatus#OPENED}, - * then this should always return {@code null}. If there are {@link TemplateConfiguration}-s coming from other - * sources, such as from {@link Configuration#getTemplateConfigurations()}, this won't replace them, but will be - * merged with them, with properties coming from the returned {@link TemplateConfiguration} having the highest - * priority. - * - * @return {@code null}, or a {@link TemplateConfiguration}. The parent configuration of the - * {@link TemplateConfiguration} need not be set. The returned {@link TemplateConfiguration} won't be - * modified. (If the caller needs to modify it, such as to call - * {@link TemplateConfiguration#setParentConfiguration(Configuration)}, it has to copy it first.) - */ - public TemplateConfiguration getTemplateConfiguration() { - return templateConfiguration; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLoadingResultStatus.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLoadingResultStatus.java b/src/main/java/freemarker/cache/TemplateLoadingResultStatus.java deleted file mode 100644 index 6ea5e50..0000000 --- a/src/main/java/freemarker/cache/TemplateLoadingResultStatus.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.Serializable; - -/** - * Used for the value of {@link TemplateLoadingResult#getStatus()}. - */ -public enum TemplateLoadingResultStatus { - - /** - * The template with the requested name doesn't exist (not to be confused with "wasn't accessible due to error"). If - * there was and error because of which we can't know for sure if the template is there or not (for example we - * couldn't access the backing store due to a network connection error or other unexpected I/O error or - * authorization problem), this value must not be used, instead an exception should be thrown by - * {@link TemplateLoader#load(String, TemplateLoadingSource, Serializable, TemplateLoaderSession)}. - */ - NOT_FOUND, - - /** - * If the template was found, but its source and version is the same as that which was provided to - * {@link TemplateLoader#load(String, TemplateLoadingSource, Serializable, TemplateLoaderSession)} (from a cache - * presumably), so its content wasn't opened for reading. - */ - NOT_MODIFIED, - - /** - * If the template was found and its content is ready for reading. - */ - OPENED - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLoadingSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLoadingSource.java b/src/main/java/freemarker/cache/TemplateLoadingSource.java deleted file mode 100644 index ce84d24..0000000 --- a/src/main/java/freemarker/cache/TemplateLoadingSource.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.Serializable; -import java.util.HashMap; - -/** - * The point of {@link TemplateLoadingSource} is that with their {@link Object#equals(Object)} method we can tell if two - * cache entries were generated from the same physical resource or not. Comparing the template names isn't enough, - * because a {@link TemplateLoader} may uses some kind of fallback mechanism, such as delegating to other - * {@link TemplateLoader}-s until the template is found. Like if we have two {@link FileTemplateLoader}-s with different - * physical root directories, both can contain {@code "foo/bar.ftl"}, but obviously the two files aren't the same. - * - * <p> - * When implementing this interface, check these: - * - * <ul> - * <li>{@link Object#equals(Object)} must not be based on object identity, because two instances of - * {@link TemplateLoadingSource} that describe the same resource must be equivalent. - * - * <li>Each {@link TemplateLoader} implementation should have its own {@link TemplateLoadingSource} implementation, so - * that {@link TemplateLoadingSource}-s coming from different {@link TemplateLoader} implementations can't be - * accidentally equal (according to {@link Object#equals(Object)}). - * - * <li>{@link Object#equals(Object)} must still work properly if there are multiple instances of the same - * {@link TemplateLoader} implementation. Like if you have an implementation that loads from a database table, the - * {@link TemplateLoadingSource} should certain contain the JDBC connection string, the table name and the row ID, not - * just the row ID. - * - * <li>Together with {@link Object#equals(Object)}, {@link Object#hashCode()} must be also overridden. The template - * source may be used as a {@link HashMap} key. - * - * <li>Because {@link TemplateLoadingSource}-s are {@link Serializable}, they can't contain non-{@link Serializable} - * fields. Most notably, a reference to the creator {@link TemplateLoader}, so if it's an inner class of the - * {@link TemplateLoader}, it should be static. - * - * <li>Consider that cache entries, in which the source is stored, may move between JVM-s (because of clustering with a - * distributed cache). Thus they should remain meaningful for the purpose of {@link Object#equals(Object)} even in - * another JVM. - * - * <li>A {@link TemplateLoader} may chose not to support distributed caches, like {@link ByteArrayTemplateLoader} - * doesn't support that for example. In that case the serialization related points above can be ignored, but the - * {@link TemplateLoadingSource} implementation should define the {@code writeObject} method (a Java serialization - * feature) and throw an exception there to block serialization attempts. - * </ul> - */ -public interface TemplateLoadingSource extends Serializable { - // Empty -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLookupContext.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLookupContext.java b/src/main/java/freemarker/cache/TemplateLookupContext.java deleted file mode 100644 index 72827e6..0000000 --- a/src/main/java/freemarker/cache/TemplateLookupContext.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.Serializable; -import java.util.Locale; - -import freemarker.template.Configuration; - -/** - * Used as the parameter of {@link TemplateLookupStrategy#lookup(TemplateLookupContext)}. - * You can't create instances of this, only receive them from FreeMarker. - * - * @since 2.3.22 - */ -public abstract class TemplateLookupContext { - - private final String templateName; - private final Locale templateLocale; - private final Object customLookupCondition; - private final TemplateLoadingSource cachedResultSource; - private final Serializable cachedResultVersion; - - /** - * Finds the template source based on its <em>normalized</em> name; handles {@code *} steps (so called acquisition), - * otherwise it just calls {@link TemplateLoader#load(String, TemplateLoadingSource, Serializable, - * TemplateLoaderSession)}. - * - * @param templateName - * Must be a normalized name, like {@code "foo/bar/baaz.ftl"}. A name is not normalized when, among - * others, it starts with {@code /}, or contains {@code .} or {@code ..} path steps, or it uses - * backslash ({@code \}) instead of {@code /}. A normalized name might contains "*" path steps - * (acquisition). - * - * @return The result of the lookup. Not {@code null}; check {@link TemplateLookupResult#isPositive()} to see if the - * lookup has found anything. Note that in a positive result the content of the template is possibly - * also already loaded (this is the case for {@link TemplateLoader}-s when the cached content is stale, but - * not for {@link TemplateLoader}-s). Hence discarding a positive result and looking for another can - * generate substantial extra I/O. - */ - public abstract TemplateLookupResult lookupWithAcquisitionStrategy(String templateName) throws IOException; - - /** - * Finds the template source based on its <em>normalized</em> name; tries localized variations going from most - * specific to less specific, and for each variation it delegates to {@link #lookupWithAcquisitionStrategy(String)}. - * If {@code templateLocale} is {@code null} (typically, because {@link Configuration#getLocalizedLookup()} is - * {@code false})), then it's the same as calling {@link #lookupWithAcquisitionStrategy(String)} directly. This is - * the default strategy of FreeMarker (at least in 2.3.x), so for more information, see - * {@link TemplateLookupStrategy#DEFAULT_2_3_0}. - */ - public abstract TemplateLookupResult lookupWithLocalizedThenAcquisitionStrategy(String templateName, - Locale templateLocale) throws IOException; - - /** Default visibility to prevent extending the class from outside this package. */ - TemplateLookupContext(String templateName, Locale templateLocale, Object customLookupCondition, - TemplateLoadingSource cachedResultSource, Serializable cachedResultVersion) { - this.templateName = templateName; - this.templateLocale = templateLocale; - this.customLookupCondition = customLookupCondition; - this.cachedResultSource = cachedResultSource; - this.cachedResultVersion = cachedResultVersion; - } - - /** - * The normalized name (path) of the template (relatively to the {@link TemplateLoader}). Not {@code null}. - */ - public String getTemplateName() { - return templateName; - } - - /** - * {@code null} if localized lookup is disabled (see {@link Configuration#getLocalizedLookup()}), otherwise the - * locale requested. - */ - public Locale getTemplateLocale() { - return templateLocale; - } - - /** - * Returns the value of the {@code customLookupCondition} parameter of - * {@link Configuration#getTemplate(String, Locale, Object, String, boolean, boolean)}; see requirements there, such - * as having a proper {@link Object#equals(Object)} and {@link Object#hashCode()} method. The interpretation of this - * value is up to the custom {@link TemplateLookupStrategy}. Usually, it's used similarly to as the default lookup - * strategy uses {@link #getTemplateLocale()}, that is, to look for a template variation that satisfies the - * condition, and then maybe fall back to more generic template if that's missing. - */ - public Object getCustomLookupCondition() { - return customLookupCondition; - } - - /** - * Creates a not-found lookup result that then can be used as the return value of - * {@link TemplateLookupStrategy#lookup(TemplateLookupContext)}. (In the current implementation it just always - * returns the same static singleton, but that might need to change in the future.) - */ - public TemplateLookupResult createNegativeLookupResult() { - return TemplateLookupResult.createNegativeResult(); - } - - TemplateLoadingSource getCachedResultSource() { - return cachedResultSource; - } - - Serializable getCachedResultVersion() { - return cachedResultVersion; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLookupResult.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLookupResult.java b/src/main/java/freemarker/cache/TemplateLookupResult.java deleted file mode 100644 index 3fa29d3..0000000 --- a/src/main/java/freemarker/cache/TemplateLookupResult.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 freemarker.template.Template; -import freemarker.template.utility.NullArgumentException; - -/** - * The return value of {@link TemplateLookupStrategy#lookup(TemplateLookupContext)} and similar lookup methods. You - * usually get one from {@link TemplateLookupContext#lookupWithAcquisitionStrategy(String)} or - * {@link TemplateLookupContext#createNegativeLookupResult()}; you can't create instances of this directly. - * - * @since 2.3.22 - */ -public abstract class TemplateLookupResult { - - /** Used internally to get a not-found result (currently just a static singleton). */ - static TemplateLookupResult createNegativeResult() { - return NegativeTemplateLookupResult.INSTANCE; - } - - /** Used internally to create the appropriate kind of result from the parameters. */ - static TemplateLookupResult from(String templateSourceName, TemplateLoadingResult templateLoaderResult) { - return templateLoaderResult.getStatus() != TemplateLoadingResultStatus.NOT_FOUND - ? new PositiveTemplateLookupResult(templateSourceName, templateLoaderResult) - : createNegativeResult(); - } - - private TemplateLookupResult() { - // nop - } - - /** - * The source name of the template found (see {@link Template#getSourceName()}), or {@code null} if - * {@link #isPositive()} is {@code false}. - */ - public abstract String getTemplateSourceName(); - - /** - * Tells if the lookup has found a matching template. - */ - public abstract boolean isPositive(); - - /** - * Used internally to extract the {@link TemplateLoadingResult}; {@code null} if {@link #isPositive()} is - * {@code false}. - */ - abstract TemplateLoadingResult getTemplateLoaderResult(); - - private static final class PositiveTemplateLookupResult extends TemplateLookupResult { - - private final String templateSourceName; - private final TemplateLoadingResult templateLoaderResult; - - /** - * @param templateSourceName - * The name of the matching template found. This is not necessarily the same as the template name - * with which the template was originally requested. For example, one may gets a template for the - * {@code "foo.ftl"} name, but due to localized lookup the template is actually loaded from - * {@code "foo_de.ftl"}. Then this parameter must be {@code "foo_de.ftl"}, not {@code "foo.ftl"}. Not - * {@code null}. - * - * @param templateLoaderResult - * See {@link TemplateLoader#load} to understand what that means. Not - * {@code null}. - */ - private PositiveTemplateLookupResult(String templateSourceName, TemplateLoadingResult templateLoaderResult) { - NullArgumentException.check("templateName", templateSourceName); - NullArgumentException.check("templateLoaderResult", templateLoaderResult); - - this.templateSourceName = templateSourceName; - this.templateLoaderResult = templateLoaderResult; - } - - @Override - public String getTemplateSourceName() { - return templateSourceName; - } - - @Override - TemplateLoadingResult getTemplateLoaderResult() { - return templateLoaderResult; - } - - @Override - public boolean isPositive() { - return true; - } - } - - private static final class NegativeTemplateLookupResult extends TemplateLookupResult { - - private static final NegativeTemplateLookupResult INSTANCE = new NegativeTemplateLookupResult(); - - private NegativeTemplateLookupResult() { - // nop - } - - @Override - public String getTemplateSourceName() { - return null; - } - - @Override - TemplateLoadingResult getTemplateLoaderResult() { - return null; - } - - @Override - public boolean isPositive() { - return false; - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateLookupStrategy.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateLookupStrategy.java b/src/main/java/freemarker/cache/TemplateLookupStrategy.java deleted file mode 100644 index 6b50aa9..0000000 --- a/src/main/java/freemarker/cache/TemplateLookupStrategy.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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.util.Locale; - -import freemarker.template.Configuration; -import freemarker.template.Template; - -/** - * Finds the {@link TemplateLoader}-level (storage-level) template source for the template name with which the template - * was requested (as in {@link Configuration#getTemplate(String)}). This usually means trying various - * {@link TemplateLoader}-level template names (so called source names; see also {@link Template#getSourceName()}) that - * were deduced from the requested name. Trying a name usually means calling - * {@link TemplateLookupContext#lookupWithAcquisitionStrategy(String)} with it and checking the value of - * {@link TemplateLookupResult#isPositive()}. - * - * <p> - * Before you write your own lookup strategy, know that: - * <ul> - * <li>A template lookup strategy meant to operate solely with template names, not with {@link TemplateLoader}-s - * directly. Basically, it's a mapping between the template names that templates and API-s like - * {@link Configuration#getTemplate(String)} see, and those that the underlying {@link TemplateLoader} sees. - * <li>A template lookup strategy doesn't influence the template's name ({@link Template#getName()}), which is the - * normalized form of the template name as it was requested (with {@link Configuration#getTemplate(String)}, etc.). It - * only influences the so called source name of the template ({@link Template#getSourceName()}). The template's name is - * used as the basis for resolving relative inclusions/imports in the template. The source name is pretty much only used - * in error messages as error location, and of course, to actually load the template "file". - * <li>Understand the impact of the last point if your template lookup strategy fiddles not only with the file name part - * of the template name, but also with the directory part. For example, one may want to map "foo.ftl" to "en/foo.ftl", - * "fr/foo.ftl", etc. That's legal, but the result is kind of like if you had several root directories ("en/", "fr/", - * etc.) that are layered over each other to form a single merged directory. (This is what's desirable in typical - * applications, yet it can be confusing.) - * </ul> - * - * @see Configuration#setTemplateLookupStrategy(TemplateLookupStrategy) - * - * @since 2.3.22 - */ -public abstract class TemplateLookupStrategy { - - /** - * <p> - * The default lookup strategy of FreeMarker. - * - * <p> - * Through an example: Assuming localized lookup is enabled and that a template is requested for the name - * {@code example.ftl} and {@code Locale("es", "ES", "Traditional_WIN")}, it will try the following template names, - * in this order: {@code "foo_en_AU_Traditional_WIN.ftl"}, {@code "foo_en_AU_Traditional.ftl"}, - * {@code "foo_en_AU.ftl"}, {@code "foo_en.ftl"}, {@code "foo.ftl"}. It stops at the first variation where it finds - * a template. (If the template name contains "*" steps, finding the template for the attempted localized variation - * happens with the template acquisition mechanism.) If localized lookup is disabled, it won't try to add any locale - * strings, so it just looks for {@code "foo.ftl"}. - * - * <p> - * The generation of the localized name variation with the default lookup strategy, happens like this: It removes - * the file extension (the part starting with the <em>last</em> dot), then appends {@link Locale#toString()} after - * it, and puts back the extension. Then it starts to remove the parts from the end of the locale, considering - * {@code "_"} as the separator between the parts. It won't remove parts that are not part of the locale string - * (like if the requested template name is {@code foo_bar.ftl}, it won't remove the {@code "_bar"}). - */ - public static final TemplateLookupStrategy DEFAULT_2_3_0 = new Default020300(); - - /** - * Finds the template source that matches the template name, locale (if not {@code null}) and other parameters - * specified in the {@link TemplateLookupContext}. See also the class-level {@link TemplateLookupStrategy} - * documentation to understand lookup strategies more. - * - * @param ctx - * Contains the parameters for which the matching template need to be found, and operations that - * are needed to implement the strategy. Some of the important input parameters are: - * {@link TemplateLookupContext#getTemplateName()}, {@link TemplateLookupContext#getTemplateLocale()}. - * The most important operations are {@link TemplateLookupContext#lookupWithAcquisitionStrategy(String)} - * and {@link TemplateLookupContext#createNegativeLookupResult()}. (Note that you deliberately can't - * use {@link TemplateLoader}-s directly to implement lookup.) - * - * @return Usually the return value of {@link TemplateLookupContext#lookupWithAcquisitionStrategy(String)}, or - * {@code TemplateLookupContext#createNegativeLookupResult()} if no matching template exists. Can't be - * {@code null}. - */ - public abstract TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException; - - private static class Default020300 extends TemplateLookupStrategy { - - @Override - public TemplateLookupResult lookup(TemplateLookupContext ctx) throws IOException { - return ctx.lookupWithLocalizedThenAcquisitionStrategy(ctx.getTemplateName(), ctx.getTemplateLocale()); - } - - @Override - public String toString() { - return "TemplateLookupStrategy.DEFAULT_2_3_0"; - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateNameFormat.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateNameFormat.java b/src/main/java/freemarker/cache/TemplateNameFormat.java deleted file mode 100644 index 34782c5..0000000 --- a/src/main/java/freemarker/cache/TemplateNameFormat.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * 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 freemarker.template.Configuration; -import freemarker.template.MalformedTemplateNameException; -import freemarker.template.TemplateNotFoundException; -import freemarker.template.Version; -import freemarker.template.utility.StringUtil; - -/** - * Symbolized template name format. The API of this class isn't exposed as it's too immature, so custom - * template name formats aren't possible yet. - * - * @since 2.3.22 - */ -public abstract class TemplateNameFormat { - - private TemplateNameFormat() { - // Currently can't be instantiated from outside - } - - /** - * The default template name format when {@link Configuration#Configuration(Version) incompatible_improvements} is - * below 2.4.0. As of FreeMarker 2.4.0, the default {@code incompatible_improvements} is still {@code 2.3.0}, and it - * will certainly remain so for a very long time. In new projects it's highly recommended to use - * {@link #DEFAULT_2_4_0} instead. - */ - public static final TemplateNameFormat DEFAULT_2_3_0 = new Default020300(); - - /** - * The default template name format only when {@link Configuration#Configuration(Version) incompatible_improvements} - * is set to 2.4.0 (or higher). This is not the out-of-the-box default format of FreeMarker 2.4.x, because the - * default {@code incompatible_improvements} is still 2.3.0 there. - * - * <p> - * Differences to the {@link #DEFAULT_2_3_0} format: - * - * <ul> - * - * <li>The scheme and the path need not be separated with {@code "://"} anymore, only with {@code ":"}. This makes - * template names like {@code "classpath:foo.ftl"} interpreted as an absolute name with scheme {@code "classpath"} - * and absolute path "foo.ftl". The scheme name before the {@code ":"} can't contain {@code "/"}, or else it's - * treated as a malformed name. The scheme part can be separated either with {@code "://"} or just {@code ":"} from - * the path. Hence, {@code myschme:/x} is normalized to {@code myschme:x}, while {@code myschme:///x} is normalized - * to {@code myschme://x}, but {@code myschme://x} or {@code myschme:/x} aren't changed by normalization. It's up - * the {@link TemplateLoader} to which the normalized names are passed to decide which of these scheme separation - * conventions are valid (maybe both).</li> - * - * <li>{@code ":"} is not allowed in template names, except as the scheme separator (see previous point). - * - * <li>Malformed paths throw {@link MalformedTemplateNameException} instead of acting like if the template wasn't - * found. - * - * <li>{@code "\"} (backslash) is not allowed in template names, and causes {@link MalformedTemplateNameException}. - * With {@link #DEFAULT_2_3_0} you would certainly end up with a {@link TemplateNotFoundException} (or worse, - * it would work, but steps like {@code ".."} wouldn't be normalized by FreeMarker). - * - * <li>Template names might end with {@code /}, like {@code "foo/"}, and the presence or lack of the terminating - * {@code /} is seen as significant. While their actual interpretation is up to the {@link TemplateLoader}, - * operations that manipulate template names assume that the last step refers to a "directory" as opposed to a - * "file" exactly if the terminating {@code /} is present. Except, the empty name is assumed to refer to the root - * "directory" (despite that it doesn't end with {@code /}). - * - * <li>{@code //} is normalized to {@code /}, except of course if it's in the scheme name terminator. Like - * {@code foo//bar///baaz.ftl} is normalized to {@code foo/bar/baaz.ftl}. (In general, 0 long step names aren't - * possible anymore.)</li> - * - * <li>The {@code ".."} bugs of the legacy normalizer are fixed: {@code ".."} steps has removed the preceding - * {@code "."} or {@code "*"} or scheme steps, not treating them specially as they should be. Now these work as - * expected. Examples: {@code "a/./../c"} has become to {@code "a/c"}, now it will be {@code "c"}; {@code "a/b/*} - * {@code /../c"} has become to {@code "a/b/c"}, now it will be {@code "a/*}{@code /c"}; {@code "scheme://.."} has - * become to {@code "scheme:/"}, now it will be {@code null} ({@link TemplateNotFoundException}) for backing out of - * the root directory.</li> - * - * <li>As now directory paths has to be handled as well, it recognizes terminating, leading, and lonely {@code ".."} - * and {@code "."} steps. For example, {@code "foo/bar/.."} now becomes to {@code "foo/"}</li> - * - * <li>Multiple consecutive {@code *} steps are normalized to one</li> - * - * </ul> - */ - public static final TemplateNameFormat DEFAULT_2_4_0 = new Default020400(); - - /** - * Converts a name to a template root directory based name, so that it can be used to find a template without - * knowing what (like which template) has referred to it. The rules depend on the name format, but a typical example - * is converting "t.ftl" with base "sub/contex.ftl" to "sub/t.ftl". - * - * @param baseName - * Maybe a file name, maybe a directory name. The meaning of file name VS directory name depends on the - * name format, but typically, something like "foo/bar/" is a directory name, and something like - * "foo/bar" is a file name, and thus in the last case the effective base is "foo/" (i.e., the directory - * that contains the file). Not {@code null}. - * @param targetName - * The name to convert. This usually comes from a template that refers to another template by name. It - * can be a relative name, or an absolute name. (In typical name formats absolute names start with - * {@code "/"} or maybe with an URL scheme, and all others are relative). Not {@code null}. - * - * @return The path in template root directory relative format, or even an absolute name (where the root directory - * is not the real root directory of the file system, but the imaginary directory that exists to store the - * templates). The standard implementations shipped with FreeMarker always return a root relative path - * (except if the name starts with an URI schema, in which case a full URI is returned). - */ - abstract String toRootBasedName(String baseName, String targetName) throws MalformedTemplateNameException; - - /** - * Normalizes a template root directory based name (relative to the root or absolute), so that equivalent names - * become equivalent according {@link String#equals(Object)} too. The rules depend on the name format, but typical - * examples are "sub/../t.ftl" to "t.ftl", "sub/./t.ftl" to "sub/t.ftl" and "/t.ftl" to "t.ftl". - * - * <p>The standard implementations shipped with FreeMarker always returns a root relative path - * (except if the name starts with an URI schema, in which case a full URI is returned), for example, "/foo.ftl" - * becomes to "foo.ftl". - * - * @param name - * The root based name. Not {@code null}. - * - * @return The normalized root based name. Not {@code null}. - */ - abstract String normalizeRootBasedName(String name) throws MalformedTemplateNameException; - - private static final class Default020300 extends TemplateNameFormat { - @Override - String toRootBasedName(String baseName, String targetName) { - if (targetName.indexOf("://") > 0) { - return targetName; - } else if (targetName.startsWith("/")) { - int schemeSepIdx = baseName.indexOf("://"); - if (schemeSepIdx > 0) { - return baseName.substring(0, schemeSepIdx + 2) + targetName; - } else { - return targetName.substring(1); - } - } else { - if (!baseName.endsWith("/")) { - baseName = baseName.substring(0, baseName.lastIndexOf("/") + 1); - } - return baseName + targetName; - } - } - - @Override - String normalizeRootBasedName(final String name) throws MalformedTemplateNameException { - // Disallow 0 for security reasons. - checkNameHasNoNullCharacter(name); - - // The legacy algorithm haven't considered schemes, so the name is in effect a path. - // Also, note that `path` will be repeatedly replaced below, while `name` is final. - String path = name; - - for (; ; ) { - int parentDirPathLoc = path.indexOf("/../"); - if (parentDirPathLoc == 0) { - // If it starts with /../, then it reaches outside the template - // root. - throw newRootLeavingException(name); - } - if (parentDirPathLoc == -1) { - if (path.startsWith("../")) { - throw newRootLeavingException(name); - } - break; - } - int previousSlashLoc = path.lastIndexOf('/', parentDirPathLoc - 1); - path = path.substring(0, previousSlashLoc + 1) + - path.substring(parentDirPathLoc + "/../".length()); - } - for (; ; ) { - int currentDirPathLoc = path.indexOf("/./"); - if (currentDirPathLoc == -1) { - if (path.startsWith("./")) { - path = path.substring("./".length()); - } - break; - } - path = path.substring(0, currentDirPathLoc) + - path.substring(currentDirPathLoc + "/./".length() - 1); - } - // Editing can leave us with a leading slash; strip it. - if (path.length() > 1 && path.charAt(0) == '/') { - path = path.substring(1); - } - return path; - } - - @Override - public String toString() { - return "TemplateNameFormat.DEFAULT_2_3_0"; - } - - } - - private static final class Default020400 extends TemplateNameFormat { - @Override - String toRootBasedName(String baseName, String targetName) { - if (findSchemeSectionEnd(targetName) != 0) { - return targetName; - } else if (targetName.startsWith("/")) { // targetName is an absolute path - final String targetNameAsRelative = targetName.substring(1); - final int schemeSectionEnd = findSchemeSectionEnd(baseName); - if (schemeSectionEnd == 0) { - return targetNameAsRelative; - } else { - // Prepend the scheme of baseName: - return baseName.substring(0, schemeSectionEnd) + targetNameAsRelative; - } - } else { // targetName is a relative path - if (!baseName.endsWith("/")) { - // Not a directory name => get containing directory name - int baseEnd = baseName.lastIndexOf("/") + 1; - if (baseEnd == 0) { - // For something like "classpath:t.ftl", must not remove the scheme part: - baseEnd = findSchemeSectionEnd(baseName); - } - baseName = baseName.substring(0, baseEnd); - } - return baseName + targetName; - } - } - - @Override - String normalizeRootBasedName(final String name) throws MalformedTemplateNameException { - // Disallow 0 for security reasons. - checkNameHasNoNullCharacter(name); - - if (name.indexOf('\\') != -1) { - throw new MalformedTemplateNameException( - name, - "Backslash (\"\\\") is not allowed in template names. Use slash (\"/\") instead."); - } - - // Split name to a scheme and a path: - final String scheme; - String path; - { - int schemeSectionEnd = findSchemeSectionEnd(name); - if (schemeSectionEnd == 0) { - scheme = null; - path = name; - } else { - scheme = name.substring(0, schemeSectionEnd); - path = name.substring(schemeSectionEnd); - } - } - - if (path.indexOf(':') != -1) { - throw new MalformedTemplateNameException(name, - "The ':' character can only be used after the scheme name (if there's any), " - + "not in the path part"); - } - - path = removeRedundantSlashes(path); - // path now doesn't start with "/" - - path = removeDotSteps(path); - - path = resolveDotDotSteps(path, name); - - path = removeRedundantStarSteps(path); - - return scheme == null ? path : scheme + path; - } - - private int findSchemeSectionEnd(String name) { - int schemeColonIdx = name.indexOf(":"); - if (schemeColonIdx == -1 || name.lastIndexOf('/', schemeColonIdx - 1) != -1) { - return 0; - } else { - // If there's a following "//", it's treated as the part of the scheme section: - if (schemeColonIdx + 2 < name.length() - && name.charAt(schemeColonIdx + 1) == '/' && name.charAt(schemeColonIdx + 2) == '/') { - return schemeColonIdx + 3; - } else { - return schemeColonIdx + 1; - } - } - } - - private String removeRedundantSlashes(String path) { - String prevName; - do { - prevName = path; - path = StringUtil.replace(path, "//", "/"); - } while (prevName != path); - return path.startsWith("/") ? path.substring(1) : path; - } - - private String removeDotSteps(String path) { - int nextFromIdx = path.length() - 1; - findDotSteps: while (true) { - final int dotIdx = path.lastIndexOf('.', nextFromIdx); - if (dotIdx < 0) { - return path; - } - nextFromIdx = dotIdx - 1; - - if (dotIdx != 0 && path.charAt(dotIdx - 1) != '/') { - // False alarm - continue findDotSteps; - } - - final boolean slashRight; - if (dotIdx + 1 == path.length()) { - slashRight = false; - } else if (path.charAt(dotIdx + 1) == '/') { - slashRight = true; - } else { - // False alarm - continue findDotSteps; - } - - if (slashRight) { // "foo/./bar" or "./bar" - path = path.substring(0, dotIdx) + path.substring(dotIdx + 2); - } else { // "foo/." or "." - path = path.substring(0, path.length() - 1); - } - } - } - - /** - * @param name The original name, needed for exception error messages. - */ - private String resolveDotDotSteps(String path, final String name) throws MalformedTemplateNameException { - int nextFromIdx = 0; - findDotDotSteps: while (true) { - final int dotDotIdx = path.indexOf("..", nextFromIdx); - if (dotDotIdx < 0) { - return path; - } - - if (dotDotIdx == 0) { - throw newRootLeavingException(name); - } else if (path.charAt(dotDotIdx - 1) != '/') { - // False alarm - nextFromIdx = dotDotIdx + 3; - continue findDotDotSteps; - } - // Here we know that it has a preceding "/". - - final boolean slashRight; - if (dotDotIdx + 2 == path.length()) { - slashRight = false; - } else if (path.charAt(dotDotIdx + 2) == '/') { - slashRight = true; - } else { - // False alarm - nextFromIdx = dotDotIdx + 3; - continue findDotDotSteps; - } - - int previousSlashIdx; - boolean skippedStarStep = false; - { - int searchSlashBacwardsFrom = dotDotIdx - 2; // before the "/.." - scanBackwardsForSlash: while (true) { - if (searchSlashBacwardsFrom == -1) { - throw newRootLeavingException(name); - } - previousSlashIdx = path.lastIndexOf('/', searchSlashBacwardsFrom); - if (previousSlashIdx == -1) { - if (searchSlashBacwardsFrom == 0 && path.charAt(0) == '*') { - // "*/.." - throw newRootLeavingException(name); - } - break scanBackwardsForSlash; - } - if (path.charAt(previousSlashIdx + 1) == '*' && path.charAt(previousSlashIdx + 2) == '/') { - skippedStarStep = true; - searchSlashBacwardsFrom = previousSlashIdx - 1; - } else { - break scanBackwardsForSlash; - } - } - } - - // Note: previousSlashIdx is possibly -1 - // Removed part in {}: "a/{b/*/../}c" or "a/{b/*/..}" - path = path.substring(0, previousSlashIdx + 1) - + (skippedStarStep ? "*/" : "") - + path.substring(dotDotIdx + (slashRight ? 3 : 2)); - nextFromIdx = previousSlashIdx + 1; - } - } - - private String removeRedundantStarSteps(String path) { - String prevName; - removeDoubleStarSteps: do { - int supiciousIdx = path.indexOf("*/*"); - if (supiciousIdx == -1) { - break removeDoubleStarSteps; - } - - prevName = path; - - // Is it delimited on both sided by "/" or by the string boundaires? - if ((supiciousIdx == 0 || path.charAt(supiciousIdx - 1) == '/') - && (supiciousIdx + 3 == path.length() || path.charAt(supiciousIdx + 3) == '/')) { - path = path.substring(0, supiciousIdx) + path.substring(supiciousIdx + 2); - } - } while (prevName != path); - - // An initial "*" step is redundant: - if (path.startsWith("*")) { - if (path.length() == 1) { - path = ""; - } else if (path.charAt(1) == '/') { - path = path.substring(2); - } - // else: it's wasn't a "*" step. - } - - return path; - } - - @Override - public String toString() { - return "TemplateNameFormat.DEFAULT_2_4_0"; - } - } - - private static void checkNameHasNoNullCharacter(final String name) throws MalformedTemplateNameException { - if (name.indexOf(0) != -1) { - throw new MalformedTemplateNameException(name, - "Null character (\\u0000) in the name; possible attack attempt"); - } - } - - private static MalformedTemplateNameException newRootLeavingException(final String name) { - return new MalformedTemplateNameException(name, "Backing out from the root directory is not allowed"); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/TemplateSourceMatcher.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/TemplateSourceMatcher.java b/src/main/java/freemarker/cache/TemplateSourceMatcher.java deleted file mode 100644 index 478aaee..0000000 --- a/src/main/java/freemarker/cache/TemplateSourceMatcher.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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; - -/** - * @since 2.3.24 - */ -public abstract class TemplateSourceMatcher { - - abstract boolean matches(String sourceName, Object templateSource) throws IOException; - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/URLTemplateLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/URLTemplateLoader.java b/src/main/java/freemarker/cache/URLTemplateLoader.java deleted file mode 100644 index 56d5bdd..0000000 --- a/src/main/java/freemarker/cache/URLTemplateLoader.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * 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.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.net.JarURLConnection; -import java.net.URL; -import java.net.URLConnection; -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import freemarker.template.Configuration; - -/** - * This is an abstract template loader that can load templates whose location can be described by an URL. Subclasses - * only need to override the {@link #getURL(String)}, {@link #extractNegativeResult(URLConnection)}, and perhaps the - * {@link #prepareConnection(URLConnection)} method. - */ -// TODO JUnit test (including implementing a HTTP-based template loader to test the new protected methods) -public abstract class URLTemplateLoader implements TemplateLoader { - - private static final Logger LOG = LoggerFactory.getLogger("freemarker.cache"); - - private Boolean urlConnectionUsesCaches = false; - - /** - * Getter pair of {@link #setURLConnectionUsesCaches(Boolean)}. - * - * @since 2.3.21 - */ - public Boolean getURLConnectionUsesCaches() { - return urlConnectionUsesCaches; - } - - /** - * Sets if {@link URLConnection#setUseCaches(boolean)} will be called, and with what value. By default this is - * {@code false}, because FreeMarker has its own template cache with its own update delay setting - * ({@link Configuration#setTemplateUpdateDelay(int)}). If this is set to {@code null}, - * {@link URLConnection#setUseCaches(boolean)} won't be called. - */ - public void setURLConnectionUsesCaches(Boolean urlConnectionUsesCaches) { - this.urlConnectionUsesCaches = urlConnectionUsesCaches; - } - - @Override - public TemplateLoaderSession createSession() { - return null; - } - - @Override - public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom, - Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException { - URL url = getURL(name); - if (url == null) { - return TemplateLoadingResult.NOT_FOUND; - } - - URLConnection conn = url.openConnection(); - Boolean urlConnectionUsesCaches = getURLConnectionUsesCaches(); - if (urlConnectionUsesCaches != null) { - conn.setUseCaches(urlConnectionUsesCaches); - } - - prepareConnection(conn); - conn.connect(); - - InputStream inputStream = null; - Long version; - URLTemplateLoadingSource source; - try { - TemplateLoadingResult negativeResult = extractNegativeResult(conn); - if (negativeResult != null) { - return negativeResult; - } - - // To prevent clustering issues, getLastModified(fallbackToJarLMD=false) - long lmd = getLastModified(conn, false); - version = lmd != -1 ? lmd : null; - - source = new URLTemplateLoadingSource(url); - - if (ifSourceDiffersFrom != null && ifSourceDiffersFrom.equals(source) - && Objects.equals(ifVersionDiffersFrom, version)) { - return TemplateLoadingResult.NOT_MODIFIED; - } - - inputStream = conn.getInputStream(); - } catch (Throwable e) { - try { - if (inputStream == null) { - // There's no URLConnection.close(), so we do this hack. In case of HttpURLConnection we could call - // disconnect(), but that's perhaps too aggressive. - conn.getInputStream().close(); - } - } catch (IOException e2) { - LOG.debug("Failed to close connection inputStream", e2); - } - throw e; - } - return new TemplateLoadingResult(source, version, inputStream, null); - } - - @Override - public void resetState() { - // Do nothing - } - - /** - * {@link URLConnection#getLastModified()} with JDK bug workarounds. Because of JDK-6956385, for files inside a jar, - * it returns the last modification time of the jar itself, rather than the last modification time of the file - * inside the jar. - * - * @param fallbackToJarLMD - * Tells if the file is in side jar, then we should return the last modification time of the jar itself, - * or -1 (to work around JDK-6956385). - */ - public static long getLastModified(URLConnection conn, boolean fallbackToJarLMD) throws IOException { - if (conn instanceof JarURLConnection) { - // There is a bug in sun's jar url connection that causes file handle leaks when calling getLastModified() - // (see https://bugs.openjdk.java.net/browse/JDK-6956385). - // Since the time stamps of jar file contents can't vary independent from the jar file timestamp, just use - // the jar file timestamp - if (fallbackToJarLMD) { - URL jarURL = ((JarURLConnection) conn).getJarFileURL(); - if (jarURL.getProtocol().equals("file")) { - // Return the last modified time of the underlying file - saves some opening and closing - return new File(jarURL.getFile()).lastModified(); - } else { - // Use the URL mechanism - URLConnection jarConn = null; - try { - jarConn = jarURL.openConnection(); - return jarConn.getLastModified(); - } finally { - try { - if (jarConn != null) { - jarConn.getInputStream().close(); - } - } catch (IOException e) { - LOG.warn("Failed to close URL connection for: {}", conn, e); - } - } - } - } else { - return -1; - } - } else { - return conn.getLastModified(); - } - } - - /** - * 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, or other decorations the - * {@link TemplateLookupStrategy} uses). - * - * @return An URL that points to the template source, or null if it can be determined that the template source does - * not exist. For many implementations the existence of the template can't be decided at this point, and you - * rely on {@link #extractNegativeResult(URLConnection)} instead. - */ - protected abstract URL getURL(String name); - - /** - * Called before the resource if read, checks if we can immediately return a {@link TemplateLoadingResult#NOT_FOUND} - * or {@link TemplateLoadingResult#NOT_MODIFIED}, or throw an {@link IOException}. For example, for a HTTP-based - * storage, the HTTP response status 404 could result in {@link TemplateLoadingResult#NOT_FOUND}, 304 in - * {@link TemplateLoadingResult#NOT_MODIFIED}, and some others, like 500 in throwing an {@link IOException}. - * - * <p>Some - * implementations rely on {@link #getURL(String)} returning {@code null} when a template is missing, in which case - * this method is certainly not applicable. - */ - protected abstract TemplateLoadingResult extractNegativeResult(URLConnection conn) throws IOException; - - /** - * Called before anything that causes the connection to actually build up. This is where - * {@link URLConnection#setIfModifiedSince(long)} and such can be called if someone overrides this. - * The default implementation in {@link URLTemplateLoader} does nothing. - */ - protected void prepareConnection(URLConnection conn) { - // Does nothing - } - - /** - * 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; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/URLTemplateLoadingSource.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/URLTemplateLoadingSource.java b/src/main/java/freemarker/cache/URLTemplateLoadingSource.java deleted file mode 100644 index bf84bef..0000000 --- a/src/main/java/freemarker/cache/URLTemplateLoadingSource.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.net.URL; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import freemarker.template.utility.NullArgumentException; - -@SuppressWarnings("serial") -public class URLTemplateLoadingSource implements TemplateLoadingSource { - - private final URL url; - - public URLTemplateLoadingSource(URL url) { - NullArgumentException.check("url", url); - this.url = url; - } - - public URL getUrl() { - return url; - } - - @Override - public int hashCode() { - return url.hashCode(); - } - - @Override - @SuppressFBWarnings("EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS") - public boolean equals(Object obj) { - return url.equals(obj); - } - - @Override - public String toString() { - return url.toString(); - } - -}
