I was on a project using OSGi where some of the applications relied on removing 
and replacing modules.
Generally they replaced applications modules at the top with no dependencies 
into the module.
For example, in one application that dealt with RFID, it was common for new 
RFID clients to be introduced or modifications required to existing RFID 
clients (the technology was changing very quickly).
The handling of these clients was done with modules that could be swapped in as 
necessary.
There were well defined interfaces with various implementations for the 
different clients.

-----Original Message-----
From: Neil Bartlett [mailto:njbartl...@gmail.com] 
Sent: Friday, May 20, 2016 11:20 AM
To: Alan Bateman
Cc: jigsaw-dev
Subject: Re: Mutable modules


> On 20 May 2016, at 15:12, Alan Bateman <alan.bate...@oracle.com> wrote:
> 
> On 18/05/2016 22:47, David M. Lloyd wrote:
>> 
>> I mean in *our* current concept of a module, we can add/remove/modify the 
>> contents of a module (its "class path") at run time.  It is up to the user 
>> to ensure that doing so makes sense.
> I don't think I can relate to the use case. As you probably know then ZIP 
> files have historically had their central directory mapped into memory. 
> Removing or replacing a file that is memory mapped will likely lead to 
> processes accessing the mapped file to crash (SIGBUS usually). So if users 
> are really doing such hairy things they would need a lot of insight into what 
> is running and whether the file is opened before taking this risk.
> 

Mutable module graphs have an 18 year history in OSGi, so they are certainly 
practical, of course with certain limitations. The use cases are to allow 
runtime installation or upgrade of modules without shutting down an entire 
application. Such capabilities proved indispensable in OSGi’s original market 
of home gateways, and now in the IoT world.

They key point is that it is a cooperative mechanism. When a module is 
uninstalled in OSGi, a callback is sent to the module in question, and it is 
then responsible for safely cleaning up anything that it was doing. If it does 
so properly then the module, along with all of its loaded objects, their 
classes and the classloader, become available for garbage collection. When a 
module is updated, a new classloader is created for the new version. Therefore 
if a module fails to implement correct clean-up and is updated many times, you 
have a memory leak. This is inescapable… the JVM can no more force a module to 
unload then it can force a thread to stop, and we all know the dire 
consequences of calling Thread#stop().

In case of a dependency (module A imports a package from module B), when B is 
uninstalled then module A must be refreshed. This involves calling the shutdown 
callback on modules A and B, and then re-resolving A. That resolution will 
likely fail as it will not be able to import the required packaged (unless they 
are exported from somewhere else).

Obviously this model depends heavily on a 1-to-1 mapping of classloaders to 
modules, in common with the JBoss Module System as described previously by 
David Lloyd.

>> :
>> 
>> Our modules each correspond to their own class loader: so far so good, we 
>> can just have one Module per class loader.  Problem is that we support 
>> circularity, and also we support dependencies that go across module systems 
>> with isolated namespaces (basically, our module loaders are a higher order 
>> of the exact same concept of class loaders).
> If there are cyclic relationships between your modules then it will be 
> problematic. Do you see much of this? If you've read Alex's JavaOne slides 
> then you'll know that some of us like Kirk Knoernschild's book on Java 
> Application Architecture and section "4.4 Cyclic Dependencies - the Death 
> Knell" where he poses the question "Are Cycles Always Bad?". I don't want to 
> say too much on this topic here as it is listed as an open issue on the JSR 
> issues list.
> 

OSGi permits cyclical dependencies, but such cycles can only be resolved 
all-at-once. This is essentially why OSGi separates its resolution phase (i.e. 
solving all dependencies) from its activation phase. Modules involved in a 
cycle will not be GC’d until all of the modules in that cycle are uninstalled 
or refreshed.


>> 
>> Our modules support specifications including the content of the module 
>> ("resource loaders") and the dependencies of the module. At run time, custom 
>> ModuleLoader implementations can change the resource loader list and/or the 
>> dependency list at any time, causing the module to be relinked on the spot; 
>> the most useful aspect of this is the ability to incrementally deploy 
>> applications which may include circular dependencies. 
> Aside from cycles then what other use-cases do you have here? I read "change 
> the resource loader list" to mean that the set of resources in the module 
> changes, which is a bit weird if those resources are class files that have 
> already been loaded. Maybe there is dynamic code generation with class bytes 
> generated to the file system or into somewhere virtual? Or maybe these 
> resources are something else, data files? I'm just trying to understand what 
> you mean as we are using differently terminology.
> 
>> We also support delegating "fallback" class loading decisions to outside 
>> suppliers for dynamic class loading behavior (this was done to support a 
>> dynamic OSGi environment).  The ongoing integrity of the system is up to the 
>> party doing the relinking (the EE deployer or the OSGi resolver); most of 
>> the time it can reason about what is "safe" and what might cause system 
>> breakage (but still might be useful to do anyway).  These are the features 
>> we can't seem to support under Jigsaw, architecturally speaking.
> This sounds like class loader delegation to resolve types that are not in the 
> module.
> 
>> 
>> Specifically this includes (but is not limited to) changing the package set 
>> associated with a JDK module at run time, something that this native code 
>> block makes impossible.  Also the ability to dynamically change module 
>> dependencies is an essential ingredient to making this work.
> Suppose that module m has package p and p.C has been loaded. Are you saying 
> that you can drop package p from the module?
> 
> As things currently stand in JDK 9 then packages may be added to modules at 
> runtime, the main use case is the dynamic proxy to a public interface in a 
> non-exported packages. So I can relate to adding packages for code gen cases, 
> I'm less sure about a module starting out as an XML API and suddenly changing 
> into a JDBC driver. Do you really mean the same module instance?

Modules coming and going affects the state of the service registry. It’s true 
that an API module (say, one that exports a bunch of interfaces) does not often 
need to dynamically change, and when it does change it causes a substantial 
amount of churn in the dependency graph. But If a module that provides a 
service is dynamically updated then consumers of that service should 
immediately see the new service implementation. If the provider module does not 
export any packages then it cannot have an affect on the imports of other 
modules, so the resolution can be done entirely locally to that module.

We have found that the dynamics in the service registry are extremely valuable 
because service availability can be used to reflect the availability of the 
real-world resources that those services represent. So OSGi’s dynamics are 
about far more than just module updates. Indeed, my enterprise customers rarely 
perform runtime module updates but they do employ service dynamics heavily.


> 
>> 
>> In my view, architecturally speaking, most of the constraints imposed by the 
>> core module framework should be layer policy.  If the system's core module 
>> layer wants to maintain strict, static integrity, name constraints, version 
>> syntax and semantics, etc., that's fine, but why should all modules 
>> everywhere be forced to the same constraints?
> Using module names as an example, then it should be possible to develop a 
> module that is deployed on the application module path or instantiated in a 
> layer of modules that a container creates. The author of the module (that 
> chooses the name) isn't going to know in advance how the module is deployed. 
> I'm not even sure how such a module could be compiled or how anyone could 
> depend on it when the characters or format can vary like this. I see there is 
> an issue on the JSR issues list so I don't want to say any more on this topic.
> 
> 
>> There is no way that existing containers and class loading environments 
>> (other than, apparently, WebLogic) can conform to Jigsaw's constraints 
>> without losing functionality (and I'm trying hard to find ways to make it 
>> work).  This is where most of my raised issues are coming from.
> The module system imposes surprising few constraints.  If you are using your 
> own class loaders then the delegation needs to respect module readability, 
> something that should not be controversial.
> 
> However it is possible that you are still at the starting line because your 
> have a dependency graph with cycles and/or modules that don't have names that 
> can be expressed as a Java identifier, is that right?
> 

As a disclaimer, I am not involved with OSGi’s official effort to evaluate and 
integrate the Java 9 module system but I am interested in the subject. The 
biggest decision that needs to be made is whether to create a direct mapping of 
OSGi bundles to J9 modules, or to exist in parallel with it. To achieve the 
former, there seem to be four major problems that must be tackled:

1. Lack of extensibility in the module-info.java format for version, imports 
and other metadata; 2. No reflective access to non-exported packages — often 
needed for frameworks like dependency injectors; 3. No dependency cycles at the 
module level — this is not encouraged in OSGi but has never been forbidden 
because there was no need to. To forbid it now would be a 
backwards-incompatible change for us; 4. Lack of dynamics. Nothing in the 
currently published API for J9 modules suggests to me that we can support the 
refresh, update, uninstall or install operations.


Regards,
Neil

> 
>> 
>> All these problems seem surmountable to me, but it becomes substantially 
>> more difficult when it is necessary to report all of a module's packages to 
>> the module when it is created, since this information is now not easily 
>> changed.
> I'm surprised that this is an issue as module membership is critical to 
> access control.
> 
> -Alan.

Reply via email to