You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@felix.apache.org by Lars Fischer <lf...@fast-mail.org> on 2009/07/16 17:36:25 UTC

dynamic access to services

Hello,

I have some special needs for accessing OSGi services and would be 
happy, if someone could give me a hint how I can archive this in a safe way.

Some common facts:
- a generic "Function" interface defines a method "work"
- all functions have to implement this interface
- all functions should be threadsafe
- all functions have some identifiers (name, version)
- different implementations of a named function should be available at 
runtime in multiple instances with different versions

By registering different function-instances with specific filter 
attributes as OSGi services, I can make the functions available.

But how do I solve this?
- functionA should be able to use functionB#work() only by name
- the used instance of functionB has to by dynamic changable per call, 
depending on some "context"-parameters without making a decision in 
functionA itself. For example: 2 calls of the same functionA instance 
result in calls to 2 different versions of functionB.


Variant 1 is to use a "Retriever"-Service. It should create a filter 
with the context-parameters and return the matching service from the 
local stored BundleContext.
The retriever itself would be a registered service too and would be 
referenced by every function instance.

FunctionA would use something like this in its work-method:


Function functionB = retriever.getByName("B");
functionB.work();



In variant 2 all functions extend an abstractFunction with a method 
"getByName". So every function instance itself holds the BundleContext 
or uses it from the bundleactivator to retrieve other functions dynamically.



Can I use services in that way?

Which variant is better? Or are there other solutions for retrieving 
services dynamically?

Do I have to release the recieved functionB after leaving the work-scope 
of functionA?


Thank you in advance!

Regards,
Lars

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: dynamic access to services

Posted by Lars Fischer <la...@fast-mail.org>.
Hello Todor,

Todor Boev schrieb:
> Here is the simplest and lest performant, but *correct* approach I can 
> think of:
 >
> [snip]
> 
> Finally I must say Service Dynamics are a big and hard topic (just look 
> at my huge write up!). For an even more detailed explanations I must 
> shamelessly plug my blog entry on the subject right now:
> 
> http://rinswind.blogspot.com/2009/05/service-dynamics-lazy-mans-way.html

I thank you very much for your detailed answer! You gave me a great help 
and I see, I have a lot to learn and to try out. But it sounds good that 
you think it is realizable.

I will start implement a prototype in the way you described it and will 
have a look at the listed helpers.

Maybe I will soon be back on the group with additional questions... ;)

Thanks again.

Regards,
Lars


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: dynamic access to services

Posted by Lars Fischer <lf...@fast-mail.org>.
Hello Todor,

Todor Boev wrote:
> Here is the simplest and lest performant, but *correct* approach I can 
> think of:
> 
> [snip]
> 
> 
> Finally I must say Service Dynamics are a big and hard topic (just look 
> at my huge write up!). For an even more detailed explanations I must 
> shamelessly plug my blog entry on the subject right now:
> 
> http://rinswind.blogspot.com/2009/05/service-dynamics-lazy-mans-way.html

I thank you very much for your detailed answer! You gave me a great help 
and I see, I have a lot to learn and to try out. But it sounds good that 
you think it is realizable.

I will start implement a prototype in the way you described it and will 
have a look at the listed helpers.

Maybe I will soon be back on the group with additional questions... ;)

Thanks again.

Regards,
Lars





---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: dynamic access to services

Posted by Todor Boev <t....@prosyst.bg>.
Lars Fischer wrote:
> This is what I'm asking for. I have not used OSGi before, so I have no 
> experiences how to implement the dynamic retrieving of functions in a 
> good way and how to get the system stable.
> 
> If the retriever is an OSGi service and it uses the 
> BundleContext#getService(ServiceReference) method. This means that the 
> retriever has to release service? In a multithreaded environment, where 
> I can have multiple calls to the same function instance, this could be 
> problematic.
> On the other hand with a retrieverUtil, then I could bind the retrieved 
> services also to a threadlocal and have to release them on the end. This 
>   looks good for me. Can this be the solution?
> Maybe I use an AbstractFunction which can do the boilerplate and store 
> all needed things in a threadlocal. Then every function instance has to 
> hold the bundlecontext. Is this a good way?
> 
> Let me say, that the number of functions and the instances for all pairs 
> could increase heavily during runtime. I would like to deploy new 
> versions and new functions during runtime keeping all others alive.
> 
> Is it possible to dynamically react on new versions instances with a 
> servicetracker or iPojo? Does this mean that I will have one 
> serviceTracker for each function instance? Then I have to do the same 
> work as the servieregistry for the services in the serviceretriever for 
> the servicetrackers: manage all available.
> I thought I can use the serviceregistry as manager for the functions and 
> the retriever handles only how the functions can reach other ones.
> 
> Maybe for each call again. Could this result in a bad performance?
> 
> 
> Thanks for reading the long text :)
> 

Here is the simplest and lest performant, but *correct* approach I can think of:

0) Pass the environment explicitly or in a ThreadLocal makes no real difference. 
I personally would go for the explicit approach and fall back to a ThreadLocal 
if it becomes too painful.

1) When FunctionX wants to call FunctionY it turns to the environment to get the 
appropriate filter properties.

2) FunctionX uses it's BundleContext to get the appropriate FunctionY.

3) FunctionX calls FunctionY. During the call FunctionX can store the FunctionY 
object in local variables or pass it as parameter. It CAN NOT store it in a 
field - this will screw up the unloading of the bundle that exports FunctionY if 
gets updated for example.

4) FunctinX uses it's BundleContext to release FunctionY.

5) FunctionX must be prepared to handle crashes from FunctionY. This is because 
FunctionY can be uninstalled at any time from another thread. Event if FunctionY 
is still here it in turn can crash because of some FunctionZ down the line is 
going down. Dynamics mean crashes! You can't avoid them - just handle them properly.

6) All Function implementations must support thread-safe shutdown. This means at 
any time a thread running concurrently to the "business flow" can come along an 
touch them to say "you are no longer valid". This invalidation happens in 
BundleActivator.stop(). The Function must clean up any non-memory resources and 
begin to fail-fast from this point on. If your Function is totally stateless 
(nice!) you don't need any invalidation. The Function will fail when it tries to 
use it's invalid BundleContext. The point is to crash cleanly any threads 
captured inside the Function at the moment of shutdown and than let the garbage 
collector clean up then the last of them leave. This means you must detach the 
Function object from BundleActivator.stop() i.e. null the field in which you 
store it.

7) You must set up appropriate fault-barriers in your code. For example the 
bundle that sets up the environment and initiates the FunctionX chain of calls 
must wrap the call to the first Function in try/catch Exception. If must catch 
crashes from direct or transitive dependencies going down (or crashing for any 
other reason). It must do cleanup if any is required, pop a dialog to the user , 
return code 500 to the browser or whatever. The idea is that during bundle 
update inevitably some activities will crash - live with it :)

Notice that in this setup you don't need to react to events about instances of 
FunctionX coming and going. Everything is driven from the business control flow. 
If a new service appears it will be picked up the next time a business control 
flow hits a potential importer. Maybe only the bundle that sets up the 
environment needs to track services coming and going. Dynamics are covered with 
appropriate error handling. If you keep things stateless (e.g. no state related 
to FunctionX needs to be set up) you would probably not need dynamic reactions 
at all.

Now when things are working you can add caching of services to speed things up. 
Every FunctionX can cache any FunctionY it has ever used and drop it after some 
period of time. Or simply use Peaberry and it's dynamic Iterable. It will do a 
much better job than you. And iPojo does exactly the ThreadLocal caching of 
services you imagine. It will also do a better job than you :)

Finally I must say Service Dynamics are a big and hard topic (just look at my 
huge write up!). For an even more detailed explanations I must shamelessly plug 
my blog entry on the subject right now:

http://rinswind.blogspot.com/2009/05/service-dynamics-lazy-mans-way.html

Cheers,
Todor

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: dynamic access to services

Posted by Lars Fischer <lf...@fast-mail.org>.
Hello Todor,

thank you for the helpful answer!

Todor Boev schrieb:
> There are many ambiguities here. At least to me :) Some notes:
> 
> 1) So every Function implementation represents some "formula" like this?
> 
> FunctionA() = call "B" + call "C"
> 
> 2) And you want to set "B" and "C" before you call "A"?

No, the functions should be some kind of business methods or services 
like a stateless sessionbean. I named it function to avoid wrong 
associations.
They have an Object[] parameter and an Object[] return. They can do some 
java operations on these parameters and could call some other functions.

The content, which other functions are called, is static. But there can 
be some different implementations of one named functionA. For example:
- functionA in version 1 is registered with the pair name="functionA" 
version="1" and just calls functionB without any version
- functionB in version 1 is registered with the pair name="functionB" 
version="1"
- functionB in version 2 is registered with the pair name="functionB" 
version="2"

I want this behavior:
- With context set to "B1", calling functionA results in a call of 
functionB version 1
- A changed context set to "B2" results in a call of functionB version 2.
- Context could be some kind of threadlocal variable or something else 
as you stated later. It depends not on the function itself and can not 
be changed by a function.


> 3) You have multiple instances identified with the same (name, version) 
> pair? Isn't this problematic? How do you distinguish between them :)

No, each pair has only one function instance. Name and version are only 
examples. The pair could also contain a field "scope". This is only an 
example.


> 4) You essentially want to configure an environment of  (Name->Function) 
> pairs and than do a call to a FunctionX. Within the current thread you 
> want this environment to hold while in another thread the environment 
> can differ? I.e. you need a thread-local environment rather than a 
> thread-safe functions? If this is the case you solve this in a "library" 
> way by storing a ThreadLocal in some well known static field. Or 
> alternatively thread the environment as a parameter to work() (same deal).

Yes, I have something like this in mind. Thank you for confirming my 
thoughts.


> 6) Is the RetrieverService an OSGi service? If so it will be the one 
> using the FunctionX instances and it has to track them to make sure they 
> are released if the FunctionX bundle goes away. The users of 
> RetrieverService must never cache the FunctionX instances returned to 
> them. 
> Alternatively RetrieverService can be a is a utility that wraps a 
> the BundleContext of the bundle owning a FunctionX service. In this case 
> consider using a ServiceTracker instead. Or better still use iPojo, 
> Peaberry or Spring DM to handle service binding, unbinding for you. 
> iPojo and Peaberry in particular cache service references and release 
> them when not used for a while (I am not sure for iPojo but Peaberry 
> does it in this way).


This is what I'm asking for. I have not used OSGi before, so I have no 
experiences how to implement the dynamic retrieving of functions in a 
good way and how to get the system stable.

If the retriever is an OSGi service and it uses the 
BundleContext#getService(ServiceReference) method. This means that the 
retriever has to release service? In a multithreaded environment, where 
I can have multiple calls to the same function instance, this could be 
problematic.
On the other hand with a retrieverUtil, then I could bind the retrieved 
services also to a threadlocal and have to release them on the end. This 
   looks good for me. Can this be the solution?
Maybe I use an AbstractFunction which can do the boilerplate and store 
all needed things in a threadlocal. Then every function instance has to 
hold the bundlecontext. Is this a good way?

Let me say, that the number of functions and the instances for all pairs 
could increase heavily during runtime. I would like to deploy new 
versions and new functions during runtime keeping all others alive.

Is it possible to dynamically react on new versions instances with a 
servicetracker or iPojo? Does this mean that I will have one 
serviceTracker for each function instance? Then I have to do the same 
work as the servieregistry for the services in the serviceretriever for 
the servicetrackers: manage all available.
I thought I can use the serviceregistry as manager for the functions and 
the retriever handles only how the functions can reach other ones.

Maybe for each call again. Could this result in a bad performance?


Thanks for reading the long text :)


Regards,
Lars

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org


Re: dynamic access to services

Posted by Todor Boev <t....@prosyst.bg>.
There are many ambiguities here. At least to me :) Some notes:

1) So every Function implementation represents some "formula" like this?

FunctionA() = call "B" + call "C"

2) And you want to set "B" and "C" before you call "A"?

3) You have multiple instances identified with the same (name, version) pair? 
Isn't this problematic? How do you distinguish between them :)

4) You essentially want to configure an environment of  (Name->Function) pairs 
and than do a call to a FunctionX. Within the current thread you want this 
environment to hold while in another thread the environment can differ? I.e. you 
need a thread-local environment rather than a thread-safe functions? If this is 
the case you solve this in a "library" way by storing a ThreadLocal in some well 
known static field. Or alternatively thread the environment as a parameter to 
work() (same deal).

6) Is the RetrieverService an OSGi service? If so it will be the one using the 
FunctionX instances and it has to track them to make sure they are released if 
the FunctionX bundle goes away. The users of RetrieverService must never cache 
the FunctionX instances returned to them. Alternatively RetrieverService can be 
a is a utility that wraps a the BundleContext of the bundle owning a FunctionX 
service. In this case consider using a ServiceTracker instead. Or better still 
use iPojo, Peaberry or Spring DM to handle service binding, unbinding for you. 
iPojo and Peaberry in particular cache service references and release them when 
not used for a while (I am not sure for iPojo but Peaberry does it in this way).

Cheers,
Todor

Lars Fischer wrote:

> Hello,
> 
> I have some special needs for accessing OSGi services and would be 
> happy, if someone could give me a hint how I can archive this in a safe 
> way.
> 
> Some common facts:
> - a generic "Function" interface defines a method "work"
> - all functions have to implement this interface
> - all functions should be threadsafe
> - all functions have some identifiers (name, version)
> - different implementations of a named function should be available at 
> runtime in multiple instances with different versions
> 
> By registering different function-instances with specific filter 
> attributes as OSGi services, I can make the functions available.
> 
> But how do I solve this?
> - functionA should be able to use functionB#work() only by name
> - the used instance of functionB has to by dynamic changable per call, 
> depending on some "context"-parameters without making a decision in 
> functionA itself. For example: 2 calls of the same functionA instance 
> result in calls to 2 different versions of functionB.
> 
> 
> Variant 1 is to use a "Retriever"-Service. It should create a filter 
> with the context-parameters and return the matching service from the 
> local stored BundleContext.
> The retriever itself would be a registered service too and would be 
> referenced by every function instance.
> 
> FunctionA would use something like this in its work-method:
> 
> 
> Function functionB = retriever.getByName("B");
> functionB.work();
> 
> 
> 
> In variant 2 all functions extend an abstractFunction with a method 
> "getByName". So every function instance itself holds the BundleContext 
> or uses it from the bundleactivator to retrieve other functions 
> dynamically.
> 
> 
> 
> Can I use services in that way?
> 
> Which variant is better? Or are there other solutions for retrieving 
> services dynamically?
> 
> Do I have to release the recieved functionB after leaving the work-scope 
> of functionA?
> 
> 
> Thank you in advance!
> 
> Regards,
> Lars
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org
> 
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org