> On 16 Feb 2022, at 04:25, Peter Firmstone <peter.firmst...@zeus.net.au> wrote:
> 
> From the CodebaseAccessor service.
> 
> The CodebaseAccessor proxy (local code) is passed as a parameter along with a 
> MarshalledInstance of the proxy, by ProxySerializer to ProxyCodebaseSpi.
> 
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/export/CodebaseAccessor.java
>  
> <https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/export/CodebaseAccessor.java>

Ok, so you have introduced a level of indirection to retrieve String codebase 
annotations. Why not go one step further and instead of:

interface CodebaseAccessor {
  String getClassAnnotation() throws IOException;
}

have something along the lines of (conceptually):

interface Codebase extends RemoteMethodControl {
  ClassLoader getClassLoader() throws IOException;
}

The reasoning is:
In principle class annotation is a program in (unspecified) language that is 
executed by the client to create a ClassLoader instance.
You have to make sure all participants share this language and can execute it 
in the same way.
If the type of class annotation is String - it only means this is some kind of 
obscure interpreted scripting language.

The insight here is that we _already have_ the language that we _know_ all 
participants can execute: Java bytecode.
There is no reason not to use it.

>>> 
>> Ok, so the client has to know in advance how to load the service code?
> 
> Yes, the client knows how to load the service code dynamically just prior to 
> proxy unmarshalling, a default ProxyCodebaseSpi is provided for that purpose 
> and it is used by default.

See above:
you can move this code from the client to the service and let it provide the 
implementation of class resolution algorithm.

> 
> If you are using Maven, eg Rio Resolver, or OSGi, then a ProxyCodebaseSpi 
> implementation specific to one of these should be used.  If you have a mixed 
> environment, then you can use the codebase string to determine which to use.

See above: you can also abstract it away behind an interface.

> 
>>> 
>>>> Does it require to have it installed in advance? If so - how?
>>> 
>>> Only JGDMS platform and JERI.
>>> 
>>> 
>> How are service proxy classes loaded then?
> 
> ProxyCodebaseSpi::resolve does this by provisioning a ClassLoader then 
> unmarshalling the proxy into it.
> 
> OSGi:
> 
> https://github.com/pfirmstone/JGDMS/blob/a774a9141e6571f1d7f9771f74b714850d447d3e/JGDMS/jgdms-osgi-proxy-bundle-provider/src/main/java/org/apache/river/osgi/ProxyBundleProvider.java#L131
>  
> <https://github.com/pfirmstone/JGDMS/blob/a774a9141e6571f1d7f9771f74b714850d447d3e/JGDMS/jgdms-osgi-proxy-bundle-provider/src/main/java/org/apache/river/osgi/ProxyBundleProvider.java#L131>

[...]

> 
>> I am asking about something different - the smart proxy class depends on 
>> _two_ interfaces:
>> 
>> RemoteEventListener <—— proxy class ——> JavaSpace
>> 
>> RemoteEventListener is its service interface.
>> But it is not known in advance what interfaces the client already has:
>> 
>> 1) Just RemoteEventListener
>> 2) Both RemoteEventListener and JavaSpace
>> 3) None
>> 
>> How is class resolution implemented in JGDMS so that it works properly in 
>> _all_ of the above cases?
> 
> This is a responsibility of the underlying platform used for class resolution 
> or modularity.
> 
> If using OSGi, OSGi will resolve the required dependencies and download them 
> if not already present on the client, OSGi will give preference if a 
> compatible version of the bundle dependencies already loaded at the client.   
> If using preferred classes the preferred class list will determine the order 
> of preference, whether classes are loaded from the proxy codebase or the 
> client ClassLoader (the parent loader of the proxy ClassLoader) first.

I also tried this route and it is a dead end because

* it is not possible to statically (ie. as part of the software package like 
OSGi manifest) provide dependency resolution constraints to be able to exchange 
arbitrarily constructed object graphs *

Take for example the RemoteEventSpacePublisher class from my previous email:

interface RemoteEventListener {
}

package net.jini.space;
interface JavaSpace {
}

Bundle manifest:
Import-Package: net.jini.space;version=“[1.0,1.7)”

//implements JavaSpace up to version 1.7
class JavaSpaceImplProxy implements JavaSpace, Serializable {
}

Bundle manifest:
Import-Package: net.jini.space;version=“[1.5,2.0)”

//Requires JavaSpace of at least version 1.5
class RemoteEventSpacePublisher implements RemoteEventListener, Serializable {
  private JavaSpace space;
}


During deserialisation of RemoteEventSpacePublisher the resolution of a bundle 
containing JavaSpace interface has to result in a _single_ bundle that provides 
net.jini.space package obeying _two_ constraints:
Import-Package: net.jini.space;version=“[1.5,2.0)” - from 
RemoteEventSpacePublisher
Import-Package: net.jini.space;version=“[1.0,1.7)” - from JavaSpaceImplProxy

The problem  is that this information is not known to the client OSGi runtime:

1. It first resolves RemoteEventSpacePublisher annotation to a bundle wired to 
some bundle providing net.jini.space;version=“[1.5,2.0)”
2. After that it _separately_ resolves JavaSpaceImplProxy annotation to a 
bundle wired to _possibly different_ bundle providing 
net.jini.space;version=“[1.0,1.7)”

The reason is that when serialising the object graph in your solution you are 
loosing information about effective runtime constraints used for class 
resolution.
Your ProxyBundleProvider interprets codebase annotation as a path to a specific 
bundle - but it does not contain any information about this bundle wiring in 
the service VM.

> 
> If using Rio Resolver, it will downloaded any required dependencies 
> dynamically using Maven.

I am afraid it does not change anything.

> 
> https://github.com/pfirmstone/JGDMS/wiki/OSGi-and-JGDMS 
> <https://github.com/pfirmstone/JGDMS/wiki/OSGi-and-JGDMS>
> 
> What I learned from the many discussions and arguments on River mailing 
> lists, was that developers use different platforms to manage class resolution 
> visibility or provide modularity, so I considered it important not to 
> constrain developers and allow them to use their preferred platform, not to 
> decide for them.

The point is that _none_ of the existing platforms can handle it properly (see 
above).

Once you solve the problem of exchanging arbitrarily constructed object graphs 
of dynamically downloaded and resolved classes it opens up a whole lot of 
possibilities because you can quite easily model solutions as POJOs.

Cheers,
Michal

Reply via email to