Thomas, if you use DS idiomatically then the service reference cannot
change to null during your method call.

First, as Chris pointed out, static references will not change while
your component is active, because as soon as the referenced services
goes away your component will be deactivated. So we don't need to
worry about these.

For dynamic references, you do need to find a way to deal with the
dynamics in a thread safe way. My preferred solution is to store the
service value in an AtomicReference field. At the start of any method
that uses the service, I copy the content of the AtomicReference to a
local variable, using the get() method. Once in a local variable, I
can check for null and then use the service. The value of the local
variable cannot change while I am using it in my method.

You seem to be concerned about the deeper call stack, but as the
caller of a service it is simply not your concern to try to enforce
something about the implementation of the service you are calling. You
should however be prepared for the service invocation to go wrong in
unpredictable ways. Usually the best way to deal with this is simply
to bubble up the exception to your own caller.

Note that although the Java memory model permits you to "pin" the
service instance in memory temporarily -- i.e. by pointing a local
variable at it -- that does not mean that the underlying service is
still valid. As BJ points out, the service *may* be a proxy for a
remote service, or it may represent some device attached to the
computer that has just been ripped out. So the technique of referring
to services with local vars helps to avoid the worst case of having to
lock and null-check *every* time you use the service within your
method, but it does NOT enforce that the underlying service is still
working sensibly under the covers, and nothing you do CAN ever enforce
this, so get used to it and adapt your coding style appropriately.

Neil

On Tue, Sep 10, 2013 at 3:54 PM, Thomas Diesler
<thomas.dies...@jboss.com> wrote:
> Thanks Chris,
>
> could you say something about the effect on call stacks that are already in 
> progress. In a complex graph of interdependent services you may have multiple 
> DS injection points and that a ref is null is only the most obvious case. 
> What about the ref not being null but being a different instance than has 
> been used earlier in the call stack. Also the possibility of different 
> configuration data getting associated with the same service instance.
>
> cheers
> --thomas
>
> On Sep 10, 2013, at 4:39 PM, chris.g...@kiffer.be wrote:
>
>>> I'm wondering how other folks deal with the issues of service
>>> dynamicity and configuration change in the duration of a single call to a
>>> complex graph of interconnected services.
>>
>> Services injected by DS are, as you say, non-final fields so they can
>> change their value. This situation is not unique to DS - in principle
>> *any* non-final field of your class could be modified at any time by any
>> other thread which can access it, so you have to either handle this or
>> prove that it can't happen.  For example you make a copy in a (final)
>> local variable: then you are safe from NPEs but you may be using an
>> instance which is somehow obsolete - so you have to be aware of that.
>> Etc..
>>
>> Turning to DS, the solution can depend upon whether the absence of a
>> dependency is a "normal" or an "abnormal" state of affairs. If it is
>> normal then you declare the dependency as "optional unary" and indeed you
>> have be aware that it can go away or be replaced at the most inconvenient
>> moment.  As you say there are "a lot of callbacks": in this case you
>> almost certainly want to write your own set/unset methods so that you can
>> deal with synchronisation issues etc..  If OTOH you really don't want to
>> deal with the dynamics then you declare the dependency as "mandatory
>> unary" and then if it goes away, so do you.  If it comes back a new
>> instance of your component is created so there is no problem of stale
>> references etc..
>>
>> It is important that components properly handle being stopped: any
>> subsequent service calls should be handled in a way which helps the caller
>> realise that the service object is no longer usable.
>>
>> I don't think this is a problem which can be solved by adding one more
>> layer of abstraction; rather it is a case of applying best practices and
>> using DS idiomatically.  Does this make sense?
>>
>> Regards
>>
>> Chris Gray
>>
>>
>> _______________________________________________
>> OSGi Developer Mail List
>> osgi-dev@mail.osgi.org
>> https://mail.osgi.org/mailman/listinfo/osgi-dev
>
> _______________________________________________
> OSGi Developer Mail List
> osgi-dev@mail.osgi.org
> https://mail.osgi.org/mailman/listinfo/osgi-dev
_______________________________________________
OSGi Developer Mail List
osgi-dev@mail.osgi.org
https://mail.osgi.org/mailman/listinfo/osgi-dev

Reply via email to