An alternative way to look at this is simply that your DS component needs to be
sufficiently thread-safe to deal with the consequences of its own internal
threading model. In this case:
> What would be a good (and simple) strategy to handle this type of
> long-running configuration, where the configuration is in a different thread
> and depends on services that may come and go?
Long-running asynchronous activation isn’t where DS really shines for several
reasons:
There’s no way to tell DS that your component activation is asynchronous. Once
the activate method returns then DS will give your object to the client bundle.
As you’ve already discovered, Promises can make this much simpler to deal with.
As you’ve seen, the DS “happens before” model is based on when your activate
method returns. Once you go into another thread you have to deal with the
consequences of that
If your long-running activation fails, then it’s too late to tell DS that the
component is broken. To be safe here you really need to disable your component
on failure.
That said, it is perfectly possible to activate asynchronously in a safe way.
It’s just very important to signal to any thread(s) that you started that they
need to stop and abandon their work. Thread.interrupt() is useful here, as is
having an AtomicBoolean flag in your component that you set to false during
deactivation. These states should be checked regularly during startup, and the
“startup thread" should be prepared to abandon any work it has done if/when it
has become invalid.
Best Regards,
Tim
> On 23 Jul 2018, at 08:00, Peter Kriens via osgi-dev
> wrote:
>
>
>
> Ok … on the top of my head …
>
>
> public interface Bar {
> void m1();
> void m2();
> }
>
> @Component
> public class BarImpl implements Bar {
> Deferred delegate = new Deferred<>();
>
> @Reference
> void setExec( Executor e ) {
> delegate.resolve( new BarImpl2(e) );
> }
>
>
> public void m1() {
> delegate.getPromise().m1();
> }
>
> public void m2() {
> delegate.getPromise().m2();
> }
> }
>
> This works for you?
>
> Kind regards,
>
> Peter Kriens
>
>
>
>> On 22 Jul 2018, at 22:51, David Leangen via osgi-dev
>> wrote:
>>
>>
>> Hi Peter,
>>
>> Thanks for the tip.
>>
>> I’m not quite getting it. Would you be able to direct me to an example?
>>
>> Thanks!
>> =David
>>
>>
>>
>>> On Jul 22, 2018, at 21:49, Peter Kriens wrote:
>>>
>>> In some cases (when the extra complexity was warranted) I let the component
>>> class act as a proxy to a delegate. I then get the delegate from a
>>> Promise. So you just forward every method in your service interface to the
>>> delegate. There is a function in Eclipse that will create the delegation
>>> methods.
>>>
>>> In general you want to afford this complexity and for example use a simple
>>> init() method that blocks until init is done. However, the delegate has
>>> some nice qualities if you switch more often than just at init.
>>>
>>> Kind regards,
>>>
>>> Peter Kriens
>>>
On 22 Jul 2018, at 10:35, David Leangen via osgi-dev
wrote:
Hi,
This may be more of a basic Java question, but I’ll ask it anyway because
it relates to “bouncing” and the handling of dynamic behavior.
In my @Activate method, I configure my component. Since the configuration
may be long-running (data is retrieved remotely), I use a Promise. But,
the component is available before it is actually “ready”. So far, this has
not been a problem.
It looks something like this:
@Reference private Store dataStore;
@Activate
void activate() {
configure(dataStore);
}
void configure(Store withDataStore) {
// Configuration is set up via a Promise, using a data store to retrieve
the data
}
However, because there is some bouncing occurring, I think what is
happening is that configure() starts running in a different thread, but in
the meantime the reference to the dataStore is changed. The error log
shows that the data store is in an impossible state. After following a
hunch, I could confirm that the configureData process is running on a data
store service that was deactivated during bouncing.
What would be a good (and simple) strategy to handle this type of
long-running configuration, where the configuration is in a different
thread and depends on services that may come and go?
Note: in the end, the component gets configured and the application runs,
but I would still like to be able to handle this situation properly.
Thanks!