WebResourceRoot.java
/*
* 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 org.apache.catalina;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.Set;
/**
* Represents the complete set of resources for a web application. The resources for a web application comprise of
* multiple ResourceSets and when looking for a Resource, the ResourceSets are processed in the following order:
* <ol>
* <li>Pre - Resources defined by the <PreResource> element in the web application's context.xml. Resources will
* be searched in the order they were specified.</li>
* <li>Main - The main resources for the web application - i.e. the WAR or the directory containing the expanded
* WAR</li>
* <li>JARs - Resource JARs as defined by the Servlet specification. JARs will be searched in the order they were added
* to the ResourceRoot.</li>
* <li>Post - Resources defined by the <PostResource> element in the web application's context.xml. Resources will
* be searched in the order they were specified.</li>
* </ol>
* The following conventions should be noted:
* <ul>
* <li>Write operations (including delete) will only be applied to the main ResourceSet. The write operation will fail
* if the presence of a Resource in one of the other ResourceSets effectively makes the operation on the main
* ResourceSet a NO-OP.</li>
* <li>A file in a ResourceSet will hide a directory of the same name (and all the contents of that directory) in a
* ResourceSet that is later in the search order.</li>
* <li>Only the main ResourceSet may define a META-INF/context.xml since that file defines the Pre- and
* Post-Resources.</li>
* <li>As per the Servlet specification, any META-INF or WEB-INF directories in a resource JAR will be ignored.</li>
* <li>Pre- and Post-Resources may define WEB-INF/lib and WEB-INF/classes in order to make additional libraries and/or
* classes available to the web application.
* </ul>
* This mechanism replaces and extends the following features that were present in earlier versions:
* <ul>
* <li>Aliases - Replaced by Post-Resources with the addition of support for single files as well as directories and
* JARs.</li>
* <li>VirtualWebappLoader - Replaced by Pre- and Post-Resources mapped to WEB-INF/lib and WEB-INF/classes</li>
* <li>VirtualDirContext - Replaced by Pre- and Post-Resources</li>
* <li>External repositories - Replaced by Pre- and Post-Resources mapped to WEB-INF/lib and WEB-INF/classes</li>
* <li>Resource JARs - Same feature but implemented using the same mechanism as all the other additional resources.</li>
* </ul>
*/
/*
* A potential future enhancement is to allow writing to any ResourceSet, not just the main ResourceSet although that
* adds all sorts complications including: - which ResourceSet to write to - unexpected behaviour when deleting a
* resource from one ResourceSet since that may unmask a resource in a lower priority ResourceSet so what was a delete
* looks like a replace with the user having no idea where the 'new' resource came from - how to handle PUT when the
* target is read-only but it could be written to a higher priority ResourceSet that is read-write
*/
public interface WebResourceRoot extends Lifecycle {
/**
* Obtain the object that represents the resource at the given path. Note that the resource at that path may not
* exist. If the resource does not exist, the WebResource returned will be associated with the main WebResourceSet.
*
* @param path The path for the resource of interest relative to the root of the web application. It must start with
* '/'.
*
* @return The object that represents the resource at the given path
*/
WebResource getResource(String path);
/**
* Obtain the objects that represent the resource at the given path. Note that the resource at that path may not
* exist. If the resource does not exist, the WebResource returned will be associated with the main WebResourceSet.
* This will include all matches even if the resource would not normally be accessible (e.g. because it was
* overridden by another resource)
*
* @param path The path for the resource of interest relative to the root of the web application. It must start with
* '/'.
*
* @return The objects that represents the resource at the given path
*/
WebResource[] getResources(String path);
/**
* Obtain the object that represents the class loader resource at the given path. WEB-INF/classes is always searched
* prior to searching JAR files in WEB-INF/lib. The search order for JAR files will be consistent across subsequent
* calls to this method until the web application is reloaded. No guarantee is made as to what the search order for
* JAR files may be.
*
* @param path The path of the class loader resource of interest relative to the the root of class loader resources
* for this web application.
*
* @return The object that represents the class loader resource at the given path
*/
WebResource getClassLoaderResource(String path);
/**
* Obtain the objects that represent the class loader resource at the given path. Note that the resource at that
* path may not exist. If the path does not exist, the WebResource returned will be associated with the main
* WebResourceSet. This will include all matches even if the resource would not normally be accessible (e.g. because
* it was overridden by another resource)
*
* @param path The path for the class loader resource of interest relative to the root of the class loader resources
* for the web application. It must start with '/'.
*
* @return The objects that represents the class loader resources at the given path. There will always be at least
* one element although that element may represent a resource that is not present.
*/
WebResource[] getClassLoaderResources(String path);
/**
* Obtain the list of the names of all of the files and directories located in the specified directory.
*
* @param path The path for the resource of interest relative to the root of the web application. It must start with
* '/'.
*
* @return The list of resources. If path does not refer to a directory then a zero length array will be returned.
*/
String[] list(String path);
/**
* Obtain the Set of the web applications pathnames of all of the files and directories located in the specified
* directory. Paths representing directories will end with a '/' character.
*
* @param path The path for the resource of interest relative to the root of the web application. It must start with
* '/'.
*
* @return The Set of resources. If path does not refer to a directory then null will be returned.
*/
Set<String> listWebAppPaths(String path);
/**
* Obtain the list of all of the WebResources in the specified directory.
*
* @param path The path for the resource of interest relative to the root of the web application. It must start with
* '/'.
*
* @return The list of resources. If path does not refer to a directory then a zero length array will be returned.
*/
WebResource[] listResources(String path);
/**
* Create a new directory at the given path.
*
* @param path The path for the new resource to create relative to the root of the web application. It must start
* with '/'.
*
* @return <code>true</code> if the directory was created, otherwise <code>false</code>
*/
boolean mkdir(String path);
/**
* Create a new resource at the requested path using the provided InputStream.
*
* @param path The path to be used for the new Resource. It is relative to the root of the web application and
* must start with '/'.
* @param is The InputStream that will provide the content for the new Resource.
* @param overwrite If <code>true</code> and the resource already exists it will be overwritten. If
* <code>false</code> and the resource already exists the write will fail.
*
* @return <code>true</code> if and only if the new Resource is written
*/
boolean write(String path, InputStream is, boolean overwrite);
/**
* Creates a new {@link WebResourceSet} for this {@link WebResourceRoot} based on the provided parameters.
*
* @param type The type of {@link WebResourceSet} to create
* @param webAppMount The path within the web application that the resources should be published at. It must start
* with '/'.
* @param url The URL of the resource (must locate a JAR, file or directory)
* @param internalPath The path within the resource where the content is to be found. It must start with '/'.
*/
void createWebResourceSet(ResourceSetType type, String webAppMount, URL url, String internalPath);
/**
* Creates a new {@link WebResourceSet} for this {@link WebResourceRoot} based on the provided parameters.
*
* @param type The type of {@link WebResourceSet} to create
* @param webAppMount The path within the web application that the resources should be published at. It must start
* with '/'.
* @param base The location of the resources
* @param archivePath The path within the resource to the archive where the content is to be found. If there is no
* archive then this should be <code>null</code>.
* @param internalPath The path within the archive (or the resource if the archivePath is <code>null</code> where
* the content is to be found. It must start with '/'.
*/
void createWebResourceSet(ResourceSetType type, String webAppMount, String base, String archivePath,
String internalPath);
/**
* Adds the provided WebResourceSet to this web application as a 'Pre' resource.
*
* @param webResourceSet the resource set to use
*/
void addPreResources(WebResourceSet webResourceSet);
/**
* @return the list of WebResourceSet configured to this web application as a 'Pre' resource.
*/
WebResourceSet[] getPreResources();
/**
* Adds the provided WebResourceSet to this web application as a 'Jar' resource.
*
* @param webResourceSet the resource set to use
*/
void addJarResources(WebResourceSet webResourceSet);
/**
* @return the list of WebResourceSet configured to this web application as a 'Jar' resource.
*/
WebResourceSet[] getJarResources();
/**
* Adds the provided WebResourceSet to this web application as a 'Post' resource.
*
* @param webResourceSet the resource set to use
*/
void addPostResources(WebResourceSet webResourceSet);
/**
* @return the list of WebResourceSet configured to this web application as a 'Post' resource.
*/
WebResourceSet[] getPostResources();
/**
* @return the web application this WebResourceRoot is associated with.
*/
Context getContext();
/**
* Set the web application this WebResourceRoot is associated with.
*
* @param context the associated context
*/
void setContext(Context context);
/**
* Configure if this resources allow the use of symbolic links.
*
* @param allowLinking <code>true</code> if symbolic links are allowed.
*/
void setAllowLinking(boolean allowLinking);
/**
* Determine if this resources allow the use of symbolic links.
*
* @return <code>true</code> if symbolic links are allowed
*/
boolean getAllowLinking();
/**
* Set whether or not caching is permitted for this web application.
*
* @param cachingAllowed <code>true</code> to enable caching, else <code>false</code>
*/
void setCachingAllowed(boolean cachingAllowed);
/**
* @return <code>true</code> if caching is permitted for this web application.
*/
boolean isCachingAllowed();
/**
* Set the Time-To-Live (TTL) for cache entries.
*
* @param ttl TTL in milliseconds
*/
void setCacheTtl(long ttl);
/**
* Get the Time-To-Live (TTL) for cache entries.
*
* @return TTL in milliseconds
*/
long getCacheTtl();
/**
* Set the maximum permitted size for the cache.
*
* @param cacheMaxSize Maximum cache size in kilobytes
*/
void setCacheMaxSize(long cacheMaxSize);
/**
* Get the maximum permitted size for the cache.
*
* @return Maximum cache size in kilobytes
*/
long getCacheMaxSize();
/**
* Set the maximum permitted size for a single object in the cache. Note that the maximum size in bytes may not
* exceed {@link Integer#MAX_VALUE}.
*
* @param cacheObjectMaxSize Maximum size for a single cached object in kilobytes
*/
void setCacheObjectMaxSize(int cacheObjectMaxSize);
/**
* Get the maximum permitted size for a single object in the cache. Note that the maximum size in bytes may not
* exceed {@link Integer#MAX_VALUE}.
*
* @return Maximum size for a single cached object in kilobytes
*/
int getCacheObjectMaxSize();
/**
* Controls whether the track locked files feature is enabled. If enabled, all calls to methods that return objects
* that lock a file and need to be closed to release that lock (e.g. {@link WebResource#getInputStream()} will
* perform a number of additional tasks.
* <ul>
* <li>The stack trace at the point where the method was called will be recorded and associated with the returned
* object.</li>
* <li>The returned object will be wrapped so that the point where close() (or equivalent) is called to release the
* resources can be detected. Tracking of the object will cease once the resources have been released.</li>
* <li>All remaining locked resources on web application shutdown will be logged and then closed.</li>
* </ul>
*
* @param trackLockedFiles {@code true} to enable it, {@code false} to disable it
*/
void setTrackLockedFiles(boolean trackLockedFiles);
/**
* Has the track locked files feature been enabled?
*
* @return {@code true} if it has been enabled, otherwise {@code false}
*/
boolean getTrackLockedFiles();
/**
* Set the strategy to use for the resources archive lookup.
*
* @param archiveIndexStrategy The strategy to use for the resources archive lookup
*/
void setArchiveIndexStrategy(String archiveIndexStrategy);
/**
* Get the strategy to use for the resources archive lookup.
*
* @return The strategy to use for the resources archive lookup
*/
String getArchiveIndexStrategy();
/**
* Get the strategy to use for the resources archive lookup.
*
* @return The strategy to use for the resources archive lookup
*/
ArchiveIndexStrategy getArchiveIndexStrategyEnum();
/**
* This method will be invoked by the context on a periodic basis and allows the implementation a method that
* executes periodic tasks, such as purging expired cache entries.
*/
void backgroundProcess();
/**
* Add a specified resource to track to be able to later release resources on stop.
*
* @param trackedResource the resource that will be tracked
*/
void registerTrackedResource(TrackedWebResource trackedResource);
/**
* Stop tracking specified resource, once it no longer needs to free resources.
*
* @param trackedResource the resource that was tracked
*/
void deregisterTrackedResource(TrackedWebResource trackedResource);
/**
* @return the set of {@link WebResourceSet#getBaseUrl()} for all {@link WebResourceSet}s used by this root.
*/
List<URL> getBaseUrls();
/**
* Implementations may cache some information to improve performance. This method triggers the clean-up of those
* resources.
*/
void gc();
/**
* Obtain the current caching strategy.
* <p>
* The default implementation returns {@code null}. Sub-classes wishing to utilise a {@link CacheStrategy} should
* provide an appropriate implementation.
*
* @return the current caching strategy or {@code null} if no strategy has been configured
*/
default CacheStrategy getCacheStrategy() {
return null;
}
/**
* Set the current caching strategy.
* <p>
* The default implementation is a NO-OP. Sub-classes wishing to utilise a {@link CacheStrategy} should provide an
* appropriate implementation.
*
* @param strategy The new strategy to use or {@code null} for no strategy
*/
default void setCacheStrategy(CacheStrategy strategy) {
// NO-OP
}
enum ResourceSetType {
PRE,
RESOURCE_JAR,
POST,
CLASSES_JAR
}
enum ArchiveIndexStrategy {
SIMPLE(false, false),
BLOOM(true, true),
PURGED(true, false);
private final boolean usesBloom;
private final boolean retain;
ArchiveIndexStrategy(boolean usesBloom, boolean retain) {
this.usesBloom = usesBloom;
this.retain = retain;
}
public boolean getUsesBloom() {
return usesBloom;
}
public boolean getRetain() {
return retain;
}
}
/**
* Provides a mechanism to modify the caching behaviour.
*/
interface CacheStrategy {
/**
* Should the result of looking up the resource at the given path be excluded from caching?
*
* @param path The path to check against the strategy to see if the result should be cached
*
* @return {@code true} if the result should not be cached, otherwise {@code false}
*/
boolean noCache(String path);
}
}