org.mozilla.javascript.commonjs.module.provider.CachingModuleScriptProviderBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
The Rhino JavaScript Engine for Java
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.Reader;
import java.io.Serializable;
import java.net.URI;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.commonjs.module.ModuleScript;
import org.mozilla.javascript.commonjs.module.ModuleScriptProvider;
/**
* Abstract base class that implements caching of loaded module scripts. It
* uses a {@link ModuleSourceProvider} to obtain the source text of the
* scripts. It supports a cache revalidation mechanism based on validator
* objects returned from the {@link ModuleSourceProvider}. Instances of this
* class and its subclasses are thread safe (and written to perform decently
* under concurrent access).
* @author Attila Szegedi
* @version $Id: CachingModuleScriptProviderBase.java,v 1.3 2011/04/07 20:26:12 hannes%helma.at Exp $
*/
public abstract class CachingModuleScriptProviderBase
implements ModuleScriptProvider, Serializable
{
private static final long serialVersionUID = 1L;
private static final int loadConcurrencyLevel =
Runtime.getRuntime().availableProcessors() * 8;
private static final int loadLockShift;
private static final int loadLockMask;
private static final int loadLockCount;
static {
int sshift = 0;
int ssize = 1;
while (ssize < loadConcurrencyLevel) {
++sshift;
ssize <<= 1;
}
loadLockShift = 32 - sshift;
loadLockMask = ssize - 1;
loadLockCount = ssize;
}
private final Object[] loadLocks = new Object[loadLockCount]; {
for(int i = 0; i < loadLocks.length; ++i) {
loadLocks[i] = new Object();
}
}
private final ModuleSourceProvider moduleSourceProvider;
/**
* Creates a new module script provider with the specified source.
* @param moduleSourceProvider provider for modules' source code
*/
protected CachingModuleScriptProviderBase(
ModuleSourceProvider moduleSourceProvider) {
this.moduleSourceProvider = moduleSourceProvider;
}
public ModuleScript getModuleScript(Context cx, String moduleId,
URI moduleUri, URI baseUri, Scriptable paths) throws Exception
{
final CachedModuleScript cachedModule1 = getLoadedModule(moduleId);
final Object validator1 = getValidator(cachedModule1);
final ModuleSource moduleSource = (moduleUri == null)
? moduleSourceProvider.loadSource(moduleId, paths, validator1)
: moduleSourceProvider.loadSource(moduleUri, baseUri, validator1);
if(moduleSource == ModuleSourceProvider.NOT_MODIFIED) {
return cachedModule1.getModule();
}
if(moduleSource == null) {
return null;
}
final Reader reader = moduleSource.getReader();
try {
final int idHash = moduleId.hashCode();
synchronized(loadLocks[(idHash >>> loadLockShift) & loadLockMask]) {
final CachedModuleScript cachedModule2 = getLoadedModule(moduleId);
if(cachedModule2 != null) {
if(!equal(validator1, getValidator(cachedModule2))) {
return cachedModule2.getModule();
}
}
final URI sourceUri = moduleSource.getUri();
final ModuleScript moduleScript = new ModuleScript(
cx.compileReader(reader, sourceUri.toString(), 1,
moduleSource.getSecurityDomain()),
sourceUri, moduleSource.getBase());
putLoadedModule(moduleId, moduleScript,
moduleSource.getValidator());
return moduleScript;
}
}
finally {
reader.close();
}
}
/**
* Store a loaded module script for later retrieval using
* {@link #getLoadedModule(String)}.
* @param moduleId the ID of the module
* @param moduleScript the module script
* @param validator the validator for the module's source text entity
*/
protected abstract void putLoadedModule(String moduleId,
ModuleScript moduleScript, Object validator);
/**
* Retrieves an already loaded moduleScript stored using
* {@link #putLoadedModule(String, ModuleScript, Object)}.
* @param moduleId the ID of the module
* @return a cached module script, or null if the module is not loaded.
*/
protected abstract CachedModuleScript getLoadedModule(String moduleId);
/**
* Instances of this class represent a loaded and cached module script.
* @author Attila Szegedi
* @version $Id: CachingModuleScriptProviderBase.java,v 1.3 2011/04/07 20:26:12 hannes%helma.at Exp $
*/
public static class CachedModuleScript {
private final ModuleScript moduleScript;
private final Object validator;
/**
* Creates a new cached module script.
* @param moduleScript the module script itself
* @param validator a validator for the moduleScript's source text
* entity.
*/
public CachedModuleScript(ModuleScript moduleScript, Object validator) {
this.moduleScript = moduleScript;
this.validator = validator;
}
/**
* Returns the module script.
* @return the module script.
*/
ModuleScript getModule() {
return moduleScript;
}
/**
* Returns the validator for the module script's source text entity.
* @return the validator for the module script's source text entity.
*/
Object getValidator() {
return validator;
}
}
private static Object getValidator(CachedModuleScript cachedModule) {
return cachedModule == null ? null : cachedModule.getValidator();
}
private static boolean equal(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
/**
* Returns the internal concurrency level utilized by caches in this JVM.
* @return the internal concurrency level utilized by caches in this JVM.
*/
protected static int getConcurrencyLevel() {
return loadLockCount;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy