Skip to content

Commit

Permalink
split IsolatedScriptingContainer in non OSGi and OSGiIsolatedScriptin…
Browse files Browse the repository at this point in the history
…gContainer

with this split it is possible to create an instance of IsolatedScriptingContainer
from ruby code via IsolatedScriptingContainer.new

Sponsored by Lookout Inc.
  • Loading branch information
mkristian committed Jun 26, 2015
1 parent 114a39e commit 0fb4442
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 37 deletions.
55 changes: 23 additions & 32 deletions core/src/main/java/org/jruby/embed/IsolatedScriptingContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

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

import org.osgi.framework.Bundle;
import java.util.HashMap;
import java.util.Map;

/**
* the IsolatedScriptingContainer detects the whether it is used with
Expand All @@ -16,7 +16,7 @@
*
* the root of the "main" classloader is add to LOAD_PATH and GEM_PATH.
*
* in the OSGi case there are helper methods to add ClassLoaders to the LOAD_PATH or GEM_PATH
* in the OSGi case see the OSGiIsolatedScriptingContainer
*
* 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",
Expand Down Expand Up @@ -79,6 +79,24 @@ public IsolatedScriptingContainer( LocalContextScope scope,
+ "Gem::Specification.reset;"
+ "Gem::Specification.add_dir 'uri:classloader:" + JRUBY_HOME + "/lib/ruby/gems/shared';"
+ "Gem::Specification.add_dir 'uri:classloader:';");

// setup the isolated GEM_PATH, i.e. without $HOME/.gem/**
setEnvironment(null);
}

@Override
public void setEnvironment(Map environment) {
if (environment == null || !environment.containsKey("GEM_PATH")
|| !environment.containsKey("GEM_HOME")|| !environment.containsKey("JARS_HOME")) {
Map<String,String> env = environment == null ? new HashMap<String,String>() : new HashMap<String,String>(environment);
if (!env.containsKey("GEM_PATH")) env.put("GEM_PATH", "uri:classloader://");
if (!env.containsKey("GEM_HOME")) env.put("GEM_HOME", "uri:classloader://");
if (!env.containsKey("JARS_HOME")) env.put("JARS_HOME", "uri:classloader://jars");
super.setEnvironment(env);
}
else {
super.setEnvironment(environment);
}
}

public void addLoadPath( ClassLoader cl ) {
Expand All @@ -89,37 +107,10 @@ public void addLoadPath( ClassLoader cl, String ref ) {
addLoadPath(createUri(cl, ref));
}

public void addBundleToLoadPath( Bundle cl ) {
addBundleToLoadPath( cl, JRUBYDIR );
}

public void addBundleToLoadPath( Bundle cl, String ref ) {
addLoadPath(createUriFromBundle(cl, ref));
}

private String createUriFromBundle( Bundle cl, String ref) {
URL url = cl.getResource( ref );
if ( url == null && ref.startsWith( "/" ) ) {
url = cl.getResource( ref.substring( 1 ) );
}
if ( url == null ) {
throw new RuntimeException( "reference " + ref + " not found on bundle " + cl );
}
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
}

private void addLoadPath(String uri) {
protected void addLoadPath(String uri) {
runScriptlet( "$LOAD_PATH << '" + uri + "' unless $LOAD_PATH.member?( '" + uri + "' )" );
}

public void addBundleToGemPath( Bundle cl ) {
addBundleToGemPath( cl, "/specifications" + JRUBYDIR );
}

public void addBundleToGemPath( Bundle cl, String ref ) {
addGemPath(createUriFromBundle(cl, ref));
}

public void addGemPath( ClassLoader cl ) {
addGemPath( cl, "/specifications" + JRUBYDIR );
}
Expand All @@ -139,7 +130,7 @@ private String createUri(ClassLoader cl, String ref) {
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
}

private void addGemPath(String uri) {
protected void addGemPath(String uri) {
runScriptlet( "Gem::Specification.add_dir '" + uri + "' unless Gem::Specification.dirs.member?( '" + uri + "' )" );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package org.jruby.embed.osgi;

import java.net.URL;

import org.jruby.embed.IsolatedScriptingContainer;
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;

/**
* adds some helper methods to add Bundle to the LOAD_PATH or GEM_PATH using the
* IsolatedScriptingContainer as base.
*
* <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.
*/
public class OSGiIsolatedScriptingContainer extends IsolatedScriptingContainer {

public OSGiIsolatedScriptingContainer()
{
this(LocalContextScope.SINGLETON);
}

public OSGiIsolatedScriptingContainer( LocalContextScope scope,
LocalVariableBehavior behavior )
{
this(scope, behavior, true);
}

public OSGiIsolatedScriptingContainer( LocalContextScope scope )
{
this(scope, LocalVariableBehavior.TRANSIENT);
}

public OSGiIsolatedScriptingContainer( LocalVariableBehavior behavior )
{
this(LocalContextScope.SINGLETON, behavior);
}

public OSGiIsolatedScriptingContainer( LocalContextScope scope,
LocalVariableBehavior behavior,
boolean lazy )
{
super(scope, behavior, lazy);
}

private Bundle toBundle(String symbolicName) {
BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
Bundle bundle = null;
for (Bundle b : context.getBundles()) {
if (b.getSymbolicName().equals(symbolicName)) {
bundle = b;
break;
}
}
if (bundle == null ) {
throw new RuntimeException("unknown bundle: " + symbolicName);
}
return bundle;
}

private String createUri(Bundle cl, String ref) {
URL url = cl.getResource( ref );
if ( url == null && ref.startsWith( "/" ) ) {
url = cl.getResource( ref.substring( 1 ) );
}
if ( url == null ) {
throw new RuntimeException( "reference " + ref + " not found on classloader " + cl );
}
return "uri:" + url.toString().replaceFirst( ref + "$", "" );
}
/**
* add the classloader from the given bundle to the LOAD_PATH
* @param bundle
*/
public void addBundleToLoadPath(Bundle bundle) {
addLoadPath(createUri(bundle, "/.jrubydir"));
}

/**
* add the classloader from the given bundle to the LOAD_PATH
* using the bundle symbolic name
*
* @param symbolicName
*/
public void addBundleToLoadPath(String symbolicName) {
addBundleToLoadPath(toBundle(symbolicName));
}

/**
* add the classloader from the given bundle to the GEM_PATH
* @param bundle
*/
public void addBundleToGemPath(Bundle bundle) {
addGemPath(createUri(bundle, "/specifications/.jrubydir"));
}

/**
* add the classloader from the given bundle to the GEM_PATH
* using the bundle symbolic name
*
* @param symbolicName
*/
public void addBundleToGemPath(String symbolicName) {
addBundleToGemPath(toBundle(symbolicName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.ScriptingContainer;
import org.jruby.embed.IsolatedScriptingContainer;
import org.jruby.embed.osgi.OSGiIsolatedScriptingContainer;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -80,8 +80,8 @@ public void testJRubyCreate() throws Exception {
// System.setProperty( "jruby.debug.loadService", "true" );
//System.setProperty( "jruby.native.enabled", "true" );

IsolatedScriptingContainer jruby = new IsolatedScriptingContainer();
jruby.addLoadPath( Scripts.class.getClassLoader() );
OSGiIsolatedScriptingContainer jruby = new OSGiIsolatedScriptingContainer();
jruby.addBundleToLoadPath( "org.jruby.osgi.scripts-bundle" );
jruby.addBundleToGemPath( FrameworkUtil.getBundle( Gems.class ) );

// run a script from LOAD_PATH
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import org.jruby.embed.LocalContextScope;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.ScriptingContainer;
import org.jruby.embed.IsolatedScriptingContainer;
import org.jruby.embed.osgi.OSGiIsolatedScriptingContainer;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -67,7 +67,7 @@ public void testJRubyCreate() throws InterruptedException {
System.err.println();

// System.setProperty( "jruby.debug.loadService", "true" );
IsolatedScriptingContainer jruby = new IsolatedScriptingContainer();
OSGiIsolatedScriptingContainer jruby = new OSGiIsolatedScriptingContainer();

// run a script from LOAD_PATH
String hello = (String) jruby.runScriptlet( "require 'hello'; Hello.say" );
Expand Down

0 comments on commit 0fb4442

Please sign in to comment.