http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/build.xml ---------------------------------------------------------------------- diff --git a/build.xml b/build.xml index 5bf9dee..1ca68b4 100644 --- a/build.xml +++ b/build.xml @@ -32,8 +32,8 @@ <!-- ================================================================== --> <!-- Maven project coordinates: --> - <property name="mavenGroupId" value="org.freemarker" /> - <property name="mavenArtifactId" value="freemarker-gae" /> + <property name="mavenGroupId" value="org.apache.freemarker" /> + <property name="mavenArtifactId" value="freemarker" /> <!-- Ivy project coordinates: --> <property name="moduleOrg" value="org.freemarker" /> <property name="moduleName" value="freemarker" /> @@ -75,7 +75,7 @@ <mkdir dir="build"/> <!-- Copying is needed to substitute the timestamps. --> <copy - file="src/main/resources/freemarker/version.properties" + file="src/main/resources/org/apache/freemarker/core/version.properties" tofile="build/version.properties.tmp" filtering="true" overwrite="true" @@ -131,7 +131,7 @@ /> <property name="_javaccOutputDir" - value="build/generated-sources/java/freemarker/core/" + value="build/generated-sources/java/org/apache/freemarker/core/ast" /> <mkdir dir="${_javaccOutputDir}" /> @@ -226,9 +226,7 @@ classpathref="ivy.dep" bootclasspath="${boot.classpath.j2se1.7}" excludes=" - freemarker/ext/jsp/**, - freemarker/ext/servlet/**, - freemarker/cache/Web?ppTemplateLoader*.java" + org/apache/freemarker/servlet/**" > <src> <pathelement location="build/src-main-java-filtered" /> @@ -237,7 +235,7 @@ </javac> <rmic - base="build/classes" includes="freemarker/debug/impl/Rmi*Impl.class" + base="build/classes" includes="org/apache/freemarker/core/debug/impl/Rmi*Impl.class" classpathref="ivy.dep" verify="yes" stubversion="1.2" /> @@ -249,33 +247,24 @@ classpathref="ivy.dep.jsp2.1" bootclasspath="${boot.classpath.j2se1.7}" includes=" - freemarker/ext/jsp/**, - freemarker/ext/servlet/**, - freemarker/cache/WebappTemplateLoader.java" + org/apache/freemarker/servlet/**" /> <rmic base="build/classes" classpathref="ivy.dep" - includes="build/src-main-java-filtered/freemarker/debug/impl/Rmi*Impl.class" + includes="build/src-main-java-filtered/org/apache/freemarker/core/debug/impl/Rmi*Impl.class" verify="yes" stubversion="1.2" /> - <!-- We don't have this file in 2.4.X... yet? - <copy - file="build/classes/freemarker/core/SecureRendererImpl.class" - tofile="build/classes/freemarker/core/SecureRendererImpl.clazz" - /> - --> - <copy toDir="build/classes"> <fileset dir="src/main/resources" excludes=" - freemarker/version.properties" + org/apache/freemarker/core/version.properties" /> </copy> <copy toDir="build/classes" filtering="true" overwrite="true"> <fileset dir="src/main/resources" includes=" - freemarker/version.properties" + org/apache/freemarker/core/version.properties" /> </copy> <copy toDir="build/classes/META-INF"> @@ -313,26 +302,10 @@ classpathref="ivy.dep" /> - <!-- Hack: This file should be excluded, but I can't explain that to bnd. --> - <!-- We don't have this file in 2.4.X... yet? - <move - file="build/classes/freemarker/core/SecureRendererImpl.class" - tofile="build/SecureRendererImpl.class.tmp" - preservelastmodified="true" overwrite="true" - /> - --> <bnd:bnd files="osgi.bnd" eclipse="false" output="build/freemarker.jar" /> - <!-- Revert previous hack... --> - <!-- We don't have this file in 2.4.X... yet? - <move - file="build/SecureRendererImpl.class.tmp" - tofile="build/classes/freemarker/core/SecureRendererImpl.class" - preservelastmodified="true" overwrite="true" - /> - --> </target> <!-- ================================================================= --> @@ -403,9 +376,15 @@ destdir="build/api" doctitle="FreeMarker ${version}" packagenames=" - freemarker.debug, freemarker.template.*, - freemarker.core.*, freemarker.ext.*, - freemarker.cache.*, freemarker.log.*" + org.apache.freemarker.core.*, + org.apache.freemarker.core.debug.*, + org.apache.freemarker.core.templateresolver.*, + org.apache.freemarker.core.model.*, + org.apache.freemarker.core.model.impl.*, + org.apache.freemarker.core.model.impl.beans.*, + org.apache.freemarker.core.model.impl.dom.*, + org.apache.freemarker.servlet.*, + org.apache.freemarker.servlet.jsp.*" use="true" version="true" author="true" @@ -525,7 +504,7 @@ <u:manual offline="true" locale="zh_CN" /> </target> - <target name="manualFreemarkerOrg_zh_CN" depends="init" description="Build the Manual to be upload to freemarker.org" > + <target name="manualFreemarkerOrg_zh_CN" depends="init" description="Build the Manual to be upload to freemarker.org"> <u:manual offline="false" locale="zh_CN" /> </target>
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/osgi.bnd ---------------------------------------------------------------------- diff --git a/osgi.bnd b/osgi.bnd index e1c7acb..049073e 100644 --- a/osgi.bnd +++ b/osgi.bnd @@ -31,13 +31,13 @@ Bundle-Vendor: freemarker.org Include-Resource: META-INF=build/classes/META-INF -Export-Package: !freemarker.test.*, freemarker.*;version="${versionForOSGi}" +Export-Package: !org.apache.freemarker.test.*, org.apache.freemarker.*;version="${versionForOSGi}" # Important: # Packages that don't match nor the Export-Package nor the # Private-Package mainfest header will be excluded from # the .jar file! -Import-Package: !freemarker.*, *;resolution:="optional" +Import-Package: !org.apache.freemarker.*, *;resolution:="optional" # The above makes all imports optional (like org.python, etc.), # except those that were explicitly listed (or are inside java.*). # Thus, even when the Java platfrom includes a package, it won't @@ -52,13 +52,13 @@ DynamicImport-Package: * # The required minimum is 1.4, but we utilize 1.5 if available. # See also: http://wiki.eclipse.org/Execution_Environments, "Compiling # against more than is required" -Bundle-RequiredExecutionEnvironment: J2SE-1.5, J2SE-1.4 +Bundle-RequiredExecutionEnvironment: J2SE-1.7 # Non-OSGi meta: -Extension-name: FreeMarker -Specification-Title: FreeMarker +Extension-name: Apache FreeMarker +Specification-Title: Apache FreeMarker Specification-Version: ${versionForMf} Specification-Vendor: freemarker.org -Implementation-Title: FreeMarker +Implementation-Title: Apache FreeMarker Implementation-Version: ${versionForMf} Implementation-Vendor: freemarker.org http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/AndMatcher.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/AndMatcher.java b/src/main/java/freemarker/cache/AndMatcher.java deleted file mode 100644 index 7cf9082..0000000 --- a/src/main/java/freemarker/cache/AndMatcher.java +++ /dev/null @@ -1,45 +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; - -/** - * Logical "and" operation among the given matchers. - * - * @since 2.3.24 - */ -public class AndMatcher extends TemplateSourceMatcher { - - private final TemplateSourceMatcher[] matchers; - - public AndMatcher(TemplateSourceMatcher... matchers) { - if (matchers.length == 0) throw new IllegalArgumentException("Need at least 1 matcher, had 0."); - this.matchers = matchers; - } - - @Override - public boolean matches(String sourceName, Object templateSource) throws IOException { - for (TemplateSourceMatcher matcher : matchers) { - if (!(matcher.matches(sourceName, templateSource))) return false; - } - return true; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java b/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java deleted file mode 100644 index 974a0ef..0000000 --- a/src/main/java/freemarker/cache/ByteArrayTemplateLoader.java +++ /dev/null @@ -1,194 +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.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; - -import freemarker.template.utility.StringUtil; - -/** - * A {@link TemplateLoader} that uses a {@link Map} with {@code byte[]} as its source of templates. This is similar to - * {@link StringTemplateLoader}, but uses {@code byte[]} instead of {@link String}; see more details there. - * - * <p>Note that {@link ByteArrayTemplateLoader} can't be used with a distributed (cluster-wide) {@link CacheStorage}, - * as it produces {@link TemplateLoadingSource}-s that deliberately throw exception on serialization (because the - * content is only accessible within a single JVM, and is also volatile). - */ -// TODO JUnit tests -public class ByteArrayTemplateLoader implements TemplateLoader { - - private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(); - - private final long instanceId = INSTANCE_COUNTER.get(); - private final AtomicLong templatesRevision = new AtomicLong(); - private final ConcurrentMap<String, ContentHolder> templates = new ConcurrentHashMap<>(); - - /** - * Puts a template into the template loader. The name can contain slashes to denote logical directory structure, but - * must not start with a slash. Each template will get an unique revision number, thus replacing a template will - * cause the template cache to reload it (when the update delay expires). - * - * <p>This method is thread-safe. - * - * @param name - * the name of the template. - * @param content - * the source code of the template. - */ - public void putTemplate(String name, byte[] content) { - templates.put( - name, - new ContentHolder(content, new Source(instanceId, name), templatesRevision.incrementAndGet())); - } - - /** - * Removes the template with the specified name if it was added earlier. - * - * <p> - * This method is thread-safe. - * - * @param name - * Exactly the key with which the template was added. - * - * @return Whether a template was found with the given key (and hence was removed now) - */ - public boolean removeTemplate(String name) { - return templates.remove(name) != null; - } - - @Override - public TemplateLoaderSession createSession() { - return null; - } - - @Override - public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom, - Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException { - ContentHolder contentHolder = templates.get(name); - if (contentHolder == null) { - return TemplateLoadingResult.NOT_FOUND; - } else if (ifSourceDiffersFrom != null && ifSourceDiffersFrom.equals(contentHolder.source) - && Objects.equals(ifVersionDiffersFrom, contentHolder.version)) { - return TemplateLoadingResult.NOT_MODIFIED; - } else { - return new TemplateLoadingResult( - contentHolder.source, contentHolder.version, - new ByteArrayInputStream(contentHolder.content), - null); - } - } - - @Override - public void resetState() { - // Do nothing - } - - /** - * Show class name and some details that are useful in template-not-found errors. - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(TemplateLoaderUtils.getClassNameForToString(this)); - sb.append("(Map { "); - int cnt = 0; - for (String name : templates.keySet()) { - cnt++; - if (cnt != 1) { - sb.append(", "); - } - if (cnt > 10) { - sb.append("..."); - break; - } - sb.append(StringUtil.jQuote(name)); - sb.append("=..."); - } - if (cnt != 0) { - sb.append(' '); - } - sb.append("})"); - return sb.toString(); - } - - private static class ContentHolder { - private final byte[] content; - private final Source source; - private final long version; - - public ContentHolder(byte[] content, Source source, long version) { - this.content = content; - this.source = source; - this.version = version; - } - - } - - @SuppressWarnings("serial") - private static class Source implements TemplateLoadingSource { - - private final long instanceId; - private final String name; - - public Source(long instanceId, String name) { - this.instanceId = instanceId; - this.name = name; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (instanceId ^ (instanceId >>> 32)); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - Source other = (Source) obj; - if (instanceId != other.instanceId) return false; - if (name == null) { - if (other.name != null) return false; - } else if (!name.equals(other.name)) { - return false; - } - return true; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - throw new IOException(ByteArrayTemplateLoader.class.getName() - + " sources can't be serialized, as they don't support clustering."); - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/CacheStorage.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/CacheStorage.java b/src/main/java/freemarker/cache/CacheStorage.java deleted file mode 100644 index cd9d720..0000000 --- a/src/main/java/freemarker/cache/CacheStorage.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; - -/** - * Cache storage abstracts away the storage aspects of a cache - associating - * an object with a key, retrieval and removal via the key. It is actually a - * small subset of the {@link java.util.Map} interface. - * The implementations can be coded in a non-threadsafe manner as the natural - * user of the cache storage, {@link TemplateCache} does the necessary - * synchronization. - * - * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) - */ -public interface CacheStorage { - public Object get(Object key); - public void put(Object key, Object value); - public void remove(Object key); - public void clear(); -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/CacheStorageWithGetSize.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/CacheStorageWithGetSize.java b/src/main/java/freemarker/cache/CacheStorageWithGetSize.java deleted file mode 100644 index 0d0f006..0000000 --- a/src/main/java/freemarker/cache/CacheStorageWithGetSize.java +++ /dev/null @@ -1,36 +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; - -/** - * A cache storage that has a {@code getSize()} method for returning the current number of cache entries. - * - * @since 2.3.21 - */ -public interface CacheStorageWithGetSize extends CacheStorage { - - /** - * Returns the current number of cache entries. This is intended to be used for monitoring. Note that depending on - * the implementation, the cost of this operation is not necessary trivial, although calling it a few times per - * minute should not be a problem. - */ - int getSize(); - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/ClassTemplateLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/ClassTemplateLoader.java b/src/main/java/freemarker/cache/ClassTemplateLoader.java deleted file mode 100644 index c4e7987..0000000 --- a/src/main/java/freemarker/cache/ClassTemplateLoader.java +++ /dev/null @@ -1,182 +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.net.URL; -import java.net.URLConnection; - -import freemarker.template.utility.NullArgumentException; -import freemarker.template.utility.StringUtil; - -/** - * A {@link TemplateLoader} that can load templates from the "classpath". Naturally, it can load from jar files, or from - * anywhere where Java can load classes from. Internally, it uses {@link Class#getResource(String)} or - * {@link ClassLoader#getResource(String)} to load templates. - */ -// TODO -public class ClassTemplateLoader extends URLTemplateLoader { - - private final Class<?> resourceLoaderClass; - private final ClassLoader classLoader; - private final String basePackagePath; - - /** - * 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 package path (absolute or relative). - * - * <p> - * Examples: - * <ul> - * <li>Relative base path (will load from the {@code com.example.myapplication.templates} package):<br> - * {@code new ClassTemplateLoader(com.example.myapplication.SomeClass.class, "templates")} - * <li>Absolute base path:<br> - * {@code new ClassTemplateLoader(somepackage.SomeClass.class, "/com/example/myapplication/templates")} - * </ul> - * - * @param resourceLoaderClass - * 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 - * {@code null}. - * @param basePackagePath - * The package that contains the templates, in path ({@code /}-separated) format. If it doesn't start - * with a {@code /} then it's relative to the path (package) of the {@code resourceLoaderClass} class. If - * it starts with {@code /} then it's relative to the root of the package hierarchy. Note that path - * components should be separated by forward slashes independently of the separator character used by the - * underlying operating system. This parameter can't be {@code null}. - * - * @see #ClassTemplateLoader(ClassLoader, String) - */ - public ClassTemplateLoader(Class<?> resourceLoaderClass, String basePackagePath) { - this(resourceLoaderClass, false, null, basePackagePath); - } - - /** - * Similar to {@link #ClassTemplateLoader(Class, String)}, but instead of {@link Class#getResource(String)} it uses - * {@link ClassLoader#getResource(String)}. Because a {@link ClassLoader} isn't bound to any Java package, it - * doesn't mater if the {@code basePackagePath} starts with {@code /} or not, it will be always relative to the root - * of the package hierarchy - */ - public ClassTemplateLoader(ClassLoader classLoader, String basePackagePath) { - this(null, true, classLoader, basePackagePath); - } - - private ClassTemplateLoader(Class<?> resourceLoaderClass, boolean allowNullResourceLoaderClass, - ClassLoader classLoader, String basePackagePath) { - if (!allowNullResourceLoaderClass) { - NullArgumentException.check("resourceLoaderClass", resourceLoaderClass); - } - NullArgumentException.check("basePackagePath", basePackagePath); - - // Either set a non-null resourceLoaderClass or a non-null classLoader, not both: - this.resourceLoaderClass = classLoader == null ? (resourceLoaderClass == null ? this.getClass() - : resourceLoaderClass) : null; - if (this.resourceLoaderClass == null && classLoader == null) { - throw new NullArgumentException("classLoader"); - } - this.classLoader = classLoader; - - String canonBasePackagePath = canonicalizePrefix(basePackagePath); - if (this.classLoader != null && canonBasePackagePath.startsWith("/")) { - canonBasePackagePath = canonBasePackagePath.substring(1); - } - this.basePackagePath = canonBasePackagePath; - } - - 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; - } - - /** - * Show class name and some details that are useful in template-not-found errors. - */ - @Override - public String toString() { - return TemplateLoaderUtils.getClassNameForToString(this) + "(" - + (resourceLoaderClass != null - ? "resourceLoaderClass=" + resourceLoaderClass.getName() - : "classLoader=" + StringUtil.jQuote(classLoader)) - + ", basePackagePath" - + "=" - + StringUtil.jQuote(basePackagePath) - + (resourceLoaderClass != null - ? (basePackagePath.startsWith("/") ? "" : " /* relatively to resourceLoaderClass pkg */") - : "" - ) - + ")"; - } - - /** - * See the similar parameter of {@link #ClassTemplateLoader(Class, String)}; {@code null} when other mechanism is - * used to load the resources. - */ - public Class<?> getResourceLoaderClass() { - return resourceLoaderClass; - } - - /** - * See the similar parameter of {@link #ClassTemplateLoader(ClassLoader, String)}; {@code null} when other mechanism - * is used to load the resources. - */ - public ClassLoader getClassLoader() { - return classLoader; - } - - /** - * See the similar parameter of {@link #ClassTemplateLoader(ClassLoader, String)}; note that this is a normalized - * version of what was actually passed to the constructor. - */ - public String getBasePackagePath() { - return basePackagePath; - } - - @Override - protected URL getURL(String name) { - String fullPath = basePackagePath + name; - - // Block java.net.URLClassLoader exploits: - if (basePackagePath.equals("/") && !isSchemeless(fullPath)) { - return null; - } - - return resourceLoaderClass != null ? resourceLoaderClass.getResource(fullPath) : classLoader - .getResource(fullPath); - } - - @Override - protected TemplateLoadingResult extractNegativeResult(URLConnection conn) throws IOException { - return null; - } - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/ConcurrentCacheStorage.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/ConcurrentCacheStorage.java b/src/main/java/freemarker/cache/ConcurrentCacheStorage.java deleted file mode 100644 index a791cec..0000000 --- a/src/main/java/freemarker/cache/ConcurrentCacheStorage.java +++ /dev/null @@ -1,35 +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; - -/** - * An optional interface for cache storage that knows whether it can be - * concurrently accessible without synchronization. - */ -public interface ConcurrentCacheStorage extends CacheStorage { - - /** - * Returns true if this instance of cache storage is concurrently - * accessible from multiple threads without synchronization. - * @return true if this instance of cache storage is concurrently - * accessible from multiple threads without synchronization. - */ - public boolean isConcurrent(); -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/ConditionalTemplateConfigurationFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/ConditionalTemplateConfigurationFactory.java b/src/main/java/freemarker/cache/ConditionalTemplateConfigurationFactory.java deleted file mode 100644 index 5110467..0000000 --- a/src/main/java/freemarker/cache/ConditionalTemplateConfigurationFactory.java +++ /dev/null @@ -1,76 +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 freemarker.core.TemplateConfiguration; -import freemarker.template.Configuration; - -/** - * Returns the given {@link TemplateConfiguration} directly, or another {@link TemplateConfigurationFactory}'s result, when - * the specified matcher matches the template source. - * - * @since 2.3.24 - */ -public class ConditionalTemplateConfigurationFactory extends TemplateConfigurationFactory { - - private final TemplateSourceMatcher matcher; - private final TemplateConfiguration templateConfiguration; - private final TemplateConfigurationFactory templateConfigurationFactory; - - public ConditionalTemplateConfigurationFactory( - TemplateSourceMatcher matcher, TemplateConfigurationFactory templateConfigurationFactory) { - this.matcher = matcher; - this.templateConfiguration = null; - this.templateConfigurationFactory = templateConfigurationFactory; - } - - public ConditionalTemplateConfigurationFactory( - TemplateSourceMatcher matcher, TemplateConfiguration templateConfiguration) { - this.matcher = matcher; - this.templateConfiguration = templateConfiguration; - this.templateConfigurationFactory = null; - } - - @Override - public TemplateConfiguration get(String sourceName, TemplateLoadingSource templateLoadingSource) - throws IOException, TemplateConfigurationFactoryException { - if (matcher.matches(sourceName, templateLoadingSource)) { - if (templateConfigurationFactory != null) { - return templateConfigurationFactory.get(sourceName, templateLoadingSource); - } else { - return templateConfiguration; - } - } else { - return null; - } - } - - @Override - protected void setConfigurationOfChildren(Configuration cfg) { - if (templateConfiguration != null) { - templateConfiguration.setParentConfiguration(cfg); - } - if (templateConfigurationFactory != null) { - templateConfigurationFactory.setConfiguration(cfg); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/FileExtensionMatcher.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/FileExtensionMatcher.java b/src/main/java/freemarker/cache/FileExtensionMatcher.java deleted file mode 100644 index 23d052f..0000000 --- a/src/main/java/freemarker/cache/FileExtensionMatcher.java +++ /dev/null @@ -1,85 +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; - -/** - * Matches the file extension; unlike other matchers, by default case <em>insensitive</em>. A name (a path) is - * considered to have the given extension exactly if it ends with a dot plus the extension. - * - * @since 2.3.24 - */ -public class FileExtensionMatcher extends TemplateSourceMatcher { - - private final String extension; - private boolean caseInsensitive = true; - - /** - * @param extension - * The file extension (without the initial dot). Can't contain there characters: - * {@code '/'}, {@code '*'}, {@code '?'}. May contains {@code '.'}, but can't start with it. - */ - public FileExtensionMatcher(String extension) { - if (extension.indexOf('/') != -1) { - throw new IllegalArgumentException("A file extension can't contain \"/\": " + extension); - } - if (extension.indexOf('*') != -1) { - throw new IllegalArgumentException("A file extension can't contain \"*\": " + extension); - } - if (extension.indexOf('?') != -1) { - throw new IllegalArgumentException("A file extension can't contain \"*\": " + extension); - } - if (extension.startsWith(".")) { - throw new IllegalArgumentException("A file extension can't start with \".\": " + extension); - } - this.extension = extension; - } - - @Override - public boolean matches(String sourceName, Object templateSource) throws IOException { - int ln = sourceName.length(); - int extLn = extension.length(); - if (ln < extLn + 1 || sourceName.charAt(ln - extLn - 1) != '.') { - return false; - } - - return sourceName.regionMatches(caseInsensitive, ln - extLn, extension, 0, extLn); - } - - public boolean isCaseInsensitive() { - return caseInsensitive; - } - - /** - * Sets if the matching will be case insensitive (UNICODE compliant); default is {@code true}. - */ - public void setCaseInsensitive(boolean caseInsensitive) { - this.caseInsensitive = caseInsensitive; - } - - /** - * Fluid API variation of {@link #setCaseInsensitive(boolean)} - */ - public FileExtensionMatcher caseInsensitive(boolean caseInsensitive) { - setCaseInsensitive(caseInsensitive); - return this; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/FileNameGlobMatcher.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/FileNameGlobMatcher.java b/src/main/java/freemarker/cache/FileNameGlobMatcher.java deleted file mode 100644 index 12d2ac6..0000000 --- a/src/main/java/freemarker/cache/FileNameGlobMatcher.java +++ /dev/null @@ -1,86 +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.regex.Pattern; - -import freemarker.template.utility.StringUtil; - -/** - * As opposed to {@link PathGlobMatcher}, it only compares the "file name" part (the part after the last {@code /}) of - * the source name with the given glob. For example, the file name glob {@code *.ftlh} matches both {@code foo.ftlh} and - * {@code foo/bar.ftlh}. With other words, that file name glob is equivalent with the {@code **}{@code /*.ftlh}) - * <em>path</em> glob ( {@link PathGlobMatcher}). - * - * @since 2.3.24 - */ -public class FileNameGlobMatcher extends TemplateSourceMatcher { - - private final String glob; - - private Pattern pattern; - private boolean caseInsensitive; - - /** - * @param glob - * Glob with the syntax defined by {@link StringUtil#globToRegularExpression(String, boolean)}. Must not - * start with {@code /}. - */ - public FileNameGlobMatcher(String glob) { - if (glob.indexOf('/') != -1) { - throw new IllegalArgumentException("A file name glob can't contain \"/\": " + glob); - } - this.glob = glob; - buildPattern(); - } - - private void buildPattern() { - pattern = StringUtil.globToRegularExpression("**/" + glob, caseInsensitive); - } - - @Override - public boolean matches(String sourceName, Object templateSource) throws IOException { - return pattern.matcher(sourceName).matches(); - } - - public boolean isCaseInsensitive() { - return caseInsensitive; - } - - /** - * Sets if the matching will be case insensitive (UNICODE compliant); default is {@code false}. - */ - public void setCaseInsensitive(boolean caseInsensitive) { - boolean lastCaseInsensitive = this.caseInsensitive; - this.caseInsensitive = caseInsensitive; - if (lastCaseInsensitive != caseInsensitive) { - buildPattern(); - } - } - - /** - * Fluid API variation of {@link #setCaseInsensitive(boolean)} - */ - public FileNameGlobMatcher caseInsensitive(boolean caseInsensitive) { - setCaseInsensitive(caseInsensitive); - return this; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/FileTemplateLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/FileTemplateLoader.java b/src/main/java/freemarker/cache/FileTemplateLoader.java deleted file mode 100644 index fef103c..0000000 --- a/src/main/java/freemarker/cache/FileTemplateLoader.java +++ /dev/null @@ -1,381 +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.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Objects; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import freemarker.template.Configuration; -import freemarker.template.utility.SecurityUtilities; -import freemarker.template.utility.StringUtil; - -/** - * A {@link TemplateLoader} that uses files inside a specified directory as the source of templates. By default it does - * security checks on the <em>canonical</em> path that will prevent it serving templates outside that specified - * directory. If you want symbolic links that point outside the template directory to work, you need to disable this - * feature by using {@link #FileTemplateLoader(File, boolean)} with {@code true} second argument, but before that, - * check the security implications there! - */ -public class FileTemplateLoader implements TemplateLoader { - - /** - * By setting this Java system property to {@code true}, you can change the default of - * {@code #getEmulateCaseSensitiveFileSystem()}. - */ - public static String SYSTEM_PROPERTY_NAME_EMULATE_CASE_SENSITIVE_FILE_SYSTEM - = "org.freemarker.emulateCaseSensitiveFileSystem"; - private static final boolean EMULATE_CASE_SENSITIVE_FILE_SYSTEM_DEFAULT; - static { - final String s = SecurityUtilities.getSystemProperty(SYSTEM_PROPERTY_NAME_EMULATE_CASE_SENSITIVE_FILE_SYSTEM, - "false"); - boolean emuCaseSensFS; - try { - emuCaseSensFS = StringUtil.getYesNo(s); - } catch (Exception e) { - emuCaseSensFS = false; - } - EMULATE_CASE_SENSITIVE_FILE_SYSTEM_DEFAULT = emuCaseSensFS; - } - - private static final int CASE_CHECH_CACHE_HARD_SIZE = 50; - private static final int CASE_CHECK_CACHE__SOFT_SIZE = 1000; - private static final boolean SEP_IS_SLASH = File.separatorChar == '/'; - - private static final Logger LOG = LoggerFactory.getLogger("freemarker.cache"); - - public final File baseDir; - private final String canonicalBasePath; - private boolean emulateCaseSensitiveFileSystem; - private MruCacheStorage correctCasePaths; - - /** - * Creates a new file template loader that will use the specified directory - * as the base directory for loading templates. It will not allow access to - * template files that are accessible through symlinks that point outside - * the base directory. - * @param baseDir the base directory for loading templates - */ - public FileTemplateLoader(final File baseDir) - throws IOException { - this(baseDir, false); - } - - /** - * Creates a new file template loader that will use the specified directory as the base directory for loading - * templates. See the parameters for allowing symlinks that point outside the base directory. - * - * @param baseDir - * the base directory for loading templates - * - * @param disableCanonicalPathCheck - * If {@code true}, it will not check if the file to be loaded is inside the {@code baseDir} or not, - * according the <em>canonical</em> paths of the {@code baseDir} and the file to load. Note that - * {@link Configuration#getTemplate(String)} and (its overloads) already prevents backing out from the - * template directory with paths like {@code /../../../etc/password}, however, that can be circumvented - * with symbolic links or other file system features. If you really want to use symbolic links that point - * outside the {@code baseDir}, set this parameter to {@code true}, but then be very careful with - * template paths that are supplied by the visitor or an external system. - */ - public FileTemplateLoader(final File baseDir, final boolean disableCanonicalPathCheck) - throws IOException { - try { - Object[] retval = AccessController.doPrivileged(new PrivilegedExceptionAction<Object[]>() { - @Override - public Object[] run() throws IOException { - if (!baseDir.exists()) { - throw new FileNotFoundException(baseDir + " does not exist."); - } - if (!baseDir.isDirectory()) { - throw new IOException(baseDir + " is not a directory."); - } - Object[] retval = new Object[2]; - if (disableCanonicalPathCheck) { - retval[0] = baseDir; - retval[1] = null; - } else { - retval[0] = baseDir.getCanonicalFile(); - String basePath = ((File) retval[0]).getPath(); - // Most canonical paths don't end with File.separator, - // but some does. Like, "C:\" VS "C:\templates". - if (!basePath.endsWith(File.separator)) { - basePath += File.separatorChar; - } - retval[1] = basePath; - } - return retval; - } - }); - this.baseDir = (File) retval[0]; - this.canonicalBasePath = (String) retval[1]; - - setEmulateCaseSensitiveFileSystem(getEmulateCaseSensitiveFileSystemDefault()); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); - } - } - - private File getFile(final String name) throws IOException { - try { - return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { - @Override - public File run() throws IOException { - File source = new File(baseDir, SEP_IS_SLASH ? name : - name.replace('/', File.separatorChar)); - if (!source.isFile()) { - return null; - } - // Security check for inadvertently returning something - // outside the template directory when linking is not - // allowed. - if (canonicalBasePath != null) { - String normalized = source.getCanonicalPath(); - if (!normalized.startsWith(canonicalBasePath)) { - throw new SecurityException(source.getAbsolutePath() - + " resolves to " + normalized + " which " + - " doesn't start with " + canonicalBasePath); - } - } - - if (emulateCaseSensitiveFileSystem && !isNameCaseCorrect(source)) { - return null; - } - - return source; - } - }); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); - } - } - - private long getLastModified(final File templateSource) { - return (AccessController.<Long>doPrivileged(new PrivilegedAction<Long>() { - @Override - public Long run() { - return Long.valueOf((templateSource).lastModified()); - } - })).longValue(); - } - - private InputStream getInputStream(final File templateSource) - throws IOException { - try { - return AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { - @Override - public InputStream run() throws IOException { - return new FileInputStream(templateSource); - } - }); - } catch (PrivilegedActionException e) { - throw (IOException) e.getException(); - } - } - - /** - * Called by {@link #getFile(String)} when {@link #getEmulateCaseSensitiveFileSystem()} is {@code true}. - */ - private boolean isNameCaseCorrect(File source) throws IOException { - final String sourcePath = source.getPath(); - synchronized (correctCasePaths) { - if (correctCasePaths.get(sourcePath) != null) { - return true; - } - } - - final File parentDir = source.getParentFile(); - if (parentDir != null) { - if (!baseDir.equals(parentDir) && !isNameCaseCorrect(parentDir)) { - return false; - } - - final String[] listing = parentDir.list(); - if (listing != null) { - final String fileName = source.getName(); - - boolean identicalNameFound = false; - for (int i = 0; !identicalNameFound && i < listing.length; i++) { - if (fileName.equals(listing[i])) { - identicalNameFound = true; - } - } - - if (!identicalNameFound) { - // If we find a similarly named file that only differs in case, then this is a file-not-found. - for (int i = 0; i < listing.length; i++) { - final String listingEntry = listing[i]; - if (fileName.equalsIgnoreCase(listingEntry)) { - if (LOG.isDebugEnabled()) { - LOG.debug("Emulating file-not-found because of letter case differences to the " - + "real file, for: {}", sourcePath); - } - return false; - } - } - } - } - } - - synchronized (correctCasePaths) { - correctCasePaths.put(sourcePath, Boolean.TRUE); - } - return true; - } - - /** - * Returns the base directory in which the templates are searched. This comes from the constructor argument, but - * it's possibly a canonicalized version of that. - * - * @since 2.3.21 - */ - public File getBaseDirectory() { - return baseDir; - } - - /** - * Intended for development only, checks if the template name matches the case (upper VS lower case letters) of the - * actual file name, and if it doesn't, it emulates a file-not-found even if the file system is case insensitive. - * This is useful when developing application on Windows, which will be later installed on Linux, OS X, etc. This - * check can be resource intensive, as to check the file name the directories involved, up to the - * {@link #getBaseDirectory()} directory, must be listed. Positive results (matching case) will be cached without - * expiration time. - * - * <p>The default in {@link FileTemplateLoader} is {@code false}, but subclasses may change they by overriding - * {@link #getEmulateCaseSensitiveFileSystemDefault()}. - * - * @since 2.3.23 - */ - public void setEmulateCaseSensitiveFileSystem(boolean nameCaseChecked) { - // Ensure that the cache exists exactly when needed: - if (nameCaseChecked) { - if (correctCasePaths == null) { - correctCasePaths = new MruCacheStorage(CASE_CHECH_CACHE_HARD_SIZE, CASE_CHECK_CACHE__SOFT_SIZE); - } - } else { - correctCasePaths = null; - } - - this.emulateCaseSensitiveFileSystem = nameCaseChecked; - } - - /** - * Getter pair of {@link #setEmulateCaseSensitiveFileSystem(boolean)}. - * - * @since 2.3.23 - */ - public boolean getEmulateCaseSensitiveFileSystem() { - return emulateCaseSensitiveFileSystem; - } - - /** - * Returns the default of {@link #getEmulateCaseSensitiveFileSystem()}. In {@link FileTemplateLoader} it's - * {@code false}, unless the {@link #SYSTEM_PROPERTY_NAME_EMULATE_CASE_SENSITIVE_FILE_SYSTEM} system property was - * set to {@code true}, but this can be overridden here in custom subclasses. For example, if your environment - * defines something like developer mode, you may want to override this to return {@code true} on Windows. - * - * @since 2.3.23 - */ - protected boolean getEmulateCaseSensitiveFileSystemDefault() { - return EMULATE_CASE_SENSITIVE_FILE_SYSTEM_DEFAULT; - } - - /** - * Show class name and some details that are useful in template-not-found errors. - * - * @since 2.3.21 - */ - @Override - public String toString() { - // We don't StringUtil.jQuote paths here, because on Windows there will be \\-s then that some may find - // confusing. - return TemplateLoaderUtils.getClassNameForToString(this) + "(" - + "baseDir=\"" + baseDir + "\"" - + (canonicalBasePath != null ? ", canonicalBasePath=\"" + canonicalBasePath + "\"" : "") - + (emulateCaseSensitiveFileSystem ? ", emulateCaseSensitiveFileSystem=true" : "") - + ")"; - } - - @Override - public TemplateLoaderSession createSession() { - return null; - } - - @Override - public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom, - Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException { - File file = getFile(name); - if (file == null) { - return TemplateLoadingResult.NOT_FOUND; - } - - FileTemplateLoadingSource source = new FileTemplateLoadingSource(file); - - long lmd = getLastModified(file); - Long version = lmd != -1 ? lmd : null; - - if (ifSourceDiffersFrom != null && ifSourceDiffersFrom.equals(source) - && Objects.equals(ifVersionDiffersFrom, version)) { - return TemplateLoadingResult.NOT_MODIFIED; - } - - return new TemplateLoadingResult(source, version, getInputStream(file), null); - } - - @Override - public void resetState() { - // Does nothing - } - - @SuppressWarnings("serial") - private static class FileTemplateLoadingSource implements TemplateLoadingSource { - - private final File file; - - FileTemplateLoadingSource(File file) { - this.file = file; - } - - @Override - public int hashCode() { - return file.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - return file.equals(((FileTemplateLoadingSource) obj).file); - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/FirstMatchTemplateConfigurationFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/FirstMatchTemplateConfigurationFactory.java b/src/main/java/freemarker/cache/FirstMatchTemplateConfigurationFactory.java deleted file mode 100644 index d521cc2..0000000 --- a/src/main/java/freemarker/cache/FirstMatchTemplateConfigurationFactory.java +++ /dev/null @@ -1,118 +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 freemarker.core.TemplateConfiguration; -import freemarker.template.Configuration; -import freemarker.template.utility.StringUtil; - -/** - * Returns the first non-{@code null} result of the child factories, ignoring all further child factories. The child - * factories are called in the order as they were added. - */ -public class FirstMatchTemplateConfigurationFactory extends TemplateConfigurationFactory { - - private final TemplateConfigurationFactory[] templateConfigurationFactories; - private boolean allowNoMatch; - private String noMatchErrorDetails; - - public FirstMatchTemplateConfigurationFactory(TemplateConfigurationFactory... templateConfigurationFactories) { - this.templateConfigurationFactories = templateConfigurationFactories; - } - - @Override - public TemplateConfiguration get(String sourceName, TemplateLoadingSource templateLoadingSource) - throws IOException, TemplateConfigurationFactoryException { - for (TemplateConfigurationFactory tcf : templateConfigurationFactories) { - TemplateConfiguration tc = tcf.get(sourceName, templateLoadingSource); - if (tc != null) { - return tc; - } - } - if (!allowNoMatch) { - throw new TemplateConfigurationFactoryException( - FirstMatchTemplateConfigurationFactory.class.getSimpleName() - + " has found no matching choice for source name " - + StringUtil.jQuote(sourceName) + ". " - + (noMatchErrorDetails != null - ? "Error details: " + noMatchErrorDetails - : "(Set the noMatchErrorDetails property of the factory bean to give a more specific error " - + "message. Set allowNoMatch to true if this shouldn't be an error.)")); - } - return null; - } - - /** - * Getter pair of {@link #setAllowNoMatch(boolean)}. - */ - public boolean getAllowNoMatch() { - return allowNoMatch; - } - - /** - * Use this to specify if having no matching choice is an error. The default is {@code false}, that is, it's an - * error if there was no matching choice. - * - * @see #setNoMatchErrorDetails(String) - */ - public void setAllowNoMatch(boolean allowNoMatch) { - this.allowNoMatch = allowNoMatch; - } - - /** - * Use this to specify the text added to the exception error message when there was no matching choice. - * The default is {@code null} (no error details). - * - * @see #setAllowNoMatch(boolean) - */ - public String getNoMatchErrorDetails() { - return noMatchErrorDetails; - } - - - public void setNoMatchErrorDetails(String noMatchErrorDetails) { - this.noMatchErrorDetails = noMatchErrorDetails; - } - - /** - * Same as {@link #setAllowNoMatch(boolean)}, but return this object to support "fluent API" style. - */ - public FirstMatchTemplateConfigurationFactory allowNoMatch(boolean allow) { - setAllowNoMatch(allow); - return this; - } - - /** - * Same as {@link #setNoMatchErrorDetails(String)}, but return this object to support "fluent API" style. - */ - public FirstMatchTemplateConfigurationFactory noMatchErrorDetails(String message) { - setNoMatchErrorDetails(message); - return this; - } - - @Override - protected void setConfigurationOfChildren(Configuration cfg) { - for (TemplateConfigurationFactory templateConfigurationFactory : templateConfigurationFactories) { - templateConfigurationFactory.setConfiguration(cfg); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/MergingTemplateConfigurationFactory.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/MergingTemplateConfigurationFactory.java b/src/main/java/freemarker/cache/MergingTemplateConfigurationFactory.java deleted file mode 100644 index b0df922..0000000 --- a/src/main/java/freemarker/cache/MergingTemplateConfigurationFactory.java +++ /dev/null @@ -1,78 +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 freemarker.core.TemplateConfiguration; -import freemarker.template.Configuration; - -/** - * Returns the merged results of all the child factories. The factories are merged in the order as they were added. - * {@code null} results from the child factories will be ignored. If all child factories return {@code null}, the result - * of this factory will be {@code null} too. - * - * @since 2.3.24 - */ -public class MergingTemplateConfigurationFactory extends TemplateConfigurationFactory { - - private final TemplateConfigurationFactory[] templateConfigurationFactories; - - public MergingTemplateConfigurationFactory(TemplateConfigurationFactory... templateConfigurationFactories) { - this.templateConfigurationFactories = templateConfigurationFactories; - } - - @Override - public TemplateConfiguration get(String sourceName, TemplateLoadingSource templateLoadingSource) - throws IOException, TemplateConfigurationFactoryException { - TemplateConfiguration mergedTC = null; - TemplateConfiguration resultTC = null; - for (TemplateConfigurationFactory tcf : templateConfigurationFactories) { - TemplateConfiguration tc = tcf.get(sourceName, templateLoadingSource); - if (tc != null) { - if (resultTC == null) { - resultTC = tc; - } else { - if (mergedTC == null) { - Configuration cfg = getConfiguration(); - if (cfg == null) { - throw new IllegalStateException( - "The TemplateConfigurationFactory wasn't associated to a Configuration yet."); - } - - mergedTC = new TemplateConfiguration(); - mergedTC.setParentConfiguration(cfg); - mergedTC.merge(resultTC); - resultTC = mergedTC; - } - mergedTC.merge(tc); - } - } - } - return resultTC; - } - - @Override - protected void setConfigurationOfChildren(Configuration cfg) { - for (TemplateConfigurationFactory templateConfigurationFactory : templateConfigurationFactories) { - templateConfigurationFactory.setConfiguration(cfg); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/MruCacheStorage.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/MruCacheStorage.java b/src/main/java/freemarker/cache/MruCacheStorage.java deleted file mode 100644 index 4717876..0000000 --- a/src/main/java/freemarker/cache/MruCacheStorage.java +++ /dev/null @@ -1,322 +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.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; -import java.util.HashMap; -import java.util.Map; - -/** - * A cache storage that implements a two-level Most Recently Used cache. In the - * first level, items are strongly referenced up to the specified maximum. When - * the maximum is exceeded, the least recently used item is moved into the - * second level cache, where they are softly referenced, up to another - * specified maximum. When the second level maximum is also exceeded, the least - * recently used item is discarded altogether. This cache storage is a - * generalization of both {@link StrongCacheStorage} and - * {@link SoftCacheStorage} - the effect of both of them can be achieved by - * setting one maximum to zero and the other to the largest positive integer. - * On the other hand, if you wish to use this storage in a strong-only mode, or - * in a soft-only mode, you might consider using {@link StrongCacheStorage} or - * {@link SoftCacheStorage} instead, as they can be used by - * {@link TemplateCache} concurrently without any synchronization on a 5.0 or - * later JRE. - * - * <p>This class is <em>NOT</em> thread-safe. If it's accessed from multiple - * threads concurrently, proper synchronization must be provided by the callers. - * Note that {@link TemplateCache}, the natural user of this class provides the - * necessary synchronizations when it uses the class. - * Also you might consider whether you need this sort of a mixed storage at all - * in your solution, as in most cases SoftCacheStorage can also be sufficient. - * SoftCacheStorage will use Java soft references, and they already use access - * timestamps internally to bias the garbage collector against clearing - * recently used references, so you can get reasonably good (and - * memory-sensitive) most-recently-used caching through - * {@link SoftCacheStorage} as well. - * - * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) - */ -public class MruCacheStorage implements CacheStorageWithGetSize { - private final MruEntry strongHead = new MruEntry(); - private final MruEntry softHead = new MruEntry(); - { - softHead.linkAfter(strongHead); - } - private final Map map = new HashMap(); - private final ReferenceQueue refQueue = new ReferenceQueue(); - private final int strongSizeLimit; - private final int softSizeLimit; - private int strongSize = 0; - private int softSize = 0; - - /** - * Creates a new MRU cache storage with specified maximum cache sizes. Each - * cache size can vary between 0 and {@link Integer#MAX_VALUE}. - * @param strongSizeLimit the maximum number of strongly referenced templates; when exceeded, the entry used - * the least recently will be moved into the soft cache. - * @param softSizeLimit the maximum number of softly referenced templates; when exceeded, the entry used - * the least recently will be discarded. - */ - public MruCacheStorage(int strongSizeLimit, int softSizeLimit) { - if (strongSizeLimit < 0) throw new IllegalArgumentException("strongSizeLimit < 0"); - if (softSizeLimit < 0) throw new IllegalArgumentException("softSizeLimit < 0"); - this.strongSizeLimit = strongSizeLimit; - this.softSizeLimit = softSizeLimit; - } - - public Object get(Object key) { - removeClearedReferences(); - MruEntry entry = (MruEntry) map.get(key); - if (entry == null) { - return null; - } - relinkEntryAfterStrongHead(entry, null); - Object value = entry.getValue(); - if (value instanceof MruReference) { - // This can only happen with strongSizeLimit == 0 - return ((MruReference) value).get(); - } - return value; - } - - public void put(Object key, Object value) { - removeClearedReferences(); - MruEntry entry = (MruEntry) map.get(key); - if (entry == null) { - entry = new MruEntry(key, value); - map.put(key, entry); - linkAfterStrongHead(entry); - } else { - relinkEntryAfterStrongHead(entry, value); - } - - } - - public void remove(Object key) { - removeClearedReferences(); - removeInternal(key); - } - - private void removeInternal(Object key) { - MruEntry entry = (MruEntry) map.remove(key); - if (entry != null) { - unlinkEntryAndInspectIfSoft(entry); - } - } - - public void clear() { - strongHead.makeHead(); - softHead.linkAfter(strongHead); - map.clear(); - strongSize = softSize = 0; - // Quick refQueue processing - while (refQueue.poll() != null); - } - - private void relinkEntryAfterStrongHead(MruEntry entry, Object newValue) { - if (unlinkEntryAndInspectIfSoft(entry) && newValue == null) { - // Turn soft reference into strong reference, unless is was cleared - MruReference mref = (MruReference) entry.getValue(); - Object strongValue = mref.get(); - if (strongValue != null) { - entry.setValue(strongValue); - linkAfterStrongHead(entry); - } else { - map.remove(mref.getKey()); - } - } else { - if (newValue != null) { - entry.setValue(newValue); - } - linkAfterStrongHead(entry); - } - } - - private void linkAfterStrongHead(MruEntry entry) { - entry.linkAfter(strongHead); - if (strongSize == strongSizeLimit) { - // softHead.previous is LRU strong entry - MruEntry lruStrong = softHead.getPrevious(); - // Attila: This is equaivalent to strongSizeLimit != 0 - // DD: But entry.linkAfter(strongHead) was just executed above, so - // lruStrong != strongHead is true even if strongSizeLimit == 0. - if (lruStrong != strongHead) { - lruStrong.unlink(); - if (softSizeLimit > 0) { - lruStrong.linkAfter(softHead); - lruStrong.setValue(new MruReference(lruStrong, refQueue)); - if (softSize == softSizeLimit) { - // List is circular, so strongHead.previous is LRU soft entry - MruEntry lruSoft = strongHead.getPrevious(); - lruSoft.unlink(); - map.remove(lruSoft.getKey()); - } else { - ++softSize; - } - } else { - map.remove(lruStrong.getKey()); - } - } - } else { - ++strongSize; - } - } - - private boolean unlinkEntryAndInspectIfSoft(MruEntry entry) { - entry.unlink(); - if (entry.getValue() instanceof MruReference) { - --softSize; - return true; - } else { - --strongSize; - return false; - } - } - - private void removeClearedReferences() { - for (; ; ) { - MruReference ref = (MruReference) refQueue.poll(); - if (ref == null) { - break; - } - removeInternal(ref.getKey()); - } - } - - /** - * Returns the configured upper limit of the number of strong cache entries. - * - * @since 2.3.21 - */ - public int getStrongSizeLimit() { - return strongSizeLimit; - } - - /** - * Returns the configured upper limit of the number of soft cache entries. - * - * @since 2.3.21 - */ - public int getSoftSizeLimit() { - return softSizeLimit; - } - - /** - * Returns the <em>current</em> number of strong cache entries. - * - * @see #getStrongSizeLimit() - * @since 2.3.21 - */ - public int getStrongSize() { - return strongSize; - } - - /** - * Returns a close approximation of the <em>current</em> number of soft cache entries. - * - * @see #getSoftSizeLimit() - * @since 2.3.21 - */ - public int getSoftSize() { - removeClearedReferences(); - return softSize; - } - - /** - * Returns a close approximation of the current number of cache entries. - * - * @see #getStrongSize() - * @see #getSoftSize() - * @since 2.3.21 - */ - public int getSize() { - return getSoftSize() + getStrongSize(); - } - - private static final class MruEntry { - private MruEntry prev; - private MruEntry next; - private final Object key; - private Object value; - - /** - * Used solely to construct the head element - */ - MruEntry() { - makeHead(); - key = value = null; - } - - MruEntry(Object key, Object value) { - this.key = key; - this.value = value; - } - - Object getKey() { - return key; - } - - Object getValue() { - return value; - } - - void setValue(Object value) { - this.value = value; - } - - MruEntry getPrevious() { - return prev; - } - - void linkAfter(MruEntry entry) { - next = entry.next; - entry.next = this; - prev = entry; - next.prev = this; - } - - void unlink() { - next.prev = prev; - prev.next = next; - prev = null; - next = null; - } - - void makeHead() { - prev = next = this; - } - } - - private static class MruReference extends SoftReference { - private final Object key; - - MruReference(MruEntry entry, ReferenceQueue queue) { - super(entry.getValue(), queue); - this.key = entry.getKey(); - } - - Object getKey() { - return key; - } - } - - -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/MultiTemplateLoader.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/MultiTemplateLoader.java b/src/main/java/freemarker/cache/MultiTemplateLoader.java deleted file mode 100644 index 583f62e..0000000 --- a/src/main/java/freemarker/cache/MultiTemplateLoader.java +++ /dev/null @@ -1,167 +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.Map; -import java.util.concurrent.ConcurrentHashMap; - -import freemarker.template.utility.NullArgumentException; - -/** - * A {@link TemplateLoader} that uses a set of other loaders to load the templates. On every request, loaders are - * queried in the order of their appearance in the array of loaders provided to the constructor. Except, when the - * {@linkplain #setSticky(boolean)} sticky} setting is set to {@code true} (default is false {@code false}), if - * a request for some template name was already satisfied in the past by one of the loaders, that loader is queried - * first (stickiness). - * - * <p>This class is thread-safe. - */ -// TODO JUnit test -public class MultiTemplateLoader implements TemplateLoader { - - private final TemplateLoader[] templateLoaders; - private final Map<String, TemplateLoader> lastTemplateLoaderForName = new ConcurrentHashMap<String, TemplateLoader>(); - - private boolean sticky = false; - - /** - * Creates a new instance that will use the specified template loaders. - * - * @param templateLoaders - * the template loaders that are used to load templates, in the order as they will be searched - * (except where {@linkplain #setSticky(boolean) stickiness} says otherwise). - */ - public MultiTemplateLoader(TemplateLoader... templateLoaders) { - NullArgumentException.check("templateLoaders", templateLoaders); - this.templateLoaders = templateLoaders.clone(); - } - - /** - * Clears the sickiness memory, also resets the state of all enclosed {@link TemplateLoader}-s. - */ - @Override - public void resetState() { - lastTemplateLoaderForName.clear(); - for (TemplateLoader templateLoader : templateLoaders) { - templateLoader.resetState(); - } - } - - /** - * Show class name and some details that are useful in template-not-found errors. - * - * @since 2.3.21 - */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("MultiTemplateLoader("); - for (int i = 0; i < templateLoaders.length; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append("loader").append(i + 1).append(" = ").append(templateLoaders[i]); - } - sb.append(")"); - return sb.toString(); - } - - /** - * Returns the number of {@link TemplateLoader}-s directly inside this {@link TemplateLoader}. - * - * @since 2.3.23 - */ - public int getTemplateLoaderCount() { - return templateLoaders.length; - } - - /** - * Returns the {@link TemplateLoader} at the given index. - * - * @param index - * Must be below {@link #getTemplateLoaderCount()}. - */ - public TemplateLoader getTemplateLoader(int index) { - return templateLoaders[index]; - } - - /** - * Getter pair of {@link #setSticky(boolean)}. - */ - public boolean isSticky() { - return sticky; - } - - /** - * Sets if for a name that was already loaded earlier the same {@link TemplateLoader} will be tried first, or - * we always try the {@link TemplateLoader}-s strictly in the order as it was specified in the constructor. - * The default is {@code false}. - */ - public void setSticky(boolean sticky) { - this.sticky = sticky; - } - - @Override - public TemplateLoaderSession createSession() { - return null; - } - - @Override - public TemplateLoadingResult load(String name, TemplateLoadingSource ifSourceDiffersFrom, - Serializable ifVersionDiffersFrom, TemplateLoaderSession session) throws IOException { - TemplateLoader lastLoader = null; - if (sticky) { - // Use soft affinity - give the loader that last found this - // resource a chance to find it again first. - lastLoader = lastTemplateLoaderForName.get(name); - if (lastLoader != null) { - TemplateLoadingResult result = lastLoader.load(name, ifSourceDiffersFrom, ifVersionDiffersFrom, session); - if (result.getStatus() != TemplateLoadingResultStatus.NOT_FOUND) { - return result; - } - } - } - - // If there is no affine loader, or it could not find the resource - // again, try all loaders in order of appearance. If any manages - // to find the resource, then associate it as the new affine loader - // for this resource. - for (TemplateLoader templateLoader : templateLoaders) { - if (lastLoader != templateLoader) { - TemplateLoadingResult result = templateLoader.load( - name, ifSourceDiffersFrom, ifVersionDiffersFrom, session); - if (result.getStatus() != TemplateLoadingResultStatus.NOT_FOUND) { - if (sticky) { - lastTemplateLoaderForName.put(name, templateLoader); - } - return result; - } - } - } - - if (sticky) { - lastTemplateLoaderForName.remove(name); - } - return TemplateLoadingResult.NOT_FOUND; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/NotMatcher.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/NotMatcher.java b/src/main/java/freemarker/cache/NotMatcher.java deleted file mode 100644 index 871b2bc..0000000 --- a/src/main/java/freemarker/cache/NotMatcher.java +++ /dev/null @@ -1,41 +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; - -/** - * Logical "not" operation on the given matcher. - * - * @since 2.3.24 - */ -public class NotMatcher extends TemplateSourceMatcher { - - private final TemplateSourceMatcher matcher; - - public NotMatcher(TemplateSourceMatcher matcher) { - this.matcher = matcher; - } - - @Override - public boolean matches(String sourceName, Object templateSource) throws IOException { - return !matcher.matches(sourceName, templateSource); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/cache/NullCacheStorage.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/cache/NullCacheStorage.java b/src/main/java/freemarker/cache/NullCacheStorage.java deleted file mode 100644 index ff79412..0000000 --- a/src/main/java/freemarker/cache/NullCacheStorage.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; - -/** - * A cache storage that doesn't store anything. Use this if you - * don't want caching. - * - * @see freemarker.template.Configuration#setCacheStorage(CacheStorage) - * - * @since 2.3.17 - */ -public class NullCacheStorage implements ConcurrentCacheStorage, CacheStorageWithGetSize { - - /** - * @since 2.3.22 - */ - public static final NullCacheStorage INSTANCE = new NullCacheStorage(); - - public boolean isConcurrent() { - return true; - } - - public Object get(Object key) { - return null; - } - - public void put(Object key, Object value) { - // do nothing - } - - public void remove(Object key) { - // do nothing - } - - public void clear() { - // do nothing - } - - /** - * Always returns 0. - * - * @since 2.3.21 - */ - public int getSize() { - return 0; - } - -}
