Re: Module system notification mechanism
At 20:35 20/07/2007, Gordon Hirsch wrote: So I'm strongly in favor of the suggested lifecycle hooks. aol me too /aol andy Notice: This email message, together with any attachments, may contain information of BEA Systems, Inc., its subsidiaries and affiliated entities, that may be confidential, proprietary, copyrighted and/or legally privileged, and is intended solely for the use of the individual or entity named in this message. If you are not the intended recipient, and have received this message in error, please immediately return this by email and then delete it.
Re: Module system notification mechanism
Hi Bryan, Bryan Atsatt wrote: Um, I'm not arguing about the restriction in custom import policies, I certainly understand why that is present. I'm saying that an initializer *should* be able to rely on imported modules, so we need a separate mechanism. And that separate mechanism would kick in *after* resolution/validation had completed. And yes, there is potentially a pathological case even here, if two initializers have cyclic dependencies (not the Class kind ;^), but... Seems to me that this has to be discovered and eliminated in development; this is a variation on the order of static initialization problem, and one that we can't solve here. I think we agreed that in the presence of circular dependencies a module cannot rely on its initializer being called before other code in the module is called. The problem is that a module may not know if it is part of a cyclic dependency chain because that depends on its imports, their imports, etc. I don't think we can assume that this is a pathological case that never occurs in the real world. If a module cannot rely on its initializer to access other modules safely or in the right order, then it is unclear to me if such support would be very useful in practice. Instead, a module could rely on the existing custom import policy or alternatively on other measures, for example explicit checks in the code or infrastructure provided by the container. Are you just suggesting that we add start()/refresh() type methods to ImportPolicy, rather than invent a new class/annotation? And that we might then want to rename this class? For example, rename ImportPolicy to ModuleInitializer, and add to it: public abstract class ModuleInitializer { public abstract ListModuleDefinition getImports(...); public abstract void initialize(Module) throws Exception; public abstract void release(Module); } If so, I'm OK with that approach as long as the class loading restrictions during getImports() are made clear and the module state at initialize() is clearly specified. I'm fine with changing the name of the ImportPolicy class into ModuleInitializer if it makes things more obvious to developers. I think what you suggested is not unreasonable, but I want to make sure this is something we really need to support, especially outside the container environments. Specifically, I'm not yet convinced we should provide an initialize() method that allows access to the imported modules (excluding the standard SE modules) because of the potential problems. Could you provide use cases for this outside a container environment? It is also unclear to me if providing the release() method would be useful outside a container environment as well. As I hinted before, you probably want to do the clean up in the finalizer or something similar when nobody uses the module instance anymore, rather than when the module instance is released from the module system while other existing users could still access it. - Stanley
Re: Module system notification mechanism
Hi Bryan, Bryan Atsatt wrote: Custom import policies cannot leverage any other modules; this would be a severe limitation for an initialization mechanism. There are good reasons why there is such restriction. When the module is being initialized, its imported modules might also be in the process of initialization. If one module accesses another module while both are in the middle of initialization, the result could be problematic. Also, suppose two modules have cyclic dependencies and each has its own initializer, what happens when an initializer is called in one module and that initializer wants to access the other module, while the other module's initializer wants to do the same? We could either prevent this from happening by saying the initializer could only access code in the standard SE modules and the code within its own module, or we could say that the initializer could access the module itself and all its imported modules - but developers need to be aware that there is a possibility that the imported module is only half-initialized when it is called by the importer's initializer. The latter could be very error-prone, and I'm not sure how useful it is to provide it to the developers. On the other hand, if we restrict which modules the initializer could access, then the initializer is not much different from the custom import policy - it's still a piece of code that is executed during module initialization, and exception would cause the module initialization to fail. In fact, the custom import policy was called ModuleInitializer in the original JSR 277 strawman, and the intention is to allow a module to do everything it needs to initialize itself properly. - Stanley
Re: Module system notification mechanism
(Sorry, somehow this message got marked read and I only just now saw it.) Comments inline. Stanley M. Ho wrote: Bryan Atsatt wrote: Stanley, I assume you are proposing a general mechanism in which any code can register listeners? If so, then I have to agree with Glyn that this is not sufficient to implement a module activator. The mechanism I have in mind can be registered only by code that have the appropriate security permissions, and untrusted code in the sandbox won't be able to listen to the notification. I am still a bit puzzled by why the module's state needs to be coupled directly to the result from the module's activator because this looks to me more like a solution to a problem than a requirement. For that model to work, I think there are couple underlying assumptions, but they might not be valid in our case: 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? In this case, the module system probably needs to be highly integrated with the service lookup mechanism, and that mechanism should be the only one used by all the modules' activators. However, in practice, multiple service lookup mechanisms exist and can be used in the Java platform, and I don't think we should expect the module system will know how to work with these arbitrary mechanisms to provide the suggested module's state semantic in conjunction with the module's activator. Also, from our previous discussions, I think our consensus is to avoid pushing the service mechanism down to the module layer if possible. 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. 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. 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. // Bryan
Re: Module system notification mechanism
Bryan Atsatt wrote: Stanley, I assume you are proposing a general mechanism in which any code can register listeners? If so, then I have to agree with Glyn that this is not sufficient to implement a module activator. The mechanism I have in mind can be registered only by code that have the appropriate security permissions, and untrusted code in the sandbox won't be able to listen to the notification. I am still a bit puzzled by why the module's state needs to be coupled directly to the result from the module's activator because this looks to me more like a solution to a problem than a requirement. For that model to work, I think there are couple underlying assumptions, but they might not be valid in our case: 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. In this case, the module system probably needs to be highly integrated with the service lookup mechanism, and that mechanism should be the only one used by all the modules' activators. However, in practice, multiple service lookup mechanisms exist and can be used in the Java platform, and I don't think we should expect the module system will know how to work with these arbitrary mechanisms to provide the suggested module's state semantic in conjunction with the module's activator. Also, from our previous discussions, I think our consensus is to avoid pushing the service mechanism down to the module layer if possible. If the use case is that the module's activator should be called by the container when the module is fully initialized or is released, the notification mechanism should be sufficient for this purpose. If the use case is that a module instance should be released if its module's activator fails to start, the notification mechanism should still be sufficient, assuming the container will call ModuleSystem.releaseModule() after the container has received the module initialized notification but fails to start the activator. (Yes, there are side effects with releaseModule() as we discussed before, but it's a problem the container can probably deal with.) Is there any other use case that you think is important to consider but not allowed by this notification mechanism? - Stanley
Re: Module system notification mechanism
Hi Glyn, Glyn Normington wrote: Yes, but my point was that separating lifecycle out in that way would make it harder to enforce constraints like if a module's state is initialised, the module's activator completed successfully. The mechanism I suggested is simply for informing the application that something has happened. This is a notification only and does not change the state of the module system in any way. If we want to enforce constraints like you mentioned, one approach is to execute the activator code in the custom import policy. If this is not sufficient, then we'll probably need a different mechanism to handle this use case. - Stanley