Difference between revisions of "Inter Portlet Subscription/Notification Mechanism (Client side)"

From Gcube Wiki
Jump to: navigation, search
Line 17: Line 17:
  
  
===How to use TIBCO PageBus™ GWT Wrapper with D4Science Portlets==
+
==How to use TIBCO PageBus™ GWT Wrapper with D4Science Portlets==
  
 
'''Step 1st: Download the file needed [[Media:Pagesbus_Files.zip | Click here‎]]'''
 
'''Step 1st: Download the file needed [[Media:Pagesbus_Files.zip | Click here‎]]'''
  
 
Once you extract the .zip file it contains three files, two .jar and one .js.
 
Once you extract the .zip file it contains three files, two .jar and one .js.
 +
 +
'''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:
 +
 +
<pre>
 +
<module>
 +
  ...
 +
  <inherits name="com.eliasbalasis.tibcopagebus4gwt.tibcopagebus4gwt"/>
 +
  <inherits name="org.juglar.gwt.jsonizer.Jsonizer"/>
 +
  ...
 +
  ...
 +
  ...
 +
</module>
 +
</pre>
 +
 +
 +
==Set up the D4Science portal to use tibcopagebus4gwt GWT Wrapper==
 +
 +
Copy the file pagebus.js, which is in the .zip downloaded before to $CATALINA_HOME/webapps/<portal_context>/
 +
e.g. $CATALINA_HOME/webapps/gridsphere/pagebus.js
 +
 +
Now you need now to add a little modification to the D4Science portal header, the file is located under:
 +
 +
$PORTAL_USER_HOME/.gridsphere/content/pageheader.html
 +
 +
add the following at the beggining of the file, subistitute <portal_context> with your actual portal context e.g. /grisphere/pagebus.js
 +
 +
<pre>
 +
<script src="/<portal_context>/pagebus.js" language="JavaScript1.2"></script>
 +
 +
<script type="text/javascript">
 +
    if(window.parent.PageBus) {
 +
window.PageBus = window.parent.PageBus;
 +
    }
 +
</script>
 +
</pre>
 +
 +
 +
Stop the container and make sure it loads the new header when you start it back. Now 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 in the '''tibcopagebus4gwt-1.0.8.jar''' you downloaded before (in the .zip)
 +
 +
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:
 +
 +
<pre>
 +
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){...}
 +
  ...
 +
}
 +
</pre>
 +
 +
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.
 +
 +
<pre>
 +
interface PersonJsonizer extends Jsonizer{}
 +
interface SubscriberDataJsonizer extends Jsonizer{}
 +
</pre>
 +
 +
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 look like'''
 +
 +
 +
<pre>
 +
package ...;
 +
import org.gcube.portlets......myapplication;
 +
...
 +
public class MyGWTModule implements EntryPoint {
 +
final PageBusAdapter pageBusAdapter = new PageBusAdapter();
 +
  ...
 +
  RootPanel.add(pageBusAdapter);
 +
  SubscriberData subscriberData = new SubscriberData();
 +
  subscriberData.setHeader("myHeader");
 +
  subscriberData.setBody("myHeader");
 +
  // Subscribe to message and associate subsequent receptions with custom subscriber data
 +
  pageBusAdapter.PageBusSubscribe("com.mycompany.mymessagesubjects.person", null, null, subscriberData, (Jsonizer)GWT.create(SubscriberDataJsonizer.class));
 +
  ...
 +
  Person person = new Person();
 +
  person.setName("Lucio Scorigions");
 +
  person.setAge(29);
 +
  ...
 +
  // publish a message with Person bean data
 +
  pageBusAdapter.PageBusPublish("com.mycompany.mymessagesubjects.person", person, (Jsonizer)GWT.create(PersonJsonizer.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));
 +
        ...
 +
        ...
 +
        ...
 +
      }
 +
    }
 +
  );
 +
  ...
 +
  // unsubscribe from message. future publications of message will not trigger callback
 +
  pageBusAdapter.PageBusUnsubscribe("com.mycompany.mymessagesubjects.person");
 +
}
 +
 +
</pre>

Revision as of 19:34, 17 December 2008

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/

However, the library does not currently support GWT 5.2, D4Science Portlets will have to use the same library modified to be compliant to GWT 5.2.


How does TIBCO PageBus™ help us?

PageBus helps developers drastically simplify development by using 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 TIBCO PageBus™ GWT Wrapper with D4Science Portlets

Step 1st: Download the file needed Click here‎

Once you extract the .zip file it contains three files, two .jar and one .js.

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="com.eliasbalasis.tibcopagebus4gwt.tibcopagebus4gwt"/>
   <inherits name="org.juglar.gwt.jsonizer.Jsonizer"/>
   ...
   ...
   ...
 </module>


Set up the D4Science portal to use tibcopagebus4gwt GWT Wrapper

Copy the file pagebus.js, which is in the .zip downloaded before to $CATALINA_HOME/webapps/<portal_context>/ e.g. $CATALINA_HOME/webapps/gridsphere/pagebus.js

Now you need now to add a little modification to the D4Science portal header, the file is located under:

$PORTAL_USER_HOME/.gridsphere/content/pageheader.html

add the following at the beggining of the file, subistitute <portal_context> with your actual portal context e.g. /grisphere/pagebus.js

	<script src="/<portal_context>/pagebus.js" language="JavaScript1.2"></script>

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


Stop the container and make sure it loads the new header when you start it back. Now 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 in the tibcopagebus4gwt-1.0.8.jar you downloaded before (in the .zip)

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 look like


 package ...;
 import org.gcube.portlets......myapplication;
 ...
 public class MyGWTModule implements EntryPoint {
 final PageBusAdapter pageBusAdapter = new PageBusAdapter();
   ...
   RootPanel.add(pageBusAdapter);
   SubscriberData subscriberData = new SubscriberData();
   subscriberData.setHeader("myHeader");
   subscriberData.setBody("myHeader");
   // Subscribe to message and associate subsequent receptions with custom subscriber data
   pageBusAdapter.PageBusSubscribe("com.mycompany.mymessagesubjects.person", null, null, subscriberData, (Jsonizer)GWT.create(SubscriberDataJsonizer.class));
   ...
   Person person = new Person();
   person.setName("Lucio Scorigions");
   person.setAge(29);
   ...
   // publish a message with Person bean data
   pageBusAdapter.PageBusPublish("com.mycompany.mymessagesubjects.person", person, (Jsonizer)GWT.create(PersonJsonizer.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));
         ...
         ...
         ...
       }
     }
   );
   ...
   // unsubscribe from message. future publications of message will not trigger callback
   pageBusAdapter.PageBusUnsubscribe("com.mycompany.mymessagesubjects.person");
 }