0

I'm designing an application whose functionality need to be the same in different contexts. Let refer to the picture below:


                     +----+         +----+       +----+
                     |B1  +--->-----+B2  +-->----+B3  |
                     |ctx1|  use    |ctx1|  use  |ctx1|
                     +----+ service +----+service+----+



     +-------+       +----+         +----+       +----+
     |Context|       |B1  +--->-----+B2  +-->----+B3  |
     |Manager|       |ctx2|  use    |ctx2|  use  |ctx2|
     |       |       +----+ service +----+service+----+
     |       |         :              :            :
     +-------+         :              :            :

                     +----+         +----+       +----+
                     |B1  +--->-----+B2  +-->----+B3  |
                     |ctxN|  use    |ctxN|  use  |ctxN|
                     +----+ service +----+service+----+

There are 4 bundles:

  • Context Manager
  • B1
  • B2
  • B3

Context Manager is the bundle that is in charge of knowing when a new context is available and to instantiate a new version of B1, B2 and B3. The services offered by B2 and B3 are exactly the same across contexts, just i want to add a property on the service to distinguish in which context it's running (ctx1 vs ctxN for example). Now this is the theory of what i want to achieve, i thought i could easily implement it via Declarative Services, in fact i made B1 *B2* and B3 to be ComponentFactory by specifying the component.factory property in the component header, and i set B1 to refer to a service provided by B2, also i set B2 to refer to a service provided by B3. These are the challenges i faced:

  • Context Manager learns about the ComponentFactory service provided only by B3, the first time, as long as B1 and B2 are not yet satisfied, they don't register the ComponentFactory service in the service registry. As long as this is the case B1 and B2 don't get instantiated for the first context.
  • B1 and B2 once created, gets an arbitrary service from other contexts, i was thinking to set the reference.target parameter to only pick the service from the same context but it doesn't seem there is any way to declarative do this, seems like the only way to select a service from the same context is by setting a reference with cardinality 0..n and to provide a "bind" method that select based on the current context, this means that every component has to replicate the same selection logic which instead i was thinking could be provided by the Context manager when a newInstance is called. In fact if during the call ComponentFactory.newtInstance(props); i could provide a property like .target=(context=mycontext) then this could be achieved, but I don't know all the reference the component is actually using.

At this point i'm thinking to actually avoid using Declarative Service and to have the per-context bundle extend a base class i will provide which will basically implement the dependency tracking similar to org.apache.felicy.dependencymanager but such that the developer of the per-context component don't have to worry to know in which context the code sits. However i hate to revert to this solution, i feel i'm just replicating logic may exist already in the OSGi specification and so my question is:

What is the best way to create bundles that can run on a per-context base in OSGi, such that the bundles can describe in a declarative way the dependency, without having to explicitly mention the context in which they are running?

  • There should be no problem doing this with declarative services. Due to property propagation, you can set properties like the `target` from a configuration. – Björn Pollex Oct 09 '12 at 09:53
  • Yes is would be able to know in advance on which reference i could set the target, but the issue here is two fold: 1) I need to first discover the factory components to instantiate 2) I need to discover in the components instantiated the reference to services. If i solve the first two problems i can then set the target property from configuration. But i cannot reach that point. – Giovanni Meo Oct 09 '12 at 13:05

2 Answers2

0

There is some confusing terminology in here. You talk about bundles B1, B2 and B3. And you also talk about instantiating new versions of B1, B2 and B3. Do you mean updating the bundles B1, B2 and B3? Or do you mean bundles B1, B2 and B3 offer services S1, S2 and S3, respectively?

BJ Hargrave
  • 9,324
  • 1
  • 19
  • 27
  • BJ, let me clarify it, B1 B2 and B3 are bundles, each of them has a Service Component declared in it (as Declarative Service specification defines). Each of the Service Component, in the 3 bundles, are marked as component factory, so B1, B2 and B3 actually instantiate in multiple instances, as the ones i mentioned in the picture: B1 ctx1, B2 ctx1, B3 ctx1, .., B1 ctxN, B2 ctxN, B3 ctxN. Every instance of B1 use a service (let call it S2, but not reported in the picture) provided by an instance of B2. Similar situation is for B2 in regard to B3. – Giovanni Meo Oct 08 '12 at 15:16
  • So B1 is a bundle that has a DS component C1. C1 is a component factory so there can be many instances of C1 registered as service S1. Same for B2/C2/S2 and B3/C3/S3. So you want to use the ComponentFactory for C3 to create an instance of C3 registering S3 which satisfies C2 thus registering the ComponentFactory for C2 which you then use to create an instance of C2 which uses S3 and registers S2 which then satisfies C1 thus registering a ComponentFactory for C1 which you then use to create an instance of C1 which uses S2 and registers S1? – BJ Hargrave Oct 08 '12 at 17:47
  • Yes, but i would like to learn about C1/C2/C3 factories before the dependencies are satisfied else by first problem arise. As i said seems like DS doesn't let you do that, so i'm also looking for alternatives other than DS but i would like not to revert to manual tracking of the dependencies. – Giovanni Meo Oct 08 '12 at 20:04
0

Answering my own, question. As long as i was in a need for a solution, thanks to the help of the Apache Felix DependencyManager i have replaced the Declarative Services and for each context,bundle (Container in the source code below) i create a new instance of dependency manager which helps to track the services on a per-context base.

For code reference please look at: OpenDayLight ComponentActivatorAbstractBase

For managing dependencies and ensure they are in the same context a special ServiceDependency is created, for reference look at: OpenDayLight ServiceDependency

For example on how the activator is actually used refer to: OpenDayLight sample activator

Hope this can be of use to others too.