March 9, 2021
Hot Topics:

Misusing Dynamic Binding When Static Binding Would Do, Part 1

  • By Brad Cox
  • Send Email »
  • More Articles »

HTML-based languages treat Web applications as collections of files linked to one another via <a href> and <form> commands coded inside the files. This is one example of an anti-pattern that pervades the Web application frameworks and libraries I've used to date: misusing dynamic binding when static binding could do the job better.

In this example, the JSP page hard wires a dynamically bound link to the target page in its <a href> command rather than calling a statically bound, type-checkable method of the target page. None of the Web app environments I've seen support the latter option. Pages reference other pages by filename, not as objects, because browsers use HTML, which does it this way.

But although HTML's way of doing things does apply to browsers, it does not apply to the server side of a Web application. Web apps should be object-oriented programs just like any other except that they emit HTML text to a browser. Pages should be first-class Java objects, not file names as in HTML, ASP, PHP, JSP WebMacro, Velocity or Perl.

Java Web Application Architecture provides statically bound type-checkable substitutes for each example of this anti-pattern I've encountered in my work. JWAA's statically bound solutions can and should be used to replace and/or supplement other Java Web application environments, such as JSP.

This does not mean that static binding should replace dynamic binding throughout an application, only in those places that could be handled better at compile time. A designer that uses dynamic binding for everything is like an automobile engineer that uses screwing, bolting, or riveting for everything when casting, forging, and welding would be much better for fabricating the parts of the car.

Web Applications Are Not Files

But HTML-based languages treat them as such. For example, you write <a href="filename.jsp"> to link to another page in JSP. Regardless of what goes on thereafter (for example, when JSP pages are compiled into servlet objects), the objects identify each other as members of a collection of files and not as a network of first-class objects. If filename.jsp does not exist, the error won't be noticed until it causes an Error 404. Maybe you catch it during testing, but often it goes unnoticed until it's reported by the end-user.

For example, this figure represents the top-level objects of the JWAA Demo Application. This simplest imaginable demo's state machine has six distinct states and eleven legal transitions, and the figure doesn't even show the error transitions. Scale the demo up to hundreds of states and (potentially) thousands of transitions, and the problem cries out for a way to manage the states and transitions as references between first-class Java objects. Keeping track of JSP file names as applications are refactored and renamed becomes far too hard.

The solution is so obvious and the advantages so large that it is surprising that it is not provided by the Web application environments I've examined to date. JWAA provides an AbstractPage class that applications subclass to define pages (the ovals in the figure). The servlet for the application publishes a public final static SomeClass instance variable via which other pages reference the singleton instance of each page of the application. When a page needs to emit an <a href> link to another page (the arrows in the figure), it calls SomeClass. instance. emitLink(ctx). To emit a <form> command, it calls SomeClass. instance. emitForm(ctx) instead.

Presto, invalid links will be reported at compile-time. If the application compiles, all links to dynamic pages are guaranteed to be valid. JWAA also provides an AbstractLink class that applications can subclass to specify links to legacy HTML files, graphic files, external servers, and so forth. The subclass can provide warnings of files that don't exist when the application is starting up. Presto, another common source of server errors is gone.

A JWAA application consists of one Java class per dynamic Web page. For example, the demonstration application consists of AddressPage, AdminPage, HomePage, LoginPage, LogoutPage, RefusePage, and RegisterPage. Each of these subclass another application-specific class, Page, which provides a consistent look and feel for the demo as a whole. Each application also provides a servlet class, named Demo in this case, which parses incoming URLs and dispatches them to the requested page's controller.

The pattern demonstrated here is followed throughout JWAA. JWAA simply provides a statically bound and type-checked alternative to inappropriate use of dynamic binding. The dynamically bound construct, <a href="filename.jsp"> is available too. But this is deprecated, replaced by the statically bound equivalent, OtherPage.instance.emitLink(ctx), which has exactly the same result except that invalid links will now be detected at compile time.

This trades the ability to revise HTML files underneath a running application for the ability to check links at compile time. You will need to run make to change the running image and restart the server if you haven't configured Tomcat to auto-reload changed classes. With Jikes, this is nearly instantaneous. Since everything happens at compile time, there is no need for a Java SDK inside the running image nor even to have the Java SDK on the deployment machine. This brings significant savings in space, speed and security. For example, the JWAA distribution is only about 70K whereas the Tomcat/JSP distribution is more than ten times larger (about 1000K).

Nonetheless, this trade-off is not acceptable in shops that divide responsibilities between software developers (Java programmers) and information architects (HTML developers). Therefore, JWAA's traditional support for using MLS to code HTML as strings within private view methods has recently been extended so that MLS supports the ability to maintain Java code and HTML templates in separate files. Unlike other template languages which bind at run time, binding occurs entirely at pre compile time and imposes no run time overhead at all.

Fields Are Not Strings

Yet servlet engines treat them as such. For example, the servlet engine's request.getParameter("name") method returns the String value of the named parameter if it exists or null under various error conditions. Template engines exhibit the same anti-pattern by using a Hashtable to pass named values between Java code and the template (presentation) layer.

String is a final class in Java, so an application cannot define application-specific methods by defining application-specific String subclasses that do input validation. So input validation logic winds up scattered through the application instead of being encapsulated into application-specific field classes.

Fields are not Strings. In an application that manages addresses, they should be application-specific objects like Street, USState, Zipcode, and Country. Fields are not used only during input validation and converted back to Strings for use in the application. They displace Strings and their evil consort, the Java null, from the application. Fields are the lowest-level atoms from which an application is composed: fields are to beans as atoms are to molecules. Strings and nulls are only used as lowest-level building blocks and rarely if ever appear in the application itself.

The solution is again straightforward and easily added to any environment. The servlet passes each JWAA application a servlet context object (named Ctx for brevity) that contains the request-specific state information applications use to communicate with their environment. The Ctx object provides a getField method that generates validated instances of application-specific objects like this:

Email email = (Email)ctx.getField("email", addressBean.getEmail());

The first argument is the request parameter name. The second is the default value which getField will clone (copy) and return if the requested parameter is empty ("") or null. In this example, the default value is obtained from the addressBean. In an application where the default should be empty, the application would specify Email.Null as the second argument. By convention all field classes provide a Null instance initialized with an empty string ("").

The getField method is defined in terms of the Validatable interface in the JWAA package. JWAA also provides an abstract class, AbstractField, to serve as the abstract superclass of application-specific field classes.

Briefly, it works like this. The email.ok() call returns true if the email address the user provided complies with the syntactic validity requirements of the Email class, and email.getMessage() returns a string that explains the reason for the non-compliance in the user's frame of reference. When the Email field is assigned a value via its setValue(Object aValue) method, it uses a regular expression to set the boolean returned by email.ok() and the message string that will be returned by getMessage() (too long, too short, not in user@host.dom format). The logic for editing an email address with input validation is then as simple as this:

{{ ctx.emitForm(this) }}
Email Address: {{ email.asField("email", 32) }} {{ fontRed(email.getMessage()) }}
<input type=submit name="op" value="OK"> prompt(op, new Validatable[] { email });

[The above uses multi-line string's {{aString}} syntax, which is roughly equivalent to Java's "aString" with enhancements. It will be discussed in Part 2. Also see the author's site for more information on this topic.]

This code uses application-specific methods provided by the application's Page class to display the getMessage() text in a red font and to return a standard prompt alongside the submit button (either "Click OK to proceed" or "Correct the errors marked with red text"). Notice that Strings and nulls no longer appear in the application and that the need to check for null field values is eliminated.

Beans Are Made of Fields, Not Strings

Fields are to beans as atoms are to molecules. But JDBC provides only get and set methods that encourage applications to declare bean fields as Strings and other generic Java types like int or long.

JWAA's solution is the same as the above. A bean's API to the application should be defined to accept application-specific field data types like Email instead of generic data types like String. The bean's load and save methods simply use AbstractField methods to convert between the generic data types used by JDBC and the field data types used by the application.

In Part 2, we'll discuss multi-line strings, choice of configuration language, appropriate dynamic binding, and bringing everything together.


About the Author

Brad Cox's background and interests are in software engineering and object-oriented software development. The connection with social and organizational learning is discussed in his collection of articles on the social construction of reality. Also see the book, Superdistribution: Objects as Property on the Electronic Frontier. He maintains the Middle of Nowhere Web as a vehicle for the distance education courses he teaches and to experience first-hand the bewildering phenomena that society has not yet mastered the taming of the electronic frontier.

This article was originally published on November 21, 2001

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date