Inter Portlet Subscription/Notification Mechanism (Client side)

From Gcube Wiki
Jump to: navigation, search

How to make portlets in the same page use a Subscription/Notification Mechanism client side.

Pre-development Actions

Subscription/Notification Mechanism makes use of TIBCO PageBus™ (http://www.tibco.com/devnet/pagebus/default.jsp) which is an event and message bus implemented in JavaScript that enables disparate Ajax elements in a Web page to broadcast and listen for events and messages published on topic names.

For the ones developing portlets with GWT Wrapper exists for this Library, http://code.google.com/p/tibcopagebus4gwt/


How does PageBus work?

PageBus uses publish and subscribe APIs to send events and messages between components rather than get bogged down in point to point integrations between components that lead to unwieldy and less manageable code.

Pagebus Diagram

This diagram shows three Ajax widgets communicating with each other via the PageBus. Each widget has a file defining its visuals, a file controlling its behavior including the publish and subscribe calls to the PageBus, and a file that gets data from a service on the Web.

How to use PageBus GWT Wrapper with gCube Portlets

Step 1st: Download the latest jars from ETICS. The '.gwt-jsonmaker.jar' and the 'tibcopagebus4gwt.jar'


Step 2nd: add the two jar files in the build path of your GWT application

Once they two jar files are in the build path edit your GWT Application configuration file (file.gwt.xml). Add the following:

<module>
   ...
	<inherits name="net.eliasbalasis.tibcopagebus4gwt.tibcopagebus4gwt" />
	<inherits name="org.jsonmaker.gwt.Gwt_jsonmaker" />
   ...
   ...
   ...
 </module>

Set up your D4Science Portlet to use tibcopagebus4gwt GWT Wrapper

Copy the file pagebus.js, which can be downloaded from here here‎ to your portlet war/js folder e.g. <myportletproject>/war/js/pagebus.js

Now you need now to add a little modification to the Liferay Portlet header, the file is located under: <myportletproject>/war/WEB-INF/liferay-portlet.xml

add the following under the portlet element

<portlet>

   ......
   <header-portlet-javascript>/js/pagebus.js</header-portlet-javascript>
   .....

</portlet>


now you just need to copy the following into the <head> of your jsp page loading your portlet.

	<script type="text/javascript">
	     if(window.parent.PageBus) {
		window.PageBus = window.parent.PageBus;
	     }
	</script>

You are ready to use tibcopagebus4gwt.

How to use tibcopagebus4gwt GWT Wrapper with D4Science Portlets

The main class you are going to use is the PageBusAdapter class which is included in the 'tibcopagebus4gwt.jar'

Assume now that Portlets containing GWT modules desire to communicate with the rest of the Portlets on the page. This is a task for PageBusAdapter which exposes PageBus functions as a GWT widget. Assume that the information to be communicated is represented with the following Java classes:

package org.gcube.portltes...;
 ...
 // a Person bean class.
 class Person {
   ...
   public String getName(){...}
   public void setName(String name){...}
   ...
   public int getAge(){...}
   public void setAge(int age){...}
   ...
 }
 
 class SubscriberData {
   ...
   public String getHeader(){...}
   public void setHeader(String header){...}
   ...
   public String getBody(){...}
   public void setBody(String header){...}
   ...
 }

as part of the publish and subscribe calls to the PageBus. Not only Person beans must be translated to JavaScript objects before being passed around to PageBus but also JavaScripts objects passed through PageBus by other widgets must be translated to Person beans before the GWT module can use them.

PageBusAdapter makes uses marshaller implementations created using the the gwt-jsonizer library to perform the translation. Here is the gwt-jsonizer marshaller implementation for the Person bean.

 interface PersonJsonizer extends Jsonizer{}
 interface SubscriberDataJsonizer extends Jsonizer{}

Now you may wonder where is the marshalling/unmarshalling code? It is automatically created by the gwt-jsonizer GWT compiler hook the first time a bean class is accessed. The requirements of the gwt-jsonizer marshaller are:

  • The bean must be compliant with Java Beans specification (getters, setters, default constructors etc.)
  • The bean marshaller definition must be named after the respective bean class name with the Jsonizer suffix
  • Each and every bean property must contain a hint to the marshaller in the form of javadoc annotations.
    • The following annotations are currently supported:
      • jsonizer.transient The property in not translatable
      • jsonizer.propName 'prop' This property is named 'prop' in JavaScript
      • jsonizer.required If the property doesn't exist in respetive JavaScript version an exception will be thrown


Here is how a GWT module using PageBus functions would send notification (publishing beans to subscribers)


 package ...;
 import org.gcube.portlets......myapplication;
 ...
 public class MyGWTModule { 

   final PageBusAdapter pageBusAdapter = new PageBusAdapter();
   ...
   ...
   //create the Person bean data
   Person person = new Person();
   person.setName("Mario Rossi");
   person.setAge(29);
   ...
   // publish a message with Person bean data
   pageBusAdapter.PageBusPublish("net.eliasbalasis.tibcopagebus4gwt.testsubscriber.client.Person", person, (Jsonizer)GWT.create(PersonJsonizer.class));
   ...


Here is how a GWT module using PageBus functions would Subscribe to message and associate subsequent receptions with custom subscriber data


package ...;
 import org.gcube.portlets......myapplication;
 ...
 public class MyGWTModule { 

   final PageBusAdapter pageBusAdapter = new PageBusAdapter();
   SubscriberData subscriberData = new SubscriberData();
   subscriberData.setHeader("myHeader");
   subscriberData.setBody("myHeader");
  
   //Subscribe to message and associate subsequent receptions with custom subscriber data
   pageBusAdapter.PageBusSubscribe("net.eliasbalasis.tibcopagebus4gwt.testsubscriber.client.Person", null, null, subscriberData, (Jsonizer)GWT.create(SubscriberDataJsonizer.class));


   // register listener
   pageBusAdapter.addPageBusSubscriptionCallbackListener(
     new PageBusListener() {
       public void onPageBusSubscriptionCallback(PageBusEvent event) {
         // translate JavaScript message contents and subscriber data to their Java equivalents
         Person message = (Person)event.getMessage((Jsonizer)GWT.create(PersonJsonizer.class));
         SubscriberData subscriberData = (SubscriberData)event.getSubscriberData((Jsonizer)GWT.create(SubscriberDataJsonizer.class));
         ...
         ...
         ...
       }
     }
   );


Here is how a GWT module using PageBus functions would UnSubscribe to message

   ...
   ...
   //unsubscribe from message. future publications of message will not trigger callback
   pageBusAdapter.PageBusUnsubscribe("net.eliasbalasis.tibcopagebus4gwt.testsubscriber.client.Person");
   ...
   ...