Introduction
If you haven’t checked out Enhydra, Lutris Technologies’ open-source Java application server for your web-based application needs, you don’t know what you’re missing. With version 3.0, Enhydra’s cup overflows with features like Servlets 2.2, JSP 1.1, XMLC, cookie-less sessions, and of particular interest to the visitors of this site, a fully functional WML DTD. Yes, that means you can write your entire WAP application with complete dynamic functionality in 100% Java! (Well, WML and Java Servlets to be exact, but you get the point.) What Enhydra does for you is provide a framework for servlet-based web applications, with plenty of built in tools for database access, XML parsing, on-the-fly HTML compilation, and even IDE integration. We’ll focus on the WAP functionality of Enhydra for this article, walk through how to set up Enhydra on a development machine, write a simple multi-card WAP application, and have Enhydra serve it up with it’s own multiserver, with no additional web server required!
Enhydra Overview
Enhydra’s framework is basically set up like this: It starts with HTML (or WML) documents, modified with an extra ID property in the tags you want to be dynamic (SPANs for dynamic text, TR and TDs for dynamically generated tables, etc.). Enhydra then uses its supplied XMLC program to parse and compile the pages into properly formatted XMLC classes. Then you create corresponding Java classes for each HTML page you want to show, which loads up the XMLC classes, does whatever dynamic stuff you tell it to do, and with a call to the function to serve up the page…presto! Enhydra presents the page as [page name].po in the browser, which stands for Presentation Object. To the user, it looks just like standard HTML (or WML). That was the fifty cent tour of Enhydra, if you want to get into the nitty gritty, check out the documentation or join the Enhydra mailing list. It’s really a powerful application framework, and scalable enough for any size job. Now let’s walk through setting up Enhydra on your box and configuring it to serve up some WML.
Enhydra Mini-HOWTO
Download the appropriate files for your operating system and install the Java SDK first. All this should involve is unzipping or untarring the SDK file and setting the appropriate PATH environment variable. See the Java 2 SDK documentation for more information.
If you’re in Windows, unzip the Cygwin tools to your C:\ directory. This will create all the folders Cygwin needs, like C:\usr, C:\bin, C:\usr\local\bin, and so on. If you’re in Linux, you’re already good to go.
Un(zip/tar) Enhydra. On Windows, just unzip Enhydra to your C:\ directory. If you’ve got Cygwin installed correctly, Enhydra will put itself in the directory C:\usr\local\enhydra3.0.1. In Linux, you have to move the untarred files to /usr/local, or wherever you want, but /usr/local/ is a good place. You also may want to make a symbolic link ‘enhydra’ that points to ‘enhyrda3.0.1’ to allow for easier future upgrades.
Windows users: All commands from now on should be made through the Enhydra Bash shell, whose shortcut can be found in C:\enhydra\EnhydraShell_[95_98 or NT].
Configure Enhydra by going to the enhydra3.0.1 directory and telling Enhydra where your Java 2 SDK is by typing:
Windows: ./configure //C/jdk1.2.2 Linux: ./configure /usr/local/jdk1.2.2
Now it’s time to test your installation. Type: /usr/local/enhydra3.0.1/bin/newapp HelloWAP This will create a directory called HelloWAP, which has all the basic framework of files for a typical Enhydra application. CD into the HelloWAP directory, and you’ll see another directory called HelloWAP, and a couple config and make files. We’ll get to these in a minute. For now, just type: make If everything is set up right, you’ll watch your new HelloWAP application being built. After it’s done, there should now be a output directory which has your new HelloWap.jar file in a lib directory, and a classes directory which has the structure for all the necessary classes for your new HelloWAP package. If make completed without errors, cd into the output directory, and type: ./start This will start up Enhydra’s built-in multiserver. You should see: Multiserver,INFO: HTTP listening on port: 9000 Point your favorite browser to http://localhost:9000 and after a minute or so (the first time an Enhydra application is called, it takes a while for it to come up, but then it’s fast) you should see the little Enhydra otter mascot laying back enjoying a cup of joe under the words “Welcome to HelloWAP!” Of course, this isn’t WAP, it’s HTML, but we’re running this just to make sure everything’s set up right. We’ll turn the application into a WAP application later. We first need to configure Enhydra for WAP applications. If you’re having problems getting this far, the documentation supplied with Enhydra and the enhydra.org website should have your answers.
Configuring Enhydra for WAP
While the Enhydra distribution comes with the WML 1.1 DTD (found in /usr/local/enhydra3.0.1/xml/wml/), it doesn’t come ready to handle WAP applications, so we need to do a little tweaking. You have to make some changes to the main Enhydra configuration files and to our HelloWAP configuration files, but the changes don’t break Enhydra from building standard HTML applications, it just adds the WML functionality.
Changes to the wml.xcat file
First, open up the wml.xcat file found in /usr/local/enhydra3.0.1/xml/wml/ in your favorite text editor. Change the HRef=”file:…” line to point to the directory you’re currently in. Save it, and now let’s make the bulk of the necessary changes to the stdrules.mk file.
Changes to the stdrules.mk file
Find Enhydra’s stdrules.mk file in /usr/local/enhydra3.0.1/lib/. Open it in your favorite text editor and find the line: java_pass:: do_xmlc_html_targets dojhtml_targets jpass_subdirs dojpass_targets Add ‘do_xmlc_wml_targets’ so it looks like: java_pass:: do_xmlc_html_targets do_xmlc_wml_targets dojhtml_targets jpass_subdirs dojpass_targets Now find: dojpass_targets:: $(JDDI_CLASSES:%=$(PACKAGE_OUTPUT)/%.class) $(JOLT_CLASSES:%=$(PACKAGE_OUTPUT)/%.class) $(HTML_CLASSES:%=${PACKAGE_OUTPUT}/%.class) $(CLASSES:%=$(PACKAGE_OUTPUT)/%.class) And add ‘$(WML_CLASSES:%=${PACKAGE_OUTPUT}/%.class)’ like so: dojpass_targets:: $(JDDI_CLASSES:%=$(PACKAGE_OUTPUT)/%.class) $(JOLT_CLASSES:%=$(PACKAGE_OUTPUT)/%.class) $(HTML_CLASSES:%=${PACKAGE_OUTPUT}/%.class) $(WML_CLASSES:%=${PACKAGE_OUTPUT}/%.class) $(CLASSES:%=$(PACKAGE_OUTPUT)/%.class) Now find: # # Default rule to build classes from HTML using XMLC # do_xmlc_html_targets:: $(HTML_CLASSES:%=${PACKAGE_OUTPUT}/%.class) And under it, add: # # Default rule to build classes to WML using XMLC # do_xmlc_wml_targets:: $(WML_CLASSES:%=${PACKAGE_OUTPUT}/%.class) Next, find: ifneq ($(HTML_CLASSES),) -rm -rf $(HTML_CLASSES:%=./%.java) -rm -rf $(HTML_CLASSES:%=./%Impl.java) endif And under that, add: ifneq ($(WML_CLASSES),) -rm -rf$(WML_CLASSES:%=./%.java) -rm -rf$(WML_CLASSES:%=./%Impl.java) endif (Almost done!) Now find: # # Support for XMLC recompilation # ifeq ($(XMLC_AUTO_COMP),YES) XMLC_HTML_OPTS += -for-recomp endif And insert ‘XMLC_WML_OPTS += -for-recomp’ like so: # # Support for XMLC recompilation # ifeq ($(XMLC_AUTO_COMP),YES) XMLC_HTML_OPTS += -for-recomp XMLC_WML_OPTS += -for-recomp endif Finally, after the section: # # Compile HTML with XMLC # Add the following: (You may want to cut and paste this, to eliminate typing errors) # # Complie WML with XMLC # XMLC_WML_OPTS += -domfactory org.enhydra.wireless.wml.WMLDomFactory $(PACKAGE_OUTPUT)/%WML.class: $(WML_DIR)/%.wml $(XMLC_WML_OPTS_FILE) $(XMLC_%_OPTS_FILE) @mkdir -p $(PACKAGE_OUTPUT) ifeq ($(XMLC_AUTO_COMP),YES) cp -f $(WML_DIR)/$*.wml $(PACKAGE_OUTPUT) endif @CLASSPATH=”$(ENHYDRA_CLASSPATH)” ; export CLASSPATH ; \ set -x ; \ $(XMLC_CMD) -class $(PACKAGE).$*WML $(XMLC_WML_OPTS) $(XMLC_$*_OPTS) $(XMLC_JAVAC) $(XMLC_WML_OPTS_FILE) $(XMLC_$*_OPTS_FILE) $(WML_DIR)/$*.wml $(PACKAGE_OUTPUT)/%WML.class: %.wml $(XMLC_WML_OPTS_FILE) @mkdir -p $(PACKAGE_OUTPUT) ifeq ($(XMLC_AUTO_COMP),YES) cp -f $*.wml $(PACKAGE_OUTPUT) endif @CLASSPATH=”$(ENHYDRA_CLASSPATH)” ; export CLASSPATH ; \ set -x ; \ $(XMLC_CMD) -class $(PACKAGE).$*WML $(XMLC_WML_OPTS) $(XMLC_$*_OPTS) $(XMLC_JAVAC) $(XMLC_WML_OPTS_FILE) $*.wml Whew! That’s all the changes we need to make on the main Enhydra files, now let’s move to the HelloWAP application and make the necessary changes there.
Changes to config.mk
Open up the config.mk file in your top-level HelloWAP directory. In: # # Generate interfaces and implementions # XMLC_HTML_OPTS += -generate both Add ‘XMLC_WML_OPTS += -xcatalog /usr/local/enhydra3.0.1./xml/wml/wml.xcat -generate both’ to the end like so: # # Generate interfaces and implementions # XMLC_HTML_OPTS += -generate both XMLC_WML_OPTS += -xcatalog /usr/local/enhydra3.0.1./xml/wml/wml.xcat -generate both Now cd into the HelloWAP/helloWAP/presentation directory and open the Makefile. Change the lines: HTML_DIR = . HTML_CLASSES = WelcomeHTML to WML_DIR = . WML_CLASSES = WelcomeWML
And that’s it! All the necessary configurations for your new WAP application are made. Now all we need is a WAP Application to try it out, so let’s make one!
The HelloWAP Application
Striving for simplicity here, I built a basic multi-card WML document that simply takes data from an input field in one card, passes it to another card, and prints it out. Ok, here’s the code:
Welcome.wml
<?xml version=’1.0′?> <!DOCTYPE wml PUBLIC “-//WAPFORUM//DTD WML 1.1//EN” “http://www.wapforum.org/DTD/wml_1.1.xml”> <wml> <card id=”card1″ title=”HelloWAP”> <p> <em>Welcome to HelloWAP</em> <br/> Enter your name: <input type=”text” name=”uname”/> <do type=”accept” label=”Login”> <go href=”#card2″/> </do> </p> </card> <card id=”card2″ title=”Results”> <p> <em>Hello, $(uname)!</em> <br/> Pretty cool, huh? <do type=”accept” label=”Back”> <go href=”#card1″/> </do> </p> </card> </wml> Copy this or type it and save it as Welcome.wml in the HelloWAP/helloWAP/presentation directory. You don’t have to delete the Welcome.html file, Enhydra will just overlook it because of the changes we made to the Makefile in this directory.
Now, all that’s left is to write the Welcome.java code so that Enhydra will serve up the WML. There already exists a Welcome.java file in the presentation directory, but that code is for serving up HTML pages, not WML. Rename the existing Welcome.java file and create a new one so you can compare the changes. Here is the new code:
Welcome.java
package helloWAP.presentation; import com.lutris.appserver.server.httpPresentation.HttpPresentation; import com.lutris.appserver.server.httpPresentation.HttpPresentationComms; import com.lutris.appserver.server.httpPresentation.HttpPresentationException; import com.lutris.appserver.server.httpPresentation.HttpPresentationOutputStream; import com.lutris.appserver.server.httpPresentation.HttpPresentationRequest; import com.lutris.appserver.server.httpPresentation.HttpPresentationResponse; import org.enhydra.xml.xmlc.XMLObject; import java.io.IOException; public class Welcome implements HttpPresentation { public void run(HttpPresentationComms comms) throws HttpPresentationException, IOException { WelcomeWML welcome = (WelcomeWML)comms.xmlcFactory.create(WelcomeWML.class); present(welcome,comms); } public void present(XMLObject doc, HttpPresentationComms comms) throws HttpPresentationException, IOException { HttpPresentationResponse response = comms.response; response.setContentType(“text/vnd.wap.wml”); HttpPresentationOutputStream out = response.getOutputStream(); String buffer = doc.toDocument(); out.println(buffer); response.flush(); } } There are a few interesting things to note here. First off, I explicitly imported the classes needed to present WML instead of just importing *, but it gives you a better idea what classes are needed for WML to work. Now, let’s analyze the code. The line: WelcomeWML welcome = (WelcomeWML)comms.xmlcFactory.create(WelcomeWML.class); creates a WelcomeWML (created from compiling the Welcome.wml file) object called ‘welcome’. The somewhat complicated looking assignment is for automatic recompilation of HTML (WML in our case) so that you could change the WML file and the presentation object would change accordingly without having to recompile the whole project. The ‘present’ function creates a typical servlet response object, sets the content type for WAP, and does an out.println to send the WML to the browser. Pretty straight forward servlet stuff, with a little Enhydra seasoning thrown in. Now, the java code doesn’t do much of anything dynamic, it just sends the WML code straight to the browser, but this would be where you would change a tag or add additional text or whatever.
Once you have all the code written, simply go back to the top-level HelloWAP directory, do a make and you’re golden. CD into HelloWAP/output, type: ./start browse to http://localhost:9000/ (you may want to add the ending ‘/’, some browsers are finiky about this) with your favorite WAP-enabled browser (phone.com‘s UP.SDK 4.0 works well) and watch your brand-new Enhydra-powered WAP application go. Pretty cool, huh? Well, that should get your feet wet with Enhydra and WAP. If you want to delve deeper, check out the Enhydra documentation or enhydra.org.
Screenshots
Card 1 of the HelloWAP application | Card 2 of the HelloWAP Application |
The pre-WAP HelloWAP Application |