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]

Reply via email to