4 Replies Latest reply on Sep 30, 2004 3:05 AM by ebende

    Who can help with design challenge to get data from Session

    ebende

      Hi,

      I'm working on a J2EE application with Servlets and EJBs. One of the tasks is to do a big calculation (10 min-1 hour). In order not to use all CPU resources for these calculations, I have an asynchronously design pattern and do the calculations one by one.

      To this end I use a Servlet that sends a message with Java Message Services (JMS) to a queue. A point-to-point Message Driven Bean is pulling messages from the queue and is subsequently calling a Session Bean that does the calculation. Until so far, this obeys "EJB Design Patterns of Floyd Marinescu, Chapter 1 ,Message Facade".

      Here comes my question:
      The results of the calculation, once the calculation is finished, are sitting in the Session Bean (in memory). Now I want to access the calculational results of the session bean from within a servlet. How can I do this? In some way the data in the session bean should be associated with a user session of the servlet. But I think I can not access session attributes of the HttpSession nor those of the ServletContext.

      By the way, I don't want to persist them in a database because it 's a lot of data and it's not clear whether data is needed in the future.

      This is undoubtly an issue that occurs in more applications. Can someone help me with this one?

      Thanks,

      Evert Bende

      http://212.203.14.69/topsolar/cgi-bin/climatetop50/cgi-bin/topsites.cgi?action=in&id=69]www.wattabout.com

        • 1. Re: Who can help with design challenge to get data from Sess
          enterprisejavabones

          Hi Evert,

          If i understand correctly, you need your servlet to access the result of the calculation produced by your session bean.

          First of all, is your SessionBean stateful or stateless?

          Secondly, i don't really understand this

          In some way the data in the session bean should be associated with a user session of the servlet.


          Are you saying that the data must be obtained while the HttpSession is active?

          If so, here's what i think mite help you.


          Create a JNDI bindable JavaBean (lets call it CalcContext) type of object which your session bean has access to (can instantiate). Once your session bean completes its calculations it can create an instance of the CalcContext and bind it into to the JNDI tree. If there is already a CalcContext bound, you can use the Context.rebind method to update the JNDI tree with a CalcContext that contains the most updated data.

          Your servlet then can lookup your CaclContext (even if its on a diff server or VM) using JNDI.

          To do this you'll need:

          A CalcContext interface which extends java.rmi.Remote. In this interface define a Setter/Gettter method(s) to store/retrieve your calculation values.

          public interface CalcContext extends java.rmi.Remote {
          
           public static final String JNDI_NAME = "myapp/CalcData";
          
           public void setCalcDataTotalValue(int value);
          
           public void setCalcDataLineItems(Hashtable lineItems);
          
           public int getCalcDataTotalValue();
          
           public Hashtable getCalcDataLineItems();
          }
          


          A CalcContextImpl class which extends java.rmi.server.UnicastRemoteObject and implements your CalcContext interface. This class will have the attributes to store your calc results and implementations of your setter/getter's defined in CalcContext.

          public class CalcContextImpl {
           private int calcTotal;
           private Hashtable lineItems;
          
           public void setCalcDataTotalValue(int total) {
           this.calcTotal = total;
           }
          
           public void setCalcDataLineItems(Hashtable lineitems) {
           this.lineItems = lineitems;
           }
          
           public int getCalcDataTotalValue() {
           return this.total;
           }
          
           public Hashtable getCalcDataLineItems() {
           return this.lineItems;
           }
          }
          


          Your session bean when completing its calculation will then need a method something like:

          public boolean bindResult(Object resultData) {
          
           InitialContext ic = new InitialContext();
           CalcContextImpl cci = new CalcContextImpl();
          
           // -------
           // code that sets the value of your CalcContextImpl attributes
           // -------
          
           Remote stub = UnicastRemoteObject.toStub(cci);
          
           try {
           ic.rebind(CalcContext.JNDI_NAME);
           return true;
           } catch (Exception e) {
           //exception handling code
           return false;
           }
          }
          
          


          finally your servlet when it wants to obtain the data will simply lookup the object in the JNDI tree, narrow it to the type of Object it is supposed to be and use it. This would be something like



          public void doPost(HttpServletRequest req, HttpServletResponse res) {
           InitialContext ic = new InitialContext();
           Object obj = ic.lookup(CalcContext.JNDI_NAME);
           CalcContext cc = (CalcContext)java.rmi.PortableRemoteObject.narrow(obj, CalcContext.class);
          
           cc.getCalcDataTotalValue();
           cc.getCalcDataLineItems();
          }
          


          Guess that should bout help, if i understood your question correctly :)

          • 2. Re: Who can help with design challenge to get data from Sess
            ebende

            Prem,

            thank you very much for your clear and comprehensive answer. I'm going to study it. For now, I have some questions.

            1.

            A. Since more than 1 user might do the calculation, the calculational results should be stored in a something like a HashMap() with the sessionID as key I suppose. Once the session is ending, a method in a listener servlet (that listens whether a session ends) should remove the calculational data belonging to that session.

            B. The alternative is to create a JNDI name for every session, consisting of the sessionID to make it unique (eg myapp/CalcData7af648af647af341). But this seems not very desirable to me.

            Would you also do that like that? I mean option 1A. Or does it make a difference whether you are using stateful or stateless Session Beans. I'm not sure whether I undstand the JNDI binding correctly.

            2. What is the code line

            Remote stub = UnicastRemoteObject.toStub(cci);
            

            doing? The stub object is not being used after this code line.

            Hope you can also give an answer to these questions.

            Again thanks,

            Evert

            http://212.203.14.69/topsolar/cgi-bin/climatetop50/cgi-bin/topsites.cgi?action=in&id=69



            • 3. Re: Who can help with design challenge to get data from Sess
              enterprisejavabones

              Hi Evert,

              For question 1, if i were you, i would implpement it using your suggestion 1A. I sure would not want to bind an Object to JNDI for each user session that is active. As such, I would probably change the CalcContextImpl class to be something like

              public class CalcContextImpl
               private HashMap calcData;
              
               public void setCalcDataLineItems(String userSession, Object calcs) {
               synchronized(this) {
               if (calcData.containsKey(userSession)
               //you need to create this exception
               throw new SessionAlreadyActiveException("Session ID......");
               else
               calcData.put(userSession, calcs);
               }
               }
              
              
               public Object removeCalcDataForSession(String userSession) {
               synchronize(this) {
               if (!calcData.containsKey(userSession)
               //again you need to create this
               throw new NoSuchUserSessionExceptoin("blah blah blah");
               else
               return calcData.remove(userSession);
               }
               }
              }
              


              This way, when a user requests the calculations to be done, they are computed and stored in a CalcContextImpl object and bound to the defined JNDI namespace (in this case --> myapp/CalcData). An important point to note, you have to ensure that you synchronize your access to the HashMap.

              When a user session is ending, your listener servlet can lookup the CalcContextImpl from JNDI and remove the calc data for the particular user session.

              Or does it make a difference whether you are using stateful or stateless Session Beans. I'm not sure whether I undstand the JNDI binding correctly.

              If you are storing the data in a "beanified" object and binding it to JNDI, then its probably better to use a Stateless Session Bean. If you are binding the Object (CalcContext in this case), then it dosen't make a diff whether you are using Stateless/Stateful (tho i'd recommend Stateless as they're easier to code)

              For Question 2:
              There was actually an error in my example. This code is wrong.
              Remote stub = UnicastRemoteObject.toStub(cci);
              
               try {
               ic.rebind(CalcContext.JNDI_NAME);
               return true;
               } catch (Exception e) {
               //exception handling code
               return false;
               }


              Should actually be this:
              Remote stub = UnicastRemoteObject.toStub(cci);
              
               try {
               ic.rebind(CalcContext.JNDI_NAME, stub);
               return true;
               } catch (Exception e) {
               //exception handling code
               return false;
               }


              In this case, you are creating a Remote object from your CalcContextImpl class which can be bound into JNDI.

              Another typo i realised is this:
              public class CalcContextImpl {
               private int calcTotal;
               private Hashtable lineItems;
              ......
              


              It should actually be

              public class CalcContextImpl implements CalcContext {
               private int calcTotal;
               private Hashtable lineItems;
              


              Hope that helps,
              G'luck

              Prem

              • 4. Re: Who can help with design challenge to get data from Sess
                ebende

                Prem,

                many thanks again. It's clear. If you need help, let me know. Though I'm not sure if I can help you.

                Evert

                http://212.203.14.69/topsolar/cgi-bin/climatetop50/cgi-bin/topsites.cgi?action=in&id=69