Adding Dynamic Updates with AJAX

Viewpoint
Teradata Viewpoint is Teradata's strategic and innovative SOV (single operational view) for Teradata DB, Aster, and HDP Hadoop systems management and monitoring that enables Teradata's Unified Data Architecture (UDA).
Teradata Employee

Adding Dynamic Updates with AJAX

The amount of skew in a Teradata system can change frequently as requests move from step to step. So we would like for our portlet to refresh its contents periodically. This section describes the changes you will need in order to add a periodic refresh to your page.

Background

The JSR-168 portlet specification provides only one way to refresh the content of a portlet – refreshing the entire page. However, refreshing the entire page is not very user friendly. For example, the user may be in the middle of filling out a form in another portlet. A page refresh at this point would wipe out the changes that the user made to the form.

What we need is some way to replace the contents of our portlet without disturbing the other portlets on the page. We will utilize a technique called AJAX (Asynchronouse Javascript and XML) to do this. AJAX will allow us to make an internal request for a page fragment that will replace the contents of our portlet.

An AJAX request requires both client (browser) side development to request the new data and insert it into the browser DOM (Document Object Model) and server side development to render the page fragment.

We have greatly simplified the client side development by encapsulating all the necessary javascript in a simple Refresh tag.

The server side is a little more complicated. Because the JSR-168 specification doesn't provide a way to request the contents of a single portlet, our request needs to bypass the portal. We do this by implementing a servlet inside our portlet web application. A unique feature of our Viewpoint Controllers (as compared to regular SpringMVC controllers) is that they can service both portlet requests and servlet requests using the same java code. But we still need to configure the servlet and make a minor modification to the view.

Step-by-step Instructions

Let's start with the view. We want our refresh request to return the HTML contents of our portlet summary page. We have an existing summary.jsp file that renders this content, but it also renders extra information like CSS and javascript files that we know are already loaded into the browser. So lets split this file into two pieces: one for the normal page load and a subset one for the refresh request. We can use the jsp include tag to avoid code duplication.

The revised summary.jsp looks like this:

SkewedSessions\web\WEB-INF\portlet-jsp\summary.jsp


<%@ page contentType="text/html" language="java" %>
<%@ taglib prefix="vp" uri="http://teradata.com/viewpoint/core"%>

<jsp:include page="include.jsp"/>

<jsp:include page="summary-content.jsp"/>

<vp:refresh context="${context}" refreshInterval="30000"
refreshUrl="/SkewedSessionsPortlet/dataserver/summary" />


This is where we are utilizing the Refresh tag to insert the javascript needed to refresh the portlet. The tag that we have defined here will call the URL /SkewedSessionsPortlet/dataserver/summary every 30,000 milliseconds (30 seconds). The output of this request will replace all of the contents of the portlet.

We will create a new file, summary-content.jsp, that looks like this:

SkewedSessions\web\WEB-INF\portlet-jsp\summary-content.jsp


<%@ page contentType="text/html" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="vp" uri="http://teradata.com/viewpoint/core"%>

<c:choose>
<c:when test="${preferences.system == null}">
Please use preferences to choose a system.
</c:when>
<c:otherwise>
<vp:tableWidget context="${context}" model="${skewedSessions}" />
</c:otherwise>
</c:choose>

<vp:portletHeaderOverlay state="all" mode="append" namespace="${context}">
<div class="headerItem">${preferences.system} (Skew: <fmt:formatNumber value="${ampCpuSkew}"
maxFractionDigits="0" />%)</div>
</vp:portletHeaderOverlay>


Now that we have defined the URL for the refresh request (/SkewedSessionsPortlet/dataserver/summary), lets map this request to our existing controller. In dataserver-servlet.xml, we make the following change:

SkewedSessions\web\WEB-INF\dataserver-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Application context definition for dataserver Servlet. -->
<beans>

<!-- Handler Mappings -->
<!-- map requests to controllers by mapping url to the controller name -->
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- Add the following section below -->
<prop key="/summary">skewedSessionsViewController</prop>
<!-- End add section -->

</props>
</property>
</bean>

<!-- view resolvers -->
<bean id="servletViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<description>Resolves view names to JSP implementations in the
portlet-jsp directory</description>
<property name="order"><value>1</value></property>
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix"><value>/WEB-INF/portlet-jsp/</value></property>
<property name="suffix"><value>.jsp</value></property>
</bean>
</beans>

The last step is to invoke the correct view based on whether we are handling a portlet request or a servlet (refresh) request. In our controller, we can specify a different view name for each of these two cases:

SkewedSessions\src\java\com\teradata\portlets\skewedsessions\controllers\SkewedSessionsViewController.java

    public void summary(ControllerContext ctx)
{
//** Add the following section below **/

if (ctx.isPortletRequest())
{
ctx.setViewName("summary");
}
else
{
ctx.setViewName("summary-content");
}
//** End add section **/

// get the user's preferences for this portlet instance
SkewedSessionsPreferences preferences = new SkewedSessionsPreferences();
preferences = (SkewedSessionsPreferences)ctx.loadPreferences(SKEWED_SESSIONS, preferences);

// get the active sessions for the user's prefered system
List<Session> sessions =
skewedSessionsManager.getCurrentSkewedSessions(preferences);
...

This completes the changes you need to make to add periodic refreshes to your portlet. Go ahead and redeploy your portlet. You will probably notice the system skew value changing every 30 seconds.

Tags (2)