Navigation Menu

Skip to content

Commit

Permalink
Further refactor DRAF to use ScriptingContainer for runtime creation
Browse files Browse the repository at this point in the history
  • Loading branch information
nicksieger committed Mar 21, 2011
1 parent 6649e95 commit 1732b73
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 42 deletions.
101 changes: 76 additions & 25 deletions src/main/java/org/jruby/rack/DefaultRackApplicationFactory.java
Expand Up @@ -12,7 +12,6 @@
import org.jruby.exceptions.RaiseException;
import org.jruby.embed.ScriptingContainer;
import org.jruby.embed.LocalContextScope;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ClassCache;
Expand All @@ -34,17 +33,15 @@
public class DefaultRackApplicationFactory implements RackApplicationFactory {
private String rackupScript, rackupLocation;
private RackContext rackContext;
private RubyInstanceConfig defaultConfig;
private ClassCache classCache;
private RackApplication errorApplication;

public void init(RackContext rackContext) {
this.rackContext = rackContext;
this.rackupScript = findRackupScript();
this.classCache = JavaEmbedUtils.createClassCache(
Thread.currentThread().getContextClassLoader());
if (errorApplication == null) {
errorApplication = newErrorApplication();
}
this.defaultConfig = createDefaultConfig();
rackContext.log(defaultConfig.getVersionString());
}

public RackApplication newApplication() throws RackInitializationException {
Expand All @@ -65,7 +62,10 @@ public void finishedWithApplication(RackApplication app) {
app.destroy();
}

public RackApplication getErrorApplication() {
public synchronized RackApplication getErrorApplication() {
if (errorApplication == null) {
errorApplication = newErrorApplication();
}
return errorApplication;
}

Expand Down Expand Up @@ -200,40 +200,94 @@ private interface ApplicationObjectFactory {
IRubyObject create(Ruby runtime);
}

private ScriptingContainer newContainer() {
RubyInstanceConfig config = createRuntimeConfig();
private RubyInstanceConfig createDefaultConfig() {
setupJRubyManagement();
RubyInstanceConfig config = new RubyInstanceConfig();
config.setLoader(Thread.currentThread().getContextClassLoader());

ScriptingContainer container = new ScriptingContainer(LocalContextScope.SINGLETHREAD);
if (rackContext.getConfig().getCompatVersion() != null) {
config.setCompatVersion(rackContext.getConfig().getCompatVersion());
}

container.setClassLoader(Thread.currentThread().getContextClassLoader());
container.setHomeDirectory(config.getJRubyHome());
container.setEnvironment(config.getEnvironment());
container.setLoadPaths(config.loadPaths());
try { // try to set jruby home to jar file path
URL resource = RubyInstanceConfig.class.getResource("/META-INF/jruby.home");
if (resource.getProtocol().equals("jar")) {
String home;
try { // http://weblogs.java.net/blog/2007/04/25/how-convert-javaneturl-javaiofile
home = resource.toURI().getSchemeSpecificPart();
} catch (URISyntaxException urise) {
home = resource.getPath();
}

if (rackContext.getConfig().getCompatVersion() != null) {
container.setCompatVersion(config.getCompatVersion());
// Trim trailing slash. It confuses OSGi containers...
if (home.endsWith("/")) {
home = home.substring(0, home.length() - 1);
}
config.setJRubyHome(home);
}
} catch (Exception e) { }

// Process arguments, namely any that might be in RUBYOPT
config.processArguments(new String[0]);
return config;
}

private void configureContainer(ScriptingContainer container) {
container.setClassLoader(defaultConfig.getLoader());
container.setClassCache(defaultConfig.getClassCache());
container.setCompatVersion(defaultConfig.getCompatVersion());
container.setHomeDirectory(defaultConfig.getJRubyHome());
container.setEnvironment(defaultConfig.getEnvironment());
container.setLoadPaths(defaultConfig.loadPaths());
container.getProvider().getRubyInstanceConfig().requiredLibraries().addAll(defaultConfig.requiredLibraries());
}

private void initializeContainer(ScriptingContainer container) throws RackInitializationException {
try {
container.put("$servlet_context", rackContext);
if (rackContext.getConfig().isIgnoreEnvironment()) {
container.runScriptlet("ENV.clear");
}
container.runScriptlet("require 'rack/handler/servlet'");
} catch (RaiseException re) {
throw new RackInitializationException(re);
}
}

/** This method is only public for unit tests */
public ScriptingContainer newContainer() throws RackInitializationException {
ScriptingContainer container = new ScriptingContainer(LocalContextScope.SINGLETHREAD);
configureContainer(container);
initializeContainer(container);
return container;
}

private Ruby getRuntimeFrom(ScriptingContainer container) {
Ruby runtime = (Ruby) rackContext.getAttribute("jruby.runtime");
if (runtime == null) {
return container.getProvider().getRuntime();
} else {
return runtime;
}
}

private RackApplication createApplication(final ApplicationObjectFactory appfact)
throws RackInitializationException {
try {
final Ruby runtime = newRuntime();
final ScriptingContainer container = newContainer();
return new DefaultRackApplication() {
@Override
public void init() throws RackInitializationException {
try {
setApplication(appfact.create(runtime));
setApplication(appfact.create(getRuntimeFrom(container)));
} catch (RaiseException re) {
captureMessage(re);
throw new RackInitializationException(re);
}
}
@Override
public void destroy() {
JavaEmbedUtils.terminate(runtime);
container.terminate();
}
};
} catch (RackInitializationException rie) {
Expand Down Expand Up @@ -340,12 +394,9 @@ private String findRackupScript() {
return rackup;
}

/** Used only for testing; not part of the public API. */
public String verify(Ruby runtime, String script) {
try {
return runtime.evalScriptlet(script).toString();
} catch (Exception e) {
return e.getMessage();
private void setupJRubyManagement() {
if (!"false".equalsIgnoreCase(System.getProperty("jruby.management.enabled"))) {
System.setProperty("jruby.management.enabled", "true");
}
}

Expand Down
29 changes: 12 additions & 17 deletions src/spec/ruby/rack/application_spec.rb
Expand Up @@ -91,35 +91,30 @@
end
end

describe "newRuntime" do
it "should create a new Ruby runtime with the rack environment pre-loaded" do
runtime = app_factory.newRuntime
lazy_string = proc {|v| "(begin; #{v}; rescue Exception => e; e.class; end).name"}
@app_factory.verify(runtime, lazy_string.call("Rack")).should == "Rack"
@app_factory.verify(runtime, lazy_string.call("Rack::Handler::Servlet")
).should == "Rack::Handler::Servlet"
@app_factory.verify(runtime, lazy_string.call("Rack::Handler::Bogus")
).should_not == "Rack::Handler::Bogus"
describe "newContainer" do
it "should create a new Ruby container with the rack environment pre-loaded" do
container = app_factory.newContainer
container.runScriptlet("defined?(::Rack)").should be_true
container.runScriptlet("defined?(::Rack::Handler::Servlet)").should be_true
container.runScriptlet("defined?(Rack::Handler::Bogus)").should_not be_true
end

it "should initialize the $servlet_context global variable" do
runtime = app_factory.newRuntime
app_factory.verify(runtime, "defined?($servlet_context)").should_not be_empty
container = app_factory.newContainer
container.runScriptlet("defined?($servlet_context)").should_not be_empty
end

it "should handle jruby.compat.version == '1.9' and start up in 1.9 mode" do
@rack_config.stub!(:getCompatVersion).and_return org.jruby.CompatVersion::RUBY1_9
runtime = app_factory.newRuntime
runtime.instance_config.compat_version.should == org.jruby.CompatVersion::RUBY1_9
container = app_factory.newContainer
container.compat_version.should == org.jruby.CompatVersion::RUBY1_9
end

it "should have environment variables cleared if the configuration ignores the environment" do
ENV["HOME"].should_not == ""
runtime = app_factory.newRuntime
app_factory.verify(runtime, 'ENV["HOME"]').should == ENV["HOME"]
@rack_config.stub!(:isIgnoreEnvironment).and_return true
runtime = app_factory.newRuntime
app_factory.verify(runtime, 'ENV["HOME"]').should == ""
container = app_factory.newContainer
container.runScriptlet('ENV["HOME"]').should be_nil
end
end
end
Expand Down

0 comments on commit 1732b73

Please sign in to comment.