{"id":2158,"date":"2015-12-01T15:35:25","date_gmt":"2015-12-01T13:35:25","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=2158"},"modified":"2015-12-01T15:36:20","modified_gmt":"2015-12-01T13:36:20","slug":"things-i-never-blogged-about-the-eventbus","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=2158","title":{"rendered":"Things I never blogged about: XPages &#038; Google&#8217;s EventBus"},"content":{"rendered":"<p>This is another topic I wanted to blog about for a long time: The use of <a href=\"https:\/\/github.com\/google\/guava\/wiki\/EventBusExplained\" target=\"_blank\">Google&#8217;s EventBus<\/a> in XPages applications. <em>EventBus<\/em> is a replacement for the Java in-process event distribution. It makes life a lot easier.<\/p>\n<p>My first plan was to add the <a href=\"http:\/\/search.maven.org\/remotecontent?filepath=com\/google\/guava\/guava\/18.0\/guava-18.0.jar\" target=\"_blank\">guava.jar<\/a> into an OSGi plugin because of security reasons (otherwise you have to use the &#8222;<em>grant{ permission java.security.AllPermission;}<\/em>&#8222;) but I never had the time. That&#8217;s why I created a simple example which uses the jar in the <em>lib\/ext<\/em> folder instead.<\/p>\n<p>To use the <em>EventBus<\/em> in an application, you first have to define an event. This simple example has a message only, but you can add any properties you want.<\/p>\n<pre><code>package ch.hasselba.xpages;\r\n\r\npublic class FrontendEvent {\r\n\r\n\u00a0\u00a0 \u00a0private final String message;\r\n\r\n\u00a0\u00a0 \u00a0public FrontendEvent(final String message) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.message = message;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public String getMessage() {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return message;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n}<\/code><\/pre>\n<p>Then we need a subscriber. For this we have to add the annotation <em>@Subscribe<\/em> to a method of a managed bean which should handle an event.\u00a0The class type of the parameter tells the <em>EventBus<\/em> what kind of event our method should handle.<\/p>\n<p>This is a managed bean which stores the last message sent over the <em>EventBus<\/em>:<\/p>\n<pre><code>package ch.hasselba.xpages;\r\n\r\nimport com.google.common.eventbus.Subscribe;\r\n\r\npublic class EventSubscriber {\r\n\r\n\u00a0\u00a0 \u00a0private String message;\r\n\r\n\u00a0\u00a0 \u00a0@Subscribe\r\n\u00a0\u00a0 \u00a0public void handleEvent(FrontendEvent event) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.message = event.getMessage();\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void getMessage(String msg) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.message = msg;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public String getMessage() {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0return this.message;\r\n\u00a0\u00a0 \u00a0}\r\n}<\/code><\/pre>\n<p>Then we have to create a managed bean which has an instance of <em>EventBus<\/em>, the <em>FrontendEventBus.<\/em> The bus has a managed property <em>subscribers<\/em>. As soon the bean is instantiated, the managed property is called and the list of objects is registered to the <em>EventBus<\/em> instance.<\/p>\n<pre><code>package ch.hasselba.xpages;\r\n\r\nimport java.io.Serializable;\r\nimport java.util.ArrayList;\r\n\r\nimport com.google.common.eventbus.EventBus;\r\nimport com.google.common.eventbus.SubscriberExceptionContext;\r\nimport com.google.common.eventbus.SubscriberExceptionHandler;\r\n\r\n@SuppressWarnings(\"serial\")\r\npublic class FrontendEventBus implements SubscriberExceptionHandler,\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0Serializable {\r\n\r\n\u00a0\u00a0 \u00a0final EventBus eventBus = new EventBus();\r\n\u00a0\u00a0 \u00a0ArrayList&lt;Object&gt; subscribers;\r\n\r\n\u00a0\u00a0 \u00a0\/**\r\n\u00a0\u00a0 \u00a0 * registers all subscribing managed beans from faces-config.xml\r\n\u00a0\u00a0 \u00a0 * \r\n\u00a0\u00a0 \u00a0 * @param subscribers\r\n\u00a0\u00a0 \u00a0 *\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ArrayList with references to managed beans\r\n\u00a0\u00a0 \u00a0 *\/\r\n\u00a0\u00a0 \u00a0public void setSubscribers(ArrayList&lt;Object&gt; subscribers) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0this.subscribers = subscribers;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0for (Object subscriber : subscribers) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0register(subscriber);\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void post(final Object event) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0eventBus.post(event);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void register(final Object object) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0eventBus.register(object);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public void unregister(final Object object) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0eventBus.unregister(object);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0public final void handleException(Throwable exception,\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0SubscriberExceptionContext context) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0exception.printStackTrace();\r\n\r\n\u00a0\u00a0 \u00a0}\r\n\r\n}\r\n<\/code><\/pre>\n<p>There is only one problem: If a bean is in a lower scope, the initialization will fail. In this case we have to do the opposite to attach a subscriber to the bus. Instead of telling the bus which subscriber we want to register, we are telling the subscriber which bus to attach to.<\/p>\n<pre><code>package ch.hasselba.xpages;\r\n\r\npublic class EventSubscriberRequestScope extends EventSubscriber {\r\n\r\n\u00a0\u00a0 \u00a0\/**\r\n\u00a0\u00a0 \u00a0 * registers the current instance to the event bus\r\n\u00a0\u00a0 \u00a0 * \r\n\u00a0\u00a0 \u00a0 * @param eventBus\r\n\u00a0\u00a0 \u00a0 *\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 the frontend event bus\r\n\u00a0\u00a0 \u00a0 *\/\r\n\u00a0\u00a0 \u00a0public void setEventBus(FrontendEventBus eventBus) {\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0eventBus.register(this);\r\n\u00a0\u00a0 \u00a0}\r\n\r\n}<\/code><\/pre>\n<p>As soon the bean is instantiated, the managed property will have an instance of our <em>FrontendEventBus<\/em> and the bean can register itself.<\/p>\n<p>The <em>faces-config.xml<\/em> looks like this:<\/p>\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;faces-config&gt;\r\n\r\n\u00a0\u00a0 \u00a0&lt;managed-bean&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-name&gt;frontendEventBus&lt;\/managed-bean-name&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-class&gt;ch.hasselba.xpages.FrontendEventBus&lt;\/managed-bean-class&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-scope&gt;session&lt;\/managed-bean-scope&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-property&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;property-name&gt;subscribers&lt;\/property-name&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;list-entries&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;value-class&gt;java.lang.Object&lt;\/value-class&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;value&gt;#{eventSubscriber}&lt;\/value&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/list-entries&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/managed-property&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/managed-bean&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;managed-bean&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-name&gt;eventSubscriber&lt;\/managed-bean-name&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-class&gt;ch.hasselba.xpages.EventSubscriber&lt;\/managed-bean-class&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-scope&gt;session&lt;\/managed-bean-scope&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/managed-bean&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;managed-bean&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-name&gt;eventSubscriberRequestScope&lt;\/managed-bean-name&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-class&gt;ch.hasselba.xpages.EventSubscriberRequestScope&lt;\/managed-bean-class&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-bean-scope&gt;request&lt;\/managed-bean-scope&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;managed-property&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;property-name&gt;eventBus&lt;\/property-name&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;value&gt;#{frontendEventBus}&lt;\/value&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/managed-property&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/managed-bean&gt;\r\n\u00a0\u00a0\u00a0 \r\n&lt;\/faces-config&gt;<\/code><\/pre>\n<p>The first subscribing bean is in the same scope as the <em>FrontendEventBus<\/em>, but the second one is a request scoped bean.<\/p>\n<p>Now it&#8217;s time to send an event. This can be realized by creating a new instance of our <em>FrontendEvent<\/em> we have created earlier and posting it to the bus.<\/p>\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;xp:view xmlns:xp=\"http:\/\/www.ibm.com\/xsp\/core\"&gt;\r\n\r\n\u00a0\u00a0 \u00a0&lt;xp:button\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0id=\"button1\" value=\"Click me\"&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xp:eventHandler\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0event=\"onclick\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0submit=\"true\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0refreshMode=\"complete\"&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xp:this.action&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;![CDATA[#{javascript:importPackage( ch.hasselba.xpages );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0var msg = \"Timestamp: \" + java.lang.System.currentTimeMillis();\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0var se = new ch.hasselba.xpages.FrontendEvent( msg );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0frontendEventBus.post( se );\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0}]]&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/xp:this.action&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;\/xp:eventHandler&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;\/xp:button&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;br \/&gt;\r\n\u00a0\u00a0 \u00a0&lt;br \/&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;xp:label\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0value=\"#{eventSubscriber.message}\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0id=\"labelSubscriberMessage\"&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/xp:label&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;br \/&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;xp:label\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0value=\"#{eventSubscriberRequestScope.message}\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0id=\"labelSubscriberRequestScope\"&gt;\r\n\u00a0\u00a0 \u00a0&lt;\/xp:label&gt;\r\n\u00a0\u00a0 \u00a0\r\n&lt;\/xp:view&gt;<\/code><\/pre>\n<p>As soon the button is clicked, both beans are receiving the event and updating their message.<\/p>\n<p><a href=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/12\/2015-12-01-14_04_04-Mozilla-Firefox.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2191\" src=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/12\/2015-12-01-14_04_04-Mozilla-Firefox.png\" alt=\"2015-12-01 14_04_04-Mozilla Firefox\" width=\"302\" height=\"166\" srcset=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/12\/2015-12-01-14_04_04-Mozilla-Firefox.png 302w, https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/12\/2015-12-01-14_04_04-Mozilla-Firefox-300x165.png 300w\" sizes=\"auto, (max-width: 302px) 100vw, 302px\" \/><\/a><\/p>\n<p>Hope someone finds it usefull.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is another topic I wanted to blog about for a long time: The use of Google&#8217;s EventBus in XPages applications. EventBus is a replacement for the Java in-process event distribution. It makes life a lot easier. My first plan &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=2158\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[89,26,74],"tags":[],"class_list":["post-2158","post","type-post","status-publish","format-standard","hentry","category-java","category-jsf","category-xpages"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2158"}],"version-history":[{"count":7,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2158\/revisions"}],"predecessor-version":[{"id":2197,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2158\/revisions\/2197"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}