Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 22 additions & 57 deletions core/src/main/java/org/jruby/embed/IsolatedScriptingContainer.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,36 @@
package org.jruby.embed;

import java.net.URL;
import java.util.Arrays;

/**
* the IsolatedScriptingContainer detects the whether it is used with
* a Thread.currentThread.contextClassLoader (J2EE) or with the classloader
* which loaded IsolatedScriptingContainer.class (OSGi case)
*
* the setup of LOAD_PATH and GEM_PATH and JRUBY_HOME uses ONLY uri: or uri:classloader:
* protocol paths. i.e. everything lives within one or more classloaders - no jars added from
* jave.class.path or similar "magics"
*
* the root of the "main" classloader is add to LOAD_PATH and GEM_PATH.
* the root of the "main" classloader is added to LOAD_PATH and GEM_PATH.
*
* in the OSGi case there are helper methods to add ClassLoaders to the LOAD_PATH or GEM_PATH
*
* a typical setup for the ContextClassLoader case looks likes this:
* <li>LOAD_PATH == [ "uri:classloader:/META-INF/jruby.home/lib/ruby/1.9/site_ruby",
*
* a typical setup for the ContextClassLoader case and OSGi case looks likes this:
* <li>LOAD_PATH == [ "uri:classloader:/META-INF/jruby.home/lib/ruby/1.9/site_ruby",
* "uri:classloader:/META-INF/jruby.home/lib/ruby/shared",
* "uri:classloader:/META-INF/jruby.home/lib/ruby/1.9",
* "uri:classloader:" ]</li>
* <li>Gem::Specification.dirs == [ "uri:classloader:", "uri:classloader:/META-INF/jruby.home/lib/ruby/gems/shared" ]
* <li>Gem::Specification.dirs == [ "uri:classloader:/specifications", "uri:classloader:/META-INF/jruby.home/lib/ruby/gems/shared/specifications" ]
* here very resource is loaded via <code>Thread.currentTHread.getContextClassLoader().getResourceAsStream(...)</code>
*
* a typical setup for OSGi case (one bundle with everything):
* <li>LOAD_PATH == [ "uri:bundle://16.0:1/META-INF/jruby.home/lib/ruby/1.9/site_ruby",
* "uri:bundle://16.0:1/META-INF/jruby.home/lib/ruby/shared",
* "uri:bundle://16.0:1/META-INF/jruby.home/lib/ruby/1.9",
* "uri:bundle://16.0:1" ]</li>
* <li>Gem::Specification.dirs == [ "uri:bundle://16.0:1", "uri:bundle://16.0:1/META-INF/jruby.home/lib/ruby/gems/shared" ]
* other OSGi frameworks use other uris like bundleresource:/16.fwk1661197821. here very resource is loaded via
* <code>new URL( uri )openStream()</code>, i.e. <code>new URL(classloader.getResource().toString()).openStream()</code> has to work for
* those classloaders. felix and equinox OSGi framework do work.
*
* NOTE: <code>Gem.path</code> is base for determine the <code>Gem::Specification.dirs</code> and <code>Gem::Specification.dirs</code> is
*
* <code>new URL( uri ).openStream()</code>, i.e. <code>new URL(classloader.getResource().toString()).openStream()</code> has to work for
* those classloaders. felix, knoplerfish and equinox OSGi framework do work.
*
* NOTE: <code>Gem.path</code> is used to setup the <code>Gem::Specification.dirs</code> and <code>Gem::Specification.dirs</code> are
* used to find gemspec files of the installed gems.
*/
public class IsolatedScriptingContainer extends ScriptingContainer {

private static final String JRUBYDIR = "/.jrubydir";
private static final String JRUBY_HOME = "/META-INF/jruby.home";
private static final String JRUBY_HOME_DIR = JRUBY_HOME + JRUBYDIR;


public IsolatedScriptingContainer()
{
this(LocalContextScope.SINGLETON);
Expand All @@ -67,41 +56,17 @@ public IsolatedScriptingContainer( LocalContextScope scope,
LocalVariableBehavior behavior,
boolean lazy )
{
super( scope, behavior, lazy );
boolean isContextClassLoader = true;
URL home = Thread.currentThread().getContextClassLoader().getResource( JRUBY_HOME_DIR.substring( 1 ) );
if ( home == null ) {
isContextClassLoader = false;
home = this.getClass().getClassLoader().getResource( JRUBY_HOME_DIR );
if ( home == null ) {
throw new RuntimeException( "BUG can not find " + JRUBY_HOME_DIR );
}
setClassLoader( this.getClass().getClassLoader() );
setHomeDirectory( "uri:" + home.toString().replaceFirst( JRUBYDIR + "$", "" ) );
}
else {
setHomeDirectory( "uri:classloader:" + JRUBY_HOME );
}
super(scope, behavior, lazy);

// clean up LOAD_PATH
runScriptlet( "$LOAD_PATH.delete_if{|p| p =~ /jar$/ };"
// TODO NormalizedFile does too much - should leave uri: files as they are
+ "$LOAD_PATH.each{|p| p.sub!( /:\\/([^\\/])/,'://\\1' )}" );

if ( isContextClassLoader ) {
runScriptlet( "Gem::Specification.reset;"
+ "Gem::Specification.add_dir 'uri:classloader:" + JRUBY_HOME + "/lib/ruby/gems/shared';"
+ "Gem::Specification.add_dir 'uri:classloader:/';"
+ "$LOAD_PATH << 'uri:classloader:/'; $LOAD_PATH.inspect" );
}
else {
runScriptlet( "Gem::Specification.reset;"
+ "Gem::Specification.add_dir '" + getHomeDirectory() + "/lib/ruby/gems/shared'" );
addLoadPath( getClassLoader(), JRUBY_HOME_DIR );
addGemPath( getClassLoader(), JRUBY_HOME_DIR );
}
setLoadPaths( Arrays.asList( "uri:classloader:" ) );

// setup the isolated GEM_PATH, i.e. without $HOME/.gem/**
runScriptlet("require 'rubygems/defaults/jruby';"
+ "Gem::Specification.reset;"
+ "Gem::Specification.add_dir 'uri:classloader:" + JRUBY_HOME + "/lib/ruby/gems/shared';"
+ "Gem::Specification.add_dir 'uri:classloader:';");
}

public void addLoadPath( ClassLoader cl ) {
addLoadPath( cl, JRUBYDIR );
}
Expand Down Expand Up @@ -136,4 +101,4 @@ public void addGemPath( ClassLoader cl, String ref ) {
runScriptlet( "Gem::Specification.add_dir '" + uri + "' unless Gem::Specification.dirs.member?( '" + uri + "' )" );
}

}
}
17 changes: 7 additions & 10 deletions core/src/main/java/org/jruby/embed/util/SystemPropertyCatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jruby.CompatVersion;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyInstanceConfig.CompileMode;
import org.jruby.embed.internal.LocalContextProvider;
Expand Down Expand Up @@ -120,17 +121,17 @@ public static boolean isLazy(boolean defaultLaziness) {
}
return Boolean.parseBoolean(s);
}

/**
* Sets classloader based on System property. This is only used from
* JRubyEgnineFactory.
*
*
* @param container ScriptingContainer to be set classloader
*/

public static void setClassLoader(ScriptingContainer container) {
String s = SafePropertyAccessor.getProperty(PropertyName.CLASSLOADER.toString());

// current should be removed later
if (s == null || "container".equals(s) || "current".equals(s)) { // default
container.setClassLoader(container.getClass().getClassLoader());
Expand Down Expand Up @@ -194,12 +195,8 @@ public static String findJRubyHome(Object instance) {
return jrubyhome;
} else if ((jrubyhome = SafePropertyAccessor.getProperty("jruby.home")) != null) {
return jrubyhome;
} else if (Thread.currentThread().getContextClassLoader() == null ||
Thread.currentThread().getContextClassLoader().equals(SystemPropertyCatcher.class.getClassLoader())) {
return "uri:classloader://META-INF/jruby.home";
}
else {
return "classpath:/META-INF/jruby.home";
} else {
return "uri:classloader:/META-INF/jruby.home";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ private void loadJar(Ruby runtime, boolean wrap) {
}
else if (location.startsWith(URLResource.URI)){
url = null;
runtime.getJRubyClassLoader().addURLNoIndex(URLResource.getResourceURL(location));
runtime.getJRubyClassLoader().addURLNoIndex(URLResource.getResourceURL(runtime, location));
}
else {
File f = new File(location);
Expand Down
42 changes: 21 additions & 21 deletions core/src/main/java/org/jruby/runtime/load/LoadService.java
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public void addPaths(String... additionalDirectories) {
addPath(dir);
}
}

protected boolean isFeatureInIndex(String shortName) {
return loadedFeaturesIndex.containsKey(shortName);
}
Expand All @@ -295,10 +295,10 @@ protected void addLoadedFeature(String name) {

protected void addLoadedFeature(String shortName, String name) {
loadedFeatures.append(RubyString.newString(runtime, name));

addFeatureToIndex(shortName, name);
}

protected void addFeatureToIndex(String shortName, String name) {
loadedFeaturesDup = (RubyArray)loadedFeatures.dup();
loadedFeaturesIndex.put(shortName, name);
Expand Down Expand Up @@ -431,7 +431,7 @@ private RequireState requireCommon(String requireName, boolean circularRequireWa
requireLocks.unlock(requireName);
}
}

protected final RequireLocks requireLocks = new RequireLocks();

private class RequireLocks {
Expand All @@ -448,7 +448,7 @@ private RequireLocks() {
* Get exclusive lock for the specified requireName. Acquire sync object
* for the requireName from the pool, then try to lock it. NOTE: This
* lock is not fair for now.
*
*
* @param requireName
* just a name for the lock.
* @return If the sync object already locked by current thread, it just
Expand Down Expand Up @@ -488,7 +488,7 @@ private boolean lock(String requireName) {

/**
* Unlock the lock for the specified requireName.
*
*
* @param requireName
* name of the lock to be unlocked.
*/
Expand Down Expand Up @@ -631,7 +631,7 @@ public void removeInternalLoadedFeature(String name) {
RubyString nameRubyString = runtime.newString(name);
loadedFeatures.delete(runtime.getCurrentContext(), nameRubyString, Block.NULL_BLOCK);
}

private boolean isFeaturesIndexUpToDate() {
// disable tracing during index check
runtime.getCurrentContext().preTrace();
Expand All @@ -644,13 +644,13 @@ private boolean isFeaturesIndexUpToDate() {

protected boolean featureAlreadyLoaded(String name) {
if (loadedFeatures.containsString(name)) return true;

// Bail if our features index fell out of date.
if (!isFeaturesIndexUpToDate()) {
if (!isFeaturesIndexUpToDate()) {
loadedFeaturesIndex.clear();
return false;
}

return isFeatureInIndex(name);
}

Expand Down Expand Up @@ -1099,9 +1099,9 @@ protected LoadServiceResource tryResourceFromDotSlash(SearchState state, String

for (String suffix : suffixType.getSuffixes()) {
String namePlusSuffix = baseName + suffix;

foundResource = tryResourceAsIs(namePlusSuffix, "resourceFromDotSlash");

if (foundResource != null) break;
}

Expand Down Expand Up @@ -1288,7 +1288,7 @@ protected LoadServiceResource tryResourceFromLoadPathOrURL(SearchState state, St

return foundResource;
}

protected String getLoadPathEntry(IRubyObject entry) {
return RubyFile.get_path(entry.getRuntime().getCurrentContext(), entry).asJavaString();
}
Expand Down Expand Up @@ -1347,7 +1347,7 @@ protected boolean loadPathLooksLikeJarURL(String loadPathEntry) {
protected boolean loadPathLooksLikeClasspathURL(String loadPathEntry) {
return loadPathEntry.startsWith("classpath:");
}

private String[] splitJarUrl(String loadPathEntry) {
String unescaped = loadPathEntry;

Expand All @@ -1368,11 +1368,11 @@ private String[] splitJarUrl(String loadPathEntry) {
if(filename.startsWith("jar:")) {
filename = filename.substring(4);
}

if(filename.startsWith("file:")) {
filename = filename.substring(5);
}

return new String[]{filename, entry};
}

Expand Down Expand Up @@ -1421,7 +1421,7 @@ protected LoadServiceResource tryResourceAsIs(String namePlusSuffix, String debu
if (!Ruby.isSecurityRestricted()) {
String reportedPath = namePlusSuffix;
File actualPath;

if (new File(reportedPath).isAbsolute()) {
// it's an absolute path, use it as-is
actualPath = new File(RubyFile.expandUserPath(runtime.getCurrentContext(), namePlusSuffix));
Expand All @@ -1433,17 +1433,17 @@ protected LoadServiceResource tryResourceAsIs(String namePlusSuffix, String debu

actualPath = JRubyFile.create(runtime.getCurrentDirectory(), RubyFile.expandUserPath(runtime.getCurrentContext(), namePlusSuffix));
}

debugLogTry(debugName, actualPath.toString());

if (reportedPath.contains("..")) {
// try to canonicalize if path contains ..
try {
actualPath = actualPath.getCanonicalFile();
} catch (IOException ioe) {
}
}

if (actualPath.isFile() && actualPath.canRead()) {
foundResource = new LoadServiceResource(actualPath, reportedPath);
debugLogFound(foundResource);
Expand Down Expand Up @@ -1588,7 +1588,7 @@ && isRequireable(loc)) {
path = getPath(loc);
// On windows file: urls converted to names will return /C:/foo from
// getPath versus C:/foo. Since getPath is used in a million places
// putting the newFile.getPath broke some file with-in Jar loading.
// putting the newFile.getPath broke some file with-in Jar loading.
// So I moved it to only this site.
if (Platform.IS_WINDOWS && loc.getProtocol().equals("file")) {
path = new File(path).getPath();
Expand Down
8 changes: 6 additions & 2 deletions core/src/main/java/org/jruby/util/JRubyFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ public static FileResource createResource(ThreadContext context, String pathname
}

public static FileResource createResource(Ruby runtime, String pathname) {
return createResource(runtime.getPosix(), runtime.getCurrentDirectory(), pathname);
return createResource(runtime.getPosix(), runtime, runtime.getCurrentDirectory(), pathname);
}

public static FileResource createResource(POSIX posix, String cwd, String pathname) {
return createResource(posix, null, cwd, pathname);
}

public static FileResource createResource(POSIX posix, Ruby runtime, String cwd, String pathname) {
FileResource emptyResource = EmptyFileResource.create(pathname);
if (emptyResource != null) return emptyResource;

Expand All @@ -80,7 +84,7 @@ public static FileResource createResource(POSIX posix, String cwd, String pathna
if (pathname.startsWith("classpath:")) return ClasspathResource.create(pathname);

// replace is needed for maven/jruby-complete/src/it/app_using_classpath_uri to work
if (pathname.startsWith("uri:")) return URLResource.create(pathname.replace("classpath:/", ""));
if (pathname.startsWith("uri:")) return URLResource.create(runtime, pathname.replace("classpath:/", ""));

if (pathname.startsWith("file:")) {
pathname = pathname.substring(5);
Expand Down
Loading