Larry,

Great example!

There are two other aspects by which we can complicate this picture further:

1) the session bean needs to access/modify the session context initially created by 
the servlet
(modelled here by HTTPSession)
2) introduce the notion of process-affinity amongst the set of servlets (or JSPs) and 
session beans that
belong to a session.

The latter case above has implications on fault isolation and failure recovery, issues 
that are not so
easy to deal with in an EJB/servlet runtime that is distributed.

I am sure we need to do some more work on formalizing the notion of a session (or 
session state) that
involves different kinds of components like servlets and EJBs.

My $0.02.
Regards,
Sanjeev K.


LAURENCE CABLE wrote:

> > My question is how do I maintain session state when using HTML, Servlets and
> > EJB's?
> >
> > Scenario:
> > 1) An HTML client(view) invokes a servlet. 2) The servlet(controller) calls an
> > EJB Session bean (Model). 3)The Servlet sends a response back to the client and
> > terminates. The HTML client invokes the servlet to do something
> > else, and so on.
> >
> > Question:
> > 1) How do you maintain a reference to the Session Bean once the Servlet
> > destroy() method is called?
> >
>
>         Hi Mike,
>                 Good question, let me try to give you some guidance!
>
>         This is actually a very interesting problem to solve due the
> interaction
>         of Servlet lifecycle and EJB semantics, and one that we are working on
>         for the Java2 Platform Enterprise Edition Application Programming
> Model.
>
>         Let's start by restating your problem; how does one persist
> SesssionBean
>         reference(s) across Servlet instance lifecycles?
>
>         Although you do not state it I presume that we are dealing with a
> STATEFUL
>         SessionBean, since if it were STATELESS I would probably recommend that
>         (going slightly off topic here) you simply obtain and cache the
> appropriate
>         EJBHome interface to the SessionBean class as follows:
>
>                 - in a static class variable in the Servlet class
>                         - lives for as long as the Servlet Class is loaded
>                           (this is implementation dependent)
>                         - per Servlet Class
>
>                 - in an instance variable in the Servlet
>                         - lives for as long as the Servlet instance lifecycle
>                           (init() -> destroy())
>                         - at least one per instance
>
>                 - in the ServletContext using {set|get}Attribute()
>                         - lives as long as the ServletContext
>                           (this is also implementation dependent)
>                         - at least one per ServletContext
>
>                 - in the HttpSession using {put|get}Value()
>                         - lives as long as the HttpSession
>                           (until it is invalidated or the session times out)
>                         - at least one per HttpSession
>
>         and re-create an instance each time Servlet.service() is called,
> although
>         one could argue which is more efficient, to re-create, or to hold onto
> the
>         object reference itself, I believe the appropriate usage is to
> re-create
>         since by definition (in the spec) a STATELESS SesssionBean has no
> conversational
>         state.
>
>         (back on topic now)
>
>         Given that we have a STATEFUL SessionBean we cannot/do not want to
> re-create it
>         for every invocation of Servlet.service(). Furthermore, since both a
> particular
>         Servlet instance lifecycle may be shorter than that of the HttpSession,
> and that
>         the HttpSession itself may expire, we need to be able to preserve the
> reference
>         across both Servlet and HttpSession lifecycles.
>
>         In order to preserve the SessionBean across a Servlet instance's
> lifecycle I recommend
>         that you try the following (which is of course greatly simplified for
> clarity):
>
>         class ExampleServlet implements HttpServlet {
>
>                 // ...
>
>                 public void doPost(HttpServletRequest req, HttpServletResponse resp)
> throws ... {
>                         HttpSession session = req.getSession(true);
>
>                         ShoppingCart scart = null;
>
>                         if (session.isNew()) { // it's a new session create the 
>session bean
> ...
>                             ShoppingCartHome scartHome = ...; // lookup/obtain the 
>Remote
> EJBHome via JNDI
>
>                             scart = scartHome.create(...); // create instance of 
>shopping
> cart ...
>
>                             session.putValue("ShoppingCart", scart); // save it in 
>the
> HttpSession
>                         } else {
>                             scart = (ShoppingCart)session.getValue("ShoppingCart");
>                         }
>
>                         // use the shopping cart ...
>                 }
>
>                 public void doGet(HttpServletRequest req, HttpServletResponse resp)
> throws ... {
>                         // same strategy as doPost() ...
>                 }
>
>                 // ...
>         }
>
>         Now there is one problem with this ... what happens when the
> HttpSession times out, or
>         in otherwise invalidated ... well then we need to preserve the instance
> elsewhere.
>
>         One approach would be to save it as a client cookie ... as follows:
>
>         class BetterExampleServlet implements HttpServlet {
>
>                 // ...
>
>                 public void doPost(HttpServletRequest req, HttpServletResponse resp)
> throws ... {
>                         HttpSession session = req.getSession(true);
>
>                         ShoppingCart scart = null;
>
>                         if (session.isNew()) { // it's a new session create the 
>session bean
> ...
>
>                             // first we look to see if the client already has a 
>Serialized
> Handle to the
>                             // SessionBean stroed as a cookie?
>
>                             Cookie cookies    = req.getCookies();
>                             Cookie beanCookie = null;
>
>                             for (int i = 0; i < cookies.length; i++) {
>                                 if (cookies[i].getName() == "EJBHandleCookie") {
>                                     beanCookie = cookies[i];
>                                     break;
>                             }
>
>                             if (beanCookie != null) { // previously encoded ...
>                                 String encodedHandle = beanCookie.getValue();
>
>                                 // obtain the encoded serialized handle to the 
>SessionBean
>                                 // from the previously created client cookie.
>
>                                 // use a mythical BASE64 decoder to decode the 
>encoded value into
>                                 // a byte array ....
>
>                                 byte[] buf  = 
>ABase64Decoder.decodeAsByteArray(encodedHandle);
>
>                                 // ignoring the appropriate try blocks for clarity 
>...
>
>                                 ByteArrayInputStream bais = new 
>ByteArrayInputStream(buf);
>                                 ObjectInputStream    ois  = new 
>ObjectInputStream(bais);
>
>                                 scart = ((Handle)ois.readObject()).getEJBObject(); 
>// may fail ...
>
>                                 // if the object referenced by the handle does'nt 
>exist anymore then
>                                 // we'll have to re-create it ... this is 
>problematic since we have
>                                 // probably lost state due to an EJB server failure 
>...
>                             }
>
>                             if (scart == null) { // no existing object ...
>                                 ShoppingCartHome scartHome = ... ; // lookup/obtain 
>the
> Remote EJBHome
>
>                                 scart = scartHome.create(...); // create instance of 
>shopping
> cart ...
>
>                                 // now save the bean as a cookie ...
>
>                                 // ignoring the appropriate try blocks for clarity 
>...
>
>                                 ByteArrayOutputStream baos = 
>newByteArrayOuputStream();
>                                 ObjectOutputStream    oos  = new 
>OutputOutputStream(baos);
>
>                                 oos.writeObject((Serializable)scart.getHandle());
>                                 oos.close();
>                                 baos.close();
>
>                                 // use a mythical BASE64 encoder to encode the 
>serialized handle as
>                                 // a string ...
>
>                                 String encodedHandle =
> ABase64Encoder.encodeAsString(baos.toByteArray());
>
>                                 resp.addCookie(new 
>Coookie("EJBHandleCookie",encodedHandle));
>                             }
>
>                             session.putValue("ShoppingCart", scart); // save it in 
>the
> HttpSession
>                         } else {
>                             scart = (ShoppingCart)session.getValue("ShoppingCart");
>                         }
>
>                         // use the shopping cart ...
>                 }
>         }
>
>         I've done a little hand waving here for the sake of brevity but I
> believe that the idea
>         is sound, I hope this helps!
>
>         - Larry Cable,
>           Senior Staff Engineer,
>           Java Enterprise Technologies,
>           Sun Microsystems Inc.
begin:vcard
n:Kumar;Sanjeev
tel;cell:(650) 740-8501
tel;fax:(650) 654-6208
tel;home:(510) 226-7011
tel;work:(650) 506-4142
x-mozilla-html:FALSE
url:http://www.oracle.com
org:Oracle Corp.;Java & Object Services, ASG, Server Tech
adr:;;500 Oracle Parkway, Box 659604;Redwood Shores;CA;94065;USA
version:2.1
email;internet:[EMAIL PROTECTED]
title:Development Manager
end:vcard

Reply via email to