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: [email protected]
For additional commands, e-mail: [email protected]