Reputation: 35
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
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.
event.fire(...)
call.Observers should IMO have a single purpose like those described above.
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.
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 Aduring
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