先日のエントリで、MBassador
でメッセージの型によって反応するハンドラが変わるサンプルを示しました。
MBassador
では、同じ型のメッセージでもメッセージ内容をフィルタリングして受け取るハンドラを切り替えることができます。
概要
フィルタリングは大まかに以下のやり方で実施します。
IMessageFilter
を実装してフィルタークラスを定義するIMessageFilter#accepts
をオーバーライドして、引数のメッセージをハンドラで受信するかどうかを判定します@Handler
のfiltersパラメータで定義したフィルタークラスを指定する@Handler(filters = @Filter(SomethingFilter.class))
の形式でフィルターを利用することを指定します
以下具体的なサンプルとなります
文字列の内容によるフィルタリング
EventBusに発行された文字列の先頭が"http:"か"ftp:"かをフィルタリングして、メッセージを受け取るハンドラを切り替えます
■ハンドラの定義
フィルターのクラスを定義して、そのフィルターをハンドラのパラメータに指定しています。
PrefixHttpFilter
・・・ 文字列の先頭が"http:"であるかどうかを判定するためのフィルターですPrefixFtpFilter
・・・ 文字列の先頭が"ftp:"であるかどうかを判定するためのフィルターです
import net.engio.mbassy.listener.Filter; import net.engio.mbassy.listener.Handler; import net.engio.mbassy.listener.IMessageFilter; import net.engio.mbassy.subscription.SubscriptionContext; class MsgListener1 { @Handler(filters = @Filter(PrefixHttpFilter.class)) public void httpHandle(String msg) { System.out.println("http Handle::" + msg); } @Handler(filters = @Filter(PrefixFtpFilter.class)) public void ftpHandle(String msg) { System.out.println("ftp Handle::" + msg); } public static class PrefixHttpFilter implements IMessageFilter<String> { @Override public boolean accepts(String message, SubscriptionContext context) { return message.startsWith("http:"); } } public static class PrefixFtpFilter implements IMessageFilter<String> { @Override public boolean accepts(String message, SubscriptionContext context) { return message.startsWith("ftp:"); } } }
■EventBus生成・Handlerのsubscribe・メッセージ発行
"ftp:"で始まるメッセージと"http:"で始まるメッセージとを発行しています
import net.engio.mbassy.bus.MBassador; public class SampleLauncher1 { public static void main(String[] args) { System.out.println(">>> App start"); MBassador eventBus = new MBassador(); MsgListener1 listener = new MsgListener1(); eventBus.subscribe(listener); // ハンドラの登録 // FTP messeage eventBus.publishAsync("ftp://user1:pass000@example-dummy.org/"); eventBus.publishAsync("ftp://user2:pass000@example-dummy.org/"); eventBus.publishAsync("ftp://user3:pass000@example-dummy.org/"); // HTTP messeage eventBus.publishAsync("http://example-dummy.org/books/1001"); eventBus.publishAsync("http://example-dummy.org/books/1002"); eventBus.publishAsync("http://sample-dummy.org:8080/books/"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("\n>>> App end"); } }
■実行結果
>>> App start ftp Handle::ftp://user1:pass000@example-dummy.org/ ftp Handle::ftp://user2:pass000@example-dummy.org/ ftp Handle::ftp://user3:pass000@example-dummy.org/ http Handle::http://example-dummy.org/books/1001 http Handle::http://example-dummy.org/books/1002 http Handle::http://sample-dummy.org:8080/books/ >>> App end
"ftp:"で始まるメッセージにはftpHandle
メソッドが反応して、"http:"で始まるメッセージにはhttpHandle
メソッドが反応していることが分かります。
独自定義したクラスのメンバの内容によるフィルタリング
自分で独自に定義したクラスをメッセージとしてEventBusに対して発行し、そのクラスのメンバの値によって反応するハンドラを切り分けるサンプルです。
■独自クラス(メッセージ)
以下のPet
クラスをEventBusに対して発行します
import lombok.Value; @Value public class Pet { private String name; private Type type; enum Type { CAT, DOG, OTHER; } }
■ハンドラの定義
Pet
クラスのtypeのenumの値を判定するフィルタークラスを定義して、各ハンドラに指定しています。
CatFilter
・・・Pet
クラスのtypeの値がCATかどうかを判定するためのフィルターですDogFilter
・・・Pet
クラスのtypeの値がDOGかどうかを判定するためのフィルターですOtherFilter
・・・Pet
クラスのtypeの値がOTHERかどうかを判定するためのフィルターです
import net.engio.mbassy.listener.Filter; import net.engio.mbassy.listener.Handler; import net.engio.mbassy.listener.IMessageFilter; import net.engio.mbassy.subscription.SubscriptionContext; class PetListener { @Handler(filters = @Filter(CatFilter.class)) public void catHandle(Pet pet) { System.out.println("Cat Handle::" + pet); } @Handler(filters = @Filter(DogFilter.class)) public void dogHandle(Pet pet) { System.out.println("Dog Handle::" + pet); } @Handler(filters = @Filter(OtherFilter.class)) public void otherHandle(Pet pet) { System.out.println("Other Handle::" + pet); } public static class CatFilter implements IMessageFilter<Pet> { @Override public boolean accepts(Pet pet, SubscriptionContext context) { return pet.getType() == Pet.Type.CAT; } } public static class DogFilter implements IMessageFilter<Pet> { @Override public boolean accepts(Pet pet, SubscriptionContext context) { return pet.getType() == Pet.Type.DOG; } } public static class OtherFilter implements IMessageFilter<Pet> { @Override public boolean accepts(Pet pet, SubscriptionContext context) { return pet.getType() == Pet.Type.OTHER; } } }
■EventBus生成・Handlerのsubscribe・メッセージ発行
Cat, Dog, Otherの3種のPetをメッセージとしてEventBusに発行します
import net.engio.mbassy.bus.MBassador; public class SampleLauncher2 { public static void main(String[] args) { System.out.println(">>> App start"); MBassador eventBus = new MBassador(); PetListener listener = new PetListener(); eventBus.subscribe(listener); // ハンドラの登録 // cat eventBus.publishAsync(new Pet("miko", Pet.Type.CAT)); // dog eventBus.publishAsync(new Pet("panchi", Pet.Type.DOG)); // other eventBus.publishAsync(new Pet("hebio", Pet.Type.OTHER)); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("\n>>> App end"); } }
■実行結果
>>> App start Cat Handle::Pet(name=miko, type=CAT) Dog Handle::Pet(name=panchi, type=DOG) Other Handle::Pet(name=hebio, type=OTHER) >>> App end
各typeに対応するフィルターが設定されたハンドラが反応していることが分かります。