EJB 3.0 - Stateful... getHandle()?
Hello,
I just start working with EJB 3.0 and it's much better if we compare with EJB 2.x... It's easier, cleaner, etc. However I'm about to throw all away and return the EJB 2.x
I simply cannot efficiently call getHandle() on a stateful session bean. Well, actually withing the bean itself I can do cxt.getEJBObject().getHandle() but that's weird. I want a handle in the client side and I can't. Here's the situation
I'm developing an app that will have a number of different clients. Web and desktop. In my project it's defined that the user session will be in the EJB tier and will be a Stateful Session Bean. So far so good.
The thing is, for the web client, I want to store each user's session in the HttpSession. With EJB 2.x I would get the ejb handle and would serialize it in the httpsession, then when the user get's back in a few minutes we can restore the EJB from the handle. Another weird thing is the way we're forced to declare:
publicclass ServletTestextends HttpServlet{
@EJB
private UserSessionRemote session;
With the above declaration I understand that for every single time someone access ServletTest all web users will get the very same stateful. Well I made that test :-/
We have no control of stateful session bean in EJB 3.
How to control that from the web side? In a swing/swt client I can keep the reference...
Thanks in advance
Aurelio
# 1
Hi Aurelio,
There are a number of statements to clarify regarding the behavior of stateful session beans
in Java EE. First of all, there is no requirement that you need a handle to the stateful session
bean in order to store a reference to it in the Http Session.You can just put the
EJB reference itself directly in the HttpSession.EJB references are special objects that are
required to be storable in HttpSessions within web containers in Java EE application servers.
It's up to the container to make it work, so the application doesn't need to worry about whether
the concrete class of the reference object itself is a subtype of Serializable.
Second, it's correct that in the EJB 3.0 business interface view of Stateful Session beans,
each injection or lookup of a Stateful Session Bean results in the creation of a unique
bean identity.However, in the example you cite there would be only one SFSB instance
created per servlet *instance*, not for each servlet invocation.For this reason, injecting
a stateful session bean into a servlet field is typically not the behavior developers need.
A better way is to declare a class-level @EJB dependency within the servlet (or any
other managed class within the web application)
This is the equivalent of declaring an ejb-ref/ejb-local-ref without the injection part.
Then, you simply do a lookup of that dependency via "java:comp/env/" each time you
want to create a new instance(identity) of that SFSB bean type.
--ken
ksaksa at 2007-7-12 10:40:35 >

# 2
Hey Ken,
Once again you come to the rescue!
Yes, you're right, my fault! I'm still in love with EE 5... The solution was simpler than I could ever imagine:
(...)
public class ServletTest extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession s = request.getSession();
(...)
if(s.getAttribute("session")!=null){
UserSessionRemote remote = (UserSessionRemote)s.getAttribute("session");
remote.setName(name);
}else{
try{
InitialContext ic = new InitialContext();
UserSessionRemote remote = (UserSessionRemote)ic.lookup("ejb.session.UserSessionRemote");
remote.setName(name);
s.setAttribute("session",remote);
}catch(Exception e){
e.printStackTrace();
}
}
Thanks!
Aurelio
# 3
Hi Aurelio,
Glad to help.One suggestion is to use an ejb-ref or @EJB annotation to declare the
Remote EJB dependency and then look it up via the component environment rather than
doing a direct global lookup. That way you don't hard-code a physical JNDI and you can
more easily change which physical Remote EJB Component you are accessing without
changing code or standard deployment descriptors.Otherwise, the code is not as
portable.
E.g.
// Declare a dependency on a Remote EJB
// (This is equivalent to declaring an ejb-ref in web.xml)
@EJB(name="UserSessionRef", beanInterface=UserSessionRemote.class)
public class ServletTest extends HttpServlet ...
...
InitialContext ic = new InitialContext();
UserSessionRemote remote = (UserSessionRemote) ic.lookup("java:comp/env/UserSessionRef");
In Glassfish, the @EJB dependency will be mapped by default to a global JNDI name
equivalent to the fully-qualified class name of its beanInterface attribute, but if
necessary you can set that value to whatever you want using sun-web.xml.
<ejb-ref>
<ejb-ref-name>UserSessionRef</ejb-ref-name>
<jndi-name>MyTargetEJBGlobalJNDIName</jndi-name>
</ejb-ref>
Note that the sun-web.xml doesn't care whether the Remote EJB dependency was declared
using an @EJB or an ejb-ref.In either case you just use the name of the dependency,
which is either the @EJB name() attribute or the ejb-ref ejb-ref-name element.
You can find more information in our EJB FAQ :
https://glassfish.dev.java.net/javaee5/ejb/EJB_FAQ.html
--ken
ksaksa at 2007-7-12 10:40:35 >

# 4
Hi KenThanks again! Nice tip!Regards,Aurelio