org.mozilla.javascript.commonjs.module.provider.ModuleSourceProviderBase Maven / Gradle / Ivy
The newest version!
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript.commonjs.module.provider;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
/**
* A base implementation for all module script providers that actually load
* module scripts. Performs validation of identifiers, allows loading from
* preferred locations (attempted before require.paths), from require.paths
* itself, and from fallback locations (attempted after require.paths). Note
* that while this base class strives to be as generic as possible, it does
* have loading from an URI built into its design, for the simple reason that
* the require.paths is defined in terms of URIs.
* @author Attila Szegedi
* @version $Id: ModuleSourceProviderBase.java,v 1.3 2011/04/07 20:26:12 hannes%helma.at Exp $
*/
public abstract class ModuleSourceProviderBase implements
ModuleSourceProvider, Serializable
{
private static final long serialVersionUID = 1L;
public ModuleSource loadSource(String moduleId, Scriptable paths,
Object validator) throws IOException, URISyntaxException
{
if(!entityNeedsRevalidation(validator)) {
return NOT_MODIFIED;
}
ModuleSource moduleSource = loadFromPrivilegedLocations(
moduleId, validator);
if(moduleSource != null) {
return moduleSource;
}
if(paths != null) {
moduleSource = loadFromPathArray(moduleId, paths,
validator);
if(moduleSource != null) {
return moduleSource;
}
}
return loadFromFallbackLocations(moduleId, validator);
}
public ModuleSource loadSource(URI uri, URI base, Object validator)
throws IOException, URISyntaxException {
return loadFromUri(uri, base, validator);
}
private ModuleSource loadFromPathArray(String moduleId,
Scriptable paths, Object validator) throws IOException
{
final long llength = ScriptRuntime.toUint32(
ScriptableObject.getProperty(paths, "length"));
// Yeah, I'll ignore entries beyond Integer.MAX_VALUE; so sue me.
int ilength = llength > Integer.MAX_VALUE ? Integer.MAX_VALUE :
(int)llength;
for(int i = 0; i < ilength; ++i) {
final String path = ensureTrailingSlash(
ScriptableObject.getTypedProperty(paths, i, String.class));
try {
URI uri = new URI(path);
if (!uri.isAbsolute()) {
uri = new File(path).toURI().resolve("");
}
final ModuleSource moduleSource = loadFromUri(
uri.resolve(moduleId), uri, validator);
if(moduleSource != null) {
return moduleSource;
}
}
catch(URISyntaxException e) {
throw new MalformedURLException(e.getMessage());
}
}
return null;
}
private static String ensureTrailingSlash(String path) {
return path.endsWith("/") ? path : path.concat("/");
}
/**
* Override to determine whether according to the validator, the cached
* module script needs revalidation. A validator can carry expiry
* information. If the cached representation is not expired, it doesn'
* t need revalidation, otherwise it does. When no cache revalidation is
* required, the external resource will not be contacted at all, so some
* level of expiry (staleness tolerance) can greatly enhance performance.
* The default implementation always returns true so it will always require
* revalidation.
* @param validator the validator
* @return returns true if the cached module needs revalidation.
*/
protected boolean entityNeedsRevalidation(Object validator) {
return true;
}
/**
* Override in a subclass to load a module script from a logical URI. The
* URI is absolute but does not have a file name extension such as ".js".
* It is up to the ModuleSourceProvider implementation to add such an
* extension.
* @param uri the URI of the script, without file name extension.
* @param base the base URI the uri was resolved from.
* @param validator a validator that can be used to revalidate an existing
* cached source at the URI. Can be null if there is no cached source
* available.
* @return the loaded module script, or null if it can't be found, or
* {@link ModuleSourceProvider#NOT_MODIFIED} if it revalidated the existing
* cached source against the URI.
* @throws IOException if the module script was found, but an I/O exception
* prevented it from being loaded.
* @throws URISyntaxException if the final URI could not be constructed
*/
protected abstract ModuleSource loadFromUri(URI uri, URI base,
Object validator) throws IOException, URISyntaxException;
/**
* Override to obtain a module source from privileged locations. This will
* be called before source is attempted to be obtained from URIs specified
* in require.paths.
* @param moduleId the ID of the module
* @param validator a validator that can be used to validate an existing
* cached script. Can be null if there is no cached script available.
* @return the loaded module script, or null if it can't be found in the
* privileged locations, or {@link ModuleSourceProvider#NOT_MODIFIED} if
* the existing cached module script is still valid.
* @throws IOException if the module script was found, but an I/O exception
* prevented it from being loaded.
* @throws URISyntaxException if the final URI could not be constructed.
*/
protected ModuleSource loadFromPrivilegedLocations(
String moduleId, Object validator)
throws IOException, URISyntaxException
{
return null;
}
/**
* Override to obtain a module source from fallback locations. This will
* be called after source is attempted to be obtained from URIs specified
* in require.paths.
* @param moduleId the ID of the module
* @param validator a validator that can be used to validate an existing
* cached script. Can be null if there is no cached script available.
* @return the loaded module script, or null if it can't be found in the
* privileged locations, or {@link ModuleSourceProvider#NOT_MODIFIED} if
* the existing cached module script is still valid.
* @throws IOException if the module script was found, but an I/O exception
* prevented it from being loaded.
* @throws URISyntaxException if the final URI could not be constructed.
*/
protected ModuleSource loadFromFallbackLocations(
String moduleId, Object validator)
throws IOException, URISyntaxException
{
return null;
}
}