3

I know that the use of instance variables within stateless session beans is a popular discussion topic and have already read some of them, but what i am specifically need from this topic, is the actual proper design of my application.

My enterprise application, consists of several stateless beans, which fire on specific events. On such events, i want a couple timers to fire as well and keep track of certain things (e.g. new data inserted in the database, specific to the original event).

@Stateless
public class SpecificFeedbackImpl implements SpecificFeedback {

    @Resource
    protected TimerService timerService;

    //more injections here

    public String name;
    public String ip;

    @Timeout
    public void timeoutHandler(Timer timer) {
         if (timer.getInfo().toString().startsWith(name)) {

         //search db for data of event with identifier "name"
         //if anything found, then send to "ip"

         }  
    }

    public void stopTimer() {
        for (Object o : this.timerService.getTimers())
            if (((Timer) o).getInfo().toString().startsWith(name)){
                ((Timer)o).cancel();
            }       
    }

    @Override
    public void startTimer(long interval, String eventID, String serverIP){
        this.name = eventID;
        this.ip = serverIP;
        stopTimer();        
        TimerConfig config = new TimerConfig();
        config.setInfo(name);
        config.setPersistent(false);
        timerService.createIntervalTimer(interval, interval, config);
    }

}

However, when i did a small test of manually calling multiple timers, with different intervals, eventIDs and serverIPs, i did not have the expected behavior from all timers (some of them never timed-out, etc.).

Is the above source appropriate for the required usage, or should i design it/implement it differently? If yes, could you please suggest a few options?

Vishal Pawar
  • 4,324
  • 4
  • 28
  • 54

1 Answers1

3

i think you should not store state in a stateless bean. alternative would be to store it in the db/em or to store it in a singleton bean.

Edit below:

One way to store in the the database is to use JPA: http://www.vogella.com/articles/JavaPersistenceAPI/article.html

explanation on why storing state in your ejb is a bad idea:
change the timeout method of your been like this:

@Timeout
public void timeoutHandler(Timer timer) {
    String actualName = timer.getInfo().toString();
    System.out.println("actualName=" + actualName + " storedName=" + name);
}

And try starting a few timers:

@Singleton
@Startup
public class SingletonBean {

    @EJB
    LabBean labBean;

    @PostConstruct
    public void init() {
        labBean.startTimer(2000, "123", "1.2.3.4");
        labBean.startTimer(2000, "222", "1.2.3.4");
        labBean.startTimer(2000, "333", "1.2.3.4");
        labBean.startTimer(2000, "444", "1.2.3.4");
        labBean.startTimer(2000, "555", "1.2.3.4");
        labBean.startTimer(2000, "666", "1.2.3.4");
    }
}

You will see the console-output show something like this:

INFO: actualName=123 storedName=666
INFO: actualName=555 storedName=666
INFO: actualName=333 storedName=null
INFO: actualName=444 storedName=null
INFO: actualName=666 storedName=666
INFO: actualName=222 storedName=null

The reason is that the when you invoke startTimer() a Stateless EJB-instance is taken from a pool of EJBs. When startTimer() method returns the EJB is returned to the pool.

When the timeout occurs 2000ms later, it might be a different EJB-instance taken from the pool to handle the method invocation of the @timeout annotated method.

Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74
  • Another way of storing data is make your `name` property as `static`, or if the name is specifc to each timer, to have a `static Map` and use `timer.getInfo().toString()` as the `Map` key. – Julien Kronegg Feb 05 '14 at 07:52