Long Running Task in Java EE WebApp + icefaces

ⅰ亾dé卋堺 提交于 2019-12-08 00:33:26

问题


I don't have much knowledge on Java EE but am currently learning it.

I've come up with a project which involves a long running task (up to several minutes) invoked by the user. The task consists of several steps. Of course I would like to show the progress to the user.

The project uses Java EE with JPA, JSF and Icefaces. It runs on Glassfish.

An experienced colleague adviced the following pattern to me:

  1. Create a stateless, asynchronous EJB which creates a response object and processes the request
  2. Persist the response object after each step
  3. In the backing bean, query and display the response object

This works well. My only problem is to update the status site to mirror the progress. Currently I am doing this with a simple JavaScript page reload every x seconds.

Do you know a way/pattern to reflect the current step from the stateless ejb to the jsf backing bean? Or, and I would prefer that, do you know a way to query the value of a backing bean every x seconds?

Edit:

I am aware of the Icefaces push mechanism, but I want the status update site to be decoupled from the calculation EJB for the following reasons:

  • The backing bean might already be destroyed because the user left the site and return later to fetch the result
  • Multiple sessions and therefore multiple beans may exist for one user
  • Having a clean design

回答1:


There are several options to pass back this information. If EJB is living in the same JVM, you may as well use some singleton Map and store progress under certain key (session ID)

If this is not the case, you will need some shared state or comminucation. There are several options

  • store it on database accessible from both tiers ( sql, JNDI, LDAP - better solution would be key-value store , like redis - if you got it )
  • use some messaging to deposit state of processing on web tier side
  • store state in a hash it on EJB tier side, and provide another SLSB method to rtrieve this state

Your choice is not easy - all of these solution suckin a different ways.




回答2:


I accomplished this using a threaded polling model in conjunction with a ProgressBar component.

public void init()
{
    // This method is called by the constructor.
    // It doesn't matter where you define the PortableRenderer, as long as it's before it's used.
    PushRenderer.addCurrentSession("fullFormGroup");
    portableRenderer = PushRenderer.getPortableRenderer();
}   


public void someBeanMethod(ActionEvent evt)
{
    // This is a backing bean method called by some UI event (e.g. clicking a button)
    // Since it is part of a JSF/HTTP request, you cannot call portableRenderer.render

    copyExecuting = true;

    // Create a status thread and start it

    Thread statusThread = new Thread(new Runnable() {
        public void run() {
        try {
                        // message and progress are both linked to components, which change on a portableRenderer.render("fullFormGroup") call
            message = "Copying...";
            // initiates render. Note that this cannot be called from a thread which is already part of an HTTP request
            portableRenderer.render("fullFormGroup"); 
            do {
                progress = getProgress();
                portableRenderer.render("fullFormGroup"); // render the updated progress
                Thread.sleep(5000); // sleep for a while until it's time to poll again
            } while (copyExecuting);
            progress = getProgress();
            message = "Finished!";
            portableRenderer.render("fullFormGroup"); // push a render one last time
        } catch (InterruptedException e) {
            System.out.println("Child interrupted.");
        }
    });
    statusThread.start();

    // create a thread which initiates script and triggers the termination of statusThread
    Thread copyThread = new Thread(new Runnable() {           
        public void run() {
        File someBigFile = new File("/tmp/foobar/large_file.tar.gz");
            scriptResult = copyFile(someBigFile); // this will take a long time, which is why we spawn a new thread
            copyExecuting = false; // this will caue the statusThread's do..while loop to terminate


        } 
    });
    copyThread.start();
}



回答3:


As you are using icefaces you could use the ICEpush mechanism for rendering your updates.



来源:https://stackoverflow.com/questions/8496806/long-running-task-in-java-ee-webapp-icefaces

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!