Hi gain :) On Wed, Oct 5, 2011 at 2:26 PM, Marcel Offermans <[email protected]> wrote: > Hello Bram, > > On Oct 5, 2011, at 1:36 PM, Bram de Kruijff wrote: > >> 2011/10/4 Marcel Offermans <[email protected]>: >>> Hello Bram, >>> On Oct 4, 2011, at 9:06 PM, Bram de Kruijff wrote: >>> >>> On Tue, Oct 4, 2011 at 2:40 PM, Marcel Offermans >>> <[email protected]> wrote: >>> >>> Summarizing, I hope we can agree that: >>> >>> a) ultimately, a multi-container model is what we aim for >>> >>> yup >>> >>> b) for now, we need to carefully plan a migration strategy >>> >>> I have no clue how to do this (make it optional) in a non >>> multi-container model. Do you have an idea? >>> >>> Yes. Let's start with the assumption that our service implementations are >>> POJOs, that implement some service interface (I left out the import >>> statements on purpose): >>> package api; >>> public interface MyService { >>> } >>> package impl; >>> public class MyServiceImpl implements MyService { >>> } >>> The OSGi "glue" we need to make this work is: >>> package impl.osgi; >>> public class Activator extends DependencyActivatorBase { >>> public void init(BundleContext context, DependencyManager manager) throws >>> Exception { >>> manager.add(createComponent() >>> .setInterface(MyService.class.getName(), null) >>> .setImplementation(MyServiceImpl.class) >>> ); >>> } >>> public void destroy(BundleContext context, DependencyManager manager) throws >>> Exception { >>> } >>> } >>> Now in general, our tenant aware version of this service uses a different >>> activator (because it's based on an adapter) and the POJO is slightly >>> extended with a bit of extra code (we could even argue here that this code >>> does not belong in the POJO at all, but I'll leave that for now). So we get >>> an implementation that looks like this: >>> package impl.tenant; >>> public class MyServiceTenantImpl extends MyServiceImpl { >>> volatile Tenant m_tenant; >>> >>> public void init(Component component) { >>> >>> // setup tenant specific dependencies and code here >>> } >>> } >>> The code in the init method usually adds dependencies to the component, and >>> bases them on the injected Tenant. Finally, our activator looks like this: >>> package impl.tenant.osgi; >>> public class Activator extends DependencyActivatorBase { >>> public void init(BundleContext context, DependencyManager manager) throws >>> Exception { >>> manager.add(createAdapterService(Tenant.class, null) >>> .setInterface(MyService.class.getName(), null) >>> .setImplementation(MyServiceTenantImpl.class) >>> ); >>> } >>> public void destroy(BundleContext context, DependencyManager manager) throws >>> Exception { >>> } >>> } >>> So now we have all the code we need to create both alternatives, and we >>> could package this as two separate bundles. One is completely unaware of >>> tenants, and can therefore be used in any OSGi container. The other uses our >>> current tenant model and is very similar to what we have now. My gut feeling >>> is that 95% of the work will go into MyServiceImpl where maybe the only >>> location where we might have a bit of duplication is in the definition of >>> the dependencies (which for the tenant aware service will be in the init and >>> for the tenant unaware one be in the Activator). >> >> The notion of seperating osgi/dm plumbing from the pojo is something >> I'd really like! Using inheritance and being forced to manage seperate >> artifacts not so much. > > The inheritance part is quite easy to fix. That was a shortcut I took to not > complicate the first attempt at a solution too much. More below... > > The separate artifacts are a different case. If I do not want tenant support, > I ideally do not want to depend on any form of tenant API as well. That means > making those imports optional, and dealing with class not found in several > locations. Even that is something we can do, provided we can agree that the > POJO cannot use the Tenant either (which, again, it might not need if we can > separate the plumbing from the implementation better). > >> Two thoughts: >> >> 1) The DM adaptor is part of the problem as it has a fixed strategy. I >> could do the work myself with a custom factory component that can have >> multiple strategies based on <any condition> like configuration, >> system property or whatever. Eg. >> >> {code} >> class MyServiceFactoryImpl implements MyServiceFactory { >> void init(Component component){ >> if(m_strategy == Strategy.ADAPTOR) >> // start tracking services >> } >> void start(Component component){ >> if(m_strategy == Strategy.SINGLETON) >> // create/configure new MyService singleton >> } >> void stop(Component component){ >> // remove MyService instances >> } >> void serviceAdded(ServiceReference ref){ >> // create/configure new MyService instance >> } >> void serviceRemoved(ServiceReference ref){ >> // removed new MyService instance >> } >> } >> {code} >> >> Now I have one implementation that can do both. Not sure if we could >> internalize this in DM? With some fancy generics and a base factory >> the default case would be simple. > > The generics are out, as DM should be able to run on the OSGi minimum > execution environment (subset of Java 1.4). > > This idea, in a slightly different form, is possible. What is happening is > that the init/start/stop/destroy life cycle methods are being used to "setup > dependencies" which effectively is plumbing and does not belong in the POJO. > If you want to use these life cycle methods for purposes like this, it is > possible to define an instance that is being invoked whenever the DM wants to > invoke a life cycle method on an instance (see > Component.setCallback(instance, init, start, stop, destroy)). This "callback > handler" can do something like this: > > class Handler { > public void init(Component c) { > // setup dependencies for c > // maybe even invoke an init method on the instance belonging to c, maybe > not > } > // etc... > }
True, but I think I remember this does not cover the updated() for configurationDependecies yet or am I confused? I'll have to try it out. > Solving the optional import requires some more code and thought, as does > coming up with a "smart" activator that can automatically detect if tenants > are available and/or required or not. > > I'm still not convinced if it makes sense to try to integrate the two into > one artifact, especially if we eventually aim to go for a different tenant > implementation anyway. I can see it work both ways. I'm under the assmption that must mt services will have the import anyway as they do something with the Tenant. >> 2) Using the DM is still invasive in that I still have an >> init(component c) in my POJO service for all but the simplest cases. > > Solved with the solution above. > >> Again I think the factory could help in it where allowed to handle the >> DM callbacks/lifecycle. This is kind of similar to what I requested >> for configuration at https://issues.apache.org/jira/browse/FELIX-2706. >> It kind of like DS I guess. > > OSGi defines this as a compendium service, which your POJO implements just > like any other service. If you look at it from that point of view, why bother > hiding it? But I can see what you mean and I think with a bit of code you can > probably either write a "different" configuration dependency that does allow > callbacks, or extend the current one to support an optional callback instance > to validate the configuration. The question still rempains: what if your > configuration *is* needed as part of your business logic and not just for > plumbing? > >> Obviously, you will still have the <adapted class> compile dependency >> even if you don't use the adapter strategy... > > See above, that would have to become an optional import in such a scenario. > > Summarizing: > > Trying to keep all plumbing out of the POJO makes a lot of sense. If needed I > will even extend support for that (I know there's some donation coming in > this area). > > Trying to create one artifact, with optional imports and logic to deal with > both cases still does not make a lot of sense to me when I look at where we > want to go in the future. I would prefer to keep both artifacts separated, > let the user decide which one he wants to use, and in the future, deprecate > one of them. Guess that could work for me! Guess we just have try and implement it a couple of time. Unsure how hard it is to write POJO services that can act both single and multi tenant. Think we need to write some of this stuff down in guidelines. Regards, Bram > Greetings, Marcel > > > _______________________________________________ > Amdatu-developers mailing list > [email protected] > http://lists.amdatu.org/mailman/listinfo/amdatu-developers > _______________________________________________ Amdatu-developers mailing list [email protected] http://lists.amdatu.org/mailman/listinfo/amdatu-developers

