Skip to content

Commit 2bc5a0e

Browse files
committed
leverage the classloader + osgi-bundle support to ScriptingContainer
1 parent 9e79159 commit 2bc5a0e

File tree

2 files changed

+79
-92
lines changed

2 files changed

+79
-92
lines changed
Lines changed: 12 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,21 @@
11
package org.jruby.embed;
22

3-
import java.net.URL;
43
import java.util.Arrays;
54
import java.util.HashMap;
65
import java.util.Map;
76

8-
import org.osgi.framework.Bundle;
9-
107
/**
11-
* the IsolatedScriptingContainer detects the whether it is used with
12-
* a Thread.currentThread.contextClassLoader (J2EE) or with the classloader
13-
* which loaded IsolatedScriptingContainer.class (OSGi case)
14-
*
15-
* the setup of LOAD_PATH and GEM_PATH and JRUBY_HOME uses ONLY uri: or uri:classloader:
16-
* protocol paths. i.e. everything lives within one or more classloaders - no jars added from
17-
* jave.class.path or similar "magics"
18-
*
19-
* the root of the "main" classloader is add to LOAD_PATH and GEM_PATH.
20-
*
21-
* in the OSGi case there are helper methods to add ClassLoaders to the LOAD_PATH or GEM_PATH
8+
* the IsolatedScriptingContainer does set GEM_HOME and GEM_PATH and JARS_HOME
9+
* in such a way that it uses only resources which can be reached with classloader.
2210
*
23-
* a typical setup for the ContextClassLoader case and OSGi case looks likes this:
24-
* <li>LOAD_PATH == [ "uri:classloader:/META-INF/jruby.home/lib/ruby/1.9/site_ruby",
25-
* "uri:classloader:/META-INF/jruby.home/lib/ruby/shared",
26-
* "uri:classloader:/META-INF/jruby.home/lib/ruby/1.9",
27-
* "uri:classloader:" ]</li>
28-
* <li>Gem::Specification.dirs == [ "uri:classloader:/specifications", "uri:classloader:/META-INF/jruby.home/lib/ruby/gems/shared/specifications" ]
29-
* here very resource is loaded via <code>Thread.currentTHread.getContextClassLoader().getResourceAsStream(...)</code>
11+
* GEM_HOME is uri:classloader://META-INF/jruby.home/lib/ruby/gems/shared
12+
* GEM_PATH is uri:classloader://
13+
* JARS_HOME is uri:classloader://jars
3014
*
31-
* <code>new URL( uri ).openStream()</code>, i.e. <code>new URL(classloader.getResource().toString()).openStream()</code> has to work for
32-
* those classloaders. felix, knoplerfish and equinox OSGi framework do work.
33-
*
34-
* NOTE: <code>Gem.path</code> is base for determine the <code>Gem::Specification.dirs</code> and <code>Gem::Specification.dirs</code> is
35-
* used to find gemspec files of the installed gems.
15+
* but whenever you want to set them via {@link #setEnvironment(Map)} this will be honored.
3616
*/
3717
public class IsolatedScriptingContainer extends ScriptingContainer {
3818

39-
private static final String JRUBYDIR = "/.jrubydir";
4019
private static final String JRUBY_HOME = "/META-INF/jruby.home";
4120

4221
public IsolatedScriptingContainer()
@@ -74,75 +53,16 @@ public IsolatedScriptingContainer( LocalContextScope scope,
7453

7554
@Override
7655
public void setEnvironment(Map environment) {
77-
if (environment == null || !environment.containsKey("GEM_PATH")) {
78-
Map env = environment == null ? new HashMap() : new HashMap(environment);
79-
env.put("GEM_PATH", "");
56+
if (environment == null || !environment.containsKey("GEM_PATH")
57+
|| !environment.containsKey("GEM_HOME")|| !environment.containsKey("JARS_HOME")) {
58+
Map<String,String> env = environment == null ? new HashMap<String,String>() : new HashMap<String,String>(environment);
59+
if (!env.containsKey("GEM_PATH")) env.put("GEM_PATH", "uri:classloader://");
60+
if (!env.containsKey("GEM_HOME")) env.put("GEM_HOME", "uri:classloader:/" + JRUBY_HOME);
61+
if (!env.containsKey("JARS_HOME")) env.put("JARS_HOME", "uri:classloader://jars");
8062
super.setEnvironment(env);
8163
}
8264
else {
8365
super.setEnvironment(environment);
8466
}
8567
}
86-
87-
public void addLoadPath( ClassLoader cl ) {
88-
addLoadPath( cl, JRUBYDIR );
89-
}
90-
91-
public void addLoadPath( ClassLoader cl, String ref ) {
92-
addLoadPath(createUri(cl, ref));
93-
}
94-
95-
public void addBundleToLoadPath( Bundle cl ) {
96-
addBundleToLoadPath( cl, JRUBYDIR );
97-
}
98-
99-
public void addBundleToLoadPath( Bundle cl, String ref ) {
100-
addLoadPath(createUriFromBundle(cl, ref));
101-
}
102-
103-
private String createUriFromBundle( Bundle cl, String ref) {
104-
URL url = cl.getResource( ref );
105-
if ( url == null && ref.startsWith( "/" ) ) {
106-
url = cl.getResource( ref.substring( 1 ) );
107-
}
108-
if ( url == null ) {
109-
throw new RuntimeException( "reference " + ref + " not found on bundle " + cl );
110-
}
111-
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
112-
}
113-
114-
private void addLoadPath(String uri) {
115-
runScriptlet( "$LOAD_PATH << '" + uri + "' unless $LOAD_PATH.member?( '" + uri + "' )" );
116-
}
117-
118-
public void addBundleToGemPath( Bundle cl ) {
119-
addBundleToGemPath( cl, "/specifications" + JRUBYDIR );
120-
}
121-
122-
public void addBundleToGemPath( Bundle cl, String ref ) {
123-
addGemPath(createUriFromBundle(cl, ref));
124-
}
125-
126-
public void addGemPath( ClassLoader cl ) {
127-
addGemPath( cl, "/specifications" + JRUBYDIR );
128-
}
129-
130-
public void addGemPath( ClassLoader cl, String ref ) {
131-
addGemPath(createUri(cl, ref));
132-
}
133-
134-
private String createUri(ClassLoader cl, String ref) {
135-
URL url = cl.getResource( ref );
136-
if ( url == null && ref.startsWith( "/" ) ) {
137-
url = cl.getResource( ref.substring( 1 ) );
138-
}
139-
if ( url == null ) {
140-
throw new RuntimeException( "reference " + ref + " not found on classloader " + cl );
141-
}
142-
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
143-
}
144-
145-
private void addGemPath(String uri) {
146-
runScriptlet( "require 'rubygems/defaults/jruby';Gem::Specification.add_dir '" + uri + "' unless Gem::Specification.dirs.member?( '" + uri + "' )" );
147-
}
14868
}

core/src/main/java/org/jruby/embed/ScriptingContainer.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,19 @@
3030
package org.jruby.embed;
3131

3232
import java.io.UnsupportedEncodingException;
33+
3334
import org.jruby.embed.internal.LocalContextProvider;
35+
3436
import java.io.InputStream;
3537
import java.io.PrintStream;
3638
import java.io.Reader;
3739
import java.io.Writer;
3840
import java.net.URISyntaxException;
41+
import java.net.URL;
3942
import java.util.HashMap;
4043
import java.util.List;
4144
import java.util.Map;
45+
4246
import org.jruby.CompatVersion;
4347
import org.jruby.Profile;
4448
import org.jruby.Ruby;
@@ -68,6 +72,7 @@
6872
import org.jruby.util.KCode;
6973
import org.jruby.util.cli.OutputStrings;
7074
import org.jruby.util.cli.Options;
75+
import org.osgi.framework.Bundle;
7176

7277
/**
7378
* ScriptingContainer provides various methods and resources that are useful
@@ -1886,4 +1891,66 @@ public void setClassloaderDelegate(boolean classloaderDelegate) {
18861891
public boolean getClassloaderDelegate() {
18871892
return getProvider().getRubyInstanceConfig().isClassloaderDelegate();
18881893
}
1894+
1895+
/**
1896+
* add the given classloader to the LOAD_PATH
1897+
* @param classloader
1898+
*/
1899+
public void addLoadPath(ClassLoader classloader) {
1900+
addLoadPath(createUri(classloader, "/.jrubydir"));
1901+
}
1902+
1903+
/**
1904+
* add the classloader from the given bundle to the LOAD_PATH
1905+
* @param bundle
1906+
*/
1907+
public void addBundleToLoadPath(Bundle bundle) {
1908+
addLoadPath(createUriFromBundle(bundle, "/.jrubydir"));
1909+
}
1910+
1911+
private String createUriFromBundle(Bundle cl, String ref) {
1912+
URL url = cl.getResource( ref );
1913+
if ( url == null && ref.startsWith( "/" ) ) {
1914+
url = cl.getResource( ref.substring( 1 ) );
1915+
}
1916+
if ( url == null ) {
1917+
throw new RuntimeException( "reference " + ref + " not found on bundle " + cl );
1918+
}
1919+
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
1920+
}
1921+
1922+
private void addLoadPath(String uri) {
1923+
runScriptlet( "$LOAD_PATH << '" + uri + "' unless $LOAD_PATH.member?( '" + uri + "' )" );
1924+
}
1925+
1926+
/**
1927+
* add the classloader from the given bundle to the GEM_PATH
1928+
* @param bundle
1929+
*/
1930+
public void addBundleToGemPath(Bundle bundle) {
1931+
addGemPath(createUriFromBundle(bundle, "/specifications/.jrubydir"));
1932+
}
1933+
1934+
/**
1935+
* add the given classloader to the GEM_PATH
1936+
* @param classloader
1937+
*/
1938+
public void addGemPath(ClassLoader classloader) {
1939+
addGemPath(createUri(classloader, "/specifications/.jrubydir"));
1940+
}
1941+
1942+
private String createUri(ClassLoader cl, String ref) {
1943+
URL url = cl.getResource( ref );
1944+
if ( url == null && ref.startsWith( "/" ) ) {
1945+
url = cl.getResource( ref.substring( 1 ) );
1946+
}
1947+
if ( url == null ) {
1948+
throw new RuntimeException( "reference " + ref + " not found on classloader " + cl );
1949+
}
1950+
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
1951+
}
1952+
1953+
private void addGemPath(String uri) {
1954+
runScriptlet( "require 'rubygems/defaults/jruby';Gem::Specification.add_dir '" + uri + "' unless Gem::Specification.dirs.member?( '" + uri + "' )" );
1955+
}
18891956
}

0 commit comments

Comments
 (0)