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