Open Source Software Technical Articles

Want the Best of the Wazi Blogs Delivered Directly to your Inbox?

Subscribe to Wazi by Email

Your email:

Connect with Us!

Current Articles | RSS Feed RSS Feed

How to Implement Bidirectional Interaction of Jetspeed Portlets Using Events

  
  
  
Jetspeed is an open portal platform implemented in Java code released under the Apache License and XML. Within a Jetspeed portal, you can aggregate individual portlets to create a page, yet each portlet is an independent application; Jetspeed acts as the central hub, making information from multiple sources available. The Java Portlet Specification 2.0 (JSR 286) provides standard mechanisms for portlet-to-portlet communication, including public parameters and events. Here's how to implement bidirectional interaction between Jetspeed portlets through events.

First, download the most current version of Jetspeed, 2.2.1, and install the JAR file with the command java -jar jetspeed-installer-2.2.1.jar. The installation process takes you through several screens. Click through the welcome screen, accept the license, and at the installation menu, choose "Install Jetspeed Portal." Choose an installation directory for the Jetspeed server, then choose "Demo" for the installation type and "JetUI" for the Pipeline type. On the next screen you can leave the components selection as is, then choose "Derby" as the Jetspeed database on the Database Selection menu. Click Next a couple more times, and Jetspeed will complete its installation.

Before you proceed, you must set two environment variables in your operating system:

    • CATALINA_HOME should refer to the installation directory of the Jetspeed server.

    • JAVA_HOME should refer to the JDK 5.0 or later installation directory.



To verify the installation, start the Jetspeed server by executing the startup script. Under Windows, run $CATALINA_HOME\bin\startup.bat; for Unix, it's $CATALINA_HOME/bin/startup.sh. Finally, check the Jetspeed server home page by browsing to http://localhost:8080/jetspeed/portal and make sure you see the Jetspeed home page.

Generating Jetspeed Portlet Code Using Maven


To illustrate how Jetspeed portlets can communicate, you'll need two portlets. One, addressBasicInfoPortlet, gets address information from the user and sends it to another portlet. The other, addressExtendedInfoPortlet, displays the address information in a map, then returns the latitude and longitude of the address to addressBasicInfoPortlet.

Before you start generating the basic skeleton of the Jetspeed portlets, you should install Maven to make it easier to control your build and release management. Download Maven and unzip the downloaded file to an appropriate directory, such as /usr/local/apache-maven-2.2.1. Add the directory you chose to your PATH with a command such as export PATH=/usr/local/apache-maven-2.2.1/bin:$PATH under Linux, or in Windows set PATH="c:\apache-maven-2.2.1\bin";%PATH%. To verify that Maven is correctly installed, run the command mvn --version. If all went well, that command should display Maven's version.

Now you're ready to start generating the basic skeleton for the Jetspeed portlets. To create a skeleton for addressBasicInfoPortlet, run the command:


mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-4:generate -DarchetypeGroupId=
org.apache.portals.jetspeed-2 -DarchetypeArtifactId=jetspeed-archetype
-DarchetypeVersion=2.2.1 -DartifactId=addressBasicInfoPortlet -Dpackage=com.xyz.tutorial.
communications -DgroupId=com.xyz.tutorial.communications -Dversion=1.0-
SNAPSHOT


In this command, archetypeArtifactId and archetypeGroupId represents the artifact type. artifactId represents the project to be built. The package represents the project initial generated package, and the version represents the project version. The result of this command is an initial skeleton of the addressBasicInfoPortlet with the code package com.xyz.tutorial.communications.

For the addressExtendedInfoPortlet, run a similar command, changing the artifactId parameter:


mvn org.apache.maven.plugins:maven-archetype-plugin:2.0-alpha-4:generate -DarchetypeGroupId=
org.apache.portals.jetspeed-2 -DarchetypeArtifactId=jetspeed-archetype
-DarchetypeVersion=2.2.1 -DartifactId=addressExtendedInfoPortlet
-Dpackage=com.xyz.tutorial.communications -DgroupId=com.xyz.tutorial.communications
-Dversion=1.0-SNAPSHOT


So you can turn those skeletons into something useful, import the generated projects into the Eclipse IDE by running the following commands from the parent folder of both the addressBasicInfoPortlet-pa and addressExtendedInfoPortlet-pa projects.

	
mvn clean install
mvn eclipse:eclipse


After running the commands, open Eclipse and choose File -> Import -> Existing projects into workspace. Specify as the two projects addressBasicInfoPortlet-pa, which represents the the addressBasicInfo portlet project, and addressExtendedInfoPortlet-pa which represents addressExtendedInfo.
19a98812-f823-48dc-841e-bf029c63c6d7

Implementing Bidirectional Interaction


Now you can start implement bidirectional interaction between the two portlets.

In the first step, addressBasicInfoPortlet sends the address value to addressExtendedInfoPortlet through a request event. The code below shows part of the addressBasicInfoPortlet JSP code:


<FORM method="POST" action="<portlet:actionURL></portlet:actionURL>">
<LABEL for="<%= AddressBasicInfoPortlet.FORM_TEXT %>">Enter the
address (like "Cairo, Egypt"):</LABEL><BR/>
<INPUT name="<%= AddressBasicInfoPortlet.FORM_TEXT %>" ...
type="text"/><BR/>
<INPUT name="btnSubmit" type="submit" value="Submit"/><BR/>
</FORM>


With this code, when the user clicks the Submit button, the browser sends the address parameter to the server. In the portlet code, the portlet class of addressBasicInfoPortlet processes the parameter in the process action, and creates the request event to send the address parameter to addressExtendedInfoPortlet, as shown here:


public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {

if (request.getParameter(FORM_TEXT) != null) {
response.setEvent(REQUEST_EVENT_NAME,
request.getParameter(FORM_TEXT));
...
}
}


Here, response.setEvent creates a request event with the name REQUEST_EVENT_NAME and sets the address parameter as its data. After response.setEvent sends the request event from the addressBasicInfoPortlet, the addressExtendedInfoPortlet receives the request event in its process event phase:


public void processEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {

Event event = request.getEvent();
if (event.getName().equals(REQUEST_EVENT_NAME)) {
...

// Receive the request event
address = (String) event.getValue();
location = GenericServicesFactory.
getLocationService().
getLocationFromAddress(address);
...

if (location != null) {
response.setRenderParameter(
REQUEST_EVENT_LAT_PARAMETER,
location.getLatitude().toString());

response.setRenderParameter(
REQUEST_EVENT_LNG_PARAMETER,
location.getLongitude().toString());
}

response.setRenderParameter(REQUEST_EVENT_ADDR_PARAMETER,
address);
...
}
}


event.getValue extracts the address value from the event. The LocationService of a third-party open source library called Mashups4JSF resolves the location of the address (latitude and longitude). Finally, response.setRenderParameter sends the address, longitude, and latitude as render parameters of the portlet. The addressExtendedInfoPortlet JSP code receives the address, longitude, and latitude and uses them to render the location information in a Google Map:


<script type="text/javascript">
function initializeLocationMap(place) {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(place.lat, place.lng),
mapTypeId: google.maps.MapTypeId.HYBRID
};

var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

var marker = new google.maps.Marker({
position: new google.maps.LatLng(place.lat, place.lng),
title: place.address
});

marker.setMap(map);

var infoWindow = new google.maps.InfoWindow({
content: place.address
});

infoWindow.open(map, marker);
}
</script>

<div id="map_canvas" style="width:100%; height:500px"></div>

<script type="text/javascript">
initializeLocationMap(
{
address: "<%=
request.getParameter(AddressExtendedInfoPortlet.REQUEST_EVENT_ADDR_PARAMETER) %>",
lat: <%=
request.getParameter(AddressExtendedInfoPortlet.REQUEST_EVENT_LAT_PARAMETER) %>,
lng: <%=
request.getParameter(AddressExtendedInfoPortlet.REQUEST_EVENT_LNG_PARAMETER) %>
}
);
</script>


The function caller sends initializeLocationMap a JSON object that contains the address, latitude, and longitude and uses this JSON object to render the location information using the Google Maps v3 APIs.

In its event processing phase, and after resolving the location information, addressExtendedInfoPortlet creates a new response event with the location information (latitude and longitude) to addressBasicInfoPortlet:

public void processEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {

...
// Send the response event
try {
location = GenericServicesFactory.
getLocationService().
getLocationFromAddress(address);
} catch (Exception e) {
// ...
}

if (location == null) {
responseEventData = "Unrecognized address";
} else {
responseEventData = "Location is (" +
location.getLatitude() + ", " +
location.getLongitude() + ")";
}

response.setEvent(RESPONSE_EVENT_NAME, responseEventData);
...
}


response.setEvent creates a response event with the name RESPONSE_EVENT_NAME and sets the location information (responseEventData) as its data. addressBasicInfoPortlet receives the response event in its event processing phase, as shown below:


public void processEvent(EventRequest request, EventResponse response)
throws PortletException, IOException {

Event event = request.getEvent();

if (event.getName().equals(RESPONSE_EVENT_NAME)) {
String responseEventData = event.getValue().toString();
response.setRenderParameter(RESPONSE_EVENT_PARAMETER, responseEventData);
}
}


responseEventData, which holds the latitude and longitude information, is set as a render parameter to be rendered finally in the addressBasicInfoPortlet JSP:


<div><b>
<%= request.getParameter(AddressBasicInfoPortlet.RESPONSE_EVENT_PARAMETER) %>
</b></div>


Finally, in this step, you define both the request event and the response event in the configuration files of both addressBasicInfoPortlet and addressExtendedInfoPortlet to put these events in action.

The code below shows the addressBasicInfoPortlet portlet.xml file. The supported-processing-event tag includes the event that the portlet will process, while the supported-publishing-event tag includes the event the portlet will publish:


<portlet-app ...>
<portlet>
...
<portlet-name>addressBasicInfoPortlet</portlet-name>
...
<supported-processing-event>
<name>responseEvent</name>
</supported-processing-event>
<supported-publishing-event>
<name>requestEvent</name>
</supported-publishing-event>
</portlet>

<default-namespace>http://com.test.xyz/</default-namespace>
<event-definition>
<name>requestEvent</name>
<value-type>java.lang.String</value-type>
</event-definition>
<event-definition>
<name>responseEvent</name>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>


The event-definition tag includes the definition of each event; both the request and the response events here are defined as String.

The code for the addressExtendedInfoPortlet portlet.xml file is the same as the code above, except that it reverses the publishing and processing events, so that it can receive the published event of addressBasicInfoPortlet, and publish an event that will be received by addressBasicInfoPortlet:


<portlet-app ...>
<portlet>
...
<portlet-name>addressExtendedInfoPortlet</portlet-name>
...
<supported-processing-event>
<name>requestEvent</name>
</supported-processing-event>
<supported-publishing-event>
<name>responseEvent</name>
</supported-publishing-event>
</portlet>

<default-namespace>http://com.test.xyz/</default-namespace>
<event-definition>
<name>requestEvent</name>
<value-type>java.lang.String</value-type>
</event-definition>
<event-definition>
<name>responseEvent</name>
<value-type>java.lang.String</value-type>
</event-definition>
</portlet-app>


Deploying the Portlets


Now you have all the pieces you need to deploy the portlets and test the bidirectional interaction between the them. Run mvn clean install from the parent folder of every project to build the WAR file of every portlet. The command generates two WAR files in every project target folder: addressBasicInfoPortlet-pa.war and addressExtendedInfoPortlet-pa.war. To deploy the two WAR files, perform the following steps:

    • Open http://localhost:8080/jetspeed/portal, and log in using the administrator account. The default user name and password are both "admin."

  • Select Public Space -> Jetspeed Administrative portlets:




  • In the Registry Applications List portlet, click Deploy, then select each of the two WAR files and click upload:




  • You can test the portlets by including them in a test page. To create the page, first create a space, which is a group of pages, and call it "TestSpace":




  • Search for the word "Address" in the Jetspeed Toolbox and click the Add link for both "Address Basic Information Portlet" and "Address Extended Information Portlet". This is how they will appear:




  • To test the portlets, enter a value like "Lima, Peru" in the Address Basic Information portlet and click Submit. You should see the location of Lima displayed in the Address Extended Information portlet, and the location information (latitude and longitude) displayed in the Address Basic Information portlet:




Conclusion


If you've worked through the process, you can see Apache Jetspeed makes it easy to develop, deploy, and test portal applications. And by using the eventing feature provided by the Java Portlet Specification 2.0, you can implement bidirectional communication for your portlets.




This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.


This work is licensed under a Creative Commons Attribution 3.0 Unported License
Creative Commons License.

Comments

Currently, there are no comments. Be the first to post one!
Post Comment
Name
 *
Email
 *
Website (optional)
Comment
 *

Allowed tags: <a> link, <b> bold, <i> italics