Last month, we looked at XMLC, a new system for displaying dynamic web content that comes with the Enhydra application server. This month, we will look at how to write servlets and basic applications using the tools that come with Enhydra. While Enhydra's web applications are not as standardized as servlets with Jakarta-Tomcat, they do offer a fair amount of power and the possibility of creating Enterprise JavaBeans with a fully open-source infrastructure.
Enhydra is an open-source application server written in Java, aiming for full compliance with Sun's J2EE specifications. Lutris, the company that spearheads Enhydra development, has made the application server available under a BSD-like license. The current stable version of Enhydra is 3.x and includes support for a large number of standards, including servlets and JSPs. Enhydra Enterprise, which is slated for release during the summer of 2001, will have additional J2EE features, including support for Enterprise Java Beans (EJB).
Enhydra itself is available as a fully open-source product, meaning that you can download it from the Web and install it. But for those clients who might be suspicious of open-source software, who want to use a packaged product that has gone through quality assurance or who want to get support from Lutris, commercial versions of Enhydra are available. I suspect that most people reading this column will not need support from Lutris, but it is good to know that they are ready and willing to help others use the product.
Lutris is aiming Enhydra not just at the J2EE market but also at the market for wireless internet applications. I personally have yet to see a compelling use of cellular internet technologies—the WAP functionality on my mobile phone could charitably be called pathetic—but Lutris is positioning Enhydra as a player in what will inevitably become a hot market.
While Enhydra has yet to develop the mindshare or community of Zope and the ArsDigita Community System, they have managed to score a fair number of impressive commercial triumphs. In particular, Hewlett-Packard recently announced that they would work with Lutris to market and use Enhydra in a number of applications. If nothing else, this proves that open-source application servers do have an important place in the world of web application development and that they can provide a compelling case even to companies that could otherwise afford to pay much more.
Now that we've reviewed a bit of the background, let's try to create some basic web applications using Enhydra. The first task, of course, is to download and install the product. I decided to download the beta of Enhydra Enterprise, in no small part because I wanted to play with the EJB features. As of the beta release, Enhydra Enterprise requires JDK 1.3, a pleasant contrast to previous releases that required JDK 1.2 even after 1.3 had been released for quite a while.
I downloaded and unpacked the Enhydra tar file, which created a large number of files and directories under the enhydra4.0 directory. As you might guess, the doc directory contains documentation, the lib directory contains .jar files that Enhydra needs and the conf directory contains global Enhydra configuration files. There is also a bin directory, in which nearly all files are shell scripts (with Windows .bat equivalents) that execute the various Java programs that make up Enhydra.
To ensure that the Enhydra shell scripts and Java programs are aware of the directory in which you installed Enhydra, run the configure shell script in the root directory of the Enhydra distribution (to which I will refer as $ENHYDRA). configure takes a single mandatory argument, the root directory of your JDK installation. configure modifies a number of Makefiles and other configuration files but does not force a recompilation of any code. After running configure (which does not produce any visible output), run the bash shell script (setup.bash) in $ENHYDRA, which adds the JDK executable directory to your PATH.
Enhydra consists of a number of different interrelated software packages. The application server itself, known as the multiserver, can work directly opposite HTTP clients or with a front-end web server such as Apache acting as a proxy. You can reduce the number of services that the multiserver starts up or change the order in which they are started by changing the loadOrder property in $ENHYDRA/conf/bootstrap.conf.
To start the multiserver, simply run $ENHYDRA/bin/multiserver. It should start up right away, launching services one at a time until you finally see the message, “Bootstrapper initialized normally”. At this point, you can test the multiserver by pointing your web browser at port 8001, which should bring up a control panel for viewing the current state of your multiserver.
My initial attempts to launch the multiserver failed, with the program complaining that it was unable to find enhydra.jar in my CLASSPATH. Particularly confusing here was the fact that I couldn't find any such file as enhydra.jar in the entire Enhydra distribution.
The solution turned out to be simple, if not obvious: Enhydra knows what CLASSPATH is necessary in order to run each of its programs but will ignore those settings if you have already set your CLASSPATH. So before running the multiserver, make sure to unset CLASSPATH, removing this environment variable. Once you have done this, the multiserver should come up as expected.
Over the last few months, we have looked at Java servlets and JavaServer Pages. Enhydra, as a J2EE-compliant application server, fully supports these technologies. Moreover, as an open-source server, Enhydra uses the Jakarta-Tomcat engine as the basis for its servlets and JSPs. As we will see later, it is possible (and often preferable) to use Enhydra's own advanced form of web applications.
It's relatively easy to create servlets using the tools that come with Enhydra. And indeed, Enhydra's authors have spent a great deal of time creating a system that is not only powerful when deployed, but relatively easy to work with during development.
If you are used to simply writing a servlet, compiling it and dropping it into a directory, then you will find that Enhydra gets in the way, complicating the process. This is in no small part due to the way in which Enhydra applications are deployed—rather than requiring an external server, Enhydra expects that you will want to test (and run) many of your web applications independently of any others.
To create a simple servlet, we will use the application generation wizard (appwizard) that comes with Enhydra, which you can invoke as $ENHYDRA/bin/appwizard. The appwizard is not an IDE but rather a sophisticated file-copying program that provides a basic skeleton application that already works.
When you first run appwizard, it will ask you whether you want to develop a web application (i.e., standard servlet) or an Enhydra super servlet. Choose a standard web application; super servlets will come later. The next screen will ask whether you want to produce output in HTML or WML, the latter being the standard XML-based format for cellular internet applications. We will use HTML and will call both the project directory and the package “atf”. By default, Enhydra applications are placed under your home directory in the subdirectory enhydraApps. Choose a license under which your code will be released, and appwizard will generate files for your new application.
And indeed, appwizard creates a large number of automatically generated files and directories. Among them are:
a global Makefile that allows us to build the application. There are individual Makefiles in a number of the applications subdirectories as well.
config.mk, which defines a number of environment variables on which the Makefile depends, with such information as the Enhydra version, the location of your JDK installation and the location of your Enhydra installation.
the src directory that contains the source code for Java servlets and HTML files. Under src is a standard WEB-INF directory, whose web.xml file names each of the servlets we plan to deploy. The atf directory, whose name depends on the project we created, contains four subdirectories: business, data, presentation and resources. The two that interest us most are the presentation and resources directories, since the former contains servlets and the latter contains HTML files and JSPs.
To build the application, simply run a make in the root directory of our project. (The Enhydra Enterprise documentation makes a big deal out of saying that it now uses the Java-based Ant build tool in favor of make, but application creation still appears to rely on make.)
After make completes its work, there will be a new output subdirectory at the top level of our application, parallel to src and input. The output directory contains everything we need in order to launch our application, including a standard Java .war (web archive) file containing our .class files, XML descriptors, JSPs and images:
WEB-INF/classes/atf/presentation/WelcomeHTML.class WEB-INF/classes/atf/presentation/WelcomeServlet.class WEB-INF/classes/atf/presentation/RedirectServlet.class media/Enhydra.gif index.jsp WEB-INF/web.xml
Notice that we have three .class files here, while there were only two in src/atf/presentation/. That's because XMLC turned the HTML file from src/resources into a Java source file, which was then turned into a Java .class file.
So with just two commands, appwizard and make, we have managed to create a full, running Enhydra application. The application, as it stands, doesn't do anything particularly complex or interesting, but it provides us with a skeleton that we can then modify and extend.
To run our application, we run output/start4. This starts the application on port 9000 (defined in input/conf/servlet/servlet.conf.in). If you point your web browser to http://localhost:9000/, you will see the output from our servlet: the Enhydra logo, the name of our application (atf), the current time and date and a hyperlink that redirects you back to the application.
The HTML page is generated by XMLC and demonstrates how XMLC is integrated into the rest of Enhydra. XMLC compiles src/atf/resources/Welcome.html into a Java servlet, which is then turned into a .class file. The Java class created by XMLC includes a hook for each of the <span> tags in the file, allowing retrieval and modifications of anything within a <span> tag that has an ID attribute.
WelcomeServlet, the servlet that is initially executed in our application, displays the current time and date by creating an instance of the XMLC-generated class:
now = DateFormat.getTimeInstance(DateFormat.MEDIUM) .format(new Date()); welcome = new WelcomeHTML(); welcome.getElementTime().getFirstChild() .setNodeValue(now);
In other words, we replace the text within the <span> tag with an ID of “time” by turning the HTML file into a DOM-accessible tree and then changing the value of a specific node.
To add additional servlets to our application, we can write and save them in src/atf/presentation. Note that the package will be atf.presentation and not simply atf. We will write a very simple class, Foo, which you can see in Listing 1. Except for the package name, there isn't any difference between traditional servlets and Foo.java.
Now we need to tell the servlet engine to map a URL to our servlet. We do this in src/WEB-INF/web.xml. This XML file is divided into two parts: the first maps servlet classes to servlet names, and the second maps servlet names to URLs. Listing 2 contains a version of web.xml modified to handle mapping our Foo servlet.
Finally, we need to include our new class in the Makefile, adding the name of our class to the CLASSES variable:
CLASSES = WelcomeServlet \ RedirectServlet Foo
Run make and check that Foo.class has been added to the application with:
jar tvf output/archive/atf.warIf it all works, then run output/start4, and point your browser to http://localhost:9000/foo. You should see the HTML output delivered by our new Foo servlet.
Experienced web developers, regardless of the language or environment, are used to writing a separate program for each web page. If you want to display five different dynamically generated pages, then you must write five different CGI programs, mod_perl handlers, servlets or JSP pages.
Enhydra allows developers to break away from this model, thinking in terms of applications rather than individual pages. The way to do this is with super servlets, as they are known, in which a single application object is associated with multiple presentation objects.
You can easily identify a presentation object in an Enhydra URL; the suffix .po tells Enhydra that it should invoke the object named in the URL. So requesting Abc.po will execute the run() method for the presentation object Abc. Unlike standard Java servlets, presentation objects are instantiated once for each HTTP request. This may be less efficient than using multiple threads on a single-servlet instance, but it does remove the headaches associated with writing threadsafe servlet code.
A simple Enhydra application will thus consist of at least one application object, plus at least one presentation object. These POs, as they are known, can then connect to the two other main types of Enhydra objects: business objects (which perform commonly needed functions) and data objects (which map persistent storage, such as a relational database, to a Java class). Each of these three types of objects—presentation, business and data—has its own directory within an application's src subdirectory, as we have already seen. Moreover, each of these objects constitutes one of the three standard tiers in a three-tier web application. So while it might take some time to get used to the separation between object types, this model is becoming increasingly prevalent in web applications.
Once again, we will use Enhydra's appwizard to create a skeleton application that we can change. Run appwizard again, but choose super servlet from the selection list on the first screen, rather than a simple web application. I chose to call the project myproject and to put it in the il.co.lerner package, which is what I use for internal projects at my company. appwizard then creates a skeleton application in ~/enhydraApps/myproject. The application has a similar structure to our servlet, with a similar directory structure. Under src/il/co/lerner, we have presentation, data and business directories. And once again, there is a top-level Makefile that will compile and create our super servlet.
Look at presentation/WelcomePresentation.java, the source code for the presentation object that will eventually be displayed. Indeed, if we type make at the top-level directory, run output/start4 to start our application and point our web browser to http://localhost:9000/, we will find that our browser is redirected to http://localhost:9000/WelcomePresentation.po. This page displays the same sample output that our skeleton servlet printed, with the Enhydra logo and the current time and date.
The po suffix, as we already know, tells Enhydra to invoke the run() method in WelcomePresentation. In the automatically created skeleton application, WelcomePresentation.run() looks like Listing 3.
The super servlet interface is similar to that of a regular servlet and does not take much time for a programmer familiar with servlets to learn. The run() method takes a single argument of type HttpPresentationComms, which provides our presentation object with all of its communication needs to the outside world, including the HTTP request and response objects.
The run() method displays output by creating an instance of WelcomeHTML, the Java class that XMLC created from the file Welcome.HTML. Following that, run() replaces the contents of the <span> tags with an ID of “time” with the current date and time. Then we write the contents of welcome, which contains a DOM tree, to the HTTP response object.
We can create our own presentation object, FooPresentation, as demonstrated in Listing 4. Remember to add the new object to the CLASSES line in the presentation directory's Makefile. When you rerun make from the top-level application directory, FooPresentation will be compiled and inserted into our Enhydra application.
It's very nice to be able to write our own presentation objects, but where is the application object that is controlling them? In the main source directory, at the same level as the presentation, data and business directories, there is a Java class file whose name is the same as the project—so in our case, there is a file at src/il/co/lerner/myproject.java.
Until now, we have only run our super servlet on its own, outside of the overall multiserver. This functionality is great for developers who want to be able to test applications without interfering with the main production web site, but we will want to add our application to that server at some point.
Enhydra makes this relatively easy to do: we add information about our application to the multiserver's configuration file, so that it can find the application. Then we use the multiserver's control panel to add our application to the production server under the URL of our choice. At that point, our application is available for all the world to see.
In order to accomplish this, we must start the multiserver once again, with the shell script $ENHYDRA/bin/multiserver. This makes the multiserver available on port 8001. Load the administration screen in your browser, and look at the list of available applications in the top-left corner.
Now we will copy the application configuration file—but not the application itself—named output/conf/myproject.conf and copy it to the global multiserver directory, $ENHYDRA/apps. Then edit $ENHYDRA/apps/myproject.conf, changing the value of Server.ClassPath. There are already two possible values for Server.ClassPath in myproject.conf: one for running the application in standalone mode and another for running it under the multiserver. Comment out the (first) standalone value, and uncomment the (second) multiserver value.
Having done this, return to your web browser and click on the Add button (with a big + sign on it) in the multiserver control panel. We're going to add a new application, whose name (myproject) should be in the selection list. Choose a root URL for this application, and enter any text string you want for this application's group. Click on OK to add the application.
Now refresh the multiserver control panel. In the upper left-hand corner, you should see “myproject”, along with whatever other applications might currently be loaded. If you click on the myproject name, the right-hand side of the screen will fill with information about myproject.
We can test our FooPresentation object by changing the URL, replacing WelcomePresentation.po to FooPresentation.po. Sure enough, we see our simple Foo HTML output displayed in the browser.
We can remove our application from one or more ports or from the multiserver entirely using the web-based control panel. Finally, we can shut down the multiserver either using the control panel or by pressing Ctrl-C in the terminal window where we started it.
It is not inherently difficult to write servlets, but Enhydra offers much more than just servlets. In particular, they provide an environment that makes it easy to write and test servlets without having to run a full web server. Moreover, the super servlets that Enhydra provides can be easier to work with than regular servlets, especially since we can avoid having to deal with threading issues and writing a new overall handler application for each page.
There are, of course, some drawbacks. Enhydra, like most Java programs, requires a fair amount of patience when setting CLASSPATH. (Although to the credit of Lutris, removing my own CLASSPATH solved almost all of those problems.) And while Enhydra's automatically generated Makefiles dramatically reduce the amount of thought that you must put into creating a finished web application, Java programs always seem to require ten times as many files as their Perl and Python counterparts.
While super servlets are certainly an improvement over their nonsuper cousins, I always hesitate before jumping into a technology that deviates from a known, well-documented and mature standard—particularly when the Open Source community seems to be taking its time to rally around Enhydra in a major way. Finally, while it's true that Enhydra Enterprise is not yet a released product, the installation instructions and documentation leave something to be desired.
With all of these reservations, I easily can see myself using Enhydra for future Java development, instead of the plain, vanilla Jakarta-Tomcat that I have used in the past. The combination of XMLC and an integrated environment is quite attractive in many ways.
As I mentioned earlier, one of the reasons I am most excited about Enhydra Enterprise is its ability to connect to Sun's Enterprise JavaBeans. Over the next two months, we will look more closely at Enhydra, first investigating its DODS tool for mapping relational databases to Java objects. Then we will dip our toes into the world of EJB, demonstrating that just because we rely on open-source products doesn't mean that our tools are any less capable than proprietary programmers.