While waiting for R7, an other way to address the race condition between a reference event method and the activate method, is to get rid of the activate method and inject MyServiceProcessor as a static reference:

    @Component(name="Bar")
    public class MyComponent {
@Reference
    private MyServiceProcessor processor;
@Reference(name="zFoo", cardinality = ReferenceCardinality.MULTIPLE, policy=ReferencePolicy.DYNAMIC)
    public void bindFoo(ServiceReference<Foo> ref) {
/* some code here */
    processor.process(ref.getService());
    /* some more code here */
}


This works because the DS spec requires the component runtime to process references in the order defined in the component xml, and the annotiation processor to generate the reference xml elements in name order, hence the zFoo name on the annotation. Of course you need a separate component to publish the MyServiceProcessor service.

Alternatively, if a separate component is not convenient, I use a simple reusable utility class to handle the race condition:

@Component(name="Bar")
public class MyComponent {

    private MyServiceProcessor processor;
    private final HoldingExecutor holdingExecutor = new HoldingExecutor();

    @Activate
    public void activate(ComponentContext cc) {
        processor = new MyServiceProcessor();
        executor.start();
    }

@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy=ReferencePolicy.DYNAMIC)
    public void bindFoo(ServiceReference<Foo> ref) {
        executor.execute(() -> this.doBindFoo(ref));
    }
    private void doBindFoo(ServiceReference<Foo> ref) {
        processor.process(ref.getService());
    /* some more code here */
    }
}

public class HoldingExecutor implements Executor {
    private List<Runnable> runnables = new ArrayList<>();

    @Override
    public synchronized void execute(Runnable runnable) {
        if (runnables == null) {
            runnable.run();
        } else {
            runnables.add(runnable);
        }
    }

    public synchronized void start() {
        runnables.forEach(Runnable::run);
        runnables = null;
    }

}

This has the additional advantage of also handling the race condition between two concurrent bindFoo invocations,
 so you do not have to worry about the thread safety of processor.process

  Karel

On 12/05/2017 13:30, Carsten Ziegeler wrote:
Bruce Jackson wrote
Thank you, Thomas & Neil.

As Neil suggested, the problem is that MyServiceProcessor does rely on the 
BundleContext which obviously I don’t have at that point, otherwise I could 
have used the pattern you both suggested.
It’s not a big deal to use a ServiceTracker, it just feels a bit ‘old school’ 
when using DS for everything else. Perhaps this is something that might be 
considered for future enhancements of the OSGi spec. It feels like it would be 
useful in many circumstances to have reference binding methods that are only 
operational once the component in question is activated?

This will actually be addressed with the upcoming update of Declarative
Services in R7 this year. You'll get constructor injection and other
features that help solving exactly such use cases.

Regards
Carsten
Best regards

Bruce

On 12/05/2017, 10:23, "Thomas Driessen" <thomas.dries...@ds-lab.org> wrote:

     Hi Bruce,
why aren't you using the constructor of MyComponent for this?
     Your MyServiceProceessor is neither an OSGi service nor does it need
     something from the @Activate method (e.g. the ComponentContext).
So I would do something like this: @Component(name="Bar")
     public class MyComponent {
private MyServiceProcessor processor; public MyComponent(){
          processor = new MyServiceProcessor();
     }
... } This way it is guaranteed that your reference is set before any of the
     bind methods are called.
     You can have a look at
http://enroute.osgi.org/appnotes/concurrency.html Subsection
     "Guarantees from DS"
for a little more information on this. Kind regards,
     Thomas
------ Originalnachricht ------
     Von: "Bruce Jackson" <bruce.jack...@myriadgroup.com>
     An: "users@felix.apache.org" <users@felix.apache.org>
     Gesendet: 12.05.2017 09:05:34
     Betreff: Lifecycle and Reference
>Hi Everyone
     >
     >I was wondering if anyone could provide some advice:
     >
     >I have a component of the form:
     >
     >@Component(name="Bar")
     >public class MyComponent {
     >
     >private MyServiceProcessor processor;
     >
     >@Activate
     >public void activate(ComponentContext cc) {
     >
     >processor = new MyServiceProcessor();
     >
     >}
     >
     >@Deactivate
     >public void deactivate(ComponentContext cc) {
     >
     >}
     >
     >@Reference(cardinality = ReferenceCardinality.MULTIPLE)
     >public void bindFoo(ServiceReference<Foo> ref) {
     >
     >/* some code here */
     >processor.process(ref.getService());
     >/* some more code here */
     >
     >}
     >
     >public void unbindFoo(ServiceReference<Foo> ref) {
     >
     >}
     >
     >}
     >
     >The problem here is that the bindFoo() method is called by the SCR
     >before the activate and thus a null pointer exception is thrown in the
     >processor.process() call.
     >This is perhaps not surprising, but it is not ideal for a component
     >that is ‘lazy’ about the other services that it wants to discover. I
     >could clearly move this functionality into a ServiceTracker which I
     >create in the activate() but was wondering if there was another
     >approach that allowed me to do this via DS and annotations?
     >
     >Best regards
     >
     >Bruce
     >
     >
     >*** DISCLAIMER *** This message, including attachments, is intended
     >solely for the addressee indicated in this message and is strictly
     >confidential or otherwise privileged. If you are not the intended
     >recipient (or responsible for delivery of the message to such person) :
     >- (1) please immediately (i) notify the sender by reply email and (ii)
     >delete this message and attachments, - (2) any use, copy or
     >dissemination of this transmission is strictly prohibited. If you or
     >your employer does not consent to Internet email messages of this kind,
     >please advise Myriad Group AG by reply e-mail immediately. Opinions,
     >conclusions and other information expressed in this message are not
     >given or endorsed by Myriad Group AG unless otherwise indicated by an
     >authorized representative independent of this message.
     
>Т���������������������������������������������������������������������ХF�?V�7V'67&�&R�?R��?�â?W6W'2�V�7V'67&�&T?fVƗ��???6�R��&pФf�"??FF�F���?�?6���?�G2�?R��?�â?W6W'2ֆV�??fVƗ��???6�R��&p
---------------------------------------------------------------------
     To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
     For additional commands, e-mail: users-h...@felix.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@felix.apache.org
For additional commands, e-mail: users-h...@felix.apache.org

Reply via email to