After working in this area for too many years I’ve come to the conclusion that 
objects cannot be really transferred to other systems in a reliable way, only 
self typed data can. JPA, RMI, and many other systems promise heaven to the 
programmer that they can use their objects local and remote transparently. The 
consequence of this dream is a huge amount of complexity that far outweighs any 
gains in programmer friendliness. Few things have caused so much trauma in the 
software world as ORM. (Persistence is communications to a future process.)

The reason objects are so complex to use in communications is that it is in 
direct violation of the goal of OO to hide your data. However, once you expose 
the internal data on the wire you have effectively made it public but too many 
people they can still have the advantages of abstract data types. OSGi is a 
bitch in this case because it tells you that you’re trying to do something 
wrong by refusing to cooperate. In this case, it balks at you because you 
create an invisible dependency between the sender and the receiver. Though this 
is a good thing too often the receivers of this message blame the messenger.

You can handle this dependency but you’ll find out is that it is a hugely 
complex task that introduces a lot of frailty in the overall system. Having 
tried this several times I can assure you that any gains in programmer 
friendliness are dwarfed by the complexity of creating this facade.

The best solution I found is to give up on data hiding. The fact your objects 
is on the wire means that that wire format is public. I therefore use Data 
Transfer Objects, in my case objects with public fields. On both sides I have 
my own objects to provide behavior to this data with methods and classes but 
this data record is at the core of my code. Since this data is public because 
it goes over the wire it is better to wrap you code around that ‘standardized 
public’ object than to try you internal object data.

If you look at the OSGi specifications of the past 5 year then you will notice 
that all applicable APIs have been designed to be useful with Distributed OSGi. 
Calls do not pass objects but they pass DTOs back and forth. They do not rely 
that the receiver and sender have exactly the same type and version. In this 
model it is easy to replace an endpoint using another language, which is a 
really good sign.

For Java developers this is often an unpleasant message, and quite often OSGi 
get the blame. However, the fact OSGi gives you these problems means that 
you’re trying to do something that has hidden dependencies.

Distributed computing has 7 well known fallacies[1] but I strongly believe that 
there is an eighth: ’One can communicate objects over a network’.

Now your question. Yes, you could run a resolve and load the proper bundles but 
you introduce a huge amount of error cases and a large amount of complexity and 
you won’t solve the fundamental problem. 

Kind regards,

        Peter Kriens

[1]: https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing 
<https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing>


> On 20 Feb 2017, at 05:13, Peter <j...@zeus.net.au> wrote:
> 
> Hello,
> 
> I'm currently working on converting an existing application to OSGi.
> 
> This application has a network service architecture based on java interfaces. 
>  I've broken the application into modules, using a Maven build, which uses 
> bnd and bndtools to create bundle manifests.  Some of these modules are 
> ServiceLoader provider's, so I've used annotations to ensure these are loaded 
> into the OSGi service registry using the Service Loader Mediator.
> 
> The main issue that I face is this application is a networked application and 
> has it's own Remote Invocation protocols (which currently utilise Java 
> Serialization, but not Java RMI).  As you'll appreciate, class visiblity is a 
> little different in OSGi.  :)
> 
> The services mentioned above are remote services, these remote services have 
> a proxy which implements the service interface, these services are discovered 
> and installed at the client.  There are two types of proxy's, one, called a 
> smart proxy, requires a codebase from which to retrieve a jar or jar files 
> that are downloaded and installed at the cleint (traditionally during 
> deserialization),  the other type of proxy is called a dynamic proxy (it's 
> basically just an instance of java.lang.reflect.Proxy), which is dynamically 
> generated at the client.
> 
> The Service implementation is broken up into three components:
> 
>  1. The service api
>  2. The smart proxy (resolved and provisioned into in client jvm).
>  3. The server
> 
> The server bundle imports packages from the smart proxy bundle, while the 
> smart proxy imports packages from the service api as well as exporting it's 
> own packages, as required by the server bundle.
> 
> The server that provides the remote service has three bundles loaded; 
> server-impl, smart-proxy & service-api.
> 
> The client only has the service api bundle installed at deployment and the 
> smart proxy is resolved and provisioned before the service is made available 
> via the local OSGi service registry, where the client will learn of it's 
> existence using ServiceTracker.
> 
> At first glance only the smart proxy bundle needs to be provisioned at the 
> client, however for cases where a dynamic proxy is required to implement 
> interfaces from different packages, where class visibility issues may exist, 
> it may be beneficial in these cases to utilise and provision a proxy bundle 
> that imports all these interfaces, one might do that by taking advantage of 
> java's interface multiple inheritance; create a bundle that contains one 
> interface (annotated with @ProviderType) which extends all interfaces, which 
> the bundle doesn't export, so we ensure that the dynamic proxy has a proper 
> bundle manifest with all package imports and version ranges correctly defined.
> 
> The inbuilt remote invocation protocol has server and client endpoints, the 
> protocol is extensible and has a number of implementations (for example 
> https, http, tls, kerberos, tcp).   Each endpoint is assigned a ClassLoader 
> when it's created.
> 
> For classes installed at the client, these are typically installed in a 
> URLClassLoader, typically with the Application loader as parent loader.  In 
> an OSGi environment however, the smart proxy bundle will be installed at the 
> client, it's ClassLoader utilised by the client endpoint, the smart proxy 
> bundle will also be installed at the server and it's ClassLoader utilised by 
> the server endpoint.   In this case the visibility of the bundles at each 
> endpoint will be utilised to resolve serializable classes.    Private smart 
> proxy serializable classes will be resolvable at each end, but only public 
> classes from imported packages will be deserializable, since the client 
> interacts using the Service API, all serializable classes in the Service API 
> packages will need to be exported and public and imported by the client and 
> smart proxy.
> 
> Once a bundle has been provisioned its ClassLoader will be given to the 
> client endpoint and the marshalled state of the proxy unmarshalled into it.  
> At this point the service that the proxy provides would be registered with 
> the OSGi service registry for the client to discover and consume.  The smart 
> proxy communicates with it's server via an internal dynamic proxy 
> (java.lang.reflect.Proxy), it's used to invoke methods on the server.
> 
> While the existing protocol uses Java serialization, it doesn't use Java 
> serialization's method of resolving classes.  Java Serialization walks the 
> stack and finds the first non system classloader (looking for the application 
> ClassLoader).    The existing class resolution method isn't suitable for 
> OSGi, however the mechanism is extensible, so can be replaced with something 
> suitable.
> 
> 
> 
> Does anyone have any advise or experience utilising the OSGi Enterprise 
> Resolver Service Specification (chapter 136) and the OSGi Enterprise 
> Repository Service Specification (chapter 132) to resolve and provision a 
> bundle for the smart proxy at the client?
> 
> 
> 
> The intent here is the bundle manifests at each endpoint will be used to 
> determine class visiblity, so the resolution and provisioning process will be 
> of critical importance.
> 
> For anyone curios, the application is a fork of Apache River / Jini and I'm 
> experimenting with support for OSGi.  I'm also a committer and PMC member of 
> Apache River.  This isn't the old Jini we all know and love however, there 
> are some additional features that allow provisioning to occur using a feature 
> called delayed unmarshalling, so we can avoid the need for codebase 
> annotations and URLClassLoaders.
> 
> The work in progress can be found here, for anyone who's curious:
> 
> https://github.com/pfirmstone/JGDMS/tree/Maven_build/modularize/JGDMS
> 
> Regards,
> 
> Peter.
> 
> _______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org
> https://mail.osgi.org/mailman/listinfo/osgi-dev

_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to