user1169587
user1169587

Reputation: 1340

why stateless and stateful session bean behaves not as expected

public class Test1(){  
  public vod method1(){  
    try{  
        Hashtable<String, String> env = new Hashtable<String, String>();  
        env.put(Context.INITIAL_CONTEXT_FACTORY, EJB_JNDI_FACTORY);  
        env.put(Context.PROVIDER_URL, EJB_URL);  
        InitialContext ctx = new InitialContext(env);             
        LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);  
        System.out.println("logSearchRemote = " + logSearchRemote);  
        logSearchRemote.setTest(5);  
        System.out.println("logSearchRemote.getTest() = " + logSearchRemote.getTest());  
        System.out.println("logSearchRemote.getTestAgain() = " + logSearchRemote.getTestAgain());  
        LogSearchRemote logSearchRemote2 = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);  
        System.out.println("logSearchRemote2 = " + logSearchRemote2);  
        System.out.println("logSearchRemote2.getTest() = " + logSearchRemote2.getTest());  
        System.out.println("logSearchRemote2.getTestAgain() = " + logSearchRemote2.getTestAgain());  
        this.session = session;  
        session.setAttribute("LogSearchEJB", logSearchRemote);  
        System.out.println("logSearchRemote = " + logSearchRemote);  
    }catch(Exception e){  
        e.printStackTrace();  
    }  
  // if @stateless, throw exception "$Proxy53 cannot be cast to hk.gov.ehr.service.tch.als.admin.logsearch.ejb.LogSearchRemote"  
  // if @stateful, no error!!  
LogSearchRemote logSearchRemote = (LogSearchRemote)session.getAttribute("LogSearchEJB");  
  //.....  
  }  
}   

1) for the above code, if LogSearchRemote implementation bean is stateful, then

   LogSearchRemote logSearchRemote = (LogSearchRemote)session.getAttribute("LogSearchEJB");

has no error, but if LogSearchRemote implementation bean is stateless, then exception "$Proxy53 cannot be cast to hk.gov.ehr.service.tch.als.admin.logsearch.ejb.LogSearchRemote" is thrown, why?

2) for stateful session bean, I find each time the

LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME); 

return different logSearchRemote implementation bean,
but if stateless session bean, each time the

LogSearchRemote logSearchRemote = (LogSearchRemote) ctx.lookup(LOG_SEARCH_EJB_BINDNAME);   

return the same bean!!
why is this case?
I expect stateless session bean should not keep state and each lookup should return a different implementation bean.

@Stateless(name = "AlsAdminLogSearch_1_0", mappedName = "ejb/AlsAdminLogSearch_1_0")  
public class LogSearchBean implements LogSearchRemote{  

    private int test;

    @Override  
    public void setTest(int value){  
        test = value;  
    }  

    @Override  
    public int getTest(){  
        return test;  
    }  

    @Override  
    public int getTestAgain(){  
        return test;  
    }  

//...methods  

}    

3) when I call

logSearchRemote.setTest(5);  
System.out.println("logSearchRemote.getTest() = " + logSearchRemote.getTest());  
System.out.println("logSearchRemote.getTestAgain() = " 
logSearchRemote.getTestAgain());   

for stateless session bean, the getTest() and getTestAgain() can remeber the instance variable "test" in previous method call!!

Why will it remember? stateless session bean is not supposed to call different EJB instance for each method call?

Upvotes: 0

Views: 694

Answers (1)

Christian Gosch
Christian Gosch

Reputation: 75

Stateless Session Beans ought to be used "in a stateless manner" but in fact the server keeps a pool of instances (dependent on vendors strategy). Thus it is possible that you may receive exactly the same instance on several lookups, but it is by no way guaranteed. Instead different threads and client instances may get the same Stateless EJB instance, thus effectively sharing this Stateless EJB instance. That is why Stateless EJB should not internally hold any "business logic state" because you do not know which client is next. Although not recommended, a Stateless EJB may of course hold some internal technical state which may enable it to get faster access to external "stateless" resources on instance reuse. (See EJB lifecycle diagrams available on the web and in books.)

Stateful Session Beans on the other hand ought to be used "in a stateful manner" that is they are intended to hold state over some time and spanning multiple client requests. Thus a client is guaranteed to receive a "fresh instance" on lookup, and because the container cannot be sure if any implementation "forgets" old state information after end of last usage cycle, the container simply destroys Stateful EJB after detaching them from their client and creates a new instance on lookup.

The problem with that is that a client of a Stateful EJB must hold and keep its ref to the EJB for the full planned usage cycle, because after loosing the (last) ref the Stateful EJB is lost in space and cleaned up by the container. The EJB ref on the other hand ist not serializable (as far as I know), and thus the client is required to be not serialized during its EJB usage cycle in order to keep its EJB ref alive.

Additionally I do not know about any lookup mechanism comparable to HttpSession attribute lookup to find any existing Stateful EJB after some time: A stateful EJB is either actually bound to a running client, or it is "not existent".

As a result, in a project where Stateful EJBs are used to keep some user session info over lets say hours, we decided to use a HttpSession attribute object for holding the Stateful EJB ref. Thus the application can lookup the "EJB holder" object in HttpSession and then reuse the Stateful EJB. But this obviously fails if the web container decides to serialize the HttpSession attribute object (the "EJB holder") because the EJB ref does not survive serialization. On next lookup of the "EJB holder" in HttpSession scope it is deserialized by the web container, but the Stateful EJB is cut off its ref and cannot be used any more.

Upvotes: 1

Related Questions