2011-12-13 41 views
2

我对Java EE没有太多的知识,但我目前正在学习它。Java EE中的长时间运行任务WebApp + icefaces

我想出了一个涉及用户调用的长时间运行任务(最长达几分钟)的项目。该任务由几个步骤组成。当然,我想向用户展示进展情况。

该项目使用Java EE与JPA,JSF和Icefaces。它运行在Glassfish上。

一个有经验的同事劝以下模式给我:

  1. 创建它创建了一个响应对象和处理该请求
  2. 每个步骤
  3. 在之后坚持响应对象的无状态,异步EJB支持bean,查询并显示响应对象

这很好。我唯一的问题是更新状态站点以反映进度。目前我正在通过一个简单的JavaScript页面每x秒刷新一次。

你知道一种方式/模式来反映从无状态ejb到jsf支持bean的当前步骤吗? 或者,我更喜欢这个,你知道一种方法来每隔x秒查询一个支持bean的值吗?

编辑:

我知道ICEfaces的的推动机制,但我想从计算EJB脱钩,原因如下状态更新站点:

  • 的支持bean可能已被销毁,因为用户离开网站并稍后返回以获取结果
  • 对于一个用户可能存在多个会话并因此存在多个豆
  • 拥有干净的设计

回答

1

有几个选项可以传回此信息。如果EJB生活在同一个JVM中,那么你可以使用某个单独的地图并在某个关键字(会话ID)下存储进度。

如果不是这种情况,则需要一些共享状态或comminucation。有几个选项

  • 其存储在数据库中,从两个层访问(SQL,JNDI,LDAP - 更好的解决办法是key-value存储,像Redis的 - 如果你得到了它)
  • 使用一些消息存在Web层侧的处理状态
  • 在哈希它在EJB层侧
  • 储存状态,并提供了另一种SLSB方法rtrieve这种状态

您的选择是不容易的 - 所有这些解决方案来吸不同的方式。

0

当您使用icefaces时,您可以使用ICEpush机制来呈现您的更新。

+0

当然,但不幸的是我不知道一个机制来通知支持bean的进展。 backing bean也可能已经被销毁,用户在计算完成后会回来。并且由于封装,我不想在EJB中使用任何icefaces代码。 – Michael 2011-12-13 22:14:07

0

我使用线程轮询模型和ProgressBar组件一起完成了这个任务。

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(); 
}