jekamax
jekamax

Reputation: 35

Select certain CDI event observer

I have a few classes that observe some CDI event. Is it possible to declare which class should be used in different cases?

For example I have class that produce events:

class Producer
   {
        @Inject
        private Event<SomeEvent> event;
        public void fire()
        {
             event.fire(new SomeEvent());
        }
   }

And I have two consumer classes:

class ConsumerA
{
       public void onEvent(@Observes SomeEvent event);
}
class ConsumerB
{
       public void onEvent(@Observes SomeEvent event);
}

How can I use ConsumerA instances in one case and ConsumerB instances in other case?

I need something like that:

class UseCaseA
{
    @Inject
    Producer producer;
    @Inject
    ConsumerA consumerA;
    public void doWork()
    {
         producer.fire(); //consumerA.onEvent() will be called
    }
}
class UseCaseB
{
    @Inject
    Producer producer;
    @Inject
    ConsumerB consumerB;
    public void doWork()
    {
         producer.fire(); //consumerB.onEvent() will be called
    }
}

Upvotes: 0

Views: 3761

Answers (1)

redge
redge

Reputation: 1192

The trick here is to Qualify both the event and the observer.

See the jee6 tutorial here particularly the use of @Credit and @Debit qualifiers.

To do this dynamically instead of injecting different events to fire you can use the select(java.lang.annotation.Annotation... qualifiers) methods on a single event.

Qualify your observers and then call.

event.select(.... Some annotation literal. .).fire();

You could have the fire code in a superclass and then have each subclass supply the annotation literal.

Annotation literal is javax.enterprise.util.AnnotationLiteral. you will need to create an annotation literal for each Qualifier you want to use but these can be instantiated and passed as objects.

BTW you do not need to inject your observers. This defeats the point. You should be able to add as many observers as you like for each event and not have to revisit the source of the event. Your container should instantiate them on startup.

You can also select the event on the basis of a subclass of the event class if that works better.

EDIT: Just thought I'd add my thoughts to this about the philosophy of using events.

  1. The component that is firing the event can specify both the specific type of the payload and qualifiers that are attached to the event but does not and should not actually choose the observer that will process the event.
  2. You can add many observers for any one event. There may be: one to send an email; One to write an audit log; One to send a text message; One to write a JMS message; and many more all firing at once as a result of a single event.fire(...) call.
  3. Observers should IMO have a single purpose like those described above.

  4. Observers should not rely on any order of execution (except transactional vs non-transactional ... see below) as it cannot be guaranteed. If you need to guarantee the order then the observer should fire a different event and an observer for that event can do the later processing in the order.

  5. Small observers with a single purpose like those described above are easy to superclass as often most of the code is identical eg. for all email messages except the format of the message.
  6. If you have 2 updates to perform and cannot use XA to guarantee a single atomic transaction. You can decide on the most important and make an observer for that one that executes synchronously (within the firing transaction) and a different observer for the other one that executes after success of the firing transaction (using during=AFTER_SUCCESS) that way you can guarantee that either :A and B will happen; or A will happen but B will not. That way you could even possibly put in place some periodic checking to propagate B from the results of A
  7. The during parameter of the @Observes annotation can be used to provide separation between core processing associated with the component firing the event and executed synchronously (non-transactional) and processing that must not take place except in certain circumstances related to the transaction in which the event is fired and which is "queued" for execution in those circumstances (transactional) eg log an error if the transaction fails; or send an email if the transaction succeeds.

Upvotes: 3

Related Questions