3

I have two SLSBs:

  • BeanF,
  • BeanO

in two ejb-jars:

  • ModF,
  • ModO.

BeanF fires an event and BeanO observes it.

The first fire(-) operation ends with the exception (Wildfly 8.2):

ERROR [org.jboss.as.ejb3.invocation] JBAS014134: EJB Invocation failed on component BeanF for method public void BeanF.publish(ModEvent):
javax.ejb.EJBException: org.jboss.msc.service.ServiceNotFoundException: Service service
jboss.deployment.subunit."myapp.ear"."modO.jar".component.BeanO.VIEW."BeanO".LOCAL not found

Further fire(-) operations reach the observer but I can't let any event to be lost.

Is there a way to force the initialization of the observer before the event is fired (or on the fly after the event is fired and awaits processing)?

The @Observes(notifyObserver = Reception.IF_EXISTS) only allows the event to be skipped silently when the observer is not ready yet.
In my case the BeanF cannot be dependent on BeanO because ModO must be declared after ModF in the application.xml.

Is it possible with CDI events/listeners or would I need to go with JMS?

Piotr Nowicki
  • 17,914
  • 8
  • 63
  • 82
  • Can you switch from SLSB to Singletons? Then using @Sturtup may do the trick? – Jan Galinski Apr 08 '15 at 08:41
  • Reception.IF_EXISTS is mostly applicable to beans with wider scope (like SessionScope , ApplicationScoped , etc). If your bean is @Stateless, the instance is "created" only for a single call and that makes IF_EXISTS almost always to return false (except in cases where the event firing and the observer are in the same stacktrace). – Adrian Mitev Apr 08 '15 at 12:16
  • Tried annotating both beans with `@Singleton` and `@Startup` and received the same exception (I cannot annotate `BeanF` with `@DependsOn( BeanO )` because `ModF` does not see `ModO`). Also tried changing `BeanO` to `@ApplicationScoped` and in this case the event could be received - the `BeanO.observe(@Observes ...)` method started executing, performed some logging but crashed with `ServiceNotFoundException` exception when tried to call some other `@Stateless` bean (this other bean must be `@Stateless` since it uses the `TransactionAttributeType.REQUIRES_NEW` annotation). – Piotr Nowicki Apr 09 '15 at 09:47

2 Answers2

3

Other experiments

Tried annotating both beans with @Singleton and @Startup and received the same exception (I cannot annotate BeanF with @DependsOn( BeanO ) because ModF does not see ModO). Also tried changing BeanO to @ApplicationScoped and in this case the event could be received - the BeanO.observe(@Observes ...) method started executing, performed some logging but crashed with ServiceNotFoundException exception when tried to call some other @Stateless bean (this other bean must be @Stateless since it uses the TransactionAttributeType.REQUIRES_NEW annotation).

CDI solution

A bit ugly but working solution: caching/queueing events: split BeanO into two beans: BeanO1 and BeanO2. Let BeanO1 be an @ApplicationScoped bean, let it observe the event and detect if BeanO2 is ready by calling some hollow method and catching ServiceNotFoundException. If BeanO2 is not there then the event is queued in ConcurrentLinkedQueue in BeanO1. BeanO2 is stateless and does everything what BeanO was doing except observing. When an event arrives and BeanO2 is ready then BeanO1 first pushes events from the queue. This is acceptable only when there will be some other event that will actually trigger handling older events.

JMS

I guess that using JMS would be the cleanest solution but there also are a few pitfalls:

  • if a topic is used then we may fall in the original problem again - the subscriber registers after the first message is sent (not sure about the spec but afair the message is lost when there are no subscribers).
  • if a queue is used then problem may appear when ModF is used in some other product and there is no ModO - the queue will swell and this may not be super gut.
    • maybe ModF could define some MDB that reads all events drops them and ModO somehow registers its own MDB that has higher priority (just guessing, don't know if this is possible)
    • maybe ModO could contain a configuration text file with a queue's name so ModF can read that file, initialize connection to queue on the fly and put events to this queue (if there is no ModO and there is no file then events are not fired by ModF).
rychu
  • 896
  • 1
  • 7
  • 16
1

First of all, I think that CDI creates a 'new' instance of the bean and delivers the event to it in case

  • there is no active contextual instance (in current scope), and
  • the observer is not conditional

I wrote about this here

So this behavior is strange IMO

In terms of alternatives - is it possible to declare you observer method as 'static' ? CDI will certainly invoke it in that case

Also, if you haven't already, I would strongly suggest reading the CDI spec doc (ch 10 and section 5.5.6)

Abhishek
  • 1,175
  • 1
  • 11
  • 21