Hi Larry,
That was a great email!
jc
John Crupi
Senior Enterprise Java Center
SunPS Java Center
----- Original Message -----
From: LAURENCE CABLE <[EMAIL PROTECTED]>
To: <[EMAIL PROTECTED]>
Sent: Wednesday, March 24, 1999 5:06 PM
Subject: Re: Servlets -> EJB Session Persistence
>> 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.
===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff EJB-INTEREST". For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".