1

私の JEE6-App (Glassfish 3.0.1 で実行) には、大量のメールを送信する必要がある EmailEJB があります。メールは非同期で送信されるため、新しい EJB3.1 @Asynchronous で注釈が付けられ、別のスレッドで実行できます。ここで、メソッドの現在のステータスについてユーザーに通知する必要があります。すでに送信されたメールの数は?

メールの非同期送信は正常に機能しますが、進行状況を外部からアクセスできるようにする方法がわかりません。それを行うための私のアプローチはかなり間違っているようですが、どういうわけかそれが可能でなければなりません(おそらく別のアプローチ)。これは私の EmailEJB が現在どのように見えるかです (疑似コードのようなものですが、私が望むものを説明しています):

@Stateful
public class EmailEJB {

  @Asynchronous
  public Future<Integer> sendMails() {
    for (int i=0; i<mails.size; i++) {
      sendMail(mails[i])
      // i want to return the progress without returning ;)
      return new AsyncResult<Integer>(i)
    }
  }
}

//Just for the completeness... from outside, i'm accessing the progress like this:
Future<Integer> progress = emailEJB.sendEmails();
Integer currentvalue = progress.get();

リターンでキャンセルせずに、非同期関数内で現在の進行状況を返すにはどうすればよいですか? 関数内のループの進行状況をユーザーに表示するにはどうすればよいですか? 別の非同期メソッドが必要ですか? ヒントはありますか?

4

3 に答える 3

4

誰でもない?これが私の解決策です。これが大きな回避策なのか、それともこれを実現するための単なる方法なのかはわかりません。

@Asynchronous メソッドはセッション コンテキストにアクセスできないため、セッション Bean もありません (少なくとも方法がわからないため、常に ConcurrentModificationErrors または同様のものを取得していました)、HashMap を含む Singleton ProgressEJB を作成しました。

@Singleton @LocalBean @Startup
public class ProgressEJB {
  private HashMap<String, Integer> progressMap = new HashMap<String, Integer>
  // getters and setters
}

このハッシュマップは、SessionId (文字列) を整数値 (進行状況 0->100) にマップする必要があります。したがって、ユーザー セッションは進行状況に関連付けられます。私の EmailEJB では、この ProgressEJB を注入しています。私の @Asynchronous メソッドでは、メールが送信されるたびに値を増やしています。

@Stateful @LocalBean
public class EmailEJB {
@Inject
private ProgressEJB progress;
// Mail-Settings
...
@Asynchronous
public void sendEmails(user:User, message:Message, sessionId:String) {
  progress.progressMap.put(sessionId, 0);
  for (int i=0; i<mails.size; i++) {
    sendMail(mails[i])
    progress.getProgressMap().put(sessionId, (i / mails.size) * 100)
  }
  progress.getProgressMap().remove(sessionId);
}

sessionId は、関数を呼び出すときにマネージド (Weld) Bean から取得されます。

@SessionScoped
@Named
public class EmailManager {
  @Inject 
  private ProgressEJB progress;
  @Inject
  private FacesContext facesContext;

  private String sessionId;

  @PostConstruct
  private void setSessionId() {
    this.sessionId = ((HttpSession)facesContext.getExternalContext().getSession(false)).getId();
  }

  public Integer getProgress() {
    if (progress.getProgressMap().get(sessionId) == null)
      return 100;
    else 
      return progress.getProgressMap().get(sessionId);
  }
}

これで、Ajax ポーリングを使用して JSF ビューから EmailManager の進行状況にアクセスし、既に送信されたメールの数をユーザーに伝えることができます。2人のユーザーでテストしたところ、うまくいくようです。

于 2010-07-29T14:34:33.867 に答える