Prototype for Real Time Data Streaming (Data Push) Part 3

This is the part 3 of the series. Here are the other parts of the series.

Prototype for Real Time Data Streaming (Data Push) Part 1: maven2 generated Jetty based application

Prototype for Real Time Data Streaming (Data Push) Part 2: multi-channel subscription based web application

Prototype for Real Time Data Streaming (Data Push) Part 3: channel feeder java based application

In the previous blogs, I have shown how to create a web based application to allow users to subscribe multiple channels on jetty embedded server. However, they still cannot see any data from those channels because there is no data being fed onto them.

In the following, I will show how to create a java application to feed data onto the channel.

ChannelFeeder.java

The ChannelFeeder is the generic middle man program. It reads from input and sends it immediately to the designate channel. It requires a named channel as an input argument (such /123. /sar. etc) which were defined in part 2.

ChannelFeeder.java

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import org.cometd.bayeux.Channel;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.cometd.bayeux.client.ClientSession;
import org.cometd.client.BayeuxClient;
import org.cometd.client.transport.ClientTransport;
import org.cometd.client.transport.LongPollingTransport;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpBuffers;
import org.eclipse.jetty.util.component.AbstractLifeCycle;

public class ChannelFeeder { 
    private static String CHANNEL;
    private static final ClientSessionChannel.MessageListener DevListener = new DevListener();

    private static class DevListener implements ClientSessionChannel.MessageListener
    {
        public void onMessage(ClientSessionChannel channel, Message message)
        {
            // Here we received a message on the channel
            System.out.println("Sending:"+message.getData().toString());
        }
    }

    public static void main(String[] args) throws Exception {
        try { 

        if(args.length == 1)
        {
            CHANNEL = (args[0].charAt(0) == '/') ? args[0] : '/'+args[0];
        }
        else
        {    
            System.out.println("Enter new channel name");
            System.exit(1);
        } 

        // Create (and eventually setup) Jetty's HttpClient
        <span style="color:#ff0000;">HttpClient httpClient = new HttpClient();</span>

        // Setup Jetty's HttpClient
        <span style="color:#ff0000;">httpClient.start();</span>

        // Prepare the transport    
        Map&lt;String, Object&gt; options = new HashMap&lt;String, Object&gt;();
        ClientTransport transport = LongPollingTransport.create(options, httpClient);

        //ClientSession client = new BayeuxClient("http://localhost:8080/cometd", transport);
        <span style="color:#ff0000;">final BayeuxClient client = new BayeuxClient("http://localhost:8080/DeviceMonitor/cometd", transport);
</span>
        // Setup the BayeuxClient<span style="color:#ff0000;">
        client.getChannel(Channel.META_CONNECT).addListener(new ClientSessionChannel.MessageListener()</span>
        {
            public void onMessage(ClientSessionChannel channel, Message message)
            {
                //connected.set(message.isSuccessful());
            }
        });
<span style="color:#ff0000;">        client.getChannel(Channel.META_HANDSHAKE).addListener(new ClientSessionChannel.MessageListener()</span>
        {
            public void onMessage(ClientSessionChannel channel, Message message)
            {
                //connected.set(false);
            }
        });

<span style="color:#ff0000;">        client.handshake();</span>

        boolean handshaken = client.waitFor(1000, BayeuxClient.State.CONNECTED);
        if (handshaken)
        {
            // subscribe to the channel to normal (broadcast) channels
<span style="color:#ff0000;">            client.getChannel(CHANNEL).subscribe(DevListener);</span>

<span style="color:#ff0000;">            // the follow are commented out because we don't want to publish anything here.</span>
<span style="color:#ff0000;">            // We just want to pipe it from the input</span>
            // publish data to the normal channels
            //Map&lt;String, Object&gt; data = new HashMap&lt;String, Object&gt;();
            // Fill in the data. Publishing data on a channel is an asynchronous operation.
            //client.getChannel(CHANNEL).publish(data);
            //Map&lt;String, Object&gt; data = new HashMap&lt;String, Object&gt;();
            //data.put("name", "\"DevClient\"");

            //client.getChannel(CHANNEL).publish(data);

            System.out.println("Ready... (\"q\" to exit)");
            final BufferedReader inReader = new BufferedReader(new InputStreamReader(System.in));
            do {
                final String userInput = inReader.readLine();
                if (userInput == null || "q".equals(userInput)) {
                    break;
                }

                //connection.write(userInput);

                <span style="color:#ff0000;">client.getChannel(CHANNEL).publish(userInput);</span>
            } while (true);
        }

<span style="color:#ff0000;">        client.disconnect();
        client.waitFor(1000, BayeuxClient.State.DISCONNECTED);</span>

        } catch (IOException e) {
            e.printStackTrace();
        }

    } //end of main
} // end of class

feed.bash

This is a wrapper shell script to make our test easy. The execution is like

./feed.bash 123

This will allow you to key in anything from the screen, and the result will be sent to the channel 123. If the user choose channel 123 from the web browser, it will subscribe to it and see whatever you type from that onward.

./feed.bash stopwatch is to activate Stopwatch.java program. It just a count-down second by second java program. I will provide this program in another blog.

./feed.bash sar will pipe unix ‘sar -u 2 10000’ command output to the ‘sar’ for those subscribers where they can watch real time feed from remote browser. This will apply for the rest option like iostat, vmstat and ifstat.

All of these are just the simulation of the devices. The likely application for these technologies are for field devices in transportation systems, the appliance devices in home automation etc.

#! /bin/bash
if [ $# -ne 1 ]
then
    echo "$0 channel_name"
    exit 1
fi

export CHANNEL=$1

export CLASSPATH=bayeux-api-2.4.1.jar:cometd-java-client-2.4.1.jar:cometd-java-common-2.4.1.jar:jetty-client-8.0.1.v20110908.jar:jetty-http-8.0.1.v20110908.jar:jetty-util-8.0.1.v20110908.jar:jetty-io-8.0.1.v20110908.jar:slf4j-api-1.6.4.jar:slf4j-simple-1.6.4.jar:.

cd ~/test/mvn/DevClient

case "${CHANNEL}" in
     123)
           java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     stopwatch)
           <span style="color:#ff0000;">java Stopwatch</span> | java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     sar)
           <span style="color:#ff0000;">sar -u 2 10000</span> | java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     iostat)
           <span style="color:#ff0000;">iostat -xtc 2</span> 10000 | java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     vmstat)
           <span style="color:#ff0000;">vmstat 2 10000</span> | java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     ifstat)
           <span style="color:#ff0000;">ifstat</span> | java -cp ${CLASSPATH} ChannelFeeder ${CHANNEL}
           ;;
     *)
           echo "Channel not defined."
           exit
           ;;
esac
exit 0

Test Drive

The following script should open many tabs in your terminal and feed all the channels. This can use to stress test your machine. For my 2GB machine, I only can run these 6 times, and the system is totally unresponsive after it.

#!/bin/bash
if [ $# -ne 1 ]
then
    echo "$0 Feed_base_dir"
    exit 1
fi
gnome-terminal --tab --title=123 -e "$1/feed 123"  --tab --title=stopwatch -e "$1/feed stopwatch" --tab --title=sar -e "$1/feed sar" --tab --title=iostat -e "$1/feed iostat" --tab --title=vmstat -e "$1/feed vmstat" --tab --title=ifstat -e "$1/feed ifstat"
exit 0

Prototype for Real Time Data Streaming (Data Push) Part 2

This is the part 2 of the serial. Here is the other parts of the series.

Prototype for Real Time Data Streaming (Data Push) Part 1: maven2 generated Jetty based application

Prototype for Real Time Data Streaming (Data Push) Part 2: multi-channel subscription based web application

Prototype for Real Time Data Streaming (Data Push) Part 3: channel feeder java based application

In the part 1 of this serial, I created a project DeviceMonitort by using mvn. In the following, I will modify the web application to support multi-channels subscription based web application housing on Jetty 7 embedded server.

Multi-Channel subscription based Web Application

Web Pages

First, I will replace the index.jsp with there html files: index.html, frameleft.html and frameright.html.

index.html

<html>
<head>
<title>Device Monitor</title>
</head>
<frameset cols="30%,70%">
<frame src="frameleft.html" name="left_frame">
<frame src="frameright.html" name="right_frame">
</frameset>

frameleft.html

Here I demonstrates multiple channel selections on the left frame, and users can choose whatever predefined channels they want to subscribe. In fact, the channel name can be generalized as anything.

<html>
<head>
<title>frameleft</title>
<script language="JavaScript" type="text/javascript">
<!--
function change(channel)
{
parent.left_frame.document.form1.text1.value=channel;
parent.right_frame.location="device.jsp";
}
//-->
</script>
</head>
<body bgcolor="#ffffff" text="#000000">
<FORM name="form1">
Choose a channel from the list:
<INPUT type="text" name="text1" size="25" value="/123" readonly="readonly">
</FORM>
<a href="javascript:change('/123')">/123</a>
<br>
<a href="javascript:change('/stopwatch')">/stopwatch</a>
<br>
<a href="javascript:change('/sar')">/sar</a>
<br>
<a href="javascript:change('/iostat')">/iostat</a>
<br>
<a href="javascript:change('/vmstat')">/vmstat</a>
<br>
<a href="javascript:change('/ifstat')">/ifstat</a>
</body>
</html>

frameright.html

<HTML>
<HEAD>
<TITLE>Device Monitor Introduction</TITLE>
</HEAD>
<BODY>
<p>Cometd is a project by the Dojo Fundation to implement Bayeux specification. </p>
<br>
<p>Bayeux is a purpose to implement responsive user interaction for web clients using Ajax and server-push technique called Comet.</p>
<br>
<p>The messages are routed via named channels and can be delivered server2client, client2server or client2client.</p>
<br>
<p>Channels are by default broadcast publish subscribe. </p>
</FORM>
</BODY>
</HTML>

Other Files

The device.jsp file is modified from index.jsp. It allows the parameterized channelName to be passed to dev.js.

device.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<script type="text/javascript" src="${pageContext.request.contextPath}/jquery/jquery-1.7.1.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jquery/json2.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/org/cometd.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jquery/jquery.cometd.js"></script>
<span style="color:#ff0000;"><script type="text/javascript" src="dev.js"></script></span>
<%--
The reason to use a JSP is that it is very easy to obtain server-side configuration
information (such as the contextPath) and pass it to the JavaScript environment on the client.
--%>
<script type="text/javascript">
	var config = 	{
		contextPath: 	'${pageContext.request.contextPath}',
				 channelName: parent.left_frame.document.form1.text1.value
			};</span>
</script>
</head>
<body>

<div id="body"></div>

</body>
</html>

The jquery dev.js is modified from application.js, and is called by device.jsp above, and it subscribes to config.channelName.

dev.js

(function($)
{
var cometd = $.cometd;

$(document).ready(function()
{
function _connectionEstablished()
{
$('#body').prepend('<div>CometD Connection Established</div>');
}

function _connectionBroken()
{
$('#body').prepend('<div>CometD Connection Broken</div>');
}

function _connectionClosed()
{
$('#body').prepend('<div>CometD Connection Closed</div>');
}

// Function that manages the connection status with the Bayeux server
var _connected = false;
function _metaConnect(message)
{
if (cometd.isDisconnected())
{
_connected = false;
_connectionClosed();
return;
}

var wasConnected = _connected;
_connected = message.successful === true;
if (!wasConnected && _connected)
{
_connectionEstablished();
}
else if (wasConnected && !_connected)
{
_connectionBroken();
}
}

// Function invoked when first contacting the server and
// when the server has lost the state of this client
function _metaHandshake(handshake)
{
if (handshake.successful === true)
{
cometd.batch(function()
{
cometd.subscribe(config.channelName, function(message)
{
//$('#body').append('<div>Server Says: ' + message.data + '</div>');
$('#body').prepend('<div>['+config.channelName+'] ' + message.data + '</div>');
});
// Publish on a service channel since the message is for the server only
//cometd.publish('/123', { name: 'World' });
});
}
}

// Disconnect when the page unloads
$(window).unload(function()
{
cometd.disconnect(true);
});

var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
$('#body').<span style="color:#ff0000;">prepend</span>('<div>Connecting to ['+config.channelName+']'+'</div>');
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);

cometd.handshake();
});
})(jQuery);

By now, the multi-channel web based application is ready to go. Just start your jetty server:

mvn install jetty:start

Go to http://localhost:8080/  The following is the web application page:

Device Monitor Main Page

For example, click channel ‘/sar’ and you will subscribe to /sar. Of course, you just get the following screen because there isn’t any data feed onto the channel.

Device Monitor (/sar channel)

Device Monitor (/sar channel)

In the next post, I will show how to develop a java application to feed data onto the channel.

Prototype for Real Time Data Streaming (Data Push) Part 1

Real time data streaming from remote devices (ie. data pushing) has been a fascinating topic. In this series of blogs, I will examine how to implement a prototype to demonstrate the capability of pushing data from devices (java client) via embedded light weight web server JETTY (JETTY 7 / COMETD 2 / Bayeux Protocol) to your web browser (Javascript / JQuery). The series includes three parts:

Prototype for Real Time Data Streaming (Data Push) Part 1: maven2 generated Jetty based application

Prototype for Real Time Data Streaming (Data Push) Part 2: multi-channel subscription based web application

Prototype for Real Time Data Streaming (Data Push) Part 3: channel feeder java based application
The prerequisites for the prototype are MAVEN2, JETTY 7, JAVA SDK and JQUERY. I am doing on Ubunto 11.04. I believe it can be generalized on any linux distro. Also don’t worry too much on the minor version of all the prerequisites because MAVEN2 will take care of all the software and version dependencies. That’s why we use MVN. We just need to tell it what our goal is, and let it take care of the rest.

Maven 2 Jetty based Web Application

Get Started

I will create a server side web application for Jetty 7 by using mavern2.

 mvn archetype:generate -DarchetypeCatalog=http://cometd.org

It will present a few archetypes to choose. choose the following

4: http://cometd.org -> org.cometd.archetypes:cometd-archetype-jquery-jetty7 (2.4.3 - CometD archetype for creating a server-side event-driven web application)

Then provide some parameters like the following:

Define value for property 'groupId': : henry416      
Define value for property 'artifactId': : DeviceMonitor
Define value for property 'version': 1.0-SNAPSHOT: 
Define value for property 'package': DeviceMonitor: 
[INFO] Using property: cometdVersion = 2.4.3
[INFO] Using property: jettyVersion = 7.6.4.v20120524
[INFO] Using property: slf4jVersion = 1.6.4
....

From it, a project called DeviceMonitort is created.  We can really test drive this web application now. Here is how we start jetty embedded server:

mvn install jetty:run
....
2012-09-23 12:18:28.567:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
[INFO] Starting scanner at interval of 10 seconds.

Test drive by http://localhost:8080/ from web browser:

CometD Connection Established
Server Says: Hello, World
This is just like any programming where we always start with HELLO WORLD. Don’t stop here. Let’s explore what was created:

Exploring

In web.xml, it defines two servlets:


<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.server.CometdServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>initializer</servlet-name>
<servlet-class>DevServ.BayeuxInitializer</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>

In DevServ/BayeuxInitializer.java, it creates new HelloService(bayeux);
In DevServ/HelloService.java, it adds service : addService(“/service/hello”, “processHello”);
In processHello, it reads from input (name), writes to output (“greeting”, “Hello, ” + name), and remote.deliver(getServerSession(), “/hello”, output, null); Here /hello is the channel.

In index.jsp, it obtains context-path contextPath: ‘${pageContext.request.contextPath}’ dynamically, and pass control to application.js
In application.js, it does:

...
...
        $(window).unload(function()
        {
            cometd.disconnect(true);
        });

/// 1. configure URL for cometd protocol
        var cometURL = location.protocol + "//" + location.host + config.contextPath + "/cometd";
        cometd.configure({
            url: cometURL,
            logLevel: 'debug'
        });

/// 2. add meta listener
        cometd.addListener('/meta/handshake', _metaHandshake);
        cometd.addListener('/meta/connect', _metaConnect);

/// 3 handshake
        cometd.handshake();
...

Here is what metaHandshake do: subscribe to /hello channel, and publish { name: ‘World’ } to channel ‘/service/hello’, when the message push back, it displays $(‘#body’).append(‘<div>Server Says: ‘ + message.data.greeting + ‘</div>’);

...
 function _metaHandshake(handshake)
 {
 if (handshake.successful === true)
 {
 cometd.batch(function()
 {
 cometd.subscribe('/hello', function(message)
 {
 $('#body').append('<div>Server Says: ' + message.data.greeting + '</div>');
 });
 // Publish on a service channel since the message is for the server only
 cometd.publish('/service/hello', { name: 'World' });
 });
 }
 }
 ...

Comet / WebSocket: web server/browser support

Sometimes it is hard to keep track of which web server and browser are supporting Comet and/or WebSocket. The following is from JFarcand, the developer of Grizzly and Atmosphere framework.

Web Server Support

(LP: long-Polling HS: Http Streaming)

Server Version Native Comet Native WebSocket WebSockets LP HS JSONP
Netty 3.3.x X X X X X X
Jetty 5.x X X X
Jetty 6.x X X X X
Jetty 7.x X X X X X X
Jetty 8.x X X X X X X
GlassFish 2.x X X X X
GlassFish 3.x to 3.1.1 X X X X
GlassFish 3.1.2 X X X X X X
Tomcat 5.x X X X
Tomcat 6.x X X X X
Tomcat 7.0.26 and lower X X X X
Tomcat 7.0.27 and up X X X X X X
JBoss 5.x X X X
JBoss 6.x X X X X
JBoss 7.x X X X X
WebLogic 10.x X X X X
WebLogic 11.x and up X X X X
Resin 2.x X X X
Resin 3.x X  X X X X
WebSphere 7.x X X X
WebSphere 8.x X X X

Browser Support

Browser Version WebSockets Long-Polling Http Streaming JSONP
Firefox 3.x to 8.x X X X
Firefox 9.x to 11.x X X X X
Chrome 12.x and lower X X X
Chrome 13.x and higher X X X X
Internet Explorer 6x to 9.x X X X
Internet Explorer 10.x X X X X
Opera 10.x and lower X X
Opera 11.x X X X
Safari 4.x X X X
Safari 5.x X X X X
Android 2.x and up X X X
Safari (iOS) 1.x to 4.x X X X
Safari (iOS) 5.x X X X X

Browser Based Communication

History

The web has been largely built around the so-called request/response paradigm of HTTP. A client loads up a web page and then nothing happens until the user clicks onto the next page.

Around 2005, AJAX started to make the web feel more dynamic. Still, all HTTP communication was steered by the client, which required user interaction or periodic polling to load new data from the server.

Technologies that enable the server to send data to the client in the very moment when it knows that new data is available have been around for quite some time. They go by names such as “Push” or “Comet”. One of the most common hacks to create the illusion of a server initiated connection is called long polling. With long polling, the client opens an HTTP connection to the server which keeps it open until sending response. Whenever the server actually has new data it sends the response. Long polling and the other techniques work quite well. You use them every day in applications such as GMail chat.

Protocol: Bayeux vs WebSocket

The CometD framework is an implementation of the Bayeux protocol, which allows for a multi-channel asynchronous communication stream over unreliable networks between a client and server. Implementations of this are used in many languages (JavaScript, Java, Perl …) but predominantly browser-based AJAX applications. Bayeux has the advantage that it can run in any AJAX capable browser using nothing more than the underlying HTTP communication facilities provided by the browser to achieve asynchronous/background updates as new information comes in (like Google Mail’s new mail notifications). In fact, the same protocol can be used to connect devices in other languages and where network communication may be spotty, such as mobile devices.

WebSockets is a draft standard which is sponsored by Google, Apple and others at the WhatWG working group that is standardising HTML 5. As a result, HTML 5 capable browsers (Chrome, Safari) are starting to include built-in support for the WebSocket protocol.

Both protocols aim to allow web-based AJAX applications to communicate with other services via asynchronous messaging or socket-based connections, rather than having to roll your own communications layer on top of an existing application. This allows the design of an application to focus on the component parts, and hand off messages to the communication layer for delivery. In addition, both can set up long-running connections such that events can be delivered asynchronously subsequently to the application. This is nothing new: HTTP 1.1 supported connection pipelining (the ability to keep open a connection after each request, and the ability to send multiple requests before the first was acknowledged); and other protocols like IMAP supported the IDLE command to put a connection into a hibernate state, where there is no ongoing communication but the server can push new messages at any time. Indeed, prior to either Bayeux or WebSockets, the term “HTTP Push” was used to indicate a general mechanism for long-lasting communication channel across HTTP.

Problems and Challenges

The real challenge is HOW TO MAINTAIN THE CONNECTION!

A connection that hasn’t had any data over a period of time may be considered to have died, and arbitrarily terminated, at some point in the future. To address this, the IMAP IDLE suggests that clients send a re-negotiated IMAP IDLE command every 29 minutes to avoid disconnection. With other proxies in the way of HTTP, it may be that a proxy determines that a connection is idle and drops the connection, even if the client and server agree to maintain an ongoing connection.

The other problem is resource-based; generally, browsers limit the number of concurrent HTTP connections to a single server to avoid overbearing the server (or the network link). It’s common for browsers to limit such concurrent connections to between 2 and 4 at any one time.

Both Bayeux and WebSockets attempt to avoid the resource limits by using a fall-back mechanism for long polling (in the case of Bayeux) or switching to a non-HTTP based secondary protocol instead. As a result, users of these libraries don’t generally have to worry about limitations placed on them by the browser or infrastructure.

COMETD 2.x

CometD 2 now supports both Bayeux, and Websocket (which as an alternative transport to the currently supported JSON long polling and JSONP callback polling). CometD is transparent to browsers with or without websocket support. Websocket usage will be able to give us even better throughput and latency for cometd than the already impressive results achieved with long polling.

References

Bayeux Protocol Specification

W3C The WebSocket API

Alex Russell’s original 2006 comet blog post

Order Entry System 3: JSP, Servlet, Session Bean, JQuery

This is the final part of the series:

OrderSaveServlet.java

The OrderSaveServlet is the controller to save the CustomerBean from the session memory to a table “customer” in MySQL database via JNDI connection pool on GlassFish Application Server. It obtains the generated customer id from the database. Then, it saves the OrderBean and customer id into a another table “orders” in the database, and obtains the order id generated by the database insertion. It finally generates a html page to display the order number back to user. And our Order Entry Web System will end here.

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import mybean.CustomerBean;
import mybean.OrderBean;

@WebServlet(name = "OrderSaveServlet", urlPatterns = {"/OrderSaveServlet"})
public class OrderSaveServlet extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * &lt;code&gt;GET&lt;/code&gt; and
     * &lt;code&gt;POST&lt;/code&gt; methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            HttpSession session = request.getSession();
            CustomerBean CustomerBean = (CustomerBean)session.getAttribute("CustomerBean");

            InitialContext ctx = new InitialContext();
            DataSource ds = (DataSource)ctx.lookup("jdbc/MySQLPool");

            Connection conn = ds.getConnection();
            Statement stmt = conn.createStatement();

            String query1 = "INSERT INTO customer (name, address, tel, email) VALUES ( '" +
                    CustomerBean.getName() +"','"+
                    CustomerBean.getAddress()+"','"+
                    CustomerBean.getTel()+"','"+
                    CustomerBean.getEmail()+"') ";

            stmt.executeUpdate(query1);

            int customerid = -1;

//            ResultSet rs = stmt.getGeneratedKeys();
            ResultSet rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");

            if (rs.next()) {
                customerid = rs.getInt(1);
            } else {

                // throw an exception from here
            }

            OrderBean OrderBean = (OrderBean)session.getAttribute("OrderBean");

            String query2 = "INSERT INTO orders (itemid, saleprice, gst, qty, customerid) VALUES ( " +
                    OrderBean.getItemid() +","+
                    OrderBean.getSaleprice()+","+
                    OrderBean.getGst()+","+
                    OrderBean.getQty()+","+
                    customerid+") ";

            stmt.executeUpdate(query2);

            int orderid = -1;

//            ResultSet rs = stmt.getGeneratedKeys();
            rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");

            if (rs.next()) {
                orderid = rs.getInt(1);
            } else {

                // throw an exception from here
            }

            stmt.close();
            conn.close();

            out.println("&lt;html&gt;");
            out.println("&lt;head&gt;");
            out.println("&lt;title&gt;Servlet OrderSaveServlet&lt;/title&gt;");            
            out.println("&lt;/head&gt;");
            out.println("&lt;body&gt;");
//            out.println("&lt;p&gt;query: " + query2 + "&lt;/p&gt;");
            out.println("&lt;h1&gt;Thank you. Your Order Number: " + orderid + "&lt;/h1&gt;");
            out.println("&lt;/body&gt;");
            out.println("&lt;/html&gt;");
        } catch (Exception e) {
          //  e.printStackTrace();
        } finally {                        
            out.close();
        }
    }

    // &lt;editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."&gt;
    /**
     * Handles the HTTP
     * &lt;code&gt;GET&lt;/code&gt; method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * &lt;code&gt;POST&lt;/code&gt; method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// &lt;/editor-fold&gt;
}

Order Entry System 2: JSP, Servlet, Session Bean, JQuery

This is the second part of the series:

OrderEntry.jsp

This JSP  allows the user to entre the quantity, and calculates the gst and total payment by using the on-page JQuery function, and passed the control to OrderCustomer.jsp

<%--
    Document   : OrderEntry
    Created on : 14-Mar-2012, 12:57:23 AM
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="rs" scope="request" type="java.sql.ResultSet" />
<jsp:useBean id="OrderBean" scope="session"/>

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Order Entry</title>
       <style>
           body {
               font-family: sans-serif;
           }
           #summation {
               font-size: 18px;
               font-weight: bold;
               color:#174C68;
           }
           .txt {
               background-color: #FEFFB0;
               font-weight: bold;
               text-align: right;
           }
       </style>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    </head>

     <body style="font-family:verdana;font-size:10pt;">
       <%
         if(rs.next()) {
       %>
       <form action="OrderCustomer.jsp">
         <input name="itemid" type="hidden" value="<%= rs.getString(1) %>"/>
         <input name="saleprice" type="hidden" value="<%= rs.getString(4) %>"/>
         <table width="300px" border="1" style="border-collapse:collapse;background-color:#E8DCFF">
           <tr>
             <td><b>Name:</b></td>
             <td><input id="itemname" name="itemname" type="text" value="<%= rs.getString(2)%>" readonly /></td>
           </tr>
           <tr>
             <td><b>Description:</b></td>
             <td>"<%= rs.getString(3) %></td>
           </tr>
           <tr>
             <td><b>Price:</b></td>
             <td>
                 <input id="saleprice" name=""saleprice" type=text" value="<%= rs.getString(4)%>" readonly />
             </td>
           </tr>
           <tr>
             <td><b>Quantity:</b></td>
             <td>
               <input id="qty" name="qty" type="text"
               value="0"/>
             </td>
           </tr>
           <tr>
           <tr>
             <td><b>GST:</b></td>
             <td>
               <input id="gst" name="gst" type="text"
               value="" readonly/>
             </td>
           </tr>
           <tr>
             <td><b>Total:</b></td>
             <td>
               <input id="total" "name="total" type="text"
               value="" readonly/>
             </td>
           </tr>
           <tr>               
             <td></td>
             <td>
               <input type="submit" value="Checkout"/>
           </td>
           </tr>
<p></p>

        </table>
        <%
          }
        %>
        <script>
    function displayVals() {
         var mygst =0;
        var mysum =0;
        mysum = parseFloat($("#saleprice").val())*parseFloat($("#qty").val());
        mygst = mysum * 0.13;
        mysum = mysum + mygst;
        $("#gst").val(mygst.toFixed(2));
        $("#total").val(mysum.toFixed(2));
//       $("p").html("<b>gst:</b> " + mygst.toFixed(2) + "<b>   total:</b> " +mysum.toFixed(2));
    }
    $("#qty").change(displayVals);
    displayVals();
        </script>
        </body>
</html>

OrderCustomer.jsp

This JSP saves the order entry information passed by the last JSP to the OrderBean memory structure first, then retrieves those information back to display on top the screen. It also allows the user to entre their information quantity,Finally, it  passed the control to OrderConfirm.jsp.

<%--
    Document   : OrderCustomer
    Created on : 14-Mar-2012, 2:16:41 AM
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<jsp:useBean id="OrderBean" scope="session"/>
<jsp:setProperty name="OrderBean" property="itemid"/>
<jsp:setProperty name="OrderBean" property="itemname"/>
<jsp:setProperty name="OrderBean" property="saleprice"/>
<jsp:setProperty name="OrderBean" property="qty"/>
<jsp:setProperty name="OrderBean" property="gst"/>
<HTML>
     <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Order Entry 2: Customer Contact Detail</title>
        <style>
           body {
               font-family: sans-serif;
           }
           #summation {
               font-size: 18px;
               font-weight: bold;
               color:#174C68;
           }
           .txt {
               background-color: #FEFFB0;
               font-weight: bold;
               text-align: right;
           }
        </style>
    </head>
<BODY>
        You just entered the following order: <BR>
        ItemID: <%= OrderBean.getItemid() %><BR>
        ItemIName: <%= OrderBean.getItemname() %><BR>
        Saleprice: <%= OrderBean.getSaleprice() %><BR>
        Qantity: <%= OrderBean.getQty()%><BR>
        GST: <%= OrderBean.getGst() %><BR>
        Please enter your contact detail: <BR>
        <form action="OrderConfirm.jsp">
         <table width="300px" border="1" style="border-collapse:collapse;background-color:#E8DCFF">
           <tr>
             <td><b>Name:</b></td>
             <td><input id="name" name="name" type="text" value=""/></td>
           </tr>
           <tr>
           <tr>
             <td><b>Address:</b></td>
             <td><input id="address" name="address" type="text" value="" /></td>
           </tr>
           <tr>
             <td><b>Telephone:</b></td>
             <td><input id="tel" name="tel" type="text" value="" /></td>
           </tr>
           <tr>
             <td><b>Email:</b></td>
             <td><input id="email" name="email" type="text" value="" /></td>
           </tr>
           <tr>               
             <td></td>
             <td>
               <input type="submit" value="Next"/>
           </td>
           </tr>
        </table>

</BODY>
</HTML>

OrderConfirm.jsp

This JSP saves the customer information passed by the last JSP to the CustomerBean memory structure first, then retrieves those information back to display on top the screen. Finally, it  passed the control to OrderSaveServlet.

<%--
    Document   : OrderConfirm
    Created on : 14-Mar-2012, 4:30:45 AM
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<jsp:useBean id="OrderBean" scope="session"/>
<jsp:useBean id="CustomerBean" scope="session"/>
<jsp:setProperty name="CustomerBean" property="name"/>
<jsp:setProperty name="CustomerBean" property="address"/>
<jsp:setProperty name="CustomerBean" property="tel"/>
<jsp:setProperty name="CustomerBean" property="email"/>
<HTML>
     <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Order Entry</title>
        <style>
           body {
               font-family: sans-serif;
           }
           #summation {
               font-size: 18px;
               font-weight: bold;
               color:#174C68;
           }
           .txt {
               background-color: #FEFFB0;
               font-weight: bold;
               text-align: right;
           }
        </style>
    </head>
<BODY>
        You just entered the following order: <BR>
        Item ID: <%= OrderBean.getItemid() %><BR>
        Item Name: <%= OrderBean.getItemname() %><BR>
        Saleprice: <%= OrderBean.getSaleprice() %><BR>
        Qantity: <%= OrderBean.getQty()%><BR>
        GST: <%= OrderBean.getGst() %><BR>
        <BR>
        And your contact detail: <BR>
        Name: <%= CustomerBean.getName() %><BR>
        Address: <%= CustomerBean.getAddress() %><BR>
        Telephone: <%= CustomerBean.getTel()%><BR>
        Email: <%= CustomerBean.getEmail() %><BR>
        <BR>
        Click the following button to finish the order: <BR>
        <form action="OrderSaveServlet"> <input type="submit" value="Confirm"/> </form>
</BODY>
</HTML>