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