Damodar's Musings

web development and miscellany

Browsing Posts published by Damodar Chetty

I recently had to monitor the radio signal from my router. Imagine my surprise when I found that almost 50% of the 24 networks in range were running with little or no encryption!

See my earlier post on Wi-Fi encryption schemes.

My neighbors were either very trusting or very naïve.

Of course, another possiblity was that they were just overwhelmed by the challenges of setting up their home router – a device that is beguiling in terms of the wireless freedoms that it promises; a device that is powerful enough to be a little computer in its own right; a device that is so complex that its configuration runs into 30 pages of settings, replete with technical networking jargon!

Now, if you have chosen to unleash the power of this awesome device in your home, it is up to you to ensure that you use it wisely. As uncle Ben would say, “With great power comes great responsibility”.

That’s where this article comes in. Think of it as a networking survival guide.

My goal is to make you comfortable enough with the most critical aspects of your home wireless router, so that you can effect the necessary changes easily and painlessly.

1. Three things you need to know about wireless networks

1.1  Bandwidth and Throughput

Bandwidth is defined as the amount of data that can be pushed through a network.

A good analogy  is the maximum number of vehicles that can simultaneously use a stretch of freeway – assuming perfect driving conditions, that the vehicles are being driven by the best drivers in the country, are traveling at the top speed limit, are maintaining the minimum proper distance from each other, and are not changing lanes. Highway bandwidth might be measured as the number of cars that pass per second.

Throughput is what happens in the real world. I.e., when construction areas, inclement weather, and inattentive drivers happen – causing ripples in the fabric of smooth traffic flow.

Network bandwidth is measured as the number of bits or bytes that pass through every second – e.g., as Mbps (million bits per second) or MBps (million bytes per second). While bandwidth with a N900 device is estimated at 900 Mbps, I average a throughput of mere 24 Mbps on my network.

So what happened to the rest of the promised bandwidth?

That remainder is lost due to interference, due to overhead bits needing to be transmitted for error correction and other control tasks, etc.

1.2  Range

Another key measure for routers is the distance to which it is able to project a workable signal. This is a function of the power of router’s transmitter, the sensitivity of the receiver, and the material that the signal must pass through to get from one to the other.

As you can see, only one of these relates to the router.

To ensure maximum coverage:

  • purchase the router with the most powerful transmitter (29 dbm for the WNDR4500).
  • use a wireless adapter that matches the full bandwidth of the transmitter. I.e., if you are using a N900 router, then your adapter should be N900 compliant as well.
  • move your router to the most central location in your home. The more central the location, the better the strength of your signal as it radiates outward.

1.3  Standards

Wireless standards have evolved by giant strides since 1999, when the 802.11b standard was rated at 11Mbps. Since then 802.11g (2003) raised this to 54Mbps, and 802.11n (2009) has upped the ante even farther – from 600 Mbps (N600), to 750 Mbps (N750), all the way up to 900 Mbps (N900).

The latest 802.11n standard has a few tricks up its sleeve to make these high speeds possible.

  • Multiple Input Multiple Output – it supports the use of multiple antennas that can transmit/receive simultaneously.
  • Channel Bonding – the width of the Radio Frequency channel used is increased from 20MHz to 40MHz. Since the width of a RF channel determines the throughput, this has a beneficial effect on network bandwidth.
  • Dual Bands – the radios in 802.11b/g routers transmitted on the 2.4GHz radio frequency – a rather noisy band – even your microwave transmits at this frequency. 802.11n devices can also use the cleaner and less populated 5GHz band.
  • Frame aggregation – Grouping multiple frames together amortizes the cost of acknowledgements and allows for smaller interframe spaces, improving bandwidth.

The number of MIMO antennas coupled with the dual bands give us the familiar Nxxx numbers that we see associated with 802.11n routers.

Total bandwidth = Bandwidth per Antenna x Number of Antennas x Frequency Bands

For the WNDR4500 and AE4500, which are N900 capable, this is:

150 Mbps/antenna x 3 antennas x 2 bands = 900.

A consequence of multiple antennas is increased power consumption. This is a problem with mobile devices such as tablets and phones. To conserve power, many wireless adapters limit the number of bands they support or the number of transmit/receive antennas they have. For instance, the Intel 5100 adapter has only 1 transmit radio, and 2 receive radios. As a result, it can only transmit at 150Mbps, and receive at 300Mbps. In other words, the bandwidth you can achieve will be limited by your weakest component. In most cases, this will be your wireless client.

That said, having more radio transmitters on the router than receivers on the adapter, means that the router can use additional techniques to ensure clear communications. For e.g., a router could choose the best transmitter/antenna to use to communicate with an adapter based on measures such as packet error rate or received signal strength. In addition, the router could transmit the same information using two antennas – increasing the chance that at least one copy of a packet will get through to the receiver.


2. Three things you need to know about the Internet

2.1  Addressing in Networks

Every device that connects to a network is associated with a unique 48-bit network address called its Media Access Control (MAC) address. This is a physical address encoded on to the network interface card, which encodes the manufacturer and a unique card identifier. Once a packet arrives at a given network on which the destination host lives, it is this physical address that ensures that a packet actually reaches  its destination.

However, the MAC address does not provide any information about the location of a network. For that, we have an Internet Protocol (IP) address, that combines a network identifier and a host identifier, into 32 bits. This takes the form a.b.c.d, where each of the parts is a number from 0 to 255.

Network appliances on the Internet are able to use IP addresses to route packets over the Internet to the appropriate network on which the destination host resides. Hence, these are termed routable addresses. Once the packet reaches its network, the IP address is converted to a physical address for actual delivery to a destination host.

A special set of private IP addresses, in the range 192.168.0.0 to 192.168.255.255, are meaningful only within a given network, and are not routable on the wider Internetwork.

2.2  TCP/IP

Transmission Control Protocol/Internet Protocol (TCP/IP) is the language of the Internet. It is a layered system that defines everything from the physical interfaces (such as connectors, cabling, voltage levels, etc), to the logical addressing of networked hosts, to the error correction and the sequencing of individual packets in a given transmission, to the delivery of these packets to a given application.

Just as a given host on a network is identified by an IP address, an application is represented in this model using a port. For instance, a HTTP server program would listen on port 80 on its host, while a SMTP mail server would listen on port 25.  Together, the IP address and port represent a connection end point.

Port numbers 1 to 1023 are termed well known ports, and are reserved by the Internet Corporation for Assigned Names and Numbers (ICANN), while ports 1024-49151 are registered with the ICANN by vendors. Ports 49152 to 65535 are private ports that you are free to use any way you see fit.

The idea of a “well known” port 80 for HTTP web servers is why you can reach my web site using http://www.swengsol.com, and not http://www.swengsol.com:80. The implicit “:80” suffix is appended by the browser software.

There is nothing magical about that port. As long as you are willing to always type in the port number, you could have your private web server running on port 65535 instead.

2.3  DHCP and NAT

As we saw, an Internet Protocol (IP) address uniquely identifies a computer on the Internetwork. Unfortunately, addresses on that network are a limited resource, and expensive to boot. As a result, rather than get an individual Internet address for each of my home computers, I lease them from my Internet Service Provider (ISP), Comcast, Inc.

Let us rewind to a simpler time, with a single home computer. Your computer would contact Comcast and request an IP address. Comcast would hand off an IP address from the thousands that it owns, say 11.22.33.44. From then on, this computer had a presence on the Internet – and could be found by any of the millions of computers out there.

Now this computer could reach out to a server computer out in the wild yonder, and make a request for some resource (such as an image file). That server services the request by locating the bits and bytes that make up that resource, and sent it to the IP address from which the connection originated – 11.22.33.44. My computer rendered the returned information as appropriate.

However, here is the problem. I get one IP address. Yes, ONE.

Fast forward to today. Unfortunately, the average home today has about a dozen devices that all need to connect to the Internet. These include computers, smart phones, security cameras, tablet computers, media servers, streaming devices, TVs, Network Attached Storage (NAS) appliance, and even normal appliances like refrigerators. (This diversity of networked devices is also why we talk of network hosts rather than network computers).

The challenge is that we have only one IP address, that must be shared across all these devices.

Fortunately, our router can manage the sharing of this resource.

We begin by assigning our unique IP address to the router itself. I.e., the router is now identified using the IP address 11.22.33.44.

Next we use a Dynamic Host Configuration Protocol (DHCP) server to assign a private IP address (in the special range 192.168.x.x) to every computer on the local network. If you have 10 hosts on your network, then each will be assigned an IP address in this range – e.g., 192.168.1.2 …  192.168.1.11. This solves one problem – all the computers on your LAN are now uniquely identified.

Note that our router is also a host on this network, and reserves the address 192.168.1.1 for itself. In other words, our router has two IP addresses – a private non routable IP address (192.168.1.1) and a public routable address (11.22.33.44) that can be used to locate it on the Internet.

(Enter Network Address Translation (NAT) stage left.)

The private IP addresses used for internal communication within our network, must be translated to this single public IP address when packets of data leave our network. This has the effect of making all request packets look like they originate at our router.

On the way back, all responses will be returned to our router. At the router, NAT maps the public IP address (11.22.33.44) on the response packets to the appropriate private IP address of the host making the request.

In other words, through the magic of DHCP and NAT, our single IP address is now shared across all the devices on our network!


3. Three things you need to know about your router

3.1  A Router is a versatile device

Today’s wireless routers combine multiple devices into a single convenient package.

  • Switch
    A router provides at least 4 Ethernet ports which you can use to hard wire network devices using standard Ethernet Cat 5e cables. The connected devices are then part of this private network. A computer transmitting data, causes packets to arrive at a switch port, which then establishes a dedicated circuit connection to the destination host. Multiple simultaneous connections can exist.
  • DHCP Server and Network Address Translation
    As we saw in the previous section, DHCP and NAT make it possible for a computer to interact with another over our local network as well as over the Internet.
  • Firewall
    It functions as a hardware firewall by hiding the hosts on your network from hostile port scanning tools. In addition, a Stateful Packet Inspection firewall inspects incoming data packets to make sure they correspond to an outgoing request, and automatically rejects packets that were not requested.
  • Access Point
    It supports connectivity with wireless hosts using RF transmitters and receivers, provides a connection to the wired LAN, and handles the conversion between the data formats used for wireless and wired networks.
  • Router
    It straddles two networks – the Internet as well your private LAN, and is the first link in the chain for communicating across hosts that live within these two networks.

3.2  Router and Wireless Security

Think about how you use your computer to access your bank statements or about how you store private documents and photos on your computer’s hard disk or on a network attached disk. Now think about someone being able to eavesdrop on your communication, or to access your network, without your ever knowing about it.

Scary enough?

Fortunately, you can keep yourself relatively safe if you follow these basic guidelines.

  • Establish a router administration password.
    This way no one can sneak in and, for example, point your DNS server name at a malicious server. A DNS server converts domain names you type in to a browser’s URL bar into their equivalent IP addresses. An evil DNS server is probably the scariest of all possible threats.
  • Enable WPA2 Personal (AES) security for all your wireless networks
    The older WEP is useless, and WPA2 (TKIP) is obsolete. Instead, use WPA2 with a strong passphrase (8-20 characters long, with upper and lower case characters, special characters, and numbers). Disabling SSID broadcast and enabling MAC filtering are pointless. They add nothing to security and are an avoidable inconvenience.
  • Harden your router by turning off all unnecessary options
    Many router features are provided for convenience. Unfortunately, they are also security penetrations waiting to happen.Disable Wi-Fi Protected Setup, UPnP support, as well as remote administration of your router.Disable your guest network. If you need to use it, limit guest devices to only accessing the Internet. Use WPA2 (AES) even for your guest network.
  • Upgrade your router to the latest firmware on a reasonable schedule. I usually wait for 4-8 weeks to let the bugs be worked out before upgrading.
  • Make sure that you are not using the DMZ option (that places one of your computers outside the router’s firewall) unless you really know what you’re doing.

3.3  Router Firewall configuration

By default, your router’s firewall will block external computers from connecting to any computer on your private network. However, in some cases such access may be desirable.

For instance, you may have a security camera whose video feed you would like to access from a computer outside of your network (say, while on holiday).

To connect with the camera, which has a private IP address of the form 192.168.1.x, you must configure the router’s firewall to allow access to it from external hosts.

You do this using a port forwarding rule and specifying an external port on the router (say, 9009), the private IP address of the security camera (192.168.1.3), and the port on which the camera listens for video requests (say, 80).

You can then access the router’s by specifying its routable IP address (11.22.33.44) and the configured external port (9009). The router will automatically forward this request to port 80 of the camera at private IP address 192.168.1.3.

The IP address of your router is displayed on the  Router status page. On the WNDR4500, this is the Administration > Router Status page.


4. ALL the rest is Noise

Everything else is fluff.

No you don’t need a USB print server – a wireless printer can be got for about $50.

No you don’t need a USB hard drive or a built in DLNA media server –  it is rarely as performant or as convenient as it might seem.

And, no you don’t need thick clients to configure your router – these simply serve to give you a false sense of security.

5. To summarize -

As long as you spend the time to get to know this critical piece of hardware, you will gain an incredibly resourceful companion. However, take it for granted at your peril.

Watch for my next installment – I’ll spell out the screens that you will use to configure the critical aspects of your brand new WNDR4500 or EA4500 routers.

Click here to download  the PDF version of this article.

Of the 24 networks within range of our home, almost 50% are inadequately protected! I see 2 unsecured networks, 8 that are still using WEP, and 1 that is using WPA-TKIP.

Given how much of our lives – social and financial – is happening online, and given the prevalence of wireless network access in our homes, it seems a bit reckless to see that we have the front doors to our networks so wide open for intrusion.

Well, it seems that a lesson in basic wireless security is on the cards.

The most basic networking security options include:

  1. Disable SSID broadcasting
    A wireless client that wishes to access a wireless Local Area Network (WLAN) must first provide the WLAN’s SSID. A common security technique is to have the Access Point stop broadcasting this SSID. Unfortunately, it is easy to discover this SSID by simply monitoring client frames sent across the network, as it is sent in the clear.
  2. Media Access Control (MAC) Address Authentication
    This relies on a white list of MAC addresses of clients that may connect to our Access Point. Again, this information is sent in the clear, so an attacker can sniff these and spoof one of the legal MAC addresses.
  3. Wired Equivalent Privacy (WEP)
    This uses a key that is shared between the AP and its clients. Unfortunately, it is currently very trivial to break WEP and is no longer considered a viable security option.
  4. WPA with Temporal Key Integrity Protocol (TKIP)
    This was a stop gap measure released by the Wi-Fi Alliance, for use until the IEEE finalized its standard. While still workable, there have been some minor vulnerabilities discovered with this scheme. As a result, this should now be considered obsolete

So, what does a law abiding citizen do?

Fortunately, the IEEE has since released their official standard, 802.11i, which incorporates Advanced Encryption Standard – Counter Mode with Cipher Block Chaining Message Authentication Code Protocol (AES-CCMP). This was released as WPA2, and is the best encryption possible.

My Access Point shows this option as WPA2-PSK [AES]. The PSK stands for PreShared Key, and refers to the passphrase configured into the Access Point as well as into each client. As long as your PSK is not easily guessed, you are now as protected as you can get.

Of course, in an enterprise setting you would be considering WPA2 Enterprise, which relies on a separate authentication server, but that’s a story for another day.

The simplest and easiest backup solution is built right in Redmond!

I’ve used SyncToy for a number of years now and this program is a nice little gem – sort of XCOPY with a GUI. It can be downloaded from here.

It takes pairs of source and destination directories and then keeps them in sync. It works great for backing up photographs, for instance. And, the best part is that the files are exact copies – no need to worry about native backup formats.

Even better is that SyncToy comes with a command line invoker, SyncToyCmd.exe.

You get a backup solution when you combine this invoker with the Windows 7 Task Scheduler (which lives at: Start Menu > All Programs > Accessories > System Tools.)

You can use the scheduler to set up a regularly scheduled task to run “SyncToyCmd.exe -R <folder-pair-name>”

The scheduler can also be configured to run this command line program at startup, and then at predefined intervals (of say, an hour) to give  you real time backups as you work on your system.

Awesome? Yes, truly. Simple? Ditto.

Updated  on: Mar 13, 2011. Describes the process for verifying the installation of MySQL and phpMyAdmin.

In this article, I describe the process of setting up a complete development environment for PHP, with full debugging support within the Eclipse IDE.

The complete setup includes Ubuntu 10-10, the Apache2 web server, the MySQL RDBMS, PHP, phpMyAdmin, the Zend Eclipse/PDT All in one package, and the PDT debugger.

Setting up a PHP Debugging Environment

Go to http://www.zend.com/en/community/pdt#debugger and download Eclipse PDT All-in-one. I picked the Linux 32 bit version for installation in Ubuntu.

Unpack the downloaded file (zend-eclipse-php-helios-linux-gtk-x86.tar.gz).

Execute the eclipse/eclipse executable to launch Eclipse, and pick the appropriate workspace.

Create a new PHP project (File > New) and ensure that its location is in the same area that is monitored by your Apache install. In my case, this is /home/damodar/public_html, so my “test” project is located at /home/damodar/public_html/test.

Create a new PHP file.

Debug as PHP Script, if you want to run it locally in a PHP interpreter within the PDT.

Debug as PHP Web Page, if you want to run it in a browser.

You can place breakpoints as appropriate.

Enjoy!

(Thank you Zend Technologies, for making this so easy!)

Note: You can also use the Zend Server Community Edition as your web server. As noted, I chose to stay with Apache instead.

An errant application was causing my phone to spontaneously recycle – I gave up after about a half dozen cycles.

Verizon support indicated that I should perform a safe mode reboot and uninstall any suspect apps. The process was fairly painless, and I was up and running in a few minutes … sans my most recently installed apps.

The process?

Hold the power key down, and when you see the Motorola logo (the big M), press and hold down the Menu key for 30 seconds. This boots your Droid X into safe mode.

Also the Android 2.2 update was simply awesome for the Droid X – it’s as if I installed a brand new battery. The phone seems to be a lot more conservative about using power, leaving me as one thrilled puppy. Fingers crossed.

The easiest way I’ve found to get my contacts from Outlook to my Droid X … check out transferring contacts between Outlook and Gmail .

Decidedly low tech – but it was much easier than retyping :)

To sync your calendar – try Google Calendar Sync.

Good luck!

What a pain the Droid X is turning out to be. I can’t live with it, and I can’t live without it.

It’s like a pair of shoes that look and feel amazing, but just don’t fit quite right. You spend a lot of time hoping your feet were of the right size :(

It’s actually one of the most amazing devices I’ve ever owned – the display is simply gorgeous, and the interface is amazing.

So what’s not to like? Well how about its battery life? My battery drains even while the phone is inactive. And, by drain, I mean it goes down by as much as 40% while it sits on my bedstand.

My workaround? Turn it off before I go to bed – or leave it charging all night.

And, by default, the Wifi turns itself off when the screen is turned off. Then when you turn the phone back on, you don’t get online without waiting for anywhere from 5 to 15 to 30 minutes. Even your 3G is powerless to help.

My workaround? I found this on a Moto forum – go into advanced settings and choose not to turn off Wifi when the display is turned off. I’m guessing this will eat up battery – but it’s much better than having to wait for Wifi to kick in.

Will I return this phone, and get a Droid 2 or the Incredible instead? I’m not sure – ask me in 2 weeks.

For now, I’m folding my feet so they fit into these shoes. Maybe I’ll get used to walking this way :)

One of the easiest ways to protect oneself whilst online is to function within a virtual machine environment. In such a scenario, even if you do catch a nasty bug doing something that you probably shouldn’t, the infection is confined to that virtual machine and does not spread to the rest of your computing environment.

To that end, I’ve been playing with Sun’s VirtualBox and the free distribution of Ubuntu Lucid Lynx (10.04). Together these make an unbeatable combination.

I got VirtualBox from here:

http://download.virtualbox.org/virtualbox/3.2.8/VirtualBox-3.2.8-64453-Win.exe

And, though I’m running Windows 7 64-bit, I downloaded the 32-bit version of Ubuntu from here:

http://www.ubuntu.com/desktop/get-ubuntu/download

Once VirtualBox is installed, you can directly install Ubuntu by mounting its ISO image into VirtualBox.

The only thing you should remember is to install the Guest Additions for Linux. Without doing so, maximizing the VirtualBox window does not maximize the Guest OS’s window. To do so, you need to choose Devices > Install Guest Additions to mount the guest additions disk image. Once this shows up on your desktop, browse into it, and execute the autorun.sh file from a Terminal window. If you don’t see it take effect right away, you might want to restart your virtual machine.

You can also share a folder between the host and guest operating systems, using the following commands:

1. Create the folder on the host OS. (C:\ubuntu-vbox)

2. Register it with Virtual Box using Devices > Shared Folders, and give it a logical name to be used later (ubuntu-vbox).

3. Create the mount point
$ sudo mkdir /mnt/shared

4. Next, mount the shared folder.
$ sudo mount.vboxsf ubuntu-vbox /mnt/shared

5. That’s it – now you can access files on /mnt/shared from Ubuntu, and on c:\ubuntu-vbox from Windows!

It is also very simple to install a complete LAMP stack – Apache 2, PHP 5, MySQL, and phpmyadmin on our fresh install of Ubuntu 10.04. Check out these links for tips:

http://blogote.com/2010/ubuntu/how-to-install-apache-2-on-ubuntu-10-04-with-php5-and-mysql-support-guide.html

http://www.shicho.net/lamp/?p=138

A key aspect of using Ubuntu in VirtualBox is to ensure that you have installed any guest additions. This enables sharing of folders as well as full screen displays. To install guest additions, first start up your Ubuntu instance. Then, select Devices > Install Guest Additions in the VirtualBox menu of your running Ubuntu instance. This adds a CD image to your Ubuntu  desktop named VBOXADDITIONS_<version>. Browse to this  image using the Places menu, and execute autorun.sh.

That’s the sprinkling of pixie dust necessary to get a fully functional Ubuntu install!

All right – now, we’re finally ready to get to the meat of what JSR 315 brings to the table – asynchronous servlets.

Prior to JSR 315, the world was a very simple and pleasant place. It was the world of the synchronous web. The server maintained a server socket that waited at the gates for weary incoming requests, and as each one arrived, assigned a worker to help it accomplish its needs. In this model, there was a finite set of workers (or server threads), and once all available workers were busy, new incoming requests had to wait at the gate until a worker completed processing its current request.

The process of setting up and tearing down socket connections is an expensive operation, and the process of TCP bandwidth throttling means that the earlier transmissions over a new connection are slower than later ones. As a result, HTTP 1.1 introduced its keep-alive connection model, which allowed a client to hold the connection open (i.e. to have a worker thread assigned) until all resources on a given page were retrieved.

This model works very well, and is both very performant and scalable, since requests come in at staggered intervals, allowing a small thread pool to successfully handle a large volume of client requests.

However, all was not well in the good old days.

First, was the issue of thread starvation. Each thread consumes server side resources – both memory and CPU resources. As a result, the number of threads within the pool must be constrained to some finite number. Furthermore, if the processing that the thread must perform for a client requires some blocking operation (say waiting on some slow external resource such as a database or web service), that thread is effectively unavailable to the server. In other words, it is possible that all threads in the pool are soon blocked and incoming requests can no longer be effectively handled. This is not just a theoretical problem. With the prevalence of fine grained Ajax-requests, and the adoption of SOA, the load on web servers is on an upward trend.

Second was the issue of staleness. At any given point, a client gets a view of the web application’s state at the instant that the request was procesed. Any changes to state between two consecutive requests from a client, are effectively invisible to that client. In other words, each client only gets a static snapshot view into what is effectively a dynamic system. And the currency of that view decays the longer the time period between requests. Ajax’s fine grained interactions, do mitigate this problem, but it does not completely solve the currency issue.

Third was the issue of non standard implementations. The developers of every servlet container decided to solve this problem of the synchronous web by implementing their own custom solutions. Tomcat’s Comet, WebLogic’s FutureResponseServlet, and WebSphere’s Asynchronous Request Dispatcher are examples of developers not wanting to wait for the standards  body to catch up.

A key piece of JSR 315 therefore was to solve these issues with the synchronous web, by introducing us to the asynchronous web.

The problem of thread starvation is solved by having the main request processing worker thread delegate processing to an asynchronous thread, and return to the thread pool. In other words, if processing will require blocking operations, the worker can put the request processing context on ice, and hand it off to an asynchronous thread for processing. It can then return to the thread pool and wait for the next incoming request.

The problem of staleness is solved by allowing the client to make preemptive requests. I.e., just as soon as the client receives a snapshot, it can turn around and immediately make a preemptive request for the next snapshot. This request can be handed off to an asynchronous processor on the server, which will be notified when a state change occurs, and can immediately return a response to the waiting client. As far as the client is concerned, this looks just like any other long running request. Of course, with the advantage that there’s hardly a lag between a server side state change, and a client notification.

Finally, this solves the standardization issue by codifying asynchronous behavior into the servlet specification. This is now the one approach to rule them all!

So what do we need to implement asynchronous servlets?

  • Thread Pool and Queue
    If you haven’t read my previous blog post on thread pools in Java, this is the time to go do so. An Executor and ExecutorService provide us with a mechanism to implement our pool of asynchronous workers.
  • AsyncContext
    The context of the request must be stored for later use by the asynchronous worker thread. This is achieved using an AsyncContext instance, which holds the request and response that was provided by the container to the original servlet.
  • Runnable instance
    This instance encapsulates the actual processing of the blocking operation on the asynchronous thread.
  • Servlet/Filter chain
    All components that will participate in an asynchronous request must be marked as supporting asynchronous operation.

Let’s walk through the recipe of creating an asynchronous servlet:

  1. At context startup, a context listener is used to set up an Executor.
  2. Servlets that might involve a blocking operation are identified and marked as asyncSupported (annotation or web.xml declaration). Any servlets/filters in the processing chain for this servlet are similarly marked.
  3. Within its service() method, the asynchronous servlet then:
    1. Invokes startAsync() on the request
    2. Wraps the returned AsyncContext in a Runnable
    3. Hands the Runnable off to an Executor for asynchronous processing
    4. Returns from the service() method. For an asynchronous servlet, returning from this method does not automatically commit the response. As a result, the client has no idea that it is being given the run around – it patiently waits for the response.
  4. The main thread returns to the server’s pool, ready to handle the next incoming request.
  5. The Executor assigns an async thread to process the Runnable.
  6. The Runnable:
    1. Uses the request and response stored in its AsyncContext
    2. Accesses any request attributes/parameters that are stored in its request to perform its processing
    3. Stores the final result of the processing as a request attribute
    4. “Completes” the response – either by generating the response by itself, or by dispatching to a server side resource.
  7. The client now displays the resource.

To the client, this interaction is no different from a slow server taking an inordinate amount of time to respond.

To the server, the server worker thread spent only a fraction of the time it would have normally taken to handle such a request, helping its throughput significantly.

The actual processing was handled by a thread in a separate pool – without impacting the main server pool.

The servlet context listener does nothing more than set up a ThreadPoolExecutor with 10 threads, and a request queue with a limit of 100 pending requests.

package com.swengsol.listeners;
/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 10:48:14 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.EnumSet;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

@WebListener
public class MyServletContextListener implements ServletContextListener {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    // Public constructor is required by servlet spec
    public MyServletContextListener() {
    }

    // -------------------------------------------------------
    // ServletContextListener implementation
    // -------------------------------------------------------
    public void contextInitialized(ServletContextEvent sce) {
        logger.info("Context Listener > Initialized");

        //2. Creation of a global async Executor
        Executor executor =
					new ThreadPoolExecutor(10, 10, 50000L,
						TimeUnit.MILLISECONDS,
						new LinkedBlockingQueue<Runnable>(100));
        sce.getServletContext().setAttribute("executor", executor);
    }

    public void contextDestroyed(ServletContextEvent sce) {
    }
}

The servlet is marked with an annotation to indicate that it supports async processing. Some key elements to note are:

1)    The presence of the dispatch parameter on the query string will allow us to control how the async request completes (whether it is handled completely by the asynchronous processor or whether it is forwarded on to another server side resource).

2)    The timeout parameter allows us to set a timeout for an asynchronous request. The request is aborted if it does not complete within the specified timeout.

3)    The call to startAsync() builds up the AsyncContext, which represents the context of the current request.

4)    An AsyncListener can be registered to be notified of events within the asynchronous process– such as timeouts.

5)    The thread pool with our async worker threads is retrieved from the servlet context, and is given an instance of our Runnable to process – an AsyncRequestProcessor.

6)    The main worker thread now returns without committing the response.

package com.swengsol.servlets;

import com.swengsol.AsyncRequestProcessor;
import com.swengsol.listeners.MyAsyncListener;

import javax.servlet.AsyncContext;
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 java.io.IOException;
import java.util.Date;
import java.util.concurrent.*;
import java.util.logging.Logger;

/**
 * User: Monsty
 * Date: Jul 23, 2010
 * Time: 9:43:25 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */
@WebServlet(urlPatterns = "/AsyncServlet", asyncSupported=true)
public class AsyncServlet extends HttpServlet {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    protected void doPost(HttpServletRequest request,
			HttpServletResponse response)
		throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request,
			HttpServletResponse response)
		throws ServletException, IOException {
        logger.info("AsyncServlet: Processing request: " +
					request.getParameter("id") + ". on thread: " +
					Thread.currentThread().getId() + ":" +
					Thread.currentThread().getName() + "[" +
					new Date() + "]");

				request.setAttribute("receivedAt", new Date());

        boolean dispatch = false;
        String dispatchParam = request.getParameter("dispatch");
        if ("true".equalsIgnoreCase(dispatchParam)) dispatch = true;

        boolean timeout = false;
        String timeoutParam = request.getParameter("timeout");
        if ("true".equalsIgnoreCase(timeoutParam)) timeout = true;

        AsyncContext asyncCtx = request.startAsync();
        asyncCtx.addListener(new MyAsyncListener());
        if (timeout) {
            asyncCtx.setTimeout(1000);
        }

        Executor executor =
			(Executor)request.getServletContext().getAttribute("executor");
		//delegate long running process to an "async" thread
        executor.execute(new AsyncRequestProcessor(asyncCtx, dispatch));

        logger.info("AsyncServlet: Returning after request: " +
					request.getParameter("id") + ". on thread: " +
					Thread.currentThread().getId() + ":" +
					Thread.currentThread().getName()+ "[" +
					new Date() + "]");

				//Watch out for concurrency issues at this point
				// between the "main" thread and the "async" thread
				// main thread returns now -
				// - returning from service() does not commit the response
				// - so client still waits patiently
    }
}

The nice thing about this is that the servlet itself is pretty formulaic – and shouldn’t change much from one async servlet to the next. But all the complexity of processing has to go somewhere – and that somewhere is the AsyncRequestProcessor.

Also note the comment at the bottom of the file that indicates that there is now a short window of time here when the request and response objects are no longer thread safe. Ideally, you shouldn’t be mucking around with the request and response objects once you’ve handed them off to the async processor.

The asynchronous request processor is a Runnable instance that needs access to the AsyncContext that we previously retrieved from the request. In our example, note that the long running blocking operation is encapsulated within the longRunningProcess() method.

package com.swengsol;

import javax.servlet.AsyncContext;
import javax.servlet.ServletRequest;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 9:45:22 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */
public class AsyncRequestProcessor implements Runnable {
    private static final Logger logger = Logger.getLogger("com.swengsol");

    private AsyncContext asyncContext;
    private boolean dispatch;
    public  AsyncRequestProcessor(AsyncContext asyncContext) {
        this.asyncContext = asyncContext;
        dispatch = true;
    }
    public AsyncRequestProcessor(AsyncContext asyncContext,
		boolean dispatch) {
        this(asyncContext);
        this.dispatch = dispatch;
    }
    public void run() {
        //do something asynchronously –
		//  wait for a resource to become available
		//  or for a long running computation to finish
        String reqId = asyncContext.getRequest().getParameter("id");
        if (null == reqId || reqId.length() == 0) reqId = "<unk>";
        long id = Thread.currentThread().getId();
        String threadName = Thread.currentThread().getName();
        if (null == threadName || threadName.length() == 0)
			threadName = "";
        String threadId = id + ":" + threadName;

        String result = longRunningProcess(reqId, threadId);

        //Store the result of the computation in a "view helper"
        ServletRequest req = asyncContext.getRequest();
        if (null != req && req.isAsyncStarted())
					req.setAttribute("result", result);
        else
					return;

        //once done, dispatch back to the final destination
        if (dispatch) {
            asyncContext.dispatch("/results.jsp");
        } else {
            //alternatively handle it ourselves
            String html = "Result of the process for request id: " +
					reqId + "<br/> Started at:" +
					asyncContext.getRequest().getAttribute("receivedAt") +
					".<br/> Completed at:" + result +
					"<br/> Called complete.";
            Squawker squawker = new Squawker(html);
            asyncContext.getResponse().setContentType("text/html");
            try {
                PrintWriter out = asyncContext.getResponse().getWriter();
                out.println(squawker.getHTML());
            } catch(Exception e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
            asyncContext.complete();
        }
    }

    public String longRunningProcess(String reqId, String threadId) {
        Random randomGenerator = new Random();
        int randomInt = 5000 + randomGenerator.nextInt(10000);
        logger.info("AsyncRequestProcessor: Begin long run process (" +
					randomInt + " ms) for request: " +
					reqId + ". on thread: " + threadId +
					"[" + new Date() + "]");

        try {
            Thread.sleep(randomInt);
        } catch (InterruptedException ie) {
            logger.log(Level.WARNING, ie.getMessage(), ie);
        }

        logger.info("AsyncRequestProcessor: Done processing request: " +
					reqId + ". on thread: " +
					threadId + "[" + new Date() + "]");
        return new Date().toString();
    }
}

In this example, the long running process simply sleeps for a random amount of time to simulate the randomness of accessing a remote resource. It takes anywhere from 5 to 15 seconds to complete its work – an eternity on the web. You can also imagine report generation processes that might take much longer.

Once the long running process has returned, we either dispatch the request to be handled by a server side resource (results.jsp), or we handle it ourselves by handcrafting the HTML to be returned. In the latter case, we have to explicitly call complete() on the AsyncContext instance. In the former, the container does so implicitly.

The server side resource that we forward our asynchronous request to is results.jsp. This file demonstrates how request attributes added by the async processor can be retrieved and used.


<%--
 * User: Damodar Chetty
 * Date: Jul 23, 2010
 * Time: 9:45:22 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
	<head>
  	<title>Introducing Servlet 3.0</title>
    <link rel=stylesheet type="text/css"  href="styles.css">
	</head>
	<body>
		<p class="mainpara">
			results.jsp:
			completed processing of long running activity with id:
			<span style="color:#ff3300">
				<%=request.getParameter("id")%>
			</span>
			<br/>
			received  at: <%=request.getAttribute("receivedAt")%>: <br/>
			completed at: <%=request.getAttribute("result")%>
		</p>
		<p class="copyright">Damodar Chetty,
			Software Engineering Solutions, Inc.</p>
	</body>
</html>

My sample code running on GlassFish v3 did not run until I added an XML declaration for my async servlet. To me this looks like a bug in the RI.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_3_0.xsd"

	version="3.0">
    <servlet>
        <servlet-name>AsyncServlet</servlet-name>
        <servlet-class>com.swengsol.servlets.AsyncServlet</servlet-class>
        <async-supported>true</async-supported>
    </servlet>
</web-app>

The final class we will visit is our AsyncListener which is rather trivial in my sample implementation. If you check your GlassFish logs, you’ll notice entries for the async listener which indicate when the async processing was completed.

package com.swengsol.listeners;
/**
 * User: Damodar Chetty
 * Date: Jul 24, 2010
 * Time: 2:36:08 PM
 * An introduction to Servlet 3.0 and Java 6 (TC JUG)
 * (c) Software Engineering Solutions, Inc.
 */

import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import java.util.logging.Logger;

public class MyAsyncListener implements AsyncListener {
    private static final Logger logger =
		Logger.getLogger("com.swengsol");

    // Public constructor is required by servlet spec
    public MyAsyncListener() {    }
    public void onComplete(AsyncEvent ae) {
		logger.info("AsyncListener: onComplete for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onTimeout(AsyncEvent ae) {
		logger.info("AsyncListener: onTimeout for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onError(AsyncEvent ae) {
		logger.info("AsyncListener: onError for request: " +
			ae.getAsyncContext().getRequest().getParameter("id"));
	}
    public void onStartAsync(AsyncEvent ae) {
		logger.info("AsyncListener: onStartAsync");
	}
}

This servlet can be invoked using the URL:

http://localhost:8008/jsr315/AsyncServlet?id=1&dispatch=true&timeout=false

where, jsr315 is my context path, /AsyncServlet is the URL pattern for my servlet, and the dispatch and timeout query string parameters can be used to test out alternative behaviors.

That’s all folks!