Building a Web Service Powered JSR 168 Financial Portlet

n increasing number of web applications built today use portal technology. A portal is a web application that typically provides services such as personalization, single sign-on, and content aggregation from different sources. Aggregation is the action of integrating content from different sources within a web page.

Portlets are the visible active components that users see within their portal pages. In the simplest terms, for Java-based portals, a portlet is a Java servlet that operates inside a portal. Figure 1 shows an example portal page with a portlet on it. A Portal Web Server provides a portlet container that serves portlets to users.

 
Figure 1. A Portal Page with a Portlet: Here’s a simple portlet container containing a portlet.

Commercially available Java Portal Web Servers include BEA, IBM, and Oracle, but there are also many open source Java Portal Web Servers such as Liferay, Pluto, Stringbeans, and JBoss Portal. Most of these Java Portal Web Servers have tools that allow you to build portlets. In the early days of portals, you had to develop and maintain a separate version of your portlet that complied with the vendor-specific portlet API for each and every vendor portal. Maintaining separate vendor-specific versions was time consuming, aggravating, and cumbersome, and limited the availability of generic, cross-server portlets.

Java Specifiction Request #168 (JSR 168) has solved this vendor-specific portlet configuration problem. By adhering to the standards, you can now build portlets that can run in portals irrespective of their vendors. Most Java Portal Web Servers support the JSR 168 specification.

 
Figure 2. Interacting with a Web Service: The diagram illustrates how the sample portlet interacts with an external web service.

This article concentrates on the presentation and service layers of a Portal Web Server (see Figure 2). The presentation layer interacts with services to aggregate data from different sources. These services are typically defined in the service layer and are part of any Service-Oriented Architecture (SOA) implemented in a portal. An easy way to implement SOA architecture is through web services, which Gartner defines as, “Web services are software components that employ one or more of three technologies—SOAP, WSDL, and UDDI—to perform distributed computing.”

This article will first describe how to write a JSR 168 portlet, and then cover how to implement a service within a portlet. You can use any web service provider; however, this article uses a Xignite service. Figure 2 illustrates how the portlet in the presentation layer interacts with a financial service in the service layer to get data. The Financial Service uses web services to access Xignite Financial Web Services.

Editor’s Note: This article was prepared and contributed by employees of NuWave and Xignite for DevX. We felt it had sufficient technical merit to publish on DevX. NuWave Solutions is a professional services firm specializing in solving business problems through innovative technology solutions. Xignite is a leading pure-play provider of financial web services for mission-critical corporate applications.

Preparation
Setting up a portlet supplied from an external web service involves several steps. First, you’ll need to register with the web service provider to access content, and to obtain the login credentials needed for access. Typically, you’ll find registration instructions at the web site.

The second step is to set up the development environment. The sample application described here used BEA’s WebLogic Portal 9.2.1 as the host portal server, and BEA’s Eclipse-based Workshop 9.2.1 as the IDE. You can obtain both by downloading the WebLogic Platform 9.2 MP1. Setting up the environment is outside the scope of this paper, but you’ll see the configuration settings that vary from the default portal configuration. This example leverages the following technologies:

Feel free to use a different J2EE/portal environment if you are so inclined. As long as the portal container is JSR 168 compliant and runs Java 1.5, you should be able to run the example without problems. If you decide to use different technology, substitute your own choices in the procedures shown here.

To create the sample portal project:

  • Start WebLogic Workshop and create a new ‘Portal Web Project’ using Workshop’s “New Project Wizard.”
  • Name the enterprise archive (EAR file) XigniteDemoEAR, and name the web archive (WAR file) XigniteDemoWAR. EAR and WAR are runtime files that support the WebLogic portal applications.
  • In preparation for setting up the Xignite Web Service, create a directory called wsclient under the WebContent directory of the web application.
  • Create a portlets subdirectory in the WebContent folder, and place the viewQuote.jsp file in it.
  • Create a WEB-INF/src/com/nuwave/portlets/ directory, and place the StockQuotePortlet.java file in it.
  • Place the portlet.xml file in the WEB-INF/ directory.

Before you can run the example, you must create a WebLogic Portal domain. You’ll find the instructions for doing that in the BEA documentation.

Building the Portlet
To build a JSR 168 portlet you begin by writing a GenericPortlet extension for every single portlet you develop. GenericPortlet is an abstract class that provides a default implementation for the portlet interface. Your GenericPortlet subclass should override at least one method, usually one of the following:

  • processAction— Handles action requests.
  • doView—Handles render requests when in View mode (Note: you’ll see more about modes later).
  • doEdit—Handles render requests when in Edit mode.
  • doHelp—Handles render requests when in Help mode.
  • init and destroy—Used to manage resources held for the life of the servlet.

Here’s the code for a condensed version of the JSR 168 portlet class example, StockQuotePortlet, which extends GenericPortlet, and overrides the doView and processAction methods:

   package com.nuwave.portlets;      import javax.portlet.*;   ...   public class StockQuotePortlet extends GenericPortlet {      public void doView(RenderRequest request,          RenderResponse response)         throws PortletException, IOException       {

The JSR 168 specification defines three portlet modes: View, Help, and Edit. All portlets must support the View mode, and do so by overriding the doView() method as shown above. The doView() method handles “render” requests by generating markup to display the portlet in the view mode. The RenderRequest and RenderResponse classes provide functionality similar to the HttpServletRequest and HttpServletResponse classes:

         request.setAttribute("errors",             request.getParameter("errors"));

The preceding line demonstrates setting an attribute in and retrieving a parameter from the RenderRequest object. As you can see, it’s similar to working with HTTPServletRequest objects. You’ll use that errors attribute later on in the JSP.

The next section of code obtains a PortletRequestDispatcher from the portletContext for viewQuote.jsp, and uses the include method to pass the request to it. In this example, viewQuote.jsp creates the display:

          String nextURL = "/portlets/viewQuote.jsp";         PortletRequestDispatcher rd = getPortletContext().            getRequestDispatcher(nextURL);         rd.include(request, response);         } // end doView      ...

The Portlet Container uses the processAction method to handle a portlet’s life cycle. The processAction method handles client ActionRequests to update the portlet state. In this case, it will invoke the Xignite web service and store the data for the JSP to display:

      public void processAction(ActionRequest request,          ActionResponse response)         throws PortletException, IOException {         try {            String query = request.getParameter("symbols");            // validate the query coming in            ...

The code in the try block gets the symbols parameter from the request, and validates the query coming in (the validation code is not shown above; it’s represented by the comment). The portlet uses the query string when invoking the Xignite web services.

You need to log into the external web service site to retrieve data. The example uses portlet preferences to store the login values. Portlet preferences are persistent name/value pairs used to customize portlets. The following code retrieves the Xignite login info preferences from the request object and stores their values. You specify the preferences themselves in the portlet.xml deployment descriptor discussed in the next section:

            PortletPreferences prefs = request.getPreferences();            String username = prefs.getValue("xignite_username", "");            String password = prefs.getValue("xignite_password", "");                // Web service code goes here.              // It will create a quotes ArrayList variable containing              // the data retrieved from the web service.             request.getPortletSession().setAttribute(                "quotes", quotes);          }           catch (Exception e) {             response.setRenderParameter("errors", e.getMessage());          }          } // end processAction

You’ll see the code that invokes the Xignite web services later in the article. For now, note the setting of the quotes variable in the portlet session. Portlet sessions are very similar to servlet sessions. Each user session has its own unique PortletSession object, and you can set attributes on a portlet session object in the same fashion as on a ServletSession object. The viewQuotes.jsp file uses the quotes object in the portlet session to display the data.

Portlet Deployment Descriptor
The JSR 168 specification requires the portlet deployment descriptor (portlet.xml in this case) to have an entry for each portlet in the application. The descriptor provides a location to specify settings and preferences for each portlet. The descriptor file must reside in the WEB-INF directory along with the web.xml file.

The portlet-app element is the root element of the portlet.xml file:

      

The portlet element starts the declaration of the sample portlet. The portlet-name element contains the name you give to a portlet. It must be unique within the portlet application. The portlet-class element specifies the fully qualified name of the class that implements the Portlet interface—in this example, the StockQuotePortlet:

               stockQuote_1       com.nuwave.portlets.StockQuotePortlet       

The supports element specifies the type of content that this portlet supports. The sample portlet supports HTML content and the View mode:

        text/html     view   

The portlet-preferences element declares any portlet preferences for this portlet. Here’s where you specify the xignite_username and xignite_password preferences. You’ve already seen how to access these preferences in the code. For testing purposes, set the values to the username and password you specified during registration at Xignite’s web site. Note: The password can be blank:

                  xignite_username         ENTER YOUR XIGNITE USERNAME                     xignite_password         ENTER YOUR XIGNITE PASSWORD             

Finally, close the portlet and portlet-app elements:

      

With the portlet built and configured, you can integrate the Xignite web service.

Setting Up the Web Service
Xignite has several web services available for demonstration and testing purposes. The XigniteQuotes service used here provides delayed quotes for US Equities as well as the current status of major indices. The service exposes several operations; the GetQuickQuotes operation seems like a good fit for getting the simplest solution working for this example. Retrieve the WSDL by accessing the URL http://www.xignite.com/xQuotes.asmx?WSDL. Save a copy as xQuotes.wsdl and place it in the ?/WebContent/wsclient/ directory you created earlier.

You can download the code that accompanies this article to follow along.

WebLogic Workshop has a great utility for creating web service clients that makes it easy to start using web services. Select File –> New –> Other, and then choose the Web Service Client wizard. Figure 3 shows the dialog.

 
Figure 3. Select a Wizard: Select the Web Service Client wizard to create a Java class to connect to a web service.

Follow the wizard, accepting the default values. When prompted to enter a reference to your WSDL, select the xQuotes.wsdl file you saved to the /WebContent/wsclient/ folder earlier. The wizard converts the Xignite WSDL into java classes, placing the generated code in a com.xignite.www.services package. Although the package contains more than one class, for this article, you’ll need the XigniteQuotesSoap class. The interface exposes a getQuickQuotes method, which represents the GetQuickQuotes operation of the web service. The method returns an ArrayOfQuickQuote object that holds an array of quotes returned from the web service.

Implementation
The code that invokes the Xignite Web Service is located in the StockQuotesPortlet’s processAction() method. You saw it referenced earlier in the commented code lines:

   XigniteQuotes objQuotesService = new XigniteQuotesLocator();   XigniteQuotesSoap objQuotesPort =       objQuotesService.getXigniteQuotesSoap();

The portlet sets up a XigniteQuotes service object and retrieves a XigniteQuotesSoapStub object, which it then upcasts to the XigniteQuotesSoap interface. Take a look at the XigniteQuotesSoapStub implementation class to get a better understanding of how the calls to the web service are being made.

Xignite has several authentication implementation options available for you to use. The sample application passes the authentication credentials in the SOAP message header. Be sure to enter the login credentials you supplied during registering at Xignite’s site into the portlet preferences section of the portlet.xml file.

Authors’ Note: There are limitations on the number of requests you can make on the web service within a specified time frame, so make certain you manage the number of times you access the service during development. This limitation only applies to the free demonstration version, not to those who have purchased Xignite’s web services.

The next line of code casts the XigniteQuotesSoap object to the org.apache.axis.Stub object. The Stub object contains methods that provide access to the SOAP headers so you can manipulate authentication credentials:

   org.apache.axis.client.Stub stub = (Stub) objQuotesPort;

The addAuthenticationHeader method adds the authentication credentials to the SOAP header. A detailed discussion of what happens in the code is outside the scope of this article; however, you can review the code to gain a deeper understanding of how to manipulate the SOAP message header:

   addAuthenticationHeader(username, password, stub);

Finally, the portal invokes the web service:

   ArrayOfQuickQuote objQuickQuote =       objQuotesPort.getQuickQuotes(query);

The XigniteQuotesSoap object’s getQuickQuotes() method takes a list of stock symbols or indices as an argument and returns an ArrayOfQuickQuote object containing an array of com.xignite.www.services.QuickQuote objects. These objects are used to pass the resulting data to the user interface for display.

The final step in the process is to prepare the data for presentation:

   if (objQuickQuote.getQuickQuote(0).getOutcome() ==       OutcomeTypes.Success) {         List quotes = new ArrayList();      Quote quote;         for (int i = 0; i < objQuickQuote.getQuickQuote().length; i++)       {         quote = new Quote();                              quote.setCompany(            objQuickQuote.getQuickQuote(i).getSymbol());               quote.setPrice(            objQuickQuote.getQuickQuote(i).getLast());         quotes.add(quote);      }         request.getPortletSession().setAttribute(         "quotes", quotes);   }    else    {      throw new Exception(         objQuickQuote.getQuickQuote(0).getOutcome()         .toString() + ": " +          objQuickQuote.getQuickQuote(0).getMessage());      }

The JSP page remains free of any implementation-specific code by using a custom Quote object. The Quote object is a simple bean used to hold record values. You can certainly skip this step for simplicity by accessing the implementation objects directly in the JSP if you so desire.

If errors occur during a web service call, the returned ArrayOfQuickQuote object will contain outcome types that can assist with debugging the service calls. As the preceding code shows, calling the getOutcome() method returns an OutcomeTypes object indicating the result of the operation. Possible outcome types include:

  • Success: invoking the web service is successful and no errors were detected.
  • SystemError: the web service provider did not execute properly.
  • RequestError: the SOAP message request had problems when delivered to the web service.
  • RegistrationError: there was a problem with the authentication credentials, or something is wrong with your account. (Hint: check that your login credentials are correct in the portlet.xml file.)

Putting it all Together
So far, you've seen how to build a JSR 168 portlet class, how to create a client to the Xignite web services, how to invoke the client from the portlet's processAction() method, and how the portlet class dispatches to the viewQuotes.jsp in the doView() method. To finish up, here's a quick look at the JSP code.

The stock quote portlet uses this JSP to display its content. The JSP displays a form where users can enter stock symbols, and it submits an actionRequest to the portlet. The portlet dispatches to it during the doView method to display the portlet in the View mode:

   <%@taglib uri="http://java.sun.com/portlet"       prefix="portlet"%>   

All compliant Portal Servers must implement the Portlet Tag Library. The portlet tags are useful for creating references to several portlet objects in the JSPs, and for creating action and render URLs that trigger methods on the current portlet. The preceding code shows a declaration of the portlet tag library and usage of the tag. The defineObjects tag defines the renderRequest, renderResponse, and portletConfig objects obtained from the JSP's request object.

Next, you need to get a reference to the portlet session:

   <%   pageContext.setAttribute("quotes",       renderRequest.getPortletSession().getAttribute("quotes"));   %>

The renderRequest.getPortletSession() call gets the portlet session. It gets the quotes attribute from the portlet session, and registers it to the pageContext object's quotes attribute with page scope. If you remember, the quotes ArrayList was created to store the data retrieved from the Xignite web services.

This next bit of code checks whether an errors object exists in the requestScope and is not empty. If so, it displays the errors:

         

Here's the form that lets portlet users enter one or more stock symbols:

   

When users click the Submit button, the form submits to the URL specified in the form's action attribute. Note that here, you specify the action request by using the tag. The submitted data includes the symbols input value as an attribute. The action request triggers the processAction method in the portlet class:

         
Company Symbol Stock Price

The last portion of the JSP code builds a simple table to display the data. It loops through the page's quotes object (which was registered at the top of the JSP), and generates a new table row for each quote in the list.

Author's Note: For clarity, CSS styles were omitted from the HTML shown above.

Running the example
Before running this example, you need to perform two BEA-specific tasks:

  1. Create a StockQuote.portlet file for the Stock Quotes Portlet. To create the BEA-specific .portlet file, right-click the portlets directory and select New --> Portlet. Follow the Portlet Wizard's directions, specifying that this will be a "Java Portlet," and that this portlet will use the StockQuotesPortlet class.
  2. Create a BEA TestStockQuotePortal.portal file in the same directory as the .portlet file and drop the .portlet file on the .portal's main page.

That's it. Now you can run the example by right-clicking the .portal file and selecting Run As --> Run On Server. Follow the prompts to deploy to the portal domain server you created during the preparation steps.

Authors' Note: Please consult the BEA documentation for any questions related to the steps above, because the details are outside the scope of this article.

 
Figure 4. Portal in Action: The figure shows how the portal looks after a user requested data for the stock symbols "MSFT" and "BEAS."

Figure 4 shows a screen shot of the portal containing the Stock Quotes Portlet. This image was captured after a user entered "MSFT, BEAS" in the Stock Symbol(s) input field, and submitted the form. That fired the StockQuotesPortlet's processAction() method. The screen shot displays the resulting data from the Xignite web service, obtained from the portlet session by the JSP.

You've seen how to build a JSR 168 Portlet and integrate a Xignite financial web service in the portlet. You should now be able to build your own web services-enabled JSR 168 financial portlets. This article only scratched the surface of what you can do with JSR 168 portlets and web services. For more information on the JSR 168 portlet specification, please see these links:

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: