> On 16 Feb 2022, at 04:25, Peter Firmstone <[email protected]> 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