7

This is a JSF 2 app running on WAS8.0. Here is the code for the "backing" bean of one page.

    @Named("mySessionBean")
    @SessionScoped
    @Stateful
    @LocalBean
    @StatefulTimeout(unit = TimeUnit.MINUTES, value = 10)
    public class MySessionBean implements Serializable {
        @PostConstruct
        public void init()
        {
             System.out.println("start MySessionBean: " + this.hashCode());
         }

        @PreDestroy
        public void cleanup()
        {
             System.out.println("destroy MySessionBean: " + this.hashCode());
         }
        ....
    }

The session timeout value set in web.xml is smaller than the bean's timeout. When I run the app, I see the printout from @PostConstruct but never see the one from @PreDestroy. I have tried the following 2 scenarios: 1. logout - invalidateSession; 2. simply wait until the session expires.

I'm not the designer of the app. The designer insists to make all the backing bean as a stateful session bean. I think the more mainstream approach would be just making them CDI bean. But anyway, when I do change the annotation to CDI only, I start getting the printout from @PreDestroy as well

    @Named("mySessionBean")
    @SessionScoped
    public class MySessionBean implements Serializable {
    .....

My question is, what is the reason that I'm not getting the @PreDestroy method call in the first case? If I can't see the @PreDestroy get called, is there any other ways that I can trace the lifecycle of the "backing" beans (in this case, a stateful session bean). Thanks!

chaoshangfei
  • 205
  • 4
  • 12

2 Answers2

4

Look at this section of the Java EE 6 Tutorial, it shows the lifecycle of stateful session beans. The PreDestroy method is only called when the bean is explicitly removed from the client code, calling a method annotated with @Remove.

remigio
  • 4,101
  • 1
  • 26
  • 28
  • I thought Invalidate client session or a session timeout would automatically trigger @Remove `code`FacesContext.getCurrentInstance().getExternalContext().invalidateSession()`code`. But sounds like it won't. Then what would be the best to call the @Remove method in a centralized way? – chaoshangfei Feb 08 '13 at 19:20
  • Also, even the InvalidateSession call never trigger @Remove. But after that, once the StatefulTimeout value is met, shouldn't the PreDestory get called somewhere after that? I'd been checking the log hours after session timeout but not finding output from PreDestroy. – chaoshangfei Feb 08 '13 at 22:07
  • The specification just says that upon timeout being reached the bean becomes _eligible_ for removal, it's up to the application server to decide what to do. If you need the _PreDestroy_ method to be certainly called you should call the _@Remove_ method. – remigio Feb 09 '13 at 06:38
  • If I only make Service Object as SFSB, and make all my backing beans as SessionScoped CDI beans. Then inject the Service Object into each backing bean. When the session expires, should I call the @Remove method from every backing bean that having the Service Object injected. Or just one is sufficient? What is the best practice? – chaoshangfei Feb 13 '13 at 18:10
  • 1
    Stateful session beans should be used when you need to store some data and persist them across more than one method call, typically during a client session. his means that it's an application responsibility that of marking session boundaries and decide when dismiss the sfsb. In other words, the solution to your problem is a well designed workflow with one single exit point; failing meeting this requirement means that sfsbs are not the right choice. – remigio Feb 14 '13 at 06:41
  • Good stuff, thanks! One more related question: do you think there's any reasonable scenario where you would make a JSF backing bean both CDI bean & SFSB? – chaoshangfei Feb 14 '13 at 18:22
  • I would resort to SFSBs when needing such services as transactions, security, load balancing and so on, otherwise go with CDI beans. Another reason to use SFSBs could be that of building a cleaner architecture, based on separate layers of services to be reused in a different contexts; in this case CDI beans belong to client layer and access the business layer SFSBs. – remigio Feb 15 '13 at 08:25
2

The other answer links to a Java EE 6 Tutorial, that doesn't even mention the existence of timeouts. I also don't think that tutorial clearly states that @PreDestroy method is only called after an explicit @Remove method call. The causation is not stated, it just describes two events, not necessarily directly related:

At the end of the lifecycle, the client invokes a method annotated @Remove, and the EJB container calls the method annotated @PreDestroy, if any.

The WebSphere docs mention the following:

The PreDestroy life cycle interceptor callbacks are invoked for a stateful session bean when a remove method is called. Also keep in mind that the PreDestroy life cycle interceptor callbacks are not called if the stateful session bean times out while in the passive state, or if an unexpected exception occurs during a method invocation on the bean and the bean is discarded.

Now here it does clearly state that PreDestroy callbacks are invoked when a remove method is called. At the same time it explictly states that PreDestroy callbacks are not called if the SFSB times out while in the passive state. So that would mean they do get called when the SFSB is not in the passive state?

Now let's take a look at JBoss.
First, there's a JBoss issue about PreDestroy not being called on removal timeout if removalTimeout < idleTimeout. Seems to be fixed in 5.2.
Second, I just tested on JBoss 4.3, what happens when a passivated SFSB gets removed on timeout - it gets activated before destroying.

So it seems that there exist multiple interpretations of how timeouts and bean removal should behave.

Vsevolod Golovanov
  • 4,068
  • 3
  • 31
  • 65
  • WebSphere update to the answer: I've made a few tests and when `@StatefulTimeout` expires WAS 8.5.5.1 will first call PrePassivate and then destroy the Stateful bean, without calling PreDestroy. According to specification - 2.3.2 LifeCycle diagram - it is correct as when SFSB is in passive state you don't have to call PreDestroy on timeout. But it should be clearly stated in documentation that timeout passivates bean before destroying. – Gas Aug 19 '14 at 15:39