Discussion:
Using an interface between two dl'ed applications
Calum Shaw-Mackay
2009-01-19 10:55:20 UTC
Permalink
Given a system 'A' that allows objects 'B' and 'C' to be deployed to
it, where 'C' has an interface dependency on 'B'. Also 'B' and 'C" are
independently deployed, with potentially different codebases, but with
the same interface definition (compiled) in each.

When 'C' requests access to 'B' via a dynamic proxy generated from the
Interface declared in 'B's codebase, I get a ClassNotFoundException,
I'm assuming that this is because B's classes are being declared in a
different classloader to 'C's.

Is there any way to get around this - any particular usage of
PREFERRED.LIST?

Cheers

Calum

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Calum Shaw-Mackay
2009-01-19 13:49:16 UTC
Permalink
Okay to make things clearer

System 'A' is a container of sorts, Object 'B' is a component that
Object C (the caller) wishes to utilise and conenct with at runtime

Both the component and the caller are deployed into system A via a
JINI service call (lets call it 'deploy()'), they are
deployed separately in two separate deploy() calls

The component 'B' implements an interface that the caller 'C' is aware
of and has a compile time dependency on.

To call the component, the caller obtains the component through a call
to the container. For the sake of security and transparency, the
container returns a dynamic proxy (j.l.r.proxy) that implements the
required interface (it extracts this interface from the full
definition of the component 'B', before sending it back to the caller
'C'.

The point that I'm making is that both 'B' and 'C' were created in
separate calls, and potentially separate classloaders, meaning that
the definition of the interface used by 'B' and that used by 'C' will
be marked as being different because the class is not sourced from a
the same single classloader when used/linked to by 'B' and 'C'

To be clear, this is not cross JVM as such - both B and C are in the
same JVM, but are deployed via separate remote calls into the JVM....
this can be of course solved by placing the interface on the classpath
of the container, but this is not a desirable way for me to go

Calum
On Mon, Jan 19, 2009 at 11:55 AM, Calum Shaw-Mackay
Post by Calum Shaw-Mackay
Given a system 'A' that allows objects 'B' and 'C' to be deployed
to it,
where 'C' has an interface dependency on 'B'. Also 'B' and 'C" are
independently deployed, with potentially different codebases, but
with the
same interface definition (compiled) in each.
When 'C' requests access to 'B' via a dynamic proxy generated from the
Interface declared in 'B's codebase, I get a
ClassNotFoundException, I'm
assuming that this is because B's classes are being declared in a
different
classloader to 'C's.
Are you talking a java.lang.reflect.Proxy, bytecode generated one or
something else?
I am not sure what you mean by "declared in different classloader to
C's". Is it in the same JVM? Otherwise, why do you mention it? (I know
you are not a novice... :-) )
If we are talking j.l.r.Proxy, is the InvocationHandler in B
serializable and its classes available to C? In JRMP, there is
explicit support for j.l.r.Proxy since it is not straight forward. The
Proxy from B should be reconstructed at JRMP level from the interface
classes and invocationhandler instance received from B using the RMI
Classloader in C for B's codebase.
Cheers
Niclas
--
http://www.qi4j.org - New Energy for Java
--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Niclas Hedhman
2009-01-19 15:14:08 UTC
Permalink
On Mon, Jan 19, 2009 at 2:49 PM, Calum Shaw-Mackay
Post by Calum Shaw-Mackay
Okay to make things clearer
Thanks.
Post by Calum Shaw-Mackay
System 'A' is a container of sorts, Object 'B' is a component that Object C
(the caller) wishes to utilise and conenct with at runtime
Well, a lot depends on what the "Container of Sorts" really do.

It definitely looks like the classes will end up in separate
classloader, hence be perceived different. AFAICT, you are out of
luck, unless you can dig up some cool feature in the container. What
container are we talking about?
But hold on a second, if the container passes an instance from B to C,
then there should not be much classloading involved. You should more
likely get a ClassCastException. Weird.

One way you should get this to work would be a reflective bridge,
which is a lot more effective than networked communications. In
essence;

Create in C a dynamic proxy implementing Interface, whose invocation
handler has a reference to the object retrieved from B, and the
InvHandler do

public Object invoke( Object proxy, Method m, Object[] args )
{
Method m2 = b.getMethod( m.getName(), m.getArgumentTypes() );
return m.invoke( b, m2, args );
}

but you will still have problems if any arguments are other shared types.


Cheers
--
http://www.qi4j.org - New Energy for Java
--
http://www.qi4j.org - New Energy for Java

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Gregg Wonderly
2009-01-19 16:23:10 UTC
Permalink
Post by Calum Shaw-Mackay
The point that I'm making is that both 'B' and 'C' were created in
separate calls, and potentially separate classloaders, meaning that the
definition of the interface used by 'B' and that used by 'C' will be
marked as being different because the class is not sourced from a the
same single classloader when used/linked to by 'B' and 'C'
To be clear, this is not cross JVM as such - both B and C are in the
same JVM, but are deployed via separate remote calls into the JVM....
this can be of course solved by placing the interface on the classpath
of the container, but this is not a desirable way for me to go
So it sounds like your invocation handler needs to reactivate the context class
loader to be getClass().getClassLoader() so that any calls out of a particular
dynamic proxy are exposing the correct class loader.

Gregg Wonderly

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Niclas Hedhman
2009-01-19 13:33:44 UTC
Permalink
On Mon, Jan 19, 2009 at 11:55 AM, Calum Shaw-Mackay
Given a system 'A' that allows objects 'B' and 'C' to be deployed to it,
where 'C' has an interface dependency on 'B'. Also 'B' and 'C" are
independently deployed, with potentially different codebases, but with the
same interface definition (compiled) in each.
When 'C' requests access to 'B' via a dynamic proxy generated from the
Interface declared in 'B's codebase, I get a ClassNotFoundException, I'm
assuming that this is because B's classes are being declared in a different
classloader to 'C's.
Are you talking a java.lang.reflect.Proxy, bytecode generated one or
something else?
I am not sure what you mean by "declared in different classloader to
C's". Is it in the same JVM? Otherwise, why do you mention it? (I know
you are not a novice... :-) )

If we are talking j.l.r.Proxy, is the InvocationHandler in B
serializable and its classes available to C? In JRMP, there is
explicit support for j.l.r.Proxy since it is not straight forward. The
Proxy from B should be reconstructed at JRMP level from the interface
classes and invocationhandler instance received from B using the RMI
Classloader in C for B's codebase.


Cheers
Niclas
--
http://www.qi4j.org - New Energy for Java

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Gregg Wonderly
2009-01-19 16:19:46 UTC
Permalink
Given a system 'A' that allows objects 'B' and 'C' to be deployed to it,
where 'C' has an interface dependency on 'B'. Also 'B' and 'C" are
independently deployed, with potentially different codebases, but with
the same interface definition (compiled) in each.
When 'C' requests access to 'B' via a dynamic proxy generated from the
Interface declared in 'B's codebase, I get a ClassNotFoundException, I'm
assuming that this is because B's classes are being declared in a
different classloader to 'C's.
Is there any way to get around this - any particular usage of
PREFERRED.LIST?
The standard java URLClassLoader (or when you have no PREFERRED.LIST) provides
the most often correct handing for interfaces by looking up the classloader
chain for resolution before loading locally.

PREFERRED.LIST allows you to say "use my downloaded version always", and in
general solves the "class compatibility" issue by allowing a new version of a
class to be downloaded and used in preference to the version that might already
exist in the classloader tree.

Without more information, I'd suggest that perhaps this is more likely a context
class loader issue. The thread of execution that C was loaded in, is not the
same thread of execution that B is loaded in and B's context class loader is
used to resolve the interface and it sees the A parent instead of the C context
class loader (the PreferredClassLoader that loaded C).

Something like this

A->C->load interface with C classloader
A->B->load interface with B classloader

So, if the interface is not visible in the "A" class loader, than you must force
the path to be A->C->B so that the interface is loaded from C.

Gregg Wonderly

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Dennis Reedy
2009-01-19 17:06:25 UTC
Permalink
Before 'C' wants to use 'B', make sure that 'B' is loaded by 'C''s
context classloader. One way to make this happen is to:

B = new MarshalledObject(B).get();

That way your interface will get loaded correctly
Post by Gregg Wonderly
Post by Calum Shaw-Mackay
Given a system 'A' that allows objects 'B' and 'C' to be deployed
to it, where 'C' has an interface dependency on 'B'. Also 'B' and
'C" are independently deployed, with potentially different
codebases, but with the same interface definition (compiled) in each.
When 'C' requests access to 'B' via a dynamic proxy generated from
the Interface declared in 'B's codebase, I get a
ClassNotFoundException, I'm assuming that this is because B's
classes are being declared in a different classloader to 'C's.
Is there any way to get around this - any particular usage of
PREFERRED.LIST?
The standard java URLClassLoader (or when you have no
PREFERRED.LIST) provides the most often correct handing for
interfaces by looking up the classloader chain for resolution before
loading locally.
PREFERRED.LIST allows you to say "use my downloaded version always",
and in general solves the "class compatibility" issue by allowing a
new version of a class to be downloaded and used in preference to
the version that might already exist in the classloader tree.
Without more information, I'd suggest that perhaps this is more
likely a context class loader issue. The thread of execution that C
was loaded in, is not the same thread of execution that B is loaded
in and B's context class loader is used to resolve the interface and
it sees the A parent instead of the C context class loader (the
PreferredClassLoader that loaded C).
Something like this
A->C->load interface with C classloader
A->B->load interface with B classloader
So, if the interface is not visible in the "A" class loader, than
you must force the path to be A->C->B so that the interface is
loaded from C.
Gregg Wonderly
--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Gregg Wonderly
2009-01-19 20:29:09 UTC
Permalink
Post by Dennis Reedy
Before 'C' wants to use 'B', make sure that 'B' is loaded by 'C''s
B = new MarshalledObject(B).get();
That way your interface will get loaded correctly
I haven't had to go down this path before. As long as everything in that object
can resolve in the active class loader(s), you get what you need!

Gregg Wonderly

--------------------------------------------------------------------------
Getting Started: http://www.jini.org/wiki/Category:Getting_Started
Community Web Site: http://jini.org
jini-users Archive: http://archives.java.sun.com/archives/jini-users.html
Unsubscribing: email "signoff JINI-USERS" to ***@java.sun.com
Loading...