Skip to main content link. Accesskey S
  • Anonymous
  • Log on
  • Help
  • IBM logo
  • WebSphere Portal Family wiki
  • All Wikis
  • Home
  • Community Articles
  • Product Documentation
  • Learning Center


Search

Advanced Search

Categories

Tag Cloud

  • 6.0
  • 6.1
  • 6.1.0.1
  • 6.1.5
  • 7.0
  • 7.0.0.2
  • 8.0
  • actions
  • administrator
  • authoring
  • Banking template
  • best practices
  • blogs
  • builder
  • building a site
  • caching
  • catalog
  • Clickstream Engine
  • clusters
  • ConfigEngine tasks
  • content
  • customizing
  • databases
  • demo
  • deployment
  • deployment scenario
  • developer
  • developing
  • device class
  • elements
  • examples
  • Express
  • feature set
  • fix pack 2
  • Government to Business template
  • info center
  • information center
  • installation
  • installing
  • LDAP
  • Learning
  • libraries
  • LikeMinds Recommendation Engines
  • logging
  • mentors
  • message catalog
  • messages
  • migration
  • mobile
  • mobile devices
  • mobile experience
  • mobile experience 8.0
  • mobile theme
  • mobile webkit
  • MPA
  • multiplatform
  • pages
  • performance
  • personalization
  • planning
  • portal
  • Portal 6.1
  • Portal 8 theme
  • portlets
  • product doc
  • product documentation
  • projects
  • properties
  • Redbooks
  • Redbooks Wiki
  • remember me cookie
  • resources
  • REST
  • Retail Vendor template
  • rules
  • samples
  • search
  • security
  • sifters
  • sites
  • solutions catalog
  • syndication
  • test infrastructure
  • theme
  • theme optimization
  • topologies
  • troubleshooting
  • tutorials on personalization
  • video
  • wcm
  • web content
  • webkit
  • WebSphere Portal
  • WebSphere Portlet Factory
  • wikis
  • workflows
  • worksheet
  • XML configuration interface
  • z/os
  • zos
InformationInformation
You are currently viewing machine translated content. IBM translation might be available. Click IBM Translated Product Documentation to see what is available.X


Home > WebSphere Portal > Using Comet for asynchronous user notification of autonomous server thread progression
Rate this article 1 starRate this article 2 starsRate this article 3 starsRate this article 4 starsRate this article 5 stars

Using Comet for asynchronous user notification of autonomous server thread progression 

expanded Abstract
collapsed Abstract
No abstract provided.
ShowTable of Contents
HideTable of Contents
  • 1 Introduction and background
  • 2 Setting up the Comet based servlet
  • 3 Conclusion
  • 4 Resources
  • 5 About the author

Summary: When you use the event-based Comet notifier supplied with the Ajax framework ItsNat, the request to update the user interface (UI) comes from the server, rather than from the client. This article describes in detail the setup of a Comet-based servlet for this purpose.

Introduction and background


Ordinarily, you are able to update a page only by refreshing the page, submitting a form, or by making repeated calls to an Asynchronous JavaScriptTM with XML (AJAX) servlet. This last technique is known as polling and is quite costly in terms of client resources.

The Ajax programming technique is used to update the content of a Web page by interacting with a servlet running on the same server. This update is in response to an action from the user, usually clicking a button, or entering text in a box.

Server Push is an Internet technology whereby the request to update the page is initiated by the hosting server, rather than the client. The combination of Ajax and Server Push is known as Reverse-Ajax or Comet, a pun on the real-life names of the two popular household cleaners.

First released in November 2007, ItsNat is an operating-system-independent Ajax framework based on Java. Using an approach knowns as “The Browser Is the Server” (TBITS), it simulates a Universal W3C Java Browser at the server. With ItsNat, the server mimics the behaviour of a Web browser, containing a W3C DOM Level 2 node tree and receiving W3C DOM Events.

Using the CometNotifier class supplied with ItsNat, a thread started from a servlet can be used to update the client UI with progress information from the thread, and notify the user when the thread has completed.

In his blog post, “ItsNat v0.6 released. Comet (long polling) now event based,” Jose Arranz outlines the development of an ItsNat-based servlet that uses Comet to accomplish this. Following these guidelines, this article describes how to develop your own servlet, adding extra functionality to pause and resume the worker thread.

Setting up the Comet based servlet



Consider the scenario in which a servlet you have developed is taking a considerable amount of time to complete, leaving the user unsure if it is doing anything. For the purposes of this article, let's use the example of calculating Pi (π).

One of the simplest series used to calculate Pi is the Gregory-Leibniz series in which the nth estimate of Π is calculated as follows:



Java supplies a constant for Pi in the Math package Math.PI. If the estimate is correct to five places, then the difference between the estimate and the actual value will have zero values for the first five decimal places.

Encoding this in the doGet function of a standard Java servlet yields the following:


public  void doGet(HttpServletRequest request, HttpServletResponse response) 
 	throws ServletException, IOException {

 	double piEstimate = 0.0;
    	double newEstimate = 0.0;
    	int count = -1;
    	do {

            piEstimate  = newEstimate;
            count++;
            int  divisor = (2 * count) + 1;
            newEstimate = piEstimate + (((Math.pow(-1, count)) * 4.0 ) / divisor);

    	} while(Math.abs(Math.PI - newEstimate) > 0.000001); 
	PrintWriter out = response.getWriter();
 	out.println("<html><head><title>Calculate Pi</title></head><body>Pi Estimated at: " + piEstimate + "</body></html>");
		
}

Although this is correct, this solution is far from ideal. When the user accesses this servlet, no indication is given that anything is happening—other than the browser is still trying to access the page—until the result is returned.

To give the user a quicker response, a Thread class can be used to do the work. By starting the thread when the user accesses the servlet, there is a much quicker UI response, and the user is confident that the calculation is in progress.

By including the meta http-equiv “refresh” tag in the output from the servlet while the thread is running, the page is refreshed automatically every 5 seconds with the latest estimate. This thread is stored in the servlet context and retrieved on each refresh.

When the thread is retrieved, it's used to update the output page with the current estimate. When the thread completes, the meta tag is removed from the output, and the final estimate is displayed:

 	public void doGet(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {

 		PiThread piThread = (PiThread)getServletContext().getAttribute("piThread");
 		if(piThread == null) {
			
 			piThread = new PiThread();
			piThread.start();
			
		}
 		getServletContext().setAttribute("piThread", piThread);
 		StringBuffer output = new StringBuffer("<html><head><title>Calculate Pi</title>”);
		 if(piThread.isThreadRunning())
 			output.append("<meta http-equiv=\"refresh\" content=\"5\"/>");

		 output.append("</head><body>Pi Estimated at: " + piThread.getPiEstimate() + "</body></html>");
		PrintWriter out = response.getWriter();
		out.println(output.toString());

	}

public  class PiThread extends Thread {

 	private double piEstimate;
 	private boolean threadRunning;
	
 	public PiThread() {
		
 		piEstimate = 0.0;
		threadRunning = false ;
		
	}
 	public void run() {
	
	threadRunning = true;
    	double newEstimate = piEstimate;
    	int count = -1;
    	do {
    		
            piEstimate  = newEstimate;
            count++;
            int  divisor = (2 * count) + 1;
            newEstimate = piEstimate + (((Math.pow(-1, count)) * 4.0 ) / divisor);
            
    	} while(Math.abs(Math.PI - newEstimate) > 0.000001); 
	threadRunning = false ;


	}

 	public double getPiEstimate() {
		
 		return piEstimate;
		
	}
	
 	public boolean isThreadRunning() {
		
 		return threadRunning;
		
	}
	
}

Now that the work has been spun out to a thread, the UI needs to be improved. Instead of the thread being started automatically when the servlet is first opened, we can enclose standard HTML buttons in a form that can start and stop the thread.

By using the POST method to submit the form containing the buttons, the control of the creation and destruction of the worker thread is handled by the doPost method, and the doGet method is used for setting the variables used in displaying the estimate by the compiled HTML file. The work is all being done separately from the client, consistent with the Model-View-Controller (MVC) pattern.

When a user clicks the Start button, the form in the JavaServer Page (JSP) is submitted to the servlet, and the thread is created and stored in the servlet context. Similarly, when a user clicks the Stop button, the thread is stopped.

A Boolean object is set to indicate whether the thread is running and is then added to the request object. In the JSP, this is used to decide whether to include the refresh meta tag in the compiled HTML page. Another variable is created with the latest estimate, and added to the request object, and then displayed on the page.

Another functionality included with threads is that they can be paused and resumed. Another two buttons will be added to the page pause and resume the worker thread. By adding two more buttons to the page the pause and resume functionality of threads can be used. Pressing the pause button will pause the thread at its current value, but not stop it completely, and the resume button will continue the thread from that point. Additionally, since the thread is paused, there is no need to refresh the page because the same value will be displayed repeatedly. Enclosing the refresh stag in a in “if” statement using the value of the thread status (paused or in progress) will stop the refreshing of the page while the thread is paused, and it will not resume refreshing until the thread is resumed.

If the thread is paused, there is no need to refresh the page because the same value will be displayed repeatedly. Thus the meta http-equiv tag is enclosed in an if statement to be included only if the thread is running and not paused.

As servlets are being used, it is more efficient to use a JSP instead of a HTML page for this:


<%@  page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%  
 	java.lang.Double piEstimate = (Double)request.getAttribute("piEstimate"); 
 	java.lang.Boolean isThreadPaused = (Boolean)request.getAttribute("isThreadPaused"); 
%>
<html>
 	<head>
 		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 		<title>Calculate Pi</title>
 		<%
 			if((isThreadPaused != null) && (!isThreadPaused.booleanValue())) {
 		%>
 				<meta http-equiv="refresh" content="5" />
 		<%
			}
 		%>
 	</head>
 	<body>
 		<form action="PiServlet" method="POST">
 			<table>
 				<tr>
 					<td><input type="submit" name="action" value="Start" /></td>
 					<td><input type="submit" name="action" value="Stop" /></td>
 					<td><input type="submit" name="action" value="Pause" /></td>
 					<td><input type="submit" name="action" value="Resume" /></td>
 				</tr>
 				<%
 					if(piEstimate != null) {
 				%>
 						<tr>
 							<td colspan="4">Pi Estimate: <%= piEstimate %></td>
 						</tr>
 				<%
					}
 				%>
 			</table>
 		</form>
 	</body>
</html>

 	public void doGet(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {

 		piThread = (PiThread)getServletContext().getAttribute("piThread");
 		if(piThread != null) {
			
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
 			request.setAttribute("isThreadPaused", new Boolean(piThread.isThreadPaused()));

		}
 		getServletContext().setAttribute("piThread", piThread);
 		RequestDispatcher view = request.getRequestDispatcher(JSP);
		view.forward(request, response);
		
	}

 	public void doPost(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {
		
 		String action = request.getParameter("action");
 		piThread = (PiThread)getServletContext().getAttribute("piThread");
 		if((action.equals(START_BUTTON)) && (piThread == null)){
				
 				piThread = new PiThread();
 				piThread.start();
 				request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
			
		}
 		else if((action.equals(STOP_BUTTON)) && (piThread != null)) {
			
 				piThread.stopThread();
 				request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
 				piThread = null;
			
		}
 		else if((action.equals(PAUSE_BUTTON)) && (piThread != null)){

 			if(!piThread.isThreadPaused())
 				piThread.pauseThread();

 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
			
		}
 		else if((action.equals(RESUME_BUTTON)) && (piThread != null)){

 			if(piThread.isThreadPaused())
 				piThread.resumeThread();

 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
			
		}
 		if(piThread != null)
 			request.setAttribute("isThreadPaused", new Boolean(piThread.isThreadPaused()));
		
 		getServletContext().setAttribute("piThread", piThread);
 		RequestDispatcher view = request.getRequestDispatcher(JSP);
		view.forward(request, response);

	}


If you examine the modern UIs, the stop/start and pause/resume methods are handled by single buttons, so from a usability point of view, the buttons on the page should be adapted to reflect this.

There is no need to have the Pause/Resume button enabled if the thread is not running, so we can disable this button by checking for the isThreadPaused object. If it exists, then the thread exists and the button can be enabled; if not, then the thread does not exist and the button can be disabled.

Note that the implementation of the PiThread class has not changed in these iterations of the servlet; instead, what has changed is how the information from the thread is displayed to the user:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%  
 	java.lang.Double piEstimate = (Double)request.getAttribute("piEstimate"); 
 	java.lang.Boolean isThreadPaused = (Boolean)request.getAttribute("isThreadPaused"); 
 	java.lang.String startStopValue = (String)request.getAttribute("startStopValue");
 	java.lang.String pauseResumeValue = (String)request.getAttribute("pauseResumeValue");
%>
<html>
 	<head>
 		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 		<title>Calculate Pi</title>
 		<%
 			if((isThreadPaused != null) && (!isThreadPaused.booleanValue())) {
 		%>
 				<meta http-equiv="refresh" content="5" />
 		<%
			}
 		%>
 	</head>
 	<body>
 		<form action="PiServlet" method="POST">
 			<table>
 				<tr>
 					<td><input type="submit" name="action" value="<%= startStopValue %>" /></td>
 					<td><input type="submit" name="action" value="<%= pauseResumeValue %>" <% if(isThreadPaused == null) { %> disabled <% } %> /></td>
 				</tr>
 				<%
 					if(piEstimate != null) {
 				%>
 						<tr>
 							<td colspan="2">Pi Estimate: <%= piEstimate %></td>
 						</tr>
 				<%
					}
 				%>
 			</table>
 		</form>
 	</body>
</html>

 	private static final String START = "Start";
 	private static final String STOP = "Stop";
 	private static final String PAUSE = "Pause";
 	private static final String RESUME = "Resume";
 	private static final String JSP = "PiJSP.jsp"; 
	
 	public void doGet(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {

 		PiThread piThread = (PiThread)getServletContext().getAttribute("piThread");
 		if(piThread != null) {
			
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
 			request.setAttribute("isThreadPaused", new Boolean(piThread.isThreadPaused()));

		}
		setButtonValues(request, piThread);
 		getServletContext().setAttribute("piThread", piThread);
 		RequestDispatcher view = request.getRequestDispatcher(JSP);
		view.forward(request, response);
		
	}

 	public void doPost(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {
		
 		String action = request.getParameter("action");
 		PiThread piThread = (PiThread)getServletContext().getAttribute("piThread");
 		if(action.equals(START)) {
				
 			piThread = new PiThread();
			piThread.start();
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
		
		}
 		else if(action.equals(STOP)) {
			
			piThread.stopThread();
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
 			piThread = null;
		
		}
 		else if(action.equals(PAUSE)) {

			piThread.pauseThread();
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
			
		}
 		else if(action.equals(RESUME)) {

			piThread.resumeThread();
 			request.setAttribute("piEstimate", new Double(piThread.getPiEstimate()));
			
		}
		setButtonValues(request, piThread);
 		if(piThread != null)
 			request.setAttribute("isThreadPaused", new Boolean(piThread.isThreadPaused()));
		
 		getServletContext().setAttribute("piThread", piThread);
 		RequestDispatcher view = request.getRequestDispatcher(JSP);
		view.forward(request, response);

	}
	
 	private void setButtonValues(HttpServletRequest request, PiThread piThread) {
		
 		if(piThread != null) {
			
 			request.setAttribute("isThreadPaused", new Boolean(piThread.isThreadPaused()));
 			request.setAttribute("startStopValue", STOP);
 			if(piThread.isThreadPaused())
 				request.setAttribute("pauseResumeValue", RESUME);
 			else
 				request.setAttribute("pauseResumeValue", PAUSE);

		}
 		else {
			
 			request.setAttribute("startStopValue", START);
 			request.setAttribute("pauseResumeValue", PAUSE);
			
		}
		
	}


At this point in the servlet's development the user can control when the thread is started, stopped, paused, and resumed. However, the constant refreshing of the page is not consistent with modern programming techniques.

As mentioned earlier, the Ajax programming technology updates the content of a Web page by interacting with a servlet running on the same server. Usually, this update is in response to an action from the user, such as clicking a button or entering text in a box.

In this case, the JavaScript function “setInterval()” will be used to call the servlet repeatedly to display the current estimate. As the active thread is being stored in the servlet context, it is available to all servlets in that context:


public  class PiAjaxServlet extends HttpServlet {

 	public void doGet(HttpServletRequest request, HttpServletResponse response) 
 		throws ServletException, IOException {

 		PiThread piThread = (PiThread)getServletContext().getAttribute("piThread");
 		response.setContentType("application/xml");
 		response.getWriter().write("<currentEstimate>" + piThread.getPiEstimate() + "</currentEstimate>");
		
	}

}

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%  
 	java.lang.Double piEstimate = (Double)request.getAttribute("piEstimate"); 
 	java.lang.Boolean isThreadPaused = (Boolean)request.getAttribute("isThreadPaused"); 
 	java.lang.String startStopValue = (String)request.getAttribute("startStopValue");
 	java.lang.String pauseResumeValue = (String)request.getAttribute("pauseResumeValue");
%>
<html>
 	<head>
 		<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 		<title>Calculate Pi</title>
 		<%
 			if(isThreadPaused != null) {
 		%>
 			<script type="text/javascript">

 				function callPiAjaxServlet() {

 					var xmlHttpRequest;
 					if(window.XMLHttpRequest) {
					
  						xmlHttpRequest = new XMLHttpRequest();
  						
  					}
 					else if(window.ActiveXObject) {
					
  						xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
  						
  					}
 					xmlHttpRequest.onreadystatechange = function() {
	
 						if(xmlHttpRequest.readyState == 4) {
						
 							if(xmlHttpRequest.status == 200) {
  								
  								var xmlResponse = xmlHttpRequest.responseXML.documentElement;
  								document.getElementById('piEstimate').textContent = "Pi Estimated at " + xmlResponse.textContent;
  								
  							}

						}
						
					};
 					xmlHttpRequest.open("GET","PiAjaxServlet",true);
 					xmlHttpRequest.send(null);
					
				}
 				<%
 					if(!isThreadPaused.booleanValue()) {
 				%>
 						setInterval("callPiAjaxServlet()", (1000 * 5));
 				<%
					}
 				%>
 			</script>
 		<%
			}
 		%>
 	</head>
 	<body <% if(isThreadPaused != null) { %> onload="callPiAjaxServlet()" <% } %> >
 		<form action="PiServlet" method="POST">
 			<table>
 				<tr>
 					<td><input type="submit" name="action" value="<%= startStopValue %>" /></td>
 					<td><input type="submit" name="action" value="<%= pauseResumeValue %>" <% if(isThreadPaused == null) { %> disabled <% } %> /></td>
 				</tr>
 			</table>
 		</form>
 		<div id="piEstimate"></div>
 		<%
 			if(piEstimate != null) {
 		 %>
 		 Pi Estimated at <%= piEstimate %>	
 		 <%
		 	}
 		  %>
 	</body>
</html>


Since the Ajax call is being used to display the estimate, there is no need to store the current estimate every time a button is clicked, so the setAttribute() calls in the doPost method can be removed. When the Stop button is clicked, there will be no further Ajax calls made, so the setAttribute() call in the Stop button case is not removed, and this will be used to display the final estimate.

The client is now updating cleanly, using the Ajax calls to get the current estimate from the servlet, and the UI is responding correctly to all button clicks. However, by removing the page refreshes, we now receive no notification that the worker thread has completed.

The technique used here is known as “polling,” whereby the same request is made repeatedly. This is the programming equivalent of a child in the back seat repeatedly asking “are we there yet?” and only slightly less draining on your available resources.

Note that all the implementations discussed so far have one thing in common: In each case the request for an update comes from the client. This is known as “Client Pull,”the opposite of which is known as Server Push. In this case the request for the update is sent autonomously from the server to the client, and as previously stated, the combination of Ajax and Server Push is called Reverse-Ajax, or Comet.

Creating an ItsNat servlet requires slightly more work than creating a simple Java servlet. The basics are the same in that the web.xml points to a servlet class; however, this servlet must extend the ItsNat class HttpServletWrapper instead of the standard HttpServlet class.

The init() method of the servlet registers the template XHTML files for each page to be displayed in this servlet. Each template has a listener to handle requests from the framework for the template, or when an Ajax event is received for a document target that has been loaded by this template. On loading a new page, the listener creates an event listener for that page to process events (button clicks, etc).

First, we must create the XHTML page to be displayed. Every button that will cause an event to be handled by the ItsNat framework, and every value that will be updated by the framework must be assigned an id attribute to be used in the event handler class for that document. A good tip is to enclose all the elements that will be used by the framework within a div that uses the ItsNat xml namespace,
Note that the ItsNat site has been moved to sourceforge and is now hosted at http://itsnat.sourceforge.net/

Specifically, place this <div> element in the <body> element of a standard XHTML document, as follows:

	    <div itsnat:nocache="true" xmlns:itsnat="http://itsnat.org/itsnat">
 			<table>
 				<tr>
 					<td><input id="startStopButton" type="button" value="Start" onclick='javascript:void(0)' /></td>
 					<td><input id="pauseResumeButton" type="button" value="Pause" disabled="disabled" onclick='javascript:void(0)' /></td> 
 				</tr>
 				<tr><td colspan="4"><div id="piEstimateMessage">Current Pi estimate: 4</div></td></tr>
 				<tr><td colspan="4"><div id="threadStatus"></div></td></tr>	
 			</table>
 	    </div>


You can see the two buttons that control the thread that's calculating the estimates, the div element to display the current estimate of Pi (which starts at 4), and the element that will display the status of the thread. When each button is clicked, the JavaScript call ensures the event is processed by the framework.

Next, create the servlet class, and in the init method (shown below) create a template for each page that will be displayed. For each template, add a new servlet request listener to handle events from the framework. In this example, there is only one page, so only one template and request listener are created:


public  void init(ServletConfig config)  throws ServletException {
		 
 		super.init(config);
 		String pathPrefix = getServletContext().getRealPath("/") + "WEB-INF/pages/";
 		ItsNatDocumentTemplate piTemplate = itsNatServlet.registerItsNatDocumentTemplate("pi", "text/html", pathPrefix + "/pi.xhtml");
 		piTemplate.addItsNatServletRequestListener(new PiServletRequestListener());
         
     }

Now create the listener by implementing the ItsNatServletRequestListener interface. Override the processRequest function to create a new event listener for the document requested by the framework:

    public void processRequest(ItsNatServletRequest request, ItsNatServletResponse response) {
    	
        ItsNatHTMLDocument itsNatHTMLDocument = (ItsNatHTMLDocument)request.getItsNatDocument();
        new  PiDocument(itsNatHTMLDocument);
        
    }

Finally, create the listener class for the document itself. This class will implement the org.w3c.dom.events.EventListener interface to receive and handle events. Each element that will have events handled by this class is represented as an org.w3c.dom.Element class, and each input button on the page has this class added as an event listener to handle click events:

public class PiDocument implements EventListener {
	
    protected  final ItsNatHTMLDocument itsNatHTMLDocument;
    
    private  Element startStopButton;
    private  Element pauseResumeButton;
    private  Element piEstimateMessage;
    private  Element threadStatus;
    
    private  PiThread piThread;
    private  EventListener cometListener;

    private  CometNotifier cometNotifier;
    
    private  final static String CLAZZ = PiDocument.class.getName();
	
 	private final static String CLICK_EVENT = "click";

    public  PiDocument(ItsNatHTMLDocument itsNatDocument) {
    	
        itsNatHTMLDocument  = itsNatDocument;
        HTMLDocument htmlDocument = itsNatHTMLDocument.getHTMLDocument();
        
        this .startStopButton = htmlDocument.getElementById("startStopButton");
        this .pauseResumeButton = htmlDocument.getElementById("pauseResumeButton");
        this .piEstimateMessage = htmlDocument.getElementById("piEstimateMessage");
        this .threadStatus = htmlDocument.getElementById("threadStatus");

        itsNatHTMLDocument .addEventListener((EventTarget)startStopButton, CLICK_EVENT, this, false);
        itsNatHTMLDocument .addEventListener((EventTarget)pauseResumeButton, CLICK_EVENT, this, false);
        
    }
    
    public  void stopNotifier()
    {
        if  (cometNotifier == null) 
        	return;

        cometNotifier .stop();
        cometNotifier .removeEventListener(cometListener);
        piThread .stopThread();
        piThread  = null;

        this .cometListener = null;
        this .cometNotifier = null;
        
    }


    private  void stopThread() {
    	
        Text text = (Text)piEstimateMessage.getFirstChild();
        text.setData("Final Pi Estimate: " + new Double(piThread.getCurrentEstimate()).toString());
        Text threadStatusText = (Text)threadStatus.getFirstChild();
        threadStatusText.setData("Thread completed");
        stopNotifier();
        
    }
    
}

The private CometNotifier class will be used to send the updates to the page, and the CometListener will handle the event of each new estimate calculation in the thread. The PiThread class must be altered to send the event to the CometNotifier class, so we need to add a private CometNotifier variable to the class, and call the CometNotifier.notifyClient() method to update the page.

The notify event will be handled by an EventListener defined when the CometNotifier is created. When the thread completes, the client is notified with the final estimate, and the notifier is stopped and disposed of.

Add the call to notifyClient() at the end of the do..while loop and the following code immediately after it:

        if (cometNotifier != null) {
        	
            cometNotifier .notifyClient();
            cometNotifier .stop();
        	
        }

Finally, the handleEvent method of the document class needs to be defined to handle the button clicks on the XHTML page and the notifications from the PiThread.

The logic of the event handler largely follows the same as before; that is, when the

• Start button is clicked, start the thread and enable the Stop and Pause buttons.
• Stop button is clicked, stop the thread and disable all buttons except the Start button.
• Pause button is clicked, pause the thread and enable the Resume button.
• Resume button is clicked, resume the thread and enable the Pause button.

The main difference here is that the CometNotifier is also created when the Start button is clicked, and when the event handler to handle notifications from the PiThread is defined:

    public  void handleEvent(Event event) {

    	EventTarget eventTarget = event.getCurrentTarget();
        if  (eventTarget == startStopButton)
        {
        	if(piThread == null) {
            
        		this.cometNotifier = ((ItsNatEvent)event).getClientDocument().createCometNotifier();
 		        this.cometListener = new EventListener() {
		        	
 		            public void handleEvent(Event evt) {
		            	
 		            	if(piThread.isThreadRunning()) {
		            		
 			                Text text = (Text)piEstimateMessage.getFirstChild();
 			                text.setData("Current Pi Estimate: " + new Double(piThread.getCurrentEstimate()).toString());
 			                if(!threadStatus.hasChildNodes())
 			                	threadStatus.appendChild(itsNatHTMLDocument.getHTMLDocument().createTextNode("Thread Running"));
			                
		            	}
 		            	else {
		            		
		            		stopThread();
	
		            	}
		                
		            }
		            
		        };
 		        cometNotifier.addEventListener(cometListener);
 		        this.piThread = new PiThread(cometNotifier);
 		        piThread.start();
 		        pauseResumeButton.removeAttribute("disabled");
 		        startStopButton.setAttribute("value", "Stop");
		        
	        }
        	else {
        	
        		stopThread();
 		        startStopButton.setAttribute("value", "Start");
 		        pauseResumeButton.setAttribute("disabled", "disabled");
		        
        	}
        	
        }
        else  if (eventTarget == pauseResumeButton) {
        	
        	piThread.suspendResume();
        	if(piThread.isThreadSuspended()) 
        		pauseResumeButton.setAttribute("value", "Resume");
        	else
        		pauseResumeButton.setAttribute("value", "Pause");
            
        }

    }



When the PiThread notifies the CometNotifier, the EventHandler uses the PiEstimate element defined in the init method to display the current estimate in the PiEstimateMessage element on the page, and to update the thread status with “Thread Running.”

Conclusion



This article has progressively demonstrated methods to update a user of the progress of a thread, from none at all, to periodic, to instant notification. Hopefully this is of use to you in your development.

Resources



• ItsNat home page: http://itsnat.sourceforge.net/index.php?_page=home
• Eclipse IDE: http://www.eclipse.org/
• Apache Tomcat: http://tomcat.apache.org/

About the author



Joseph McCarthy
Software Developer
IBM Software Group
Mulhuddart, Ireland

Joseph McCarthy is a Java Developer in the Dublin Software Lab. He joined IBM in July 2002 after graduating from the University of Limerick with a Bsc in Computer Systems, and a Graduate Diploma in Computer Engineering.

expanded Article information
collapsed Article information
Category:
WebSphere Portal
Tags:
opensource, itsnat, server threads, comet

This Version: Version 39 December 8, 2009 2:32:10 PM by Amanda J Bauman  IBMer

expanded Attachments (1)
collapsed Attachments (1)

 


File TypeSizeFile NameCreated On
image/jpeg 4 KB series.jpg 11/23/09 6:04 AM
expanded Versions (39)
collapsed Versions (39)
Version Comparison     
Version Date Changed by               Summary of changes
This version (39) Dec 8, 2009 2:32:10 PM Amanda J Bauman  
38 Nov 23, 2009 9:33:02 AM Joseph McCarthy  
37 Nov 23, 2009 9:28:57 AM Joseph McCarthy  
36 Nov 23, 2009 9:15:33 AM Joseph McCarthy  
35 Nov 23, 2009 9:15:01 AM Joseph McCarthy  
34 Nov 23, 2009 8:43:21 AM Joseph P McCarthy  
33 Nov 23, 2009 8:42:04 AM Joseph P McCarthy  
32 Nov 23, 2009 8:40:30 AM Joseph P McCarthy  
31 Nov 23, 2009 8:39:37 AM Joseph P McCarthy  
30 Nov 23, 2009 8:37:15 AM Joseph P McCarthy  
29 Nov 23, 2009 8:29:43 AM Joseph P McCarthy  
28 Nov 23, 2009 8:27:45 AM Joseph P McCarthy  
27 Nov 23, 2009 8:27:11 AM Joseph P McCarthy  
26 Nov 23, 2009 8:24:49 AM Joseph P McCarthy  
25 Nov 23, 2009 8:23:46 AM Joseph P McCarthy  
24 Nov 23, 2009 8:23:07 AM Joseph P McCarthy  
23 Nov 23, 2009 8:21:16 AM Joseph P McCarthy  
22 Nov 23, 2009 8:20:13 AM Joseph P McCarthy  
21 Nov 23, 2009 8:18:33 AM Joseph P McCarthy  
20 Nov 23, 2009 8:16:49 AM Joseph P McCarthy  
19 Nov 23, 2009 8:14:54 AM Joseph P McCarthy  
18 Nov 23, 2009 7:01:06 AM Joseph P McCarthy  
17 Nov 23, 2009 7:00:29 AM Joseph P McCarthy  
16 Nov 23, 2009 6:59:12 AM Joseph P McCarthy  
15 Nov 23, 2009 6:56:42 AM Joseph P McCarthy  
14 Nov 23, 2009 6:42:03 AM Joseph P McCarthy  
13 Nov 23, 2009 6:41:03 AM Joseph P McCarthy  
12 Nov 23, 2009 6:39:47 AM Joseph P McCarthy  
11 Nov 23, 2009 6:39:03 AM Joseph P McCarthy  
10 Nov 23, 2009 6:35:57 AM Joseph P McCarthy  
9 Nov 23, 2009 6:34:52 AM Joseph P McCarthy  
8 Nov 23, 2009 6:32:26 AM Joseph P McCarthy  
7 Nov 23, 2009 6:31:39 AM Joseph P McCarthy  
6 Nov 23, 2009 6:16:05 AM Joseph P McCarthy  
5 Nov 23, 2009 6:14:39 AM Joseph P McCarthy  
3 Nov 23, 2009 6:05:49 AM Joseph P McCarthy  
3 Nov 23, 2009 6:05:49 AM Joseph P McCarthy  
2 Nov 23, 2009 6:05:30 AM Joseph P McCarthy  
1 Nov 23, 2009 6:04:55 AM Joseph P McCarthy  
expanded Comments (0)
collapsed Comments (0)
Copy and paste this wiki markup to link to this article from another article in this wiki.
Go ElsewhereStay ConnectedSubscribe to RSSHelpAbout
  • All Lotus and WebSphere Portal wikis
  • IBM developerWorks
  • IBM Software support
  • IBM Social Business User Experience Blog
  • IBMSocialBizUX on Twitter
  • IBMSocialBizUX on Facebook
  • Lotus product forums
  • IBM Social Business UX blog
  • IBM Collaboration Solutions
  • Recently added feedRecently added
  • Recently edited feedRecently edited
  • Recently added comments feedRecently Added Comments
  • Wiki Help
  • Forgot user name/password
  • Wiki design feedback
  • Content feedback
  • About the wiki
  • About IBM
  • Privacy
  • Contact IBM
  • IBM Terms of use
  • Wiki terms of use