Different concepts was: Scopes

Daniel Latrémolière daniel.latremoliere at gmail.com
Sat Aug 18 11:48:01 PDT 2012


> On the other hand runtime containers like NetBeans, OSGi 4.3 as well as Jigsaw
> offer (in my opinion more flexible) solution to the problem. All of them provide
> a concept of "requires a service".:
On container (sharply for simplicity):

  * If Jigsaw is a runtime container, it does not know compile time,
    then does not need this scope in its descriptor, then it will have
    only one scope (good for me at runtime, cf. end).
  * If it is a aware of lifecycle of code, like compiling, it will need
    to accept all processes building bytecode, like direct bytecode
    generation (xsltc), or weaving (sometimes statically with JPA),
    source code generation and compilation (JAXB/XJC) then it will
    integrate with build process. Ant script for building can be complex
    and very customized then need sometimes multiple custom scopes,
    sometimes does not use even one standard javac compilation (xsltc).



On services vs. Ivy configurations:

Shortly, for me, services and Ivy configurations are not exclusive, they 
are only the two parts of solution (dynamic and static). At runtime, you 
can ask for implementations allowing dynamic cyclic dependencies with 
IoC. At build time, you avoid cyclic dependencies by having an explicit 
list of features needed and disallowing IoC.

More precisely, think services vs. Ivy configurations is a dynamic vs. 
static problem (slightly added with an Inversion of Control problem).

  * A service is mostly an execution problem (obtaining an instance of
    the service) with IoC (I name the service API and ask for
    implementations). His only static part is common API visible for
    producers and consumers.
  * An Ivy configuration is a build problem (providing a specific
    optional feature) directly (caller will list all features asked;
    there is no IoC).

Service is clearly more flexible with IoC than asking specific instance 
but can lead to code difficult to understand (binding provider-consumer 
difficult to understand/manage). It has much more module explosion 
(service API need his own small module at runtime, and possibly at build 
time to avoid cyclic dependencies when building).

For me, services in static modules would be good if they are used for a 
fully common contract defined externally between many sides using it 
without knowing the other parts. By example JavaEE is a contract with 
many providers (JavaEE servers) and many consumers (Webapps). You can 
deploy any JavaEE webapp on any JavaEE server (with hope and very good 
code). In this case, I clearly see JavaEE API as one module by itself, 
at build time (statically) and at execution time (dynamically), used by 
the two sides for communicating between them.

But many plugins systems are dissymetric: one product on one side, many 
products on the other side. By example, Eclipse or NetBeans have 
plugins, but only one Eclipse or one NetBeans (and no compatibility 
between Eclipse plugins and NetBeans plugins). In this case, I see the 
plugin API as an Ivy configuration of Eclipse/Netbeans plugin manager. A 
plugin always know its container (Netbeans or Eclipse respectively): it 
is not a common contract between code not knowing each other. The plugin 
API is only one artefact of module at build time (statically) but one 
module at execution time (dynamically). Each plugin have registered a 
static dependency to plugin API scope of Eclipse/NetBeans plugin manager.

In the two case, services can be used dynamically for finding instances 
implementing  (by examples all Eclipse/NetBeans plugins). On JavaEE, 
services are not applicable in current JavaEE-specific deployment.

> This means the system never carries "several cache implementations" - some of
> which would have to be excluded. One only depends on the hibernate API module
> and it is left up to the Jigsaw resolver[2] to provide at least one workable
> cache.
> [1] Actual style of the configuration in Jigsaw to be specified yet; but the
> need is clear, imho.
> [2] Configured by the overall application deployer, probably[1].
Exactly, Ivy configurations are useful when used at deployment time, not 
at execution time (it is only one classpath of artefacts). Yes, the need 
will be clear: how can I configure Jigsaw resolver if I want to deploy 
two webapps on my JavaEE server with different pluggable implementations 
(like strategies of cache, filesystems supported by VFS, etc.)? But it 
is important to see that this need is mostly defined at deployment time 
(not compilation, not execution).

NB: I think, that sometimes it will probably be simpler to write a 
simple deployment module with all deployment dependencies and some small 
code for explicitly binding providers and consumers (like Guava binder), 
registering all plugins allowed in their manager (like FileSystems). It 
can avoid nasty bugs created by not understood behaviour of automatic 
binding, automatic dependencies resolving (by example, when a new 
service provider come in module repository by a side effect of something 
unrelated specifically to the service, and introduce a hole in security 
with his new feature added in current environment).

---
Given I think this is important, I will add precision to something (with 
some refining of my problem).

When I have written that I understand one scope or multiple custom 
scopes but not two scopes (compilation and execution), you can see this 
as a semantic problem of "module" definition.

  * If you call module something with only one artefact (JAR by
    example), I will see only one scope for it: visible (or invisible)
    to module requiring it. This is typically the case for a runtime
    modularity container.
  * If you call module something with multiple artefacts (source,
    binary, etc.), multiples scopes/configurations, like Ivy, I will see
    various/custom scopes depending of its build process (source
    compiled, generated bytecode, weaved bytecode). This is typically
    the case of Ivy static modularity.

Fundamentally, this is only a problem of naming "module" each artefact 
in repository (dynamically) or each directory of repository containing 
artefacts (statically). The two definitions seems good for me, but one 
is for dynamic modularity, the other for static modularity, in my opinion.

Globally, my problem with compilation scope is probably in not 
understanding reasons of merging all facets of modularity in Jigsaw:

  * static part of modularity (repository of artefacts used/populated by
    build/deployment process, with multiple artefacts by static module)
    [Ivy-like].
  * dynamic part of modularity (ClassLoader used at runtime for loading
    code, with one artefact by dynamic module) [classpath on steroids].

Dynamic modularity is only one user of static modularity (with javac, 
javadoc, IDE, etc.). By example a java compiler need only signature of 
methods, etc. in dependencies for making his job: it can obtain this 
without loading bytecode in JVM; by example, ASM is sufficient for 
visiting classes.

Finally, for me a dynamic module can simply be an artefact of a static 
module. A static module is a directory containing many artefacts, 
including some dynamic modules, but potentially also source code or many 
other published files (XSD schema, etc.), sometimes deployed and used on 
a JVM (by example a schema used for validating XML), sometimes not 
deployed by administrator/creator of application. Static and Dynamic 
modularity need, for me, to be seen as separate problems (even with 
different definitions of "module").

Thank you, if you attained this line!
Daniel.



More information about the jigsaw-dev mailing list