Using jQuery in a portlet

In this recipe, we will create a stock watch list that utilizes jQuery to retrieve updated stock prices without refreshing the page.

Getting ready

The following are required for this recipe:

  • Apache Maven
  • An IDE of your choice
  • GateIn-3.2.0.Final-jbossas7-preview

How to do it...

To create a portlet that uses jQuery for Ajax calls:

  1. Create a new Maven project within your IDE, specifying Group Id: gatein.cookbook, Artifact Id: chapter10-jquery, and Packaging: war.
  2. Inside the project's pom.xml, add the following dependency:
         <dependency>
            <groupId>javax.portlet</groupId>
            <artifactId>portlet-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
  3. Create a class named WatchlistPortlet that extends javax.portlet.GenericPortlet within a package named gatein.cookbook.chapter10.
  4. Add a private variable to WatchlistPortlet called watchedStocks of type String[] and set it to null.
  5. Add a private variable to WatchlistPortlet called watchedStockPrice of type BigDecimal[] and set it to null.
  6. Create a method named init within WatchlistPortlet with the following content:
      @Override
      public void init() throws PortletException {
        initStockList();
        initStockPrices();
      }
  7. Create a method named initStockList within WatchlistPortlet with the following content:
      private void initStockList() {
        watchedStocks = new String[3];
    
        watchedStocks[0] = "IBM:International Business Machines Corp.";
        watchedStocks[1] = "REV:Revlon";
        watchedStocks[2] = "RHT:Red Hat";
      }
  8. Create a method named initStockPrices within WatchlistPortlet with the following content:
      private void initStockPrices() {
        watchedStockPrice = new BigDecimal[3];
    
        watchedStockPrice[0] = new BigDecimal(32.10).setScale(2, RoundingMode.HALF_UP);
        watchedStockPrice[1] = new BigDecimal(12.54).setScale(2, RoundingMode.HALF_UP);
        watchedStockPrice[2] = new BigDecimal(57.01).setScale(2, RoundingMode.HALF_UP);
      }
  9. Download jQuery production version and save the file to the src/main/webapp/js folder of the project.
  10. Create a method named display within WatchlistPortlet as follows:
      @RenderMode(name = "view")
      public void display(RenderRequest request, RenderResponse response) throws PortletException, IOException {
        request.setAttribute("watchList", watchedStocks);
        request.setAttribute("prices", watchedStockPrice);
        getPortletContext().getRequestDispatcher("/watchlist.jsp").include(request, response);
      }
  11. Create a method named updateStockPrice within WatchlistPortlet as follows:
      protected String updateStockPrice(int index) {
        Float increment = new Random(watchedStockPrice[index].longValue()).nextFloat();
        BigDecimal newValue = watchedStockPrice[index].add(new BigDecimal(increment.doubleValue()));
        newValue = newValue.setScale(2, RoundingMode.HALF_UP);
        watchedStockPrice[index] = newValue;
        return newValue.toString();
      }
  12. Create a method named serveResource within WatchlistPortlet as follows:
      @Override
      public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
        String resourceID = request.getResourceID();
        PrintWriter writer = response.getWriter();
    
        if ("refreshPrice".equalsIgnoreCase(resourceID)) {
            int index = Integer.parseInt(request.getParameter("stock"));
            writer.write(updateStockPrice(index));
        }
    
        writer.flush();
        writer.close();
      }
  13. Create watchlist.jsp in the src/main/webapp folder of the project.
  14. Add the following content into watchlist.jsp:
    <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>
    <%@ page import="java.math.BigDecimal" %>
    
    <portlet:defineObjects/>
    
    <div class="portlet-section-header">Stock Watchlist</div>
    <br/>
    <div class="portlet-section-body">
    <%
      String[] stocks = (String[])renderRequest.getAttribute("watchList");
      BigDecimal[] prices = (BigDecimal[])renderRequest.getAttribute("prices");
    %>
            <table border="1">
              <thead class="portlet-table-header">
                <tr>
                  <th>Ticker</th>
                  <th>Company</th>
                  <th>Stock Price</th>
                  <th></th>
                </tr>
              </thead>
              <tbody class="portlet-table-body">
              <%
                int count = 0;
                for (String stock: stocks) {
                  if (null != stock) {
                    String[] split = stock.split(":");
              %>
                     <portlet:resourceURL var="refreshPriceUrl" id="refreshPrice">
                       <portlet:param name="stock" value="<%= Integer.toString(count) %>" />
                     </portlet:resourceURL>
    
                    <tr>
                      <td align="center" class="portlet-table-text"><%= split[0] %></td>
                      <td align="center" class="portlet-table-text"><%= split[1] %></td>
                      <td align="center" class="portlet-table-text"><span id="<portlet:namespace/>price<%= count %>"><%= prices[count] %></span></td>
                      <td align="center" class="portlet-table-text"><a class="portlet-font-dim" href="#" onclick="<portlet:namespace/>updatePrice('${refreshPriceUrl}', <%= count++ %>);">Refresh Price</a></td>
                    </tr>
              <%
                  }
                }
              %>
              </tbody>
            </table>
    </div>
    <br/>
    <script type="text/javascript" src="<%= renderRequest.getContextPath() %>/js/jquery-1.7.2.min.js"></script>
    <script type='text/javascript'>
      function <portlet:namespace/>updatePrice(updatePriceUrl, index) {
        $.ajax(
                 {
                      type: "POST",
                      url: updatePriceUrl,
                      cache: false,
                      success: function (data) {
                        $('#<portlet:namespace/>price'+index).html(data);
                      }
                 }
               );
      }
    </script>
  15. Create portlet.xml in the src/main/webapp/WEB-INF folder of the project.
  16. Add the following content to portlet.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
        version="2.0">
      <portlet>
        <portlet-name>WatchList-jQuery</portlet-name>
        <portlet-class>gatein.cookbook.chapter10.WatchlistPortlet</portlet-class>
        <supports>
          <mime-type>text/html</mime-type>
          <portlet-mode>view</portlet-mode>
        </supports>
        <portlet-info>
          <title>WatchList - jQuery portlet</title>
        </portlet-info>
      </portlet>
    </portlet-app>
  17. Create web.xml in the src/main/webapp/WEB-INF folder of the project.
  18. Add the following to web.xml:
    <?xml version="1.0"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd"
            version="2.5">
    </web-app>
  19. Run the following command in the root of the project directory to build the web archive:
    >mvn clean package
    
  20. Copy the generated web archive, chapter10-jquery-1.0.0.SNAPSHOT.war, from the target folder into the deployment folder of where you unpacked the GateIn installation.
  21. Start the server and log in as an administrator.
  22. Click on the top-menu navigation with the following path: Group | Administration | Application Registry.
  23. Click on Import Applications to make the new portlet available.
  24. Create a new page in the Site area of the portal and add the Watchlist-jQuery portlet to it. The Watchlist-jQuery portlet can be found under the Chapter10-jquery category.
  25. Click on the Finish icon to save the page.
  26. The portlet page should look like the following screenshot:
    How to do it...
  27. Click on Refresh Price a few times on a couple of the stocks, and the portal page will show updated prices like the following screenshot:
    How to do it...

How it works...

Steps 7 and 8 initialize the array of stocks that are being watched and what the initial price for each of them is when the portlet is initialized at startup.

Step 10 handles the RenderRequest for the portlet, by setting the array of stocks and their prices as request attributes before redirecting the request to the JSP page for display.

Step 11 defines updateStockPrice, a method for incrementing the stock price by a random amount. This is easily modified to call a service to retrieve stock prices from a live system.

Step 12 defines serveResource, which is where the Ajax request is handled by the portlet. The resource ID is checked to make sure the ResourceRequest received by the portlet is the correct one, though in practice this check is more applicable when a single portlet handles many Ajax requests through the serveResource method. A PrintWriter is retrieved from the ResourceResponse for writing the result of the request back to the browser. The stock request parameter is retrieved and used as the index for calling updateStockPrice.

Step 14 creates the watchlist.jsp, which handles all the portlet content display. It uses the <portlet:resourceURL> tag to create a self-referencing URL for retrieving resources from the portlet. The id attribute on the tag is set as the resource ID on the ResourceRequest, so the value must match what we are expecting within serveResource, otherwise it won't successfully retrieve any content.

Within the stock table, a link is created that uses the onclick event to trigger a JavaScript call to updatePrice, using the resource URL that was created earlier.

At the bottom of watchlist.jsp, the jQuery JavaScript library is loaded and the updatePrice method is defined. It instructs jQuery to make an Ajax call using the URL passed to it, and to update the HTML element with the id of #<portlet:namespace/>price'+index with the data that was returned in the response. The call is specified as non-cacheable as there is no need to cache the stock price, because it is not a static resource.

In the JSP, <portlet:namespace/> was used to generate an ID unique to this portlet to prevent ID and JavaScript name clashes with other portlets that are on the same page.

In Step 27, when Refresh Price is clicked one or more times, the entire portal page and portlet are not re-rendered at any point; it is only the single piece of HTML content that is replaced by Ajax. This happens as calling serveResource does not result in a new RenderRequest being issued by the portal container.

Note

The serveResource method does not support coordination through events or through shared render parameters. It cannot set new render parameters, portlet mode, or window state, nor can it issue redirects or modify the application-scoped session state to prevent an inconsistent user experience.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.198.174