2009-10-29 16 views
7

Javaで非同期メッセージキューを動的に作成する必要があります。私のユースケースは、複数のSMTPサーバーを介して電子メールを送信しています。同じSMTPサーバーへの電子メールはプロセスであることを強制する必要がありますが、異なるSMTPサーバーへの電子メールは同時に処理される可能性があります。私は過去にJMSを使用していましたが、コンパイル時のキューの作成だけが可能ですが、実行時にキューを作成する必要があります(SMTPサーバーごとに1つのキュー)。Javaで非同期メッセージキューを動的に作成する

JMSに関して何か不足していますか、または私が見ておくべき他のツール/提案がありますか?

+0

JMSを特に使用していますか、これはjava.util.concurrentとそのExecutorServicesを使用して実行できることですか? –

+0

私は特にJMSを使用していないので、ExecutorServicesを見ておきます。 – Zecrates

答えて

6

私はアダムに同意します。JMSのようなユースケースの音はオーバーヘッドです。 Javaの組み込み機能で十分です。

package de.mhaller; 

import java.util.ArrayDeque; 
import java.util.ArrayList; 
import java.util.Deque; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Queue; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.LinkedBlockingDeque; 

import org.junit.Assert; 
import org.junit.Test; 

public class Mailer { 

    @Test 
    public void testMailer() throws Exception { 
     ExecutorService executor = Executors.newCachedThreadPool(); 
     ArrayList<Mail> log = new ArrayList<Mail>(); 
     LinkedBlockingDeque<Mail> incoming = new LinkedBlockingDeque<Mail>(); 

     // TODO: Put mails to be sent into the incoming queue 
     incoming.offer(new Mail("[email protected]", "localhost")); 
     incoming.offer(new Mail("[email protected]", "otherhost")); 
     incoming.offer(new Mail("[email protected]", "otherhost")); 
     incoming.offer(new Mail("[email protected]", "localhost")); 

     Map<Mailserver, Queue<Mail>> queues = new HashMap<Mailserver, Queue<Mail>>(); 
     while (!incoming.isEmpty()) { 
      Mail mail = incoming.pollFirst(); 
      Mailserver mailserver = findMailserver(mail); 
      if (!queues.containsKey(mailserver)) { 
       ArrayDeque<Mail> serverQueue = new ArrayDeque<Mail>(); 
       queues.put(mailserver, serverQueue); 
       executor.execute(new SendMail(mailserver, serverQueue)); 
      } 
      Queue<Mail> slot = queues.get(mailserver); 
      slot.offer(mail); 
     } 

     assertMailSentWithCorrectServer(log); 
    } 

    private void assertMailSentWithCorrectServer(ArrayList<Mail> log) { 
     for (Mail mail : log) { 
      if (!mail.server.equals(mail.sentBy.mailserver)) { 
       Assert.fail("Mail sent by wrong server: " + mail); 
      } 
     } 
    } 

    private Mailserver findMailserver(Mail mail) { 
     // TODO: Your lookup logic which server to use 
     return new Mailserver(mail.server); 
    } 

    private static class Mail { 
     String recipient; 
     String server; 
     SendMail sentBy; 

     public Mail(String recipient, String server) { 
      this.recipient = recipient; 
      this.server = server; 
     } 

     @Override 
     public String toString() { 
      return "mail for " + recipient; 
     } 
    } 

    public static class SendMail implements Runnable { 

     private final Deque<Mail> queue; 
     private final Mailserver mailserver; 

     public SendMail(Mailserver mailserver, Deque<Mail> queue) { 
      this.mailserver = mailserver; 
      this.queue = queue; 
     } 

     @Override 
     public void run() { 
      while (!queue.isEmpty()) { 
       Mail mail = queue.pollFirst(); 
       // TODO: Use SMTP to send the mail via mailserver 
       System.out.println(this + " sent " + mail + " via " + mailserver); 
       mail.sentBy = this; 
      } 
     } 

    } 

    public static class Mailserver { 
     String hostname; 

     public Mailserver(String hostname) { 
      this.hostname = hostname; 
     } 

     @Override 
     public String toString() { 
      return hostname; 
     } 

     @Override 
     public int hashCode() { 
      return hostname.hashCode(); 
     } 

     @Override 
     public boolean equals(Object obj) { 
      return hostname.equals(((Mailserver) obj).hostname); 
     } 

    } 

} 
1

JMS自体は仕様として、この問題に関しては静かです。ほとんどの実装では、JMS自体ではなく、独自のAPIを使用して、これを行うことができます。しかし、MDBのような正式なものを動的キューに張り付けることはできません。むしろあなた自身の接続とリスナーを管理する必要があります。

1

WebSphere環境でこれを最後に見たのは、待ち行列を動的に作成することは驚くほど困難なことです(一時的な待ち行列はあなたのために過渡的です)。キューを作成するためのAPIは存在していましたが、その後にサーバーを再起動してアクティブにする必要がありました。それでは、MDBの問題があります。

利用可能なプリンタのセットが比較的小さいと仮定して、余分なレベルの間接化によってすべての問題を解決できるという謝辞に基づいて、いかに汚れた回避策を講じていますか?

キューを作成するPrinter01〜Printer99(またはそれより小さい番号)。キューを実際のプリンタにマップする「データベース」があります。プリンタの要求が出てきたら、マッピングテーブルに追加することができます。 MDBのオーバーヘッドには、決して使用されないキューがあるかもしれませんが、プリンタの膨大な数が膨大なものでなければ余裕がありますか?

0

私はActiveMQのでこれをやった1

0

にあなたのSMTPサーバと制限キューのコンシューマ(MDBまたはメッセージ・リスナー)のそれぞれについて、キューを作成します - 私は実際として、一度にこれに関する質問を投稿私は同様の懸念を抱いていた(当時のJMS文書では、これはサポートされていないと述べられていた)、サポートされていることが保証されていた。

+0

あなたの質問へのリンク、またはこれを達成する方法を説明した文書がありますか? – Zecrates

関連する問題