Archives
 
 
 
  Special
 
 
 
  About Us
 
 
 

Newsletter
Free E-mail Newsletter from BYTE.com

 
    
           
Visit the home page Browse the four-year online archive Download platform-neutral CPU/FPU benchmarks Find information for advertisers, authors, vendors, subscribers

ArticlesJava Servlets


June 1997 / Web Project / Java Servlets

Servlets, the Java equivalent of CGI applications, can deliver on many of Java's promises while dodging some of its worst limitations.

Jon Udell

For many months I wondered when and how Java would first appear on The BYTE Site. I was determined not to use Java in a gratuitous way; the Web certainly doesn't need any more scrolling marquees. Java would have to earn its keep by solving real problems. What broke the logjam was the alpha release of JavaSoft's Jeeves ( http://jeeves.javasoft.com/ ) (aka JavaSoft's Java Web Server), which can run Java extensions called servlets.

Like CGI programs, servlets are easy to write and easy to run, and they play to the entire installed base of browsers. Servlets can do things applets can't -- write to files, open socket s -- and they can do them very quickly because they're invoked as threads in a demon process.

The truth is that I still haven't found a compelling reason to send Java applets over the wire to your browser. HTML assisted by JavaScript can handle a remarkably wide range of user-interface and data-collection chores -- not as prettily as Java, I'll grant, but a lot more efficiently. Client-side Java will really flower on next-generation computers and networks. But server-side Java is ready for prime time now.

My First Servlet: A URL Redirector

Way back in my February 1996 column, I showed how to track the use of individual links on a Web page. I'm still using that mechanism -- a Perl sc ript that logs data and then returns a "Location:" header -- but I've grown increasingly aware of its shortcomings. Mostly it's just too slow.

In part that's because I've been unable to get the ISAPI version of NT Perl to cooperate with the O'Reilly WebSite server that handles most of our site's CGI work. But even when ISAPI Perl works, it's still not a panacea. "In-process Perl doesn't deliver the speedup you'd expect," observes Bob Denny, WebSite's creator, "because all that OLE crap has to get initialized every time."

Perl just isn't a good way to implement lightweight services. And it's terrible on NT, which lacks the fork mechanism that Unix-based Perl servers rely on for a kind of poor man's multithreading. A classic Unix socket server forks copies of itself to handle incoming requests, so the parent process can remain responsive to new requests. Perl can't do this on NT.

Unix partisans like to blame "brain-dead" NT for this. But there's another side to the story. Unix-style process-cl oning is not a substitute for real lightweight multithreading, which is built into NT. Unfortunately, Perl isn't multithreaded and can't take full advantage of NT (or other threaded OSes).

Java, on the other hand, is an almost ideal way to build lightweight services. Given a Java-oriented Web server, you can create lightweight Web services, or servlets , that are automatically threaded and extremely responsive. And thanks to the Java frameworks that support servlets, they needn't be much more complicated than their Perl counterparts (see the listing "URL Redirection in Perl and Java" ). The day I wrote my first servlet it went into production, and it has now been used by thousands of visitors to The BYTE Site.

Our site's inaugural Java deployment doesn't do anything flashy. It just streamlines some basic accounting tasks. If you've used that servlet, you almost certainly did not realize you were tapping a Java-based service. That's precisely why I say that Java is now ready for real server-side work.

Deploying Servlets

For its first few weeks, my Java redirector ran as a Jeeves servlet. Now in beta, Jeeves is a full-blown Web server that supports user/group access controls, Secure Sockets Layer (SSL), and proxying, and it can also run servlets. To run Jeeves, you fire up the Java interpreter and load the Jeeves classes. The Web server appears on port 8080.

An administrative server simultaneously appears on port 9090. The Java applet that you use to manage Jeeves looks sexy , I'll admit, but I soon concluded that it's yet another example of gratuitous Java. Nothing that it does couldn't be done in HTML/JavaScript. Waiting for a dozen classes to load before being able to set a password on the server quickly grows tiresome. And since the Jeeves beta reset itself to the default administrative password every time I ran it, I had to do a lot of waiting.

Eventually I realized that I didn't need most of Jeeves; I only neede d a platform for servlets. Jeeves was overkill, and all the extra stuff it can do was just causing headaches. Was the administrative applet adequately secured? Should Jeeve's CGI servlet be disabled to ward off possible attacks? There had to be a simpler way to run servlets.

Enter Acme.Serve, Jef Poskanzer's minimal Java Web server ( http://www.acme.com/java/software/Acme.Serve.Serve.html ). This brilliant contribution to the Web emulates the Jeeves servlet API, runs servlets handily, cooperates with version 1.1 of the Java Development Kit (JDK), and (unlike Jeeves) includes source code. Thanks, Jef! My redirector ran immediately under Acme.Serve, and I have been using it ever since. It was easy to modify Acme.Serve so that the server responds only to the handful of URLs that in voke the servlets I choose to export.

I appreciated being able to tweak a few other things, too. For example, when the servlet logged the requesting browser's address, it wrote both a Domain Naming System (DNS) name and an IP address into the log. But I didn't want to log the DNS names. I don't want users to wait for reverse DNS lookups; it's my policy to do those lookups off-line in batch analysis. Adjusting the getRemoteAddr() method was straightforward.

There are other ways to run servlets. The recently released first beta of the Java Web Server comes with a ServletRunner that will run a servlet without all of Jeeves's baggage. The World Wide Web Consortium recently announced that its Jigsaw (http://www.w3.org/pub/WWW/Jigsaw/ ), the original Java Web server, will be compatible with JavaSoft's servlet API. There's also a servlet API in Netscape's Enterprise Server 3.0, although I found no examples of its use in the currently available beta version of that product and so have not yet tried it.

Making the Hard Things Easy

With servlet technology in hand, I next tackled a project that I ordinarily would have handled in Perl. The task: to write a service that would enable users to create quick polls, vote in polls, and check the results of polls. The resulting servlet, which is called Polls ( http://www.byte.com/art/download/polls.zip ), makes a fascinating counterpoint to the kinds of Perl applications I'm used to building.

Larry Wall, Perl's creator, likes to say that Perl aims to makes easy things easy and hard things possible. Java, on the othe r hand, tends to make hard things easy, but easy things hard. You'll see what I mean as I describe how Polls works.

At the heart of Polls is a data structure that Perl hackers call a hash-of-hashes (HoH) -- that is, an associative array (i.e., a set of name-value pairs) whose values are in turn another set of associative arrays (see the figure "The Polls Servlet's Central Data Structure" ). In Perl, as in Java, it's easy to grow this object on the fly. But Perl in a CGI context does not readily handle the following requirements:

  • Retain the object in memory across multiple invocations of the application.
  • Protect the object from concurrent use by multiple clients.
  • Retrieve the object from disk at start-up and keep the in-memory version synched with the on-disk version as updates occur.

These are the hard things that become easy in a Java servlet. When the server instantiates the Polls servlet, its class data (the HoH) hangs around indefinitely -- until either the server or the servlet restarts. A typical Perl solution would have to refresh its in-memory objects from disk (e.g., by doing a database query or reading in a structured text file) every time a client created a new poll or voted in a poll.

In Java, protecting the object from multiple concurrent voters is as easy as adding the synchronized keyword to the declaration of the vote() method. Saving and restoring the object are trivial tasks, too, thanks to the serialization technology in JDK 1.1. The poll data lives in a Java hash table, which implements the Serializable interface. That means you can simply open a FileOutputStream , hook an ObjectOutputStream to it, and call Polls.writeObject(stream) to save it to disk.

Restoring the in-memory object is just as easy to do. Adding the synchronized keyword to my saveObjects() method was all it took to guard the on-disk object store against corru ption by multiple update threads.

What about full-fledged object databases? You want one of those if you're dealing with objects that are too large to hold conveniently in memory. Polls, however, is tiny and not likely to get much bigger. Each of the polls it manages is really just a namespace that defines a set of counters. It's the number of counters that determines the size of the data structure, not the number of votes tallied by each counter.

There are a lot of applications in this category. Group scheduling, for example, tends to generate fairly small amounts of complex object data. With nothing more than a servlet engine, the JDK 1.1, and a bit of ingenuity, you can create useful applications in this domain very quickly.

Making the Easy Things Hard

A few things that would have been trivial in Perl consumed most of the time I spent on the Polls servlet. First, there was the problem of sorting the results of each poll. In Perl, that takes just a few lines of code. You can build an array of strings out of the values and keys of each poll and then do this:

  print reverse sort @array;

I searched the Java API docs for quite a while before it dawned on me that there just isn't anything equivalent to a Smalltalk OrderedCollection in Java. (Try looking for the word sort in the index of any Java book. You won't find it.) This is a real shame. Java gives you incredible power to create and manage dynamic, thread-safe, persistent object data, but it has absolutely no tools to manipulate that data in the most elementary ways.

Of course, there are Smalltalk-style libraries for Java. The best of these looks to be the Java Generic Library (JGL, http://www.objectspace.com/ ). It's an outstanding piece of work that's freely available and does a ll the sorting, filtering, and queueing that you'll ever need. It's also a huge chunk of code.

I decided not to kill my fly-size sorting problem with the hammer of JGL. A minimal SortedStringVector class was all my servlet needed, so I wrote one. But there should be a middle ground. The Java core should provide at least basic sorting.

Another gotcha is the chasm that divides primitive Java types (i.e., int ) from their object counterparts (i.e., Integer ). Each poll's hash table contains a set of keys (the names of the choices in that poll) and values (the count of votes for each choice). Both the keys and the values must be objects, not primitive types. But you cannot increment an Integer , so the vote() method has to unpack the Integer , increment its corresponding int , and then repackage it as an Integer to store it back in the hash table, as shown below.

Integer ObjectTally = (Integer)   
  hPoll.get ( "choice1" );
i
nt tally = ObjectTally
  .intValue();
tally++;
hPoll.put ( "choice1"), new
  Integer (tally) );

which in Perl would reduce to simply

$hPoll{'choice'}++;

Why can't you just say ObjectTally++ ? Java's not C++; it doesn't support operator overloading. And while I'm whining...What, no printf -style formatting? Excuse me? Writing Java routines to pad numbers with leading zeros seems like a very silly thing to do. Again, there are, of course, Java libraries that implement printf . But these implementations aren't in the language's core, and they won't be standard.

Did You Run Any Java Applets Today?

It's a peculiar moment in our industry's history. The Java buzz is intense. And yet when you look at the Web applications that people actually use every day to do their work, you invariably find that there are no Java applets in the mix. The universal client today is still the HTML browser. The universal client of tomorrow will be the H TML/JavaScript browser.

Client-side Java is a glorious vision that will not change the way most people use the Internet anytime soon. Why not? It's just more than what the majority of today's computers and networks can readily push. So what are millions of people running every day? Server-based applications that feed the universal HTML client.

I build such applications every day, and I am wildly excited about how Java can help. You won't find dancing penguins on The BYTE Site. But behind the scenes, Java will be helping me run the show.


TOOLWATCH

Ntcrond 2.2................$25
#ifdef Software
Internet: http://www.ifdef.com

Tasks that NT's dim-witted scheduler struggles mightily with -- such as "run this command every hour at 10 minutes past the hour" -- are trivial matters for Unix's crontab. Here's a capable NT version that's threaded, runs as a service, and does its job nicely.


BOOKNOTE

The Java Programming Language........................$34.95
by Ken Arnold and James Gosling
Addison-Wesley
ISBN 0-201-63455-4

Along with David Flanagan's indispensable Java in a Nutshell, this authoritative guide has risen to the top of my heap of Java books. When you get curious about things like synchronization, thread scheduling, and class loading, you might as well go to the source -- James Gosling, Java's inventor -- for answers.


URL Redirection in Perl and Java


A Perl redirector, invoked as http://www.byte.com/cgi-bin/goto.pl?http://elsewhere.com.


Here's a classic CGI script. It logs the user's IP address and
redirects the user to another Web page. You can write this in just
four lines of Perl. But it's computationally expensive to run the
script.

require 'cgi-lib.pl'
open(LOG,">>goto.log");
print LOG "$ARGV[0]~$ENV{HTTP_REMOTE_ADDR}\n";
print "Location: $ARGV[0]\n";


A Java redirector, invoked as 
http://www.byte.com:8080/gotoUrl?http://elsewhere.com.


Here's the same logic in Java. Thanks to the servlet API, it's only a
bit more complex than the four-line Perl script. And it's far more
efficient because the servlet runs as a thread dispatched by a Java
Web server.


import java.io.*;
import java.util.*;
import java.servlet.*;
import java.servlet.http.*;
public class gotoUrl extends HttpServlet {
 public void service(HttpServletRequest
   req, HttpServletR
esponse res)
  throws ServletException, IOException
 { 
 DataOutputStream log = new DataOutputStream
   (new FileOutputStream("goto.log",true));
 log.writeChars(req.getQueryString() + "~" +
   req.getRemoteAddr() + "\n");
 log.close();
 res.sendRedirect(req.getQueryString());
 }
}




The Polls Servlet's Central Data Structure

illustration_link (11 Kbytes)

In Java, as in Perl, you can dynamically create complex nested data structures.


The Java Programming Language

photo_link (26 Kbytes)


Spiffy Can Get Boring

screen_link (18 Kbytes)

This applet, used to control the Java Web Server, looks spiffy. But the novelty soon wears off.


Jon Udell is BYTE's executive editor for new media. You can reach him by sending e-mail to jon@byte.com .

Up to the Web Project section contents
Flexible C++
Matthew Wilson
My approach to software engineering is far more pragmatic than it is theoretical--and no language better exemplifies this than C++.

more...

BYTE Digest

BYTE Digest editors every month analyze and evaluate the best articles from Information Week, EE Times, Dr. Dobb's Journal, Network Computing, Sys Admin, and dozens of other CMP publications—bringing you critical news and information about wireless communication, computer security, software development, embedded systems, and more!

Find out more

BYTE.com Store

BYTE CD-ROM
NOW, on one CD-ROM, you can instantly access more than 8 years of BYTE.
 
The Best of BYTE Volume 1: Programming Languages
The Best of BYTE
Volume 1: Programming Languages
In this issue of Best of BYTE, we bring together some of the leading programming language designers and implementors...

Copyright © 2005 CMP Media LLC, Privacy Policy, Your California Privacy rights, Terms of Service
Site comments: webmaster@byte.com
SDMG Web Sites: BYTE.com, C/C++ Users Journal, Dr. Dobb's Journal, MSDN Magazine, New Architect, SD Expo, SD Magazine, Sys Admin, The Perl Journal, UnixReview.com, Windows Developer Network