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

[1616 byte] By [aureliocalegaria] at [2007-11-27 5:17:43]
# 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 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 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

aureliocalegaria at 2007-7-12 10:40:35 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 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 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 4
Hi KenThanks again! Nice tip!Regards,Aurelio
aureliocalegaria at 2007-7-12 10:40:36 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...