On your discussion of recreating STATELESS session-beans for each request:
Is the client of SessionBeans really entitled to know wheather a SessionBean is 
STATELESS or STATEFUL?
Your strategy for STATELESS gives hard maintenance problems when a SessionBean at a 
later stage of development is required to change from STATELESS to STATEFUL. (This 
could be at a late time at for, example, optimization-time.)
Or perhaps the design of a STATELESS sessions always requires client-knowledge of this 
property, and that this property never changes in system-lifetime? Some real-world 
experience on this?

-----Original Message-----
From:   LAURENCE CABLE [SMTP:[EMAIL PROTECTED]]
Sent:   Wednesday, March 24, 1999 11:06 PM
To:     [EMAIL PROTECTED]
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. << File: vcard.vcf >>

�������������������������o 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".

Reply via email to