Apr 09 2008

Create reverse Ajax Web-Applications with DWR and NetBeans

Published by at 10:04 PM under Ajax,GlassFish,Java,NetBeans



This blog was submitted to the NetBeans IDE 6.1 Beta Blogging Contest.

In this blog you can read how to create a (very simple) reverse Ajax Web-Application, using NetBeans 6.1 BETA and running on GlassFish v2 (YES – i like new technologies!). This example is also working with previous NetBeans versions and Apache Tomcat 6.

Note:
Download-links to all files are available at the end of this blog-entry.


Prerequisites

To work with this example you need an installed NetBeans 6.1 BETA (as above mentioned, older versions are working too) with included GlassFish v2 and the DWR-Jar’s (included in the Example-archive). If you don’t want to create this example from scratch, you can open it with NetBeans and run it immediately. You can read in my other blog how to open an existing NetBeans project.


Introduction

There are many reverse Ajax Frameworks like COMETd and Pushlets which have the ability to push data from the Web Server to the Client (Browser). This effect is similar to applications using traditional Ajax with polling to detect new information on the server.

DWR, or Direct Web Remoting, is a Java open source library which helps developers write web sites that include Ajax technology. It allows code in a web browser to use Java functions running on a web server as if those functions were within the browser.

Direct Web Remoting diagram


DWR consists of two main parts:

  • A Java Servlet running on the server that processes requests and sends responses back to the browser.
  • JavaScript running in the browser that sends requests and can dynamically update the webpage.

Inspired by the Stocks-example from the Pushlets Project, i have created this example with the DWR-Technology. Once activated (this happens by clicking the button “Get Stocks”), this application is pushing stock rates to all opened browsers (which have a valid session).


Create the Project

First, launch NetBeans 6.1 BETA and enjoy the faster startup.
For all new features visit http://www.netbeans.org/community/releases/61/.

launch NetBeans 6.1 BETA


Create a new Web Application project:

create a new netbeans project


Fill out the project-properties like this:

fill out netbeans project properties


Click finish and you should see something like this:

new netbeans web application project

Now you have to add the required Jar-files (which are included in the example-archive). Rightclick on the project-name and choose Properties:

NetBeans Project properties


Navigate to Libraries and add the Jar-files:

add jar files to netbeans project


In this example the Jar-files are located in the subdirectory /lib:

location of project jars


Add needed files

In the NetBeans-IDE, navigate to the file index.jsp and exchange the content with this JSP-code:


index.jsp

<%--
    Document   : index
    Created on : 06.04.2008, 15:39:59
    Author     : Siegfried Bolz
--%>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
        <title>DWR StocksDemo</title>
        <meta NAME="Copyright" CONTENT="Siegfried Bolz - http://blog.jdevelop.eu">

        <%-- This files are created in the runtime --%>
        <script type='text/javascript' src='/stocksdemo/dwr/util.js'></script>
        <script type='text/javascript' src='/stocksdemo/dwr/interface/StocksDemo.js'></script>
        <script type='text/javascript' src='/stocksdemo/dwr/engine.js'></script>


        <script type="text/javascript">
            function getStocks() {
                StocksDemo.sendStocks();
            }
        </script>

        <link rel="stylesheet" type="text/css" href="generic.css" />
    </head>

    <body onload="dwr.engine.setActiveReverseAjax(true);">

        <div id="page-title">[
            <a target="_blank" href="http://blog.jdevelop.eu">Another Random Developer Blog</a> |
            <a target="_blank" href="dwr/index.html">DWR API Overview</a> |
            <a target="_blank" href="http://getahead.org/dwr">Getahead.org</a>
        ]</div>

        <h1>Receiving Stock Rates using Reverse Ajax</h1>

        <p>The following example illustrates how stock rates can be pushed from the server. Note: these are faked rates. A real application would use something like a Reuters live stockfeed at the back-end.</p>
        <input type="button" value="Get Stocks" onclick="getStocks()"/>
        <hr />

        <table style="width:500px" border="0" cellpadding="0">
            <tr>
                <td class="headName" ><b>Name</b></td>
                <td class="headValue" ><b>value</b></td>
            </tr>
            <tr><td>Allianz SE</td><td><div id="allianz">wait...</div></td></tr>
            <tr><td>Bayer AG</td><td><div id="bayer">wait...</div></td></tr>
            <tr><td>BMW AG St</td><td><div id="bmw">wait...</div></td></tr>
            <tr><td>Commerzbank AG</td><td><div id="commerzbank">wait...</div></td></tr>
            <tr><td>Daimler AG</td><td><div id="daimler">wait...</div></td></tr>
            <tr><td>Deutsche Bank AG</td><td><div id="deutschebank">wait...</div></td></tr>
            <tr><td>Deutsche Post AG</td><td><div id="deutschepost">wait...</div></td></tr>
            <tr><td>Deutsche Telekom AG</td><td><div id="telekom">wait...</div></td></tr>
            <tr><td>Hypo Real Estate Holding AG</td><td><div id="hypo">wait...</div></td></tr>
            <tr><td>Infineon Technologies AG</td><td><div id="infineon">wait...</div></td></tr>
            <tr><td>Linde AG</td><td><div id="linde">wait...</div></td></tr>
            <tr><td>METRO AG St</td><td><div id="metro">wait...</div></td></tr>
            <tr><td>RWE AG St</td><td><div id="rwe">wait...</div></td></tr>
            <tr><td>SAP AG</td><td><div id="sap">wait...</div></td></tr>
            <tr><td>Siemens AG</td><td><div id="siemens">wait...</div></td></tr>
            <tr><td>TUI AG</td><td><div id="tui">wait...</div></td></tr>
            <tr><td>Volkswagen AG St</td><td><div id="vw">wait...</div></td></tr>
        </table>

        <br />

        <div id="page-footer">Copyright 2008 by <a href="http://blog.jdevelop.eu" target="_blank">Siegfried Bolz</a></div>
    </body>
</html>


index.jsp


You are wondering where the JavaScript-files located? They are generated during runtime from the DWR Jar-files. This is the reason why NetBeans shows some errors. Ignore them!

Create the stylesheet-file generic.css with this code:


generic.css

@CHARSET "ISO-8859-1";

body { margin:60px 40px 0px 40px; color:#666; line-height:1.3em;
  font-family:'Century Gothic', Helvetica, Arial, clean, sans-serif;
}

select, textarea, input[type='text'], input[type='password'] {
  font-family:'Century Gothic', Helvetica, Arial, clean, sans-serif;
  font-size:1em; padding:3px 3px; margin:2px; border:1px solid #999;
}

button, input[type='button'], input[type='submit'], input[type='cancel'] {
  font-family:'Century Gothic', Helvetica, Arial, clean, sans-serif;
  font-size:1em;
}

a { color:Blue; text-decoration:none; }
a:hover { background-color:#ffc; color:#fc6; }
a:active { color:#fc6; }

h1 { color:#000; font-weight:bold; font-size:130%; }
h2 { color:#000; font-size:110%; }
h3 { color:#000; font-size:100%; }
h4 { color:#000; font-size:90%; }

img { border:0; }

table { border-collapse:collapse; border-spacing:5px; }
table, td, th { border:1px solid #ccc; padding:5px; }
table.form th { text-align:right; font-weight:normal; }
table.grey th { background:#eee; font-weight:normal; }
table.plain { border:0; }
table.plain td { border:0; }
table.plain th { border:0; }


#page-title { background-color:#7272a2; border:1px solid #000000;
  border-top:0; padding:5px; font-size:80%; line-height:1.8em;
  position:absolute; top:0; left:0; width:100%; color:#ccc;
}
#page-title a { text-decoration:none; color:white; }
#page-title a:hover { background-color:#7272a2; color:#ff3; }
#page-title a:active { color:#fc6; }

#page-footer { background-color:#7272a2; border:1px solid #000000;
  border-top:0; padding:5px; font-size:80%; line-height:1.8em;
  position:absolute;left:0;width:100%;color:#ccc;
}

#page-footer a { text-decoration:none; color:white; }
#page-footer a:hover { background-color:#7272a2; color:#ff3; }
#page-footer a:active { color:#fc6; }

#headName { width:300px;}


Open the file web.xml and insert this:


web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>dwr-invoker</servlet-name>
        <servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>pollAndCometEnabled</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dwr-invoker</servlet-name>
        <url-pattern>/dwr/*</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>


web.xml


Now create the file dwr.xml, located in the directory /WEB-INF:

create new xml file


create new xml document


name the file ‘dwr’


Insert this in dwr.xml:


dwr.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
"http://getahead.ltd.uk/dwr/dwr20.dtd">
<dwr>
    <allow>
        <create creator="new" javascript="StocksDemo">
            <param name="class" value="eu.jdevelop.dwrstocksdemo.StocksDemo"/>
        </create>
    </allow>
</dwr>


opened file dwr.xml


Create the java class file StocksDemo:

create the java class file stocksdemo.java


and insert this:


StocksDemo.java

package eu.jdevelop.dwrstocksdemo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.proxy.dwr.Util;
import org.directwebremoting.util.Logger;

/**
 * Reverse Ajax class.
 *
 * @author Siegfried Bolz (blog.jdevelop.eu)
 */
public class StocksDemo {

    protected static final Logger log = Logger.getLogger(StocksDemo.class);

    private List<stocksBean> stocks = new ArrayList<stocksBean>();


    /**
     * Initialize the stocklist with values.
     */
    public StocksDemo() {
        stocks.add(new StocksBean("bmw", "36.55"));
        stocks.add(new StocksBean("linde", "91.01"));
        stocks.add(new StocksBean("commerzbank", "22.59"));
        stocks.add(new StocksBean("infineon", "5.07"));
        stocks.add(new StocksBean("siemens", "71.77"));
        stocks.add(new StocksBean("sap", "31.61"));
        stocks.add(new StocksBean("bayer", "51.29"));
        stocks.add(new StocksBean("metro", "52.70"));
        stocks.add(new StocksBean("tui", "16.96"));
        stocks.add(new StocksBean("daimler", "54.34"));
        stocks.add(new StocksBean("vw", "178.48"));
        stocks.add(new StocksBean("allianz", "134.48"));
        stocks.add(new StocksBean("deutschebank", "76.32"));
        stocks.add(new StocksBean("rwe", "80.63"));
        stocks.add(new StocksBean("hypo", "18.79"));
        stocks.add(new StocksBean("deutschepost", "20.19"));
        stocks.add(new StocksBean("telekom", "11.13"));
    }


    /**
     * Send the Stock-Values to the file "index.jsp"
     */
    public void sendStocks() throws InterruptedException {
        WebContext wctx = WebContextFactory.get();
        String currentPage = wctx.getCurrentPage();

        Collection sessions = wctx.getScriptSessionsByPage(currentPage);
        Util utilAll = new Util(sessions);

        for (int i = 0; i < stocks.size(); i++) {
            Thread.sleep(1000);
            utilAll.setValue(stocks.get(i).getStock(), stocks.get(i).getValue());
            log.info("Pushing stock: " + stocks.get(i).getStock() + " = " + stocks.get(i).getValue());
        }

    }

} // .EOF


Create the class StocksBean with the same package and insert this code:


StocksBean.java

package eu.jdevelop.dwrstocksdemo;

/**
 * This bean is used for storing one stock rate.
 *
 * @author Siegfried Bolz
 */
public class StocksBean {

    private String stock = "";
    private String value = "";

    public StocksBean(String stock, String value) {
        this.setStock(stock);
        this.setValue(value);
    }

    public String getStock() {
        return stock;
    }

    public void setStock(String stock) {
        this.stock = stock;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

} // .EOF


The last file, create it in the source-directory:


log4j.properties

log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x -%m%n


log4j.properties


Alright, the job is done. Your NetBeans-project just have to look like this:

addfiles_finished.png


Testing

Build, deploy and launch the project. Browse to the URL http://localhost:8080/stocksdemo . You see the simple StocksDemo-Web Application. Open more browser-windows with the same URL. Click in one of them on the button Get Stocks to activate the reverse Ajax. In short time distances you can see how the values in all opened browser-windows are filled with the same numbers. This happens because DWR stores all active sessions in the memory:

Collection sessions = wctx.getScriptSessionsByPage(currentPage);
Util utilAll = new Util(sessions);


stocksdemo running in browser window


You can see the current pushed stock-value in the NetBeans output-console:

netbeans output console


I have made a Flash-video where you can see this application in action (click on image to open video):

camtasia video link


Deploy WAR manually to GlassFish

Note:
If you don’t know how to work with GlassFish, read the first two chapters there: http://blog.jdevelop.eu/?p=7.

Login to the GlassFish Admin Console and navigate on the left side to Applications->Web Applications.

deploy war to glassfish


Hit deploy and upload the file dwrstocksdemo.war.

upload war file


After uploading the WAR-file, you can launch the application directly from the Admin Console. If you see nothing in your browser, be sure that your URL is using the correct port (standard: 8080).

deployed web application


Possible Problem

I encountered an obscure problem with the Internet Explorer 7. There are no JavaScript errors or something else, but the Get Stocks-button does not work. With Firefox, Opera and Konqueror everything is working fine. Does someone else have the same problem (or not) ? Please drop a line in the comments below.


Downloads

NetBeans 6.1 BETA Project: download
WAR-File: download

Technorati Tags: , , , ,

20 responses so far

20 Responses to “Create reverse Ajax Web-Applications with DWR and NetBeans”

  1. VLAN stands for the Virtual Local Area Network. It creates the broadcast domain by usin the switches to reduce the traffic and to provide the security, flexibility and easy management.

  2. Omkar sagt:

    Hey Siegfried,

    A very nice tutorial indeed. The moment I tried it out in my Netbeans 6.1 I felt I should integrate DWR in my work project, and I successfully did. DWR is a great framework for projects demanding “server push” mechanism and without doubt Netbeans 6.1 a great IDE.
    DWR works great on Mozilla Firefox, although, for it to run and display server updates as and when they arrive to the browser in case of Internet Explorer, one will have to use the DWR 2.0.4 library.
    Once again, a great tutorial and looking forward for many more to come from you.

    - Omkar

  3. Thanks Omkar,
    DWR is truly a great framework. Have you experienced any problems with other browsers?
    When i have more time i will write more about DWR.

    Regards,
    Siegfried

  4. Ron Monson sagt:

    I’ve had success with both FF and IE when doing a simple demo of reverse ajax with dwr running on Caucho’s Resin. However, in a larger project I’m not able to get FF to receive the script pushes. This project uses Tomcat 6, Struts 2, Spring and Acegi. DWR does see the FF sessions but they are getting lost somewhere. IE6 works fine.

  5. Ron Monson sagt:

    I solved my problem by replacing:

    window.onload = function() {
    dwr.engine.setActiveReverseAjax(true);
    };

    with:

    body onload=”dwr.engine.setActiveReverseAjax(true)”

    Strangely enough, this didn’t cause me any problems when running under the simpler demo using Resin. Go figure.

  6. Hello Ron,
    thank you for sharing your very interesting experience with DWR!

    Regards,
    Siegfried

  7. sunny85 sagt:

    Hi,
    This is a good Reverse Ajax example.

    I have one question.
    How can I make it pull stock prices automatically.
    I mean, I press the button and then it starts refreshing without stopping.

    Is there anything that should be configured in DWR ?

    Thank you.

    Sunny85

  8. Manali sagt:

    I was wondering where the stock prices are pulled from?? If I make changes to the StocksDemo.java class, i.e. change the price of the stocks, then the changes are not seen in the browser window. I was wondering why this is so??

    Is there some specific change to any other page I need to make.

    Please let me know if anyone has any input to give on this.

    Thank You.
    Manali

  9. Manali sagt:

    One more question..I commented out the main method sendStocks() present in the StocksDemo.java class…but the program still works..Is my system crazy or is this program behaving simply weird…

    Please note that I have cleared my cache and other things before running it.

    This is just a question.

    Thank You.
    Regards,
    Manali

  10. I have commented out the method and i can’t get any results. Must be some kind of cache mismatch. Sorry, i don’t know what could be the problem.

  11. Darren sagt:

    Hi,

    I tried your example and get it to compile and load the web page but the stock value does not change or update simply says wait.

    thanks in advance

  12. Hi Darren,
    try to run this application with different browsers like Firefox and Opera.

  13. Jeanette sagt:

    Hello Siegfried,

    Finally….after searching the web for hours, for a good AJAX push tutorial, I found yours..
    I’m at my last semester of Advanced Computer Studies, and I’m a week away from handing in my final rapport. Your step-by-step tutorial was easy to read and use.

    I have tried a lot of other tutorials, it seems like you just know a bit too little, or there is missing some information, that is apparently obvious to everyone but you, and the result is that it doesn’t work, and you have learned nothing.

    So thank You, from me and other noobs like me.
    It was just what I needed to top off my rapport, I’ll make sure to give You credit in the rapport.

    By the way, I would like it to push data without clicking the button, so I put the getStocks() function in the body onload:

    It seems to work, but not always…sometimes you need to open another window, and then the first window works!!!

    Is there a better way to do it?

  14. Bogdan sagt:

    Nice project, learned a lot dwr since I first implemented it.

    I found out why it does not work on IE, the problem on IE is that you cannot change tables content via innerHTML.
    It gives Unknown Runtime Error.

    You did not receive any error because you did not change the table through it’s ID but you tried to change the td tag. td is under table tag so probably it end up with same issue but without displaying the error.

    Try to get rid of the table and use div,… or create the whole string table and assign to a div innerHTML, something like this:
    -> in jsp page:
    <div id=”stocks_table”></div>
    -> in java servlet:
    utilAll.setValue(“stocks_table”,”<table><tr><td>”+Value+”</td></tr>” + another_tr… and so on +”</table>”);

    Regards,
    Bogdan

  15. ffrreeaakk sagt:

    I have similar problem as Darren. It doesn’t seem to work but after 20-30 seconds all values appear immediately. No intervals.
    Even after commenting Thread.sleep(1000); it takes so long.
    Using Netbeans 6.5 and Opera 9.62 & Opera 10beta

  16. Greetings! I could not find the .js files in the war file that is available for download. May I expect a reply?
    Thanks in advance

  17. Manu sagt:

    Hello, do you now if I can send information to browsers from a background processes (e.g batch processes, daemon, etc) ?

  18. geek.shrek sagt:

    Hi,

    Thanks for tutorial :) It’s a very good tutorial, it’s really help me a lot to understand this process.

    I’m trying to run the example using IE 8 and Firefox 3.5.3
    But unfortunately I can’t get the stock value, it keep at status “wait”.

    Is there any settings that I need to do for this two browsers?

    Thanks

  19. Timothy Wong sagt:

    Thanks for the tutorial. It is very useful and helpful. But I found one issue,

    In IE, the data can be updated only when the sendStocks() is completed. That means users need to wait and wait, and the data is updated with whole table.

    But in Firefox, the data can be updated individually. Do you have any ideas on it?

    Thanks.

Leave a Reply


6 + = elf