org.mozilla.javascript.commonjs.module.provider.ModuleSourceProviderBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino-runtime Show documentation
Show all versions of rhino-runtime Show documentation
Rhino JavaScript runtime jar, excludes tools & JSR-223 Script Engine wrapper.
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;
@Override
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);
}
@Override
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;
}
}