Issue Details (XML | Word | Printable)

Key: JRUBY_EMBED-11
Type: Bug Bug
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Christian Brensing
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
jruby-embed

JSR223-Engine not working with OSGi

Created: 13/Oct/09 12:25 PM   Updated: 21/Dec/09 03:38 PM
Component/s: Core, JSR223
Affects Version/s: None
Fix Version/s: None

Time Tracking:
Not Specified

Environment:

JRuby 1.4.0RC1, OSGi-Framework 4.1 with Equinox 3.5


Tags:


 Description  « Hide

Integrating the JSR223 script engine in the JRuby distribution is a brilliant idea. In a standard Java classloading environment it works fine, however it fails in an OSGi environment. It seems that JRuby cannot see/load the ruby files stored in META-INF/jruby.home, so executing a ruby script that requires for example test/unit fails with the following stacktrace:

<script>:1:in `require': no such file to load -- test/unit (LoadError)
	from <script>:1
	...internal jruby stack elided...
	from Kernel.require(<script>:1)
	from (unknown).(unknown)(:1)
<script>:1:in `require': no such file to load -- test/unit (LoadError)
	from <script>:1
javax.script.ScriptException: java.lang.RuntimeException: org.jruby.exceptions.RaiseException: no such file to load -- test/unit
	at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:116)
	at internal.Activator$EngineFactoryTracker.addingService(Activator.java:36)
	at org.osgi.util.tracker.ServiceTracker$Tracked.trackAdding(ServiceTracker.java:1064)
	at org.osgi.util.tracker.ServiceTracker$Tracked.track(ServiceTracker.java:1042)
	at org.osgi.util.tracker.ServiceTracker$Tracked.serviceChanged(ServiceTracker.java:967)
	at org.eclipse.osgi.framework.internal.core.FilteredServiceListener.serviceChanged(FilteredServiceListener.java:91)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.dispatchEvent(BundleContextImpl.java:1248)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:211)
	at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:141)
	at org.eclipse.osgi.framework.internal.core.Framework.publishServiceEventPrivileged(Framework.java:1563)
	at org.eclipse.osgi.framework.internal.core.Framework.publishServiceEvent(Framework.java:1538)
	at org.eclipse.osgi.framework.internal.core.ServiceRegistrationImpl.register(ServiceRegistrationImpl.java:122)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.createServiceRegistration(BundleContextImpl.java:666)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.registerService(BundleContextImpl.java:617)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.registerService(BundleContextImpl.java:685)
	at org.ops4j.pax.script.internal.ExtenderActivator$1.addingEntries(ExtenderActivator.java:103)
	at org.ops4j.pax.swissbox.extender.BundleWatcher.register(BundleWatcher.java:186)
	at org.ops4j.pax.swissbox.extender.BundleWatcher.onStart(BundleWatcher.java:145)
	at org.ops4j.pax.swissbox.lifecycle.AbstractLifecycle$Stopped.start(AbstractLifecycle.java:121)
	at org.ops4j.pax.swissbox.lifecycle.AbstractLifecycle.start(AbstractLifecycle.java:49)
	at org.ops4j.pax.script.internal.ExtenderActivator.start(ExtenderActivator.java:128)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl$2.run(BundleContextImpl.java:1009)
	at java.security.AccessController.doPrivileged(Native Method)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:1003)
	at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:984)
	at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:346)
	at org.eclipse.osgi.framework.internal.core.AbstractBundle.resume(AbstractBundle.java:355)
	at org.eclipse.osgi.framework.internal.core.Framework.resumeBundle(Framework.java:1074)
	at org.eclipse.osgi.framework.internal.core.StartLevelManager.resumeBundles(StartLevelManager.java:616)
	at org.eclipse.osgi.framework.internal.core.StartLevelManager.incFWSL(StartLevelManager.java:508)
	at org.eclipse.osgi.framework.internal.core.StartLevelManager.doSetStartLevel(StartLevelManager.java:299)
	at org.eclipse.osgi.framework.internal.core.StartLevelManager.dispatchEvent(StartLevelManager.java:489)
	at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:211)
	at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:321)
Caused by: java.lang.RuntimeException: org.jruby.exceptions.RaiseException: no such file to load -- test/unit
	at org.jruby.embed.internal.EmbedEvalUnitImpl.run(EmbedEvalUnitImpl.java:116)
	at org.jruby.embed.jsr223.JRubyEngine.eval(JRubyEngine.java:113)
	... 33 more
Caused by: org.jruby.exceptions.RaiseException: no such file to load -- test/unit
	at (unknown).new(<script>:1)
	at Kernel.require(<script>:1)
	at (unknown).(unknown)(:1)

The bundle activator internal.Activator is part of a very small test project to reproduce the error.

When the ScriptEngineFactory is first initialized it promps the following warning to STDERR:

Warning: JRuby home "/1/META-INF/jruby.home" does not exist, using /tmp

Currently we have in our project an own implementation of a JRubyScriptEngine that works fine under OSGi, because we changed (and resetted) the ThreadContextClassLoader before instantiating a new Ruby runtime:

JRubyScriptEngine() {
        ClassLoader currentTccl = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(Ruby.class.getClassLoader());
        
        try {
            runtime = JavaEmbedUtils.initialize(new ArrayList<String>());
        } finally {
            Thread.currentThread().setContextClassLoader(currentTccl);
        }
}

Perhaps this may also a solution for jruby-embed.

I'm looking forward to replace our own jruby script engine with the standard one.



Christian Brensing added a comment - 18/Nov/09 02:19 PM

I did some debugging and I think, that the ThreadContextClassLoader is (this time) not the problem. In fact JRuby isn't finding jrubyHome, as the warning message pointed out:

Warning: JRuby home "/1/META-INF/jruby.home" does not exist, using /tmp

The jrubyHome variable is set during the initialization of the JRubyEngineFactory in SystemPropertyCatcher inspecting the jar file if the system property or environment variable is not set. The problem is, that looking for a classpath resource in an OSGi environment returns an OSGi-specific URL (bundleresource://1/META-INF/jruby.home in Equinox for example). The URL scheme is then stripped of (resource.toURI().getSchemeSpecificPart()), leading to the path showed above that cannot be found from the JRuby point of view.

I could use an equinox specific resolver to resolve the OSGi bundleresource myself and setting a file-URI as the jruby.home system property, but this only works if I do this before the JRubyEngineFactory gets initialized. In OSGi the JRubyEngineFactory will be automatically registered as a service (so called extender pattern), but this happens before my application code gets a chance to set jruby.home.

Any ideas how to solve this?


yokolet added a comment - 20/Nov/09 05:39 PM

Thanks for giving an interesting info. As you wrote setting jruby.home seems to cause a trouble in OSGi environment. Probably, adding a new option that won't set any jrubyhome even though jruby-complete.jar is used would work to avoid this problem. This is easy, so I'm going to add it.
However, I don't think such a quick fix resolves every path related problem. The root cause of the trouble is that JRuby doesn't understand OSGI-specific URL. So, JRuby might fail to load Java classes or Ruby scripts referred from the first script. I'm not an OSGi expert, so I want to know there is any OSGi-way to avoid this kind of class loading troubles. If exists, JRuby doesn't need to be fixed. But, if not, JRuby should have some fix in its class loading way.

And, we'd better move this discussion to JRuby's JIRA. Probably, just you and I know this filed issue here. But, many people will see the problem in JRuby's. Someone might have the idea. If you don't mind refile the issue, would you do that?


Christian Brensing added a comment - 21/Dec/09 03:38 PM

Even when I resolve the OSGi-specific URL to a File-URL JRuby understands, the issue that a ruby module (e.g. test/unit) cannot be loaded still exists. I will raise a new JRuby JIRA issue for this load error.