Stanley M. Ho wrote:
Hi Bryan,

Bryan Atsatt wrote:
1. If a module's activator is executed before the module is fully
initialized, it can safely register something into some service lookup
mechanism in the system.
2. The service lookup mechanism will make sure the registered thing from
that module is not usable by other modules unless that module becomes
fully initialized.
3. If the module's activator fails to execute when the module is being
initialized, the module system knows how to work with the service lookup
mechanism to undo all the unregisterations automatically and correctly.

So do you expect that java.util.ServiceLoader will do this?

No. Actually, the way java.util.ServiceLoader looks up service-providers
is through the context classloader at runtime when a service is being
requested. Unlike other service lookup mechanisms, it is not necessary
to register service-providers with the java.util.ServiceLoader API at
all, so the module's activator won't be useful in this case.

The scenarios where using module's activator for registration might be
applicable are for those modules that want to register with other
service lookup mechanisms that are not based on java.util.ServiceLoader.

I agree that we shouldn't try to push a *service* mechanism into the
module layer.

But a generic *activator* certainly seems appropriate. Some modules will
need to perform initialization prior to use (e.g. process a config file,
check some environmental constraints, populate a JNDI context, etc,
etc). Successful initialization for such a module is then a
pre-condition for use, and any failure should be treated exactly as
seriously as a resolution failure.

The solution does not have to tie to the module state. I think what we
simply want is to support the use case that a module instance should not
be handed out unless certain initialization code is executed
successfully. As long as the API for obtaining such module instance
supports this semantic, it's orthogonal to how the module state changes
internally.

Yes, this *could* be done using the notification mechanism, but that
strikes me as a rather hackish approach. This use case is not limited to
"container" environments, so, IMO, should be made part of the spec.

I'm not aware of use cases which are not in the "container"
environments. Could you provide some examples?

I don't have a specific example in mind, but just consider libraries
targeted at SE that, before use, must:

- Validate a license key, or
- Establish a network connection, or
- Read a config file, or
- Validate the environment (e.g. java version, presence of some Class,
etc,), or
- Fork threads.

While these could all be done lazily, or with explicit calls by the
client, I've seen many cases of the "X must be initialized first"
problem. In my experience, many of these have been in the EE
environment, but only incidentally: some app bundles lib X, which itself
has no EE dependencies but must be initialized. I've seen many EE apps
that are configured with a servlet *only* so that they can get an init
call at startup!


And it seems like a rather small addition:

1. A simple interface that the module can implement, e.g.:

   interface ModuleActivator {
       public void start(Module module) throws Exception;
       public void release(Module module) throws Exception;
   }

2. An annotation to declare the activator impl name.

3. Module system instantiates and invokes activator (at end of
prep/validation or a new step). An exception here would put the module
into ERROR state.

Exactly what such an activator does is mostly irrelevant, though it
clearly cannot consume the thread; the usual precautions here should
suffice.

I also think that the API impact is small. However, because the module
system and the service lookup mechanisms are not integrated tightly
together, a not-yet-fully-initialized Module instance might be leaked
out to other service lookup callers after it is registered by the
ModuleActivator through the service lookup mechanism but before it is
fully initialized. Because of this, I don't think there is obvious
benefit to provide built-in support for ModuleActivator since the same
can be achieved using the notification mechanism, which we'll support
anyway.

You are coupling the ideas of activation and services; I'm explicitly
trying to de-couple them here. Yes, service registration could be done
by an activator, but I'm focused on the more general problem of module
*initialization*.

Maybe this would be clearer if we changed the interface name:

    interface ModuleInitializer {
        public void start(Module module) throws Exception;
        public void release(Module module) throws Exception;
    }

Seems to me that we can easily eliminate the leakage problem by:

1. Ensuring that initialization occurs before the module moves from
RESOLVED to READY state, and

2. Initialization failure moves the module to ERROR state, and

3. Module lifecycle events are only fired when the module enters either
READY or ERROR states (and STOPPING/STOPPED, if we add those).

If you intend to expose the states leading up to READY/ERROR as events,
then yes, leakage is a potential problem. We could get around this by
passing only the ModuleDefinition on these events, not the Module itself.



Another extreme approach is to design a very generic service lookup
mechanism that is tightly integrated with the module system, and also
requires all other service lookup mechanisms to be built on top of this
generic one (if these mechanisms are ever used in the module's
activator), so they will all provide the appropriate semantic w.r.t. the
module system and no uninitialized module instance would be leaked out
accidentally. That said, I don't think this is what we want to do. ;-)

Agreed.


- Stanley

Reply via email to