Now that we've got the background out of the way, we can move on
to actually using Enhydra. I'll discuss some things that help
newcomers to Enhydra, as well as seasoned veteran users. The first
thing we'll take a look at is the newapp script, which sets up a
basic directory structure, the default build environment, and some
Enhydra configurations that you won't need to worry about when
writing your first application.
You will definitely modify these files later, but you don't need
to worry about them right now. I'm going to go over building your
first application, and then we'll switch over to a running system
and run through the demonstration for real. This way, you won't be
lost when I run through things. A typical application development
cycle looks something like this:
Ø Write out technical
documentation for the project, including drafts of the code. This
helps greatly to keep on top of where you are, and not forget
things.
Ø Run newapp to get the
default tree created
Ø Modify the business,
presentation, and data objects to suit your project
Ø Modify the makefile(s) to
include your new classes
Ø Build and test
Ø Repeat
Newapp/Makefiles
After running newapp, the directory structure looks like
this:

The newapp command creates a working Enhydra application (in
this case, intro) that you can build and run right away. The
resulting application demonstrates some basic Enhydra patterns: the
default directory structure, naming conventions for presentation
objects and HTML files, and how to run and test your application
locally. Notice that there are business, data, and presentation
directories created by default - 3-tier code is promoted from
the beginning.
The newapp command also creates makefiles for you - anyone
who uses makefiles knows how powerful and painful they can be, so
automation in this area is greatly appreciated. Adding new objects
to your application requires a basic understanding of makefiles,
and usually involves only minor changes. To start the program, we
change to the output directory and run the start command. It then
starts up and tells us what host and port to connect to. The
default application looks like this:

We're going to modify the default application to use WML, since
that's what we're really interested in accomplishing here. I have
two WML files that we are going to bring into the Enhydra build and
use to write a simple application that asks the user for their
name. If it is a recognized name, we append a link to their
homepage to the response; otherwise they get the generic welcome
message.
The WML screens look like this:


The default build environment does not include WML build rules.
I have made some rules that you can add to the default config.mk
file after the include directive at the end of the file, to make
building WML files easier. The lines to add to config.mk are:
$(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)
@CLASSPATH="$(ENHYDRA_CLASSPATH)" ; export
CLASSPATH ; \
set -x ; \
$(XMLC_CMD) -class $(PACKAGE).$*WML -d
$(PACKAGE_OUTPUT) $(XMLC_WML_OPTS) $(XMLC_$*_OPTS) $(XMLC_JAVAC)
$(XMLC_WML_OPTS_FILE) $*.wml
do_xmlc_html_targets::
$(WML_CLASSES:%=${PACKAGE_OUTPUT}/%.class)
XMLC
XMLC stands for "XML Compiler". It converts text-based markup,
such as HTML and WML, into objects that conform to the W3C Document
Object Model (W3C-DOM). At least, that's the official explanation.
The simpler version is that XMLC is a program that converts
XML-based content into trees of Java objects that can be
manipulated in an Enhydra application. This is the preferred method
of manipulating WML, HTML, and XML files in Enhydra.
Once you have the makefile rules in place, you can put the WML
files into a wml directory under the presentation directory, and
add them to the build with the following rules:
XMLC_WML_DIR = ./wml
XMLC_WML_CLASSES = InputWML ResultWML
We then run make, and see that XMLC is invoked to compile our
WML files into DOM trees with Java bindings. Let's look a little
closer at what XMLC is doing.
XMLC is not a trivial program. XMLC translates your XML-based
markup into Java objects by parsing the HTML and creating a DOM
tree that represents the markup. The end result is that you
manipulate a tree of objects, which is efficient in Java - the
alternative being String manipulation, which is inefficient in
Java. (XMLC is totally object-oriented, which is not the case with
string manipulation.)
I have to take some time to talk about the Document Object
Model, since it's likely to confuse someone who is not familiar
with it. This comes straight from W3C:
"The Document Object Model is a platform- and language-neutral
interface that will allow programs and scripts to access and update
the content, structure and style of documents dynamically. The
document can be further processed and the results of that
processing can be incorporated back into the presented page. This
is an overview of DOM-related materials here at W3C and around the
Web."
Further information can be found at http://www.w3.org/DOM/
XMLC supports some useful command line parameters that allow us
to understand what it is doing without viewing the generated source
code. Some of the more useful ones follow:
Ø The -dump flag shows you
the generated DOM tree structure on standard output.
Ø The -methods flag shows you
the convenience methods that XMLC generated for this file. These
methods use the id attribute in the markup to generate a method of
the form getElementNamedIdAtrribute() For example, if you
had a tag in your markup like <a id="linkName"
href="nextpage.wml">, XMLC would generate a convenience method
called getElementLinkName().
Ø The -nocompile flag tells
XMLC not to actually compile the output, but to parse the file
only. It is used in conjunction with other flags.
Looking at our input.wml file, with all of the flags shown
above, we see how XMLC interprets our DOM structure and what
convenience methods it creates for us:
xmlc -dump -nocompile Input.wml
DOM hierarchy:
Document:
Document type =>
DocumentType: name=wml
Entities =>
Notations =>
ElementNS: wml
Element: head
Element: meta:
content='max-age=0' forua='true' http-equiv='Cache-Control'
Element: card: id='home'
title='AnywhereYouGo.com'
Element: p:
id='title'
Text:
Enter your name:
Element: br
Text:
Element: input:
emptyok='false'
id='iName' name='iName' title='name' type='text' value=''
Text:
Element: do:
id='sendName' label='Login' type='accept'
Element: go:
href='/WAPDemo.po' method='post'
Element: postfield:
name='name' value='$iName'
Element: postfield:
name='postedTo' value='true'
Let's build our servlet that displays the page. In the language
of Enhydra, this is called a presentation object (PO). The PO is
responsible for creating the user interface based on the HTTP
request given it, just like a servlet or a CGI program. This Java
class must implement an Enhydra interface that holds a "run"
method. Enhydra supplies an object to this method that allows you
to access the request and response objects. These objects
encapsulate things like HTTP headers, HTTP post parameters,
referrer URL, and other variables that are familiar to web
developers. Our skeleton presentation object doesn't do
anything - it just implements the correct interface, which we
now have to fill in and give a purpose.
Applying our Work
Now we need to make it do something useful. We will read the
name parameter from the request - we don't care if this
information was posted to us, or came from the query string in a
get request (as in the GET and POST methods of HTML), we read it
the same way. The syntax is as follows:
String name = comms.request.getParameter("name");
We can use the convenience method we saw XMLC generate for us to
grab the text message from the WML template file. We pass this node
and the name into our business class for additional processing
(we'll get to the details of this in a minute), and then print out
the document to a string so we can send it to the browser.
The business object is just a regular Java class, and I've
already created the business object skeleton to save time -
all we need to do now is fill it in (this filling can also be done
in PO, as no business layer is provided). Note that since we are
dealing with pass-by-reference, anything we do to the node that is
passed in will be reflected in the document the display class sends
out. First, we check if the name is usable - if we have a null
or an empty string, there is no point in doing any further
processing. Next, we check to see if the name is a key in our
knownIdentities dictionary - if we know who it is, we create a
link to their site.
This is done with the Document.createElement() method. We want
to create a link that looks like <a
href="somesite">somesite</a>. The code to do this is shown
below - we basically ask the document to create an element
based on a tag name. At this stage, I'd really like to reiterate
that getting the documentation for the W3C DOM is a good idea if
you are going to use XMLC and Enhydra; the resulting code is:
// See if we recognize the user
if (validUsers.containsKey (user)) {
// Get the owner doc so we can
create elements
Document doc =
refLink.getOwnerDocument();
// Create an "a" element for our
link. Set the href attribute
// so the device knows where to
go
Element link = doc.createElement
("a");
String linkName = (String)
validUsers.get (user);
String url = (String)
namedLinks.get (linkName);
link.setAttribute ("href",
url);
// We have to append a text node
to the link so the user sees
// something. This is the
text between the open and close of
// the a tag:
// <a href="somelink">text
node we are creating</a>
Text linkText =
doc.createTextNode(linkName);
link.appendChild (linkText);
// Append the link to the
document
Node parent =
refLink.getParentNode();
parent.appendChild (link);
// Because of the way the dom
works - if you append a child that
// is already in the child list,
it will be removed first - this
// could be done in multiple
steps, but it is not necessary.
parent.appendChild
(doc.createElement("br"));
parent.appendChild (refLink);
}
I don't show it in the code for this tutorial, but a good way to
build documents is to grab pieces from multiple documents and merge
them into one final document that is sent to the browser. As an
example, let's say you had a file for your home page that had HTML
like this:
<table>
<tr> <td id="featureSection"> This is
the features section </td> </tr>
</table>
Then you have a "features" file that contains items you would
like to feature on your home page:
<table id="features">
<tr><td> New WAP emulator available
</td></tr>
<tr><td> AnywhereYouGo.com releases
on-line WAP testing tool </td></tr>
</table>
We then take the features table and insert it into our home
page. The process requires an extra step, though: you have to
import the content you want to put from the features document into
your home page document - you use the importNode() method to
accomplish this. This (for me, at least) is the most common way to
build documents with Enhydra. The following code imports and
appends a node from another document:
// Get our documents
HomeHTML home = new HomeHTML();
Document doc = home.getDocument();
FeaturesHTML features = new FeaturesHTML();
// Grab the insertion point and node we want to import
Node insertionPoint = home.getElementFeaturesSection();
Node featureTable = features.getElementFeatures();
// Import the features table and replace the current content in
the template
insertionPoint.appendChild (doc.importNode (featureTable));
Testing our Creation
Now we can run the code and see what happens on the emulator.
This is the part where everyone in the audience with a WAP phone
can participate! If you go to http://demo.ayg.com, you should see
the demo we just created. I have added some business logic that
will tell 5 people that they won. If you get that message, show me
your phone and I'll give you an AnywhereYouGo.com T-shirt. The code
for the demonstration we built, and the modified one, is on the
Anywhereyougo.com site at
http://www.AnywhereYouGo.com/wrox2000/
The next part of the demonstration has less to do with WML than
it does with HTML, but it's a good example of how easy it is to
publish to multiple markup languages with Enhydra (using XML as a
middle step). I already have the HTML built, and it looks similar
to the WML version.
input.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2
Final//EN">
<html>
<head>
<title>Welcome to
intro!</title>
<!-- Changed by: Ryan Fife, 30-Apr-2000
-->
</head>
<body bgcolor="#FFFFFF">
<form action="WebDemo.po"
method="post">
<p id="title">
Enter your
name:<br>
<input name="name"
value="" type="text" id="iName">
</p>
<p>
<input
type="submit" value="Log In" align="middle">
</p>
<input type="hidden"
name="postedTo" value="true">
</form>
</body>
</html>
response.html
<html>
<head>
<title> Enhydra Demo </title>
<!-- Changed by: Ryan Fife, 30-Apr-2000
-->
</head>
<body bgcolor="#ffffff">
<p id="userTitle">
User Home
</p>
<p id="userLinks">
<a id="AYGLink"
href="http://www.ayg.com/">AnywhereYouGo.com</a>
</p>
</body>
</html>
We can now copy the WAPDemo.java file to WebDemo.java, and edit
it to display HTML. All we have to do is change the document we
instantiate for the input and result pages; everything else stays
the same. Let's take another look at the business class to see why
that is.
When we create the new node with the link and append it after
the message node, we used the document to create a named element.
Since a link is created with an <a> tag in both WML and HTML,
the document created the appropriate tag for the appropriate
document type - we don't have to change anything. We have made
some assumptions about tags that exist in both presentation types,
but as long as you can do that, you can write business classes that
will work with either front end.
Now you can update the business class, and both the HTML and WML
versions get the changes. If you add more names you recognize, they
will be recognized no matter how the user comes in. With the use of
a database on the backend and some more business classes, you can
see how you could build an interesting Internet application using
Enhydra.