How to handle this nicely?

Discussions

EJB design: How to handle this nicely?

  1. How to handle this nicely? (20 messages)

    Not sure if this is the right place to collect help.

    Scenario: Web client submits a request along with some data to the server. It takes the server quite a while to process the data. The whole process includes 6 steps, needs averagely 50-60 seconds to be done.

    Requirement: The web client is able to synchronously monitor the state change of the processing while it is going on and to display the state update during the process, i.e, every time a process step is done successfully, the web page should be refreshed.

    Env: J2EE. Applet not considered

    Any advice welcome.

    Threaded Messages (20)

  2. How to handle this nicely?[ Go to top ]

    1) Run the server-process in a separate thread, with status updates in a Status object. When you start the server process, store a reference to the Status object in the HttpSession.

    2) After starting the server-process, send the client to a Please-Wait.jsp, which refreshes every 5 seconds: <meta http-equiv="refresh" content="5">

    3) Whenever the Please-Wait.jsp is invoked, it checks the Status object in the session and displays the updated status.

    4) When the Status gets to "complete", the Please-Wait.jsp redirects to a Results.jsp page with the final results.

    This is not completely synchronous, but is probably close enough for your purposes.
  3. That's what I have right now[ Go to top ]

    Thanks a lot for your response. My current implementation is exactly the same as you suggested. However, I am thinking a "push" way, which would be closer to ideal.

    How about this:
    1.instantiates a data object, bind it to JNDI, this object is ready to hold the processing states and result.
    2.Page1 submits the request to Servlet1, which invokes a method to take care of real business process (MDB works here).
    3.MDB will update the data object every time it finishes a step.
    4.Servlet1 use a loop to keep querying the data object until one step is done. Response forwards to Page2. (Destroy this servlet instance manually?)
    5. Page2 open a hidden Page3 in its "onLoad". Page3 submits to Servlet1 again immediately, while Page2 stays still to waiting for next response from Servlet1.
    6. Go to step-4 if the process is not completed, else redirects to next Action once process is completed.

    I would say this is a half-pull-half-push idea, but at least we make it refresh-every-step. Is it doable?
  4. That's what I have right now[ Go to top ]

    Before you go with the server-push model, bear in mind that this will require a continuous TCP/IP connection between the client and the server for the entire operation, which will have a major impact on scaleability. It will put an upper limit on the number of concurrent client connections.

    If you do go with a server-push model (maybe because timing is very important), I suggest you use a wait/notify thread model instead of a continuous loop. The continuous loop will require some sort of delay in order not to saturate your CPU, and is really no better than the refresh approach; it just pushes the refresh to the server rather than the client.
  5. Thanks a lot for your advice[ Go to top ]

    In my application, there is not much of concurrent access to the server, say, 15 users maximum. It is safe to hold the connnetion open for 10 seconds, isn't it?
    You suggestion leads me to further questions: Is there any callback method available for servlets? How could I notify a servlet instance in the container?

    Besides, I googled a "push" framework called "Pushlet", I read some articles about it, still not quite buy it. What do you think about it?
  6. Thanks a lot for your advice[ Go to top ]

    Given your small number of users, the concern over the max number of TCP/IP connections is probably a non-issue.

    There is no callback mechanism for servlets. When I said "wait/notify", I meant using low-level thread wait() and notify() methods. You could write code something like this in your Status object:

    class Status ...

        String synchronized getStatus() {
            return this.status;
        }

        String synchronized isDone() {
            return this.status.equals("Done");
        }

        String synchronized waitForUpdate() {
            if (!isDone()) {
                wait(); // Thread sleeps until notify()
            }
        }

        String synchronized setStatus(String newStatus) {
            this.status = newStatus;
            notifyAll(); // Wake up waiting threads
        }
    }

    In your Serlvet:

    while(!status.isDone()) {
      output(status.getStatus());
      status.waitForUpdate(); // Sleep until update
    }
    // Redirect to Result.jsp

    In your process:

    // Do step one ...
    status.setStatus("Step 1"); // Wakes up servlet
    // Do step two ...
    status.setStatus("Step 2"); // Wakes up servlet
    // Do other steps ...
    // Finish up ...
    status.setStatus("Done"); // Servlet finishes work

    This will only function correctly if your servlet and the process are running the same JVM and have access to the exact same Status object (which means the MDB approach won't work).

    You can also add a timeout into the wait() method in case the process hangs or crashes.

    I thought of another major issue with this approach, though. Servlets are singletons, so with the push approach, your servlet will be dedicated to servicing a single client. You will probably need to create a GenericServlet with custom HTTP processing logic, which will probably be server-specific.
  7. Can't afford the servlet and process logic in the same JVM, so I figure I have to live with loop-querying.

    Binding the state object to JNDI is to guarantee that state object is unique in the entire context.

    HttpServlet is singleton, but it is able to deal with requests concurrently, am I right? First time the request is submit to the servlet, a correlation ID could be generated and returned with the response for future querying.
  8. HttpServlet is singleton, but it is able to deal with requests concurrently, am I right? First time the request is submit to the servlet, a correlation ID could be generated and returned with the response for future querying.
    You are right here. I had a brain-hiccup. I was thinking about the issue of synchronizing on the servlet object itself (which you should not need to do).
    Can't afford the servlet and process logic in the same JVM, so I figure I have to live with loop-querying. Binding the state object to JNDI is to guarantee that state object is unique in the entire context.
    If you are going with loop-querying, you may as well stick with the meta-refresh. The loop-querying effectively performs the same refresh operation from servlet-to-JNDI-bound-object rather than browser-to-servlet, and therefore won't be any more timely. Unless you set up some kind of callback object, you won't be any better off.

    If you do set up a callback object, it will have to be bound to thread processing the servlet, not the servlet itself (though you may be able to do some sort of clever trick using the servlet session). No matter what you do, this is going to be an ugly mess.

    Ask yourself if you really need this. The refresh mechanism is going to give the users messages accurate to within 5 or 6 seconds. The server-push mechanism is going to be a huge amount of work, and will at best increase the accuracy to 1 second or so (given the latency from browser-to-servlet, servlet-to-MDB).
  9. In my solution posted before:

    4.Servlet1 use a loop to keep querying the data object until one step is done. Response forwards to Page2. (Destroy this servlet instance manually?)
    5. Page2 open a hidden Page3 in its "onLoad". Page3 submits to Servlet1 again immediately, while Page2 stays still to waiting for next response from Servlet1.

    The hidden Page3 actually plays the role of submit-to-refresh. :)

    META-REFRESH is good enough for now, which is running pretty satisfying. I just seek more backup options here in case more critical requirements come in.
  10. I agree with thread's wait()/notify() solution. According to this way, you just put the "Meta-Reflesh" work to the server rather than deal it manually.
    That will make the client to get response as soon as the state been changed,rather than aways checking the state in the server side by himself.
    That's a pure "push" solution.

    But i have no idea about the topic "Can't afford the servlet and process logic in the same JVM". Will this affect the performance or the security?

    and "more backup options here in case more critical requirements come in"
    such as ???
  11. Notify/wait solution only works in one JVM, while the process logic currently is in MDBs. Although I am not very clear about how application servers handle MDB in JVM perspective. assumption of servlet and MDB being in the same JVM is kinda risk.

    Such as....to detecting the exact time each step is completed. :)
  12. 4. Servlet1 use a loop to keep querying the data object until one step is done. Response forwards to Page2. (Destroy this servlet instance manually?)

    5. Page2 open a hidden Page3 in its "onLoad". Page3 submits to Servlet1 again immediately, while Page2 stays still to waiting for next response from Servlet1.
    This idea has merit, and would help scaleability a lot. If you use servlet push as a mechanism to push out a refresh page to the browser, it cuts down on the amount of time the TCP/IP connection is open. With this approach, the connection is open until a given step is complete. Then you get a forced refresh, and a new connection until the next step is complete.

    You should not need to destroy the servlet after the force refresh. Just let the doGet/doPost method terminate normally.

    I still think you need some sort of wait()/notify() mechanism between the servlet and the MDB processing for this to be really effective, though.
  13. I figure now the question simplifies to:

    web browser <-> servlet <-> process logic
    or
    web browser <-> servlet -> state object <- process logic

    The mechanism wait/notify or observer/observable, I think it hard to implement between J2EE layers and containers (in case the web layer deployed in a different node other than the process logic resides).

    Bidirectional web service would solve it, if both the web application and EJBs are configed as web services, right?
  14. Sorry to take so long to get back to you. I have been busy.

    Here are my latest thoughts. The big issue seems to be how to manage the connection from servlet to process logic. If you are planning on using MDB for the process logic, the simplest way to manage the call-backs might be messaging.

    Here is how it might work:

    1) Create a StatusTracker object in the Servlet. Store it in the session so that it persists in a user-specific way during refreshes. Have the tracker initiate a connection to the process logic by sending a message with a correlation ID for replies, and then wait for a reply messages in a reply queue with the given correlation ID.

    2) The process logic is launched in an MDB by the incoming message. As it completes each step of the process, it can send "Step Completed" messages to the reply queue as it completes each step.

    3) When the StatusTracker in the servlet layer receives reply messages, it can force a browser refresh using the server-push suggested earlier by Senthil. Then the tracker can go back to waiting for new replies. This continues until the process is complete.

    So long as the correlation IDs are unique to each user session, the servlet can properly separate messages for each process. You can add in timeouts and automatic refreshes to deal with browser timeouts and process logic failures.

    An alternative to correlation ID is to use a temporary reply-to queue, and make the queue unique to the session rather than the ID. I am not sure which option would be more effecient; it would depend on your messaging system, and I am no expert on messaging anyway.

    Messaging is probably the best distributed approximation of wait/notify or event systems, and I am embarassed that I didn't think of it earlier.
  15. Need some time[ Go to top ]

    Need some time to look into Messaging technologies to understand your solution. :P
  16. Need some time[ Go to top ]

    No worries. It is a pretty interesting thought-exercise.
  17. messageing is so complicated[ Go to top ]

    I've never thought Message mechanism to be so complicated.
  18. Am I right?[ Go to top ]

    After some time on JMS, I think I got most of the picture of MESSAGING like the following:

    1. After the servlet submits the request to the process logic and gets a correlation ID back, creates a StatusTracker object with this ID and the session as the MessageListener of PROCESSING QUEUE, store it in the session.
    2. Once a update message puts into the PROCESSING QUEUE by the MDB, the StatusTracker's ONMESSAGE is invoked, which will set some info in session, such as CORRELATIONID = 1234 STEP = 2, indicating the processing of 1234 is in the step No.2 (current step)
    3. The servlet render the response as any steps prior to the current step marked as "finished" and the current step as "processing", send it back.
    4. Page updated, another request to refresh sends to the servlet if the whole process is not done, go to 3; Otherwise, remove the StatusTracker from session, redirect to next page.

    I have to stick to the approach of "hold the connection to the servlet open during each step", because there is no way to force a browser refresh. Multipart is only supported by Netscape.
  19. Am I right?[ Go to top ]

    This sounds good to. I still think it is way more trouble than it is worth, but the solution you propose would probably have decent throughput and reasonable scaleability.
  20. You said it[ Go to top ]

    You are right. Unless the client is dying to have this "push" feature, I won't implement it in this way. As you said, a thought-practice. :)
  21. How to handle this nicely?[ Go to top ]

    I think you can use any of the 2 techniques.

    1. Client Pull:
    In the client pull, you can set your html page refresh time to some seconds. After the dely, the browser will automatically refresh the page.
    http://pub.spccatv.com.cn/~rison/servlet/ch05_06.htm

    Server Push:
    You can use MultiPartResponse to achive the Server Push in Servlets. You can see the tutorial here: http://pub.spccatv.com.cn/~rison/servlet/ch06_03.htm

    Hope this helps
    Senthil.