Problms with JRuby in Eclipse

View: New views
11 Messages — Rating Filter:   Alert me  

Problms with JRuby in Eclipse

by Lagutko Nikolay :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.

Hi,

 

I have a problem with working with JRuby in Eclipse. If required scripts stored not in classpath directories but in other plugins JRuby cannot find them. As I see the problem in Equinox environment. When JRuby calculates path to required script it uses Equinox BundleClassLoader to load this script and it will return path to file in bundle-dependent format, for example

bundleresource://9/./some_script.rb

And in further calculations JRuby cannot correctly interpret this path. For example function File.expand_path will return “/./some_script” instead of full path “D:/path_to_plugin/some_script”.

 

I find out how to resolve this problem with using FileLocator class from org.eclipse.core.runtime plugin but I don’t want to have dependencies to other plugins in my org.jruby plugin.

 

Are there other ways to resolve this problem?

 

Nikolay Lagutko

 

Programmer

GERSIS SOFTWARE, LCC

 

Odoevskogo str., 131,

220018 Minsk

Republic of Belarus

ph.:    +375 (17) 2591900

fax:    +375 (17) 2591901

GSM: +375 (29) 3115430

ICQ:   457203926

Skype: lagutko_nikolay

Jabber: lagutko_n@...

http://www.gersis-software.com/

 


Re: Problms with JRuby in Eclipse

by Nick Sieger-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jun 22, 2009 at 11:26 AM, Lagutko Nikolay <Nikolay.Lagutko@...> wrote:

Hi,

 

I have a problem with working with JRuby in Eclipse. If required scripts stored not in classpath directories but in other plugins JRuby cannot find them. As I see the problem in Equinox environment. When JRuby calculates path to required script it uses Equinox BundleClassLoader to load this script and it will return path to file in bundle-dependent format, for example

bundleresource://9/./some_script.rb

And in further calculations JRuby cannot correctly interpret this path. For example function File.expand_path will return “/./some_script” instead of full path “D:/path_to_plugin/some_script”.

 

I find out how to resolve this problem with using FileLocator class from org.eclipse.core.runtime plugin but I don’t want to have dependencies to other plugins in my org.jruby plugin.

 

Are there other ways to resolve this problem?

We'd rather not take on additional dependencies to custom classloader resource URLs and schemes either. Is there any standard JDK API that gives you what you want? By chance does the Eclipse API implement getSchemeSpecificPart or getFile in a sane way on the URL returned by ClassLoader.getResource?

/Nick


Re: Problms with JRuby in Eclipse

by Craig Taverner-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

This is my take on the problem - If we register a URL handler, it will handle all cases. And it will not require any changes to JRuby itself. Consider this scenario. The URL created looks like this:
bundleresource://9/./some_script.rb

This URL is being dealt with inside JRuby. When JRuby tries to access this URL using the usual approach of url.openConnection() or url.getContents(), the actual work is passed to the URL handler registered for the protocol returned by url.getProtocol() which is 'bundleresource'. When not in equinox, there will be no registered protocol handler, so these URL's are invalid and will not work, which is correct behaviour, as JRuby should have no knowledge of equinox. However, when inside equinox, the JVM search for a protocol handler for 'bundleresource' should succeed if the classloaders are correctly setup, as described in http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements.

Then what will happen is the JVM will pass the thread that called url.openConnection() to the equinox bundle URL handler, which will be able to understand what is meant by the '9'. So the trick here is:
  • Make sure that the 'bundleresource' protocol handler is in fact registered in an equinox environment, as I believe it must be. (I did a quick google search and found that the class should be org.eclipse.osgi.framework.internal.core.BundleURLConnection)
  • Make sure that code running in JRuby has the correct classloader arrangement to ensure that the JVM actually does find this URL handler. (This is probably the only trick here, and probably requires a combination of setting the context classloader on the thread starting JRuby, as well as appropriate buddy classloader settings on the plugins).
  • Make sure that the URL handler does understand the path, including the numerical references, like the '9' above. This should be the case, since this code should be part of equinox already (ie. org.eclipse.osgi.framework.internal.core.BundleURLConnection should just work).

So, my theory here is that all the code already exists, and this is mainly a classloader issue. A variation on the same classloader issue we have seen repeatedly in using JRuby in eclipse.

To learn more about protocol handlers, read http://java.sun.com/developer/onlineTraining/protocolhandlers/. This covers also how to write them, which I believe should not be necessary in this case. Hopefully you can find here the information necessary to investigate what protocol handlers exist in various contexts (different plugins, inside and outside the JRuby runtime, etc.) Then you can work out how to make sure the right handler does exist inside JRuby.

Does this make sense? Any comments?

Cheers, Craig

On Mon, Jun 22, 2009 at 7:40 PM, Nick Sieger <nicksieger@...> wrote:
On Mon, Jun 22, 2009 at 11:26 AM, Lagutko Nikolay <Nikolay.Lagutko@...> wrote:

Hi,

 

I have a problem with working with JRuby in Eclipse. If required scripts stored not in classpath directories but in other plugins JRuby cannot find them. As I see the problem in Equinox environment. When JRuby calculates path to required script it uses Equinox BundleClassLoader to load this script and it will return path to file in bundle-dependent format, for example

bundleresource://9/./some_script.rb

And in further calculations JRuby cannot correctly interpret this path. For example function File.expand_path will return “/./some_script” instead of full path “D:/path_to_plugin/some_script”.

 

I find out how to resolve this problem with using FileLocator class from org.eclipse.core.runtime plugin but I don’t want to have dependencies to other plugins in my org.jruby plugin.

 

Are there other ways to resolve this problem?

We'd rather not take on additional dependencies to custom classloader resource URLs and schemes either. Is there any standard JDK API that gives you what you want? By chance does the Eclipse API implement getSchemeSpecificPart or getFile in a sane way on the URL returned by ClassLoader.getResource?

/Nick



Re: Problms with JRuby in Eclipse

by Nick Sieger-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Jun 23, 2009 at 8:03 AM, Craig Taverner <craig@...> wrote:
Hi,

This is my take on the problem - If we register a URL handler, it will handle all cases. And it will not require any changes to JRuby itself. Consider this scenario. The URL created looks like this:

bundleresource://9/./some_script.rb

This URL is being dealt with inside JRuby. When JRuby tries to access this URL using the usual approach of url.openConnection() or url.getContents(), the actual work is passed to the URL handler registered for the protocol returned by url.getProtocol() which is 'bundleresource'. When not in equinox, there will be no registered protocol handler, so these URL's are invalid and will not work, which is correct behaviour, as JRuby should have no knowledge of equinox. However, when inside equinox, the JVM search for a protocol handler for 'bundleresource' should succeed if the classloaders are correctly setup, as described in http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements.

Then what will happen is the JVM will pass the thread that called url.openConnection() to the equinox bundle URL handler, which will be able to understand what is meant by the '9'. So the trick here is:
  • Make sure that the 'bundleresource' protocol handler is in fact registered in an equinox environment, as I believe it must be. (I did a quick google search and found that the class should be org.eclipse.osgi.framework.internal.core.BundleURLConnection)
  • Make sure that code running in JRuby has the correct classloader arrangement to ensure that the JVM actually does find this URL handler. (This is probably the only trick here, and probably requires a combination of setting the context classloader on the thread starting JRuby, as well as appropriate buddy classloader settings on the plugins).
  • Make sure that the URL handler does understand the path, including the numerical references, like the '9' above. This should be the case, since this code should be part of equinox already (ie. org.eclipse.osgi.framework.internal.core.BundleURLConnection should just work).

So, my theory here is that all the code already exists, and this is mainly a classloader issue. A variation on the same classloader issue we have seen repeatedly in using JRuby in eclipse.

To learn more about protocol handlers, read http://java.sun.com/developer/onlineTraining/protocolhandlers/. This covers also how to write them, which I believe should not be necessary in this case. Hopefully you can find here the information necessary to investigate what protocol handlers exist in various contexts (different plugins, inside and outside the JRuby runtime, etc.) Then you can work out how to make sure the right handler does exist inside JRuby.

Does this make sense? Any comments?
 

We're working with pathnames here, not contents, so we don't actually go so far as to open the URL or get its contents, so I'm not sure that what you're describing will actually work. I'd consider it an enhancement at this point to make something like "IO.readlines('bundleresource://9/./some_script.rb')" actually do what you expect (though note that this isn't the same problem that the OP mentioned).

Context classloader bugs in JRuby were fixed long ago, so I'm less suspect of that being the problem.

/Nick

Re: Problms with JRuby in Eclipse

by Craig Taverner-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Thanks Nick,

Your explanation certainly derails my previous 'theory' :-(

We're working with pathnames here, not contents, so we don't actually go so far as to open the URL or get its contents, so I'm not sure that what you're describing will actually work. I'd consider it an enhancement at this point to make something like "IO.readlines('bundleresource://9/./some_script.rb')" actually do what you expect (though note that this isn't the same problem that the OP mentioned).

I guess IO.readlines() expects a filepath, not a url spec. I wonder if a hack like providing an alternative implementation of IO.readlines() that will consider the parameter as a url spec will work? That should have no change to JRuby code, and only requires that we take the (dangerous?) approach of adding an alternative IO impl in our deployment. (dangerous = risk of breaking the conformance to the RubySpec)

Context classloader bugs in JRuby were fixed long ago, so I'm less suspect of that being the problem.

I'm sure you are right. However that does not rule out bugs in our plugins that create the JRuby. I think we still have to get our ducks in a row to make this work properly. I remember that last time I wrote JRuby startup code, I needed to set the context classloader in the current thread before starting the ruby runtime, otherwise none of the dependent plugins were visible to JRuby, so it seems there is stuff the developer needs to think about for this all to work.

Is there perhaps a wiki page or decent discussion on the JRuby Context classloader setup? I worked out the thread trick last year by reading JRuby code, but that does not mean I actually understood the details of what was going on. I think this is a tricky area and a decent writeup would be great.

I'm actually quite happy to do that writeup myself, if I can get some pointers to the right information, even if that is just the relevant bits of code in JRuby to look through.

Cheers, Craig




Re: Problms with JRuby in Eclipse

by Nick Sieger-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jun 25, 2009 at 4:04 AM, Craig Taverner<craig@...> wrote:

> Thanks Nick,
>
> Your explanation certainly derails my previous 'theory' :-(
>
>> We're working with pathnames here, not contents, so we don't actually go
>> so far as to open the URL or get its contents, so I'm not sure that what
>> you're describing will actually work. I'd consider it an enhancement at this
>> point to make something like
>> "IO.readlines('bundleresource://9/./some_script.rb')" actually do what you
>> expect (though note that this isn't the same problem that the OP mentioned).
>
> I guess IO.readlines() expects a filepath, not a url spec. I wonder if a
> hack like providing an alternative implementation of IO.readlines() that
> will consider the parameter as a url spec will work? That should have no
> change to JRuby code, and only requires that we take the (dangerous?)
> approach of adding an alternative IO impl in our deployment. (dangerous =
> risk of breaking the conformance to the RubySpec)

We've considered it. We may go in that direction, treating paths like
URLs where we can, either transparently or possibly activated by
requiring an additional JRuby-specific library (for precedent, see
Ruby's "open-uri" library). There are still common idioms in Ruby that
are still file-based that we can't easily generalize to URLs though
(e.g., "Dir[File.dirname(__FILE__) + '/submodules/*.rb].each {|f|
require f }").

>
>> Context classloader bugs in JRuby were fixed long ago, so I'm less suspect
>> of that being the problem.
>
> I'm sure you are right. However that does not rule out bugs in our plugins
> that create the JRuby. I think we still have to get our ducks in a row to
> make this work properly. I remember that last time I wrote JRuby startup
> code, I needed to set the context classloader in the current thread before
> starting the ruby runtime, otherwise none of the dependent plugins were
> visible to JRuby, so it seems there is stuff the developer needs to think
> about for this all to work.

If you can still find a case where this isn't working properly, let us
know. A search of JIRA shows a couple areas that have been fixed in
the past:

http://jira.codehaus.org/secure/IssueNavigator.jspa?reset=true&&query=classloader&summary=true&description=true&body=true&pid=11295

> Is there perhaps a wiki page or decent discussion on the JRuby Context
> classloader setup? I worked out the thread trick last year by reading JRuby
> code, but that does not mean I actually understood the details of what was
> going on. I think this is a tricky area and a decent writeup would be great.

This page has some information, and despite the mentions of 0.9.2
actually doesn't seem to be that out of date. It could use a refresh
though.

http://kenai.com/projects/jruby/pages/RequireAndLoadBehavior


> I'm actually quite happy to do that writeup myself, if I can get some
> pointers to the right information, even if that is just the relevant bits of
> code in JRuby to look through.

If you'd like to take on that task, I'd be happy to provide pointers!

Thanks,
/Nick

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Problms with JRuby in Eclipse

by Charles Oliver Nutter-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jun 22, 2009 at 11:26 AM, Lagutko
Nikolay<Nikolay.Lagutko@...> wrote:

> I have a problem with working with JRuby in Eclipse. If required scripts
> stored not in classpath directories but in other plugins JRuby cannot find
> them. As I see the problem in Equinox environment. When JRuby calculates
> path to required script it uses Equinox BundleClassLoader to load this
> script and it will return path to file in bundle-dependent format, for
> example
>
> bundleresource://9/./some_script.rb
>
> And in further calculations JRuby cannot correctly interpret this path. For
> example function File.expand_path will return “/./some_script” instead of
> full path “D:/path_to_plugin/some_script”.
>
>
>
> I find out how to resolve this problem with using FileLocator class from
> org.eclipse.core.runtime plugin but I don’t want to have dependencies to
> other plugins in my org.jruby plugin.

Well, given that bundleresource is an org.eclipse.core thing, I'm not
sure that the dependency on it is unreasonable. Obviously there's
nothing in standard JVM/JDK classes that knows how to convert
bundleresource://9/./ into D:/path_to_plugin, so you're already going
to need help.

Nick illustrated the other issues with using normal File APIs for
URLs. It may be that we can add more URL-aware behaviors into File/Dir
or we may consider writing a small URL library that acts like
IO/File/Dir instead.

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Problms with JRuby in Eclipse

by Craig Taverner-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Charles,

Thanks for the comments. Nikolay got it working with two small modifications to the method org.jruby.runtime.load.LoadService#findFileInClasspath. However, I think it should be possible to reverse those edits (and remove the dependency on eclipse from the JRuby code), by instead using the setLoadServiceCreator() method of RubyInstanceConfig to 'inject' the new code in at runtime. I've started prototyping this by creating my own implementation of org.jruby.runtime.load.LoadService which overrides the method 'findFileInClasspath' with the modified version that Nikolay developed which uses org.eclipse.core.runtime.FileLocator to rewrite the 'bundleresource' URL of any match found on the classpath into a normal 'file:' URL before loading. Then I propose that this gets injected into the Ruby runtime using code like:
      RubyInstanceConfig config = new RubyInstanceConfig() {{
          setLoadServiceCreator(new LoadServiceCreator() {
              public LoadService create(Ruby runtime) {
                  return new EclipseLoadService(runtime);
              }
          });
      }};
      Ruby runtime = Ruby.newInstance(config);

We've tested the FileLocator code directly in modified JRuby code, but have not yet removed it and tested with the new approach above. If it works, it represents a way to achieve what we need without modifying JRuby. One problem with this approach is that we duplicate the code of the 'findFileInClasspath' method, and if that changes with JRuby upgrades we have to notice that and incorporate the changes. The method is only about 50 lines long, but still. A more durable hack would be to have a hook in the findFileInClasspath method that calls a URL rewriter method, which has a default implementation in the JRuby code that simply returns the URL. Then we would only have to overwrite that method, instead of the whole 50 lines.

Cheers, Craig

On Wed, Jul 1, 2009 at 7:03 PM, Charles Oliver Nutter <headius@...> wrote:
On Mon, Jun 22, 2009 at 11:26 AM, Lagutko
Nikolay<Nikolay.Lagutko@...> wrote:
> I have a problem with working with JRuby in Eclipse. If required scripts
> stored not in classpath directories but in other plugins JRuby cannot find
> them. As I see the problem in Equinox environment. When JRuby calculates
> path to required script it uses Equinox BundleClassLoader to load this
> script and it will return path to file in bundle-dependent format, for
> example
>
> bundleresource://9/./some_script.rb
>
> And in further calculations JRuby cannot correctly interpret this path. For
> example function File.expand_path will return “/./some_script” instead of
> full path “D:/path_to_plugin/some_script”.
>
>
>
> I find out how to resolve this problem with using FileLocator class from
> org.eclipse.core.runtime plugin but I don’t want to have dependencies to
> other plugins in my org.jruby plugin.

Well, given that bundleresource is an org.eclipse.core thing, I'm not
sure that the dependency on it is unreasonable. Obviously there's
nothing in standard JVM/JDK classes that knows how to convert
bundleresource://9/./ into D:/path_to_plugin, so you're already going
to need help.

Nick illustrated the other issues with using normal File APIs for
URLs. It may be that we can add more URL-aware behaviors into File/Dir
or we may consider writing a small URL library that acts like
IO/File/Dir instead.

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

   http://xircles.codehaus.org/manage_email




Re: Problms with JRuby in Eclipse

by Charles Oliver Nutter-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Wed, Jul 1, 2009 at 6:03 PM, Craig Taverner<craig@...> wrote:

> We've tested the FileLocator code directly in modified JRuby code, but have
> not yet removed it and tested with the new approach above. If it works, it
> represents a way to achieve what we need without modifying JRuby. One
> problem with this approach is that we duplicate the code of the
> 'findFileInClasspath' method, and if that changes with JRuby upgrades we
> have to notice that and incorporate the changes. The method is only about 50
> lines long, but still. A more durable hack would be to have a hook in the
> findFileInClasspath method that calls a URL rewriter method, which has a
> default implementation in the JRuby code that simply returns the URL. Then
> we would only have to overwrite that method, instead of the whole 50 lines.

Well, that's a pretty good idea. We could certainly structure it that
way. LoadService needs more refactoring/cleanup in general, and
ideally I have always wanted it to either work more like classloading
does (cascading hierarchy of searches) or to allow simple registration
of lookup logic. That would allow you to add your own
classloader-based searches using specialized URL logic.

I'm really open to any suggestion here. Along with handling these
custom URLs, we would also like to be able to handle
resources-within-resources, which requires similar custom URL
handling. So a general approach is certainly needed.

If you want to mock up an idea or patch and stick it into a JIRA
"feature" bug, we could go from there and try to get it into JRuby
proper.

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email



Re: Problms with JRuby in Eclipse

by Craig Taverner-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Charles,

> lines long, but still. A more durable hack would be to have a hook in the
> findFileInClasspath method that calls a URL rewriter method, which has a
> default implementation in the JRuby code that simply returns the URL. Then
> we would only have to overwrite that method, instead of the whole 50 lines.

Well, that's a pretty good idea. We could certainly structure it that
way. LoadService needs more refactoring/cleanup in general, and
ideally I have always wanted it to either work more like classloading
does (cascading hierarchy of searches) or to allow simple registration
of lookup logic. That would allow you to add your own
classloader-based searches using specialized URL logic.

We've settled on a very simple solution that involves very little code change to JRuby, with one new protected method in LoadService that simply takes a URL and returns it. This method can be overridden in special environments, like equinox, to instead re-write the URL from equinox specific to more general (from using protocol 'bundleentry' to protocol 'file' or 'jar').

I'm really open to any suggestion here. Along with handling these
custom URLs, we would also like to be able to handle
resources-within-resources, which requires similar custom URL
handling. So a general approach is certainly needed.

Well, the current code will re-write 'bundleentry' to 'file' or 'jar', but we've not actually tested if the rest of the LoadService will handle 'jar'. I assumed it would. I can see support for loadingf scripts in jars, but have not traced all the code to be sure our fix actually enables that code. It certainly works in our un-jarred development environment, but in a deployed environment we might need to make a few further modifications.

If you want to mock up an idea or patch and stick it into a JIRA
"feature" bug, we could go from there and try to get it into JRuby
proper.

I think our current code is good enough to post to a JIRA 'feature' bug. Shall I go ahead and do that or would you prefer we've confirmed that it works in a jarred up deployment environment first?

Cheers, Craig


Re: Problms with JRuby in Eclipse

by Charles Oliver Nutter-4 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, Jul 14, 2009 at 5:08 PM, Craig Taverner<craig@...> wrote:
> I think our current code is good enough to post to a JIRA 'feature' bug.
> Shall I go ahead and do that or would you prefer we've confirmed that it
> works in a jarred up deployment environment first?

Why don't you go ahead and post it and mention that you're still
testing. Looking forward to seeing it!

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email