Deploying rails app on Glassfish v3 gives LinkageError on jdk6 u18, jruby 1.4.0

I am trying to deploy a simple rails app on glassfish v3 using jdk6 u18,
jruby 1.4.0 and it gives

/tools/jruby-1.4.0/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:271:in
require_frameworks': library socket’ could not be loaded:
java.lang.LinkageError: loader (instance of java/net/URLClassLoader):
attempted duplicate class definition for name:
“org/jruby/ext/socket/RubySocket” (RuntimeError)
from
/tools/jruby-1.4.0/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:134:in
process' from /tools/jruby-1.4.0/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:113:in run’
from /myhome/vivekmz/dev/depot/config/environment.rb:13
from /myhome/vivekmz/dev/depot/config/environment.rb:31:in `require’

My understanding of “LinkageError:attempted duplicate class definition
for
name:” tells that it might be the race condition in URLClassLoader that
might be causing this. For example, multiple threads are asking a
ClassLoader.findClass() to load a class and if findClass() is not
synchronized there is chance that one thread is already loaded the class
and
second thread’s call to ClassLoader.findClass() load the same class
resulting in to this error. I am not sure what fixes went in to jdk6 u18
thats causing it.

Another detail is that glassfish gem or webrick works just fine with it.
Its
only in the glassfish v3 server environment which has osgi runtime this
error happens. On glassfish side we will continue to investigate. Can
JRuby
experts shed some light on this kind of error and how JRuby loads rails?

Here is the reference to the discussion on glassfish forum:
Developer Community - Oracle Forums.

-vivek.

On Sat, Jan 16, 2010 at 4:05 PM, Vivek P. [email protected]
wrote:

I am trying to deploy a simple rails app on glassfish v3 using jdk6 u18,
jruby 1.4.0 and it gives
/tools/jruby-1.4.0/lib/ruby/gems/1.8/gems/rails-2.3.4/lib/initializer.rb:271:in
require_frameworks': library socket’ could not be loaded:
java.lang.LinkageError: loader (instance of  java/net/URLClassLoader):
attempted  duplicate class definition for name:
“org/jruby/ext/socket/RubySocket” (RuntimeError)

error happens. On glassfish side we will continue to investigate. Can JRuby
experts shed some light on this kind of error and how JRuby loads rails?
Here is the reference to the discussion on glassfish
forum:Â Developer Community - Oracle Forums.

Someone poked me on IRC about this too…I’m just as stumped. In
JRuby’s case, we are not using a URLClassLoader directly for loading
the socket subsystem. Instead, we are just using the classloader that
loaded org.jruby.Ruby and having it lazily load the socket stuff.
There’s nothing we’re doing wrong here as far as I can tell; simply
asking the parent classloader to load another class should not lead to
linkage errors.

Here’s the relevant code from JRuby:

In org.jruby.Ruby.initBuiltins:

    addLazyBuiltin("socket.jar", "socket",

“org.jruby.ext.socket.RubySocket$Service”);

addLazyBuiltin:

private void addLazyBuiltin(String name, String shortName, String

className) {
addBuiltinIfAllowed(name, new LateLoadingLibrary(shortName,
className, getClassLoader()));
}

getClassLoader:

public static ClassLoader getClassLoader() {
    // we try to get the classloader that loaded JRuby, falling

back on System
ClassLoader loader = Ruby.class.getClassLoader();
if (loader == null) {
loader = ClassLoader.getSystemClassLoader();
}

    return loader;
}

LateLoadingLibrary:

public class LateLoadingLibrary implements Library {
private final String libraryName;
private final String className;
private ClassLoader classLoader;

public LateLoadingLibrary(String libraryName, String className,

ClassLoader classLoader) {
this.libraryName = libraryName;
this.className = className;
this.classLoader = classLoader;
}

public synchronized void load(Ruby runtime, boolean wrap) throws

IOException {
LoadService.reflectedLoad(runtime, libraryName, className,
classLoader, wrap);
}

}

LoadService.reflectedLoad:

public static void reflectedLoad(Ruby runtime, String libraryName,

String className, ClassLoader classLoader, boolean wrap) {
try {
if (classLoader == null && Ruby.isSecurityRestricted()) {
classLoader = runtime.getInstanceConfig().getLoader();
}

        Library library = (Library)

classLoader.loadClass(className).newInstance();

        library.load(runtime, false);
    } catch (RaiseException re) {
        throw re;
    } catch (Throwable e) {
        if (runtime.getDebug().isTrue()) e.printStackTrace();
        throw runtime.newLoadError("library `" + libraryName + "'

could not be loaded: " + e);
}
}

Ultimately, it boils down to the equivalent of
org.jruby.Ruby.class.getClassLoader().loadClass(“org.jruby.ext.socket.RubySocket$Service”),
and the org.jruby.ext.socket.RubySocket$Service class just directly
references all the remaining classes. I don’t see what we could do to
fix this in JRuby :frowning:

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

On Sun, Jan 17, 2010 at 8:03 PM, Vivek P. [email protected]
wrote:

Thanks for the details! One question, where does socket.jar comes from? I
dont see it in jruby/lib directory.

socket.jar is just used as a builtin name; normally such builtins
would be on-disk and named .so, and MRI would load them dynamically.
In JRuby’s case, since they’re all in the same jar, we just register
them with our equivalent extension name pointing at the actual class
representing the service.

I debated having something a bit more explicit, but this works well
enough for now (and we need to map something to require ‘socket’, so
just swapping .so for .jar and loading it internally has worked fine).

JRuby container in glassfish loads JRuby using URLClassLoader and thats why
it appears in the stack trace.
I also trying to see how  Osgi and JDK6u18 interacts with this kind of
loading. Fact that everything works fine on jdk6u17 tells that something
must have changed in u18 thats causing this failure. I am running it by OSGi
folks in glassfish team to help me debug this.
Note that everything works fine on glassfish gem or webrick with jruby and
jdk6u18. Also, glassfish gem or webrick there is no OSGi.

Thanks Vivek, keep us posted if there’s any more information you need
or if there’s anything we need to fix.

  • Charlie

To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Thanks for the details! One question, where does socket.jar comes from?
I
dont see it in jruby/lib directory.

JRuby container in glassfish loads JRuby using URLClassLoader and thats
why
it appears in the stack trace.

I also trying to see how Osgi and JDK6u18 interacts with this kind of
loading. Fact that everything works fine on jdk6u17 tells that something
must have changed in u18 thats causing this failure. I am running it by
OSGi
folks in glassfish team to help me debug this.

Note that everything works fine on glassfish gem or webrick with jruby
and
jdk6u18. Also, glassfish gem or webrick there is no OSGi.

-vivek.

On Sun, Jan 17, 2010 at 3:08 PM, Charles Oliver N.