Alternative Approaches to Markup Generation

All the approaches we've considered so far are templating solutions, in which a template language renders content made available to it by a Java view adapter. This is not the only valid approach for views. Let's now consider some approaches in which the view is built using Java code. In our framework, this means that there will be a distinct implementation of the com.interface21.web.servlet.View interface for each page that will actually generate content.

HTML Generation Libraries

One approach is to use what I'll refer to as an HTML generation library: a set of Java classes that enables us to construct HTML documents using Java code. In this model, rather than use a view template such as a JSP or Velocity template, we use Java code to construct an HTML document as an object composed of objects representing text, formatting, form fields etc before writing the generated markup to the response. The HTML generation library ensures that the generated markup is well formed, and conceals the complexity of the eventual output. This concept is quite old, and the earliest implementations predate JSP, although none has become very popular.

Most generation libraries are HTML-specific. However, some concepts can be shared between different output formats. The iText library, which we'll discuss below, allows some commonality between generating HTML and PDF, for example.

The advantages of object generation libraries are:

  • It's a more object-oriented approach than using JSP pages or a template language.

  • It is likely to perform well.

  • It may help to avoid problems such as typos, as complex output generated, rather than coded by developers.

  • It may support multiple output formats, hiding their details behind an abstraction layer. However, in my experience, this advantage is more theoretical than real, as different output formats don't share enough concepts to make such generalization worthwhile.

The disadvantages include:

  • Who changes the presentation? Is a Java developer required for every change? If Java resources are always required, it will be a serious problem, even if Java developers are freed of the need to handle fine markup details.

  • Problematic authoring model. How can HTML mockups, which are often produced during design of a new interface, be turned into Java code to generate it? Some solutions, such as XMLC, address this problem.

  • Many libraries are too tightly bound to HTML. What if we need to generate WML, for example? This will be a fatal problem if the generation library we're using doesn't support WML; it may call for major code changes even if it does.

  • We are inviting the central problem with HTML - the fact that, unlike, XML, it doesn't cleanly distinguish between content and presentation - right into our Java code.

  • HTML is a human-readable format. If we need to generate complex formats such as PDF, using a generation library makes sense. In the case of HTML, however, markup interspersed with a few dynamic statements - as in a well-written JSP or a template - will be more readable than Java code that calls a class library.

Probably the most highly developed object generation library was BEA's htmlKona. See http://www.weblogic.com/docs51/classdocs/API_html.html for a description of its capabilities. This was a closed-source, proprietary product bundled with WebLogic server. In WebLogic release 6, htmlKona was deprecated, in favor of JSP - an indication that the HTML generation library didn't prove a runaway success. The Jetty servlet engine also includes an HTML generation library that can be used separately. See http://jetty.mortbay.com/jetty/index.html#HTML.

Later we'll look at an example of using iText to generate PDF. This illustrates a similar authoring model to HTML generation libraries.

Important 

I dislike HTML generation libraries and can't think of a reason I would choose to use them. However, their use is compatible with good MVC design, and can be supported by our web application framework like any other view technology.

XMLC

The only way to address the most serious problems with HTML generation libraries - the need for a Java developer to make any presentational change, and the difficulty in turning an (X)HTML mockup into Java code to generate it - is to automate the generation of Java code to create or manipulate a predefined output format.

One technology to achieve this is XMLC. It was originally developed by Lutris as part of the Enhydra application server, but is now in open source. XMLC is a very different approach to view generation to any we've seen so far. XMLC preserves some of the advantages of HTML generation libraries, while almost eliminating the basic problem of creating holding template structure in Java code.

XMLC drives the generation approach from the markup. A page designer first creates a mockup site with static HTML. XMLC will "compile" the mocked up HTML pages, resulting in Java source code and/or classes. These classes, "XMLC objects", using the W3C DOM, represent the HTML content in Java, and allow programmatic manipulation of the HTML before it is output.

Content from the static mockup can be changed if it is within a tag with an id attribute. For example, a page title can be given an id attribute to allow it to be changed. When larger sections of markup need to be changed, an HTML <span> or <div> tag can be introduced to enclose it (these standard structural tags are defined in the HTML 4.0 specification). The XMLC object, and the HTML it represents, can be manipulated either through the standard DOM interfaces (which allow retrieval and modification of elements) or using convenience methods added by XMLC.

Thus Java developers fill in the blanks and add or delete context to the static templates with dynamic content. So long as the blanks don't change, the designers and Java developers can continue to work independently, with revised mockups resulting the generation of new Java objects. The HTML mockups are effectively a contract, defining the dynamic content of the view.

Thus at design time the XMLC approach involves the following steps:

  1. Create HTML content with placeholders for dynamic data

  2. "Compile" the HTML content to XMLC objects (Java classes) with XMLC

  3. Write Java code to manipulate the XMLC objects before output

At run time the XMLC approach involves the following steps:

  1. Construct a new instance of the "XMLC object" for the view in question

  2. Manipulate the state of that object, for example by adding elements, deleting elements or setting dynamic element content

  3. Use XMLC to output the object's final state to the HttpServletResponse

XMLC offers the following advantages:

  • XMLC is good at generating XML, as well as HTML.

  • XMLC is not tied to the Servlet API.

  • Prototyping is easy. Templates are pure HTML: they contain nothing to confuse a browser. XMLC allows the designer to insert mockup data, which can be excluded from the compiled class. This means that XMLC templates usually look more complete - when viewed in a browser - than templates using any of the other technologies we've discussed. For example, tables can include multiple rows of mockup data that will be replaced by real data at run time. This is a unique feature, which makes XMLC very attractive in some situations. However, there are two catches:

    • Output data displayed according to conditional logic is problematic. We can add or remove content from the generated XMLC object, but the content needs to be templated somewhere. The usual solution is to have the markup template include all conditionally output data. Data will be suppressed at run time as the conditions are evaluated. This doesn't pose a technical problem, but it does mean that templates may look nonsensical to designers and business users.

    • Static includes will not show up at design time unless the templates are served on a web server that understands server side includes.

  • XMLC will work better than other technologies with the unreadable HTML generated by many popular web authoring tools. However, the designer must be able to assign id attributes to dynamic content, and to create <span> and <div> elements as necessary. XMLC is the only technology we've looked at in which it doesn't matter if the markup is human readable.

The disadvantages of XMLC include:

  • Using the DOM API to manipulate XMLC-generated classes is clumsy. However, XMLC generates additional convenience methods to access elements that go some way towards addressing this problem.

  • The XMLC model is unusual, and doesn't share many of the concepts shared by other view mechanisms. This may make its introduction difficult in an organization, as it requires the adoption of a model that's likely to be unfamiliar.

  • The HTML templates maintained by page designers literally hold the keys to the Java code. Any change to them requires regeneration of the associated XMLC object. This is normally no problem, but if careless change deletes or corrupts the ids required by XMLC, the XMLC object will no longer work. So it's not quite magic: some care is needed in maintaining pure-HTML templates.

An XMLC Template for Our Example

The template is standard HTML, without any XMLC-specific tags. In fact, I started work on it by saving the dynamic output of the Velocity view.

The only special requirement is that elements with dynamic content must be given an id attribute, using an enclosing <span> or <div> tag if necessary. Note that the values inserted in template will be visible when the template is viewed in a browser.

The title is given an id, enabling us to append the performance name to its initial content of template text. We could also use a java.text.MessageFormat here:

    <html>    <head>    <title >Seats reserved for </title>                                                                                </head> 

With the name, date, and time of the performance we must introduce <span> elements, as there's no markup element we can manipulate like the <title> element in the opening fragment:

    <body>    <b><span >Hamlet</span>:                                                                                 <span >January 1, 1983</span>    at    <span >7:30 pm</span> 

Note that the contents of the <span> elements in the template will serve as placeholders, making the template display meaningfully in a browser. We adopt the same approach for the reservation information:

    <span >2</span>                                                                                           seats in    <span >Seat Type</span>                                                                                         have been reserved    for you for    <span >5</span>                                                                                              minutes to give you time to complete your purchase. 

Displaying the list of seat ids involves creating a template list id (the <li> tag can be given an id, so we don't need a <span> or <div> tag to enclose it). Note that I've also added two rows of mockup data, identified with a class of "mockup". These elements will help make the template's appearance in a browser realistic, but can be deleted by XMLC before the generation of the XMLC object:

    The seat numbers are:    <ul>        <li >Z1</li>                                                                                                        <li >Z2</li>        <li >Z3</li>    </ul> 

Displaying price information simply involves using <span> tags to identify potentially dynamic content. Note that we don't need to change these values: in some cases, we might be happy with the defaults, and only change them occasionally:

    The total cost of these tickets will be    <span >totalPrice</span>.    This includes a booking fee of    <span >bookingFee</span>. 

As the content displayed if the seats reserved aren't adjacent includes a nested <form> element, we must use a <div> element, rather than a <span> element, to enclose it:

    <div id ="nonAdjacentWarning">                                                                                               <b>Please note that due to lack of availability, some of the    seats offered are not adjacent.</b>    <form method="GET" action="otherDate.html">         <input type="submit" value="Try another date">    </form>    </div>                                                                                                                    

The only remaining dynamic data is the URL of the seating plan image. We give this element an id to allow manipulation, and give it a relative URL that will enable the template to display in a browser:

    <img alt="Seating plan"       src="/books/1/392/1/html/2/../../static/seatingplans/1.jpg" /> 

This certainly separates template from Java code. The best thing about the whole process is that this HTML template looks exactly like the dynamically generated page, unlike any template we've seen. The list of seat names is populated with dummy entries, while other dynamic content has placeholder values. The only snag is the inclusion of the non-adjacent seating warning, which won't appear on most pages (we'll have to remove the unwanted branch programmatically at runtime). The following screenshots displays this template in a browser:

click to expand

Compiling the Template

Before we can write Java code to implement the "Show Reservation" view, we need to generate an XMLC object. We can run the xmlc command shipped with XMLC, but I've chosen to use Ant to make the task repeatable. As only a single HTML file in the sample application is compiled using XMLC, I've hard-coded its name. However, it would be easy to make the Ant target more sophisticated:

    <target name="xmlc">      <java>         classname="org.enhydra.xml.xmlc.commands.xmlc.XMLC"         fork="yes">      <classpath>        <fileset dir="${lib.dir}">          <include name="runtime/xmlc/*.jar"/>        </fileset>      </classpath>      <arg value="-keep"/>      <arg value="-nocompile"/>      <arg value="-dump"/>      <arg value="-ssi"/>      <arg line="-sourceout src"/>      <arg line="-delete-class mockup"/>      <arg line="-class       com.wrox.expertj2ee.ticket.web.xmlc.generated.ShowReservationXmlcObject"/>      <arg value="war/WEB-INF/xmlc/showReservation.html"/>                                                                         </java>    </target> 

The most interesting content is in the flags to XMLC:

  • The -keep flag tells XMLC not to delete the Java source code (it defaults to leaving only a .class file).

  • The -nocompile flag tells XMLC not to compile the generated source file. We choose to make this part of our build process, rather than the XMLC compilation process.

  • The -dump flag tells XMLC to display the structure revealed by its analysis of the HTML input. This can be useful if XMLC doesn't generate the convenience setter methods we expect.

  • The -ssi flag tells XMLC to process server-side includes (it doesn't by default).

  • The -sourceout flag tells XMLC where to put the generated Java class. We choose to put it in our /src directory, along with our own classes.

  • The -delete-class flag tells XMLC to delete elements with class mockup. This will delete the dummy list data we included in the template to make it appear more realistic when viewed in a browser.

  • The -class flag specifies a fully qualified name for the Java class (the default is to generate a class with the same name as the template, in the default package).

  • The last value is the path to the template.

When this is complete we should have a class called com.wrox.expertj2ee.ticket.web.xmlc.generated.ShowReservationXmlcObject, which is the Java representation of the template HTML. We won't edit this class, but we will use its methods to manipulate its state. If generated XMLC objects are placed along with ordinary source code where an IDE can find them, an IDE should be able to provide context help on their methods, which is likely to prove very useful.

Manipulating the XMLC Object Generated from the Template

Let's now look at implementing the com.interface21.web.servlet.View interface for XMLC.

In the XMLC object, as with a code generation library, we need a distinct Java object for each view. At runtime the HTML template is no longer required, but we need one view implementation for each XMLC-generated view.

We don't need to start from scratch. Our MVC framework provides a convenient superclass for XMLC views - com.interface21.web.servlet.view.xmlc.AbstractXmlcView - which uses the template method design pattern to conceal the necessary plumbing from subclasses and leave them only the task of creating manipulating the relevant XMLC object. Subclasses need to implement only the following protected method:

    protected abstract XMLObject createXMLObject(        Map model,        HttpServletRequest request,        HttpServletResponse response,        XMLCContext context)        throws ServletException; 

Like most XMLC view subclasses, the concrete implementation that we use in the sample application doesn't expose any bean properties. Thus the entire bean definition in /WEB-INF/classes/views.properties is as follows:

    showReservation.class=      com.wrox.expertj2ee.ticket.web.xmlcviews.ShowReservationView 

Note 

See Appendix A for information on installing and configuring XMLC, and a description of the implementation of the com.interface21.web.servlet.view.xmlc.AbstractXmlcView framework class.

Now let's move to our specific example, com.wrox.expertj2ee.ticket.web.xmlcviews.ShowReservationView. We begin by extending AbstractXmlcView:

    public class ShowReservationView extends AbstractXmlcView { 

There are no bean properties, and don't need to provide a constructor. We implement the required protected abstract method as follows:

    protected XMLObject createXMLObject (        Map model,        HttpServletRequest request,        HttpServletResponse response,        XMLCContext context)        throws ServletException { 

We begin by constructing a new XMLC object. We can do this with a no-argument constructor, but it's more efficient to use the XMLC context argument to provide an object:

    ShowReservationXmlcObject showReservationXmlcObject =     (ShowReservationXmlcObject) context.getXMLCFactory().create(       ShowReservationXmlcObject.class); 

We now extract our model objects from the map, so we perform type casts once only:

    Reservation reservation = (Reservation)      model.get(TicketController.RESERVATION_KEY);    Performance performance = (Performance)      model.get(TicketController.PERFORMANCE_KEY);    PriceBand priceBand = (PriceBand)      model.get(TicketController.PRICE_BAND_KEY); 

Next we use similar code to that we've seen before to use standard Java internationalization support to format dates and currency amounts, based on the request locale:

    SimpleDateFormat df = (SimpleDateFormat)      DateFormat.getDateInstance(DateFormat.SHORT, request.getLocale()) ;    df.applyPattern("EEEE MMMM dd, yyyy");    String formattedDate = df.format (performance.getWhen());    df.applyPattern("h:mm a");    String formattedTime = df.format(performance.getWhen());    NumberFormat cf = NumberFormat.getCurrencyInstance(request.getLocale());    String formattedTotalPrice = cf.format(reservation.getTotalPrice());    String formattedBookingFee =      cf.format(reservation.getQuoteRequest() .getBookingFee()); 

Now we can begin modifying dynamic content in the elements with an id attribute. XMLC spares us the ordeal of using DOM to do this, as it generates convenience manipulation methods. Setting dynamic text is very easy:

    showReservationXmlcObject.setTextTitle(      showReservationXmlcObject.getElementTitle().getText() + " " +        performance.getShow().getName());    showReservationXmlcObject.setTextPerformanceName(      performance.getShow().getName());    showReservationXmlcObject.setTextSeatsRequested("" +      reservation.getSeats().length);    showReservationXmlcObject.setTextSeatType(priceBand.getDescription());    showReservationXmlcObject.setTextMinutesHeld("" +      reservation.getMinutesReservationWillBeValid());    showReservationXmlcObject.setTextDate(formattedDate);    showReservationXmlcObject.setTextTime(formattedTime);    showReservationXmlcObject.setTextTotalPrice(formattedTotalPrice);    showReservationXmlcObject.setTextBookingFee(formattedBookingFee); 

To build the list of seat names, we need to obtain the prototype list item, clone it for each row of data in our model, and then delete the prototype row itself. This is a very different approach to any we've seen. It's not difficult, but it isn't particularly intuitive:

    // Get template node for seat list    HTMLElement seatEle = showReservationXmlcObject.getElementSeat();    for (int i = o; i < reservation.getSeats().length; i++) {      showReservationXmlcObject.setTextSeat(        reservation.getSeats() [i].getName());      seatEle.getParentNode().insertBefore (seatEle.cloneNode (true), seatEle);    }    // Remove template node seatEle.getParentNode() .removeChild(seatEle); 

However, remember that this part of the XMLC authoring process is performed by Java developers, not markup developers (who are done when they've provided mockup HTML). So it's safe to assume the necessary programming skills. Remember that the "mockup" list data elements were ignored when XMLC generated a Java object from the HTML template:

We handle the conditional display of the adjacent seats warning by deleting this element if it's not needed:

    if (reservation.getSeatsAreAdjacent()) {      Element adjacentWarning =        showReservationXmlcObject.getElementNonAdjacentWarning();      adjacentWarning.getParentNode() .removeChild(adjacentWarning);    } 

Finally we obtain the <img> element that displays the seating plan graphic and set its source URL, before returning the configured XMLC object for the superclass to use to build the response:

    HTMLImageElement graphicEle = (HTMLImageElement)      showReservationXmlcObject.getElementSeatingPlanImg();    graphicEle.setSrc("static/seatingplans/" +      performance.getShow() .getSeatingPlanId() + ".jpg");    return showReservationXmlcObject;    } 
Important 

XMLC offers a very different way of separating presentation template from dynamic code to most view technologies. Its strengths are that the standard-HTML templates it works with can display in a browser exactly as they will appear at runtime, populated with dynamic data; and that it can cope with HTML that isn't human-readable. However, it requires an additional "compilation" step in the development process and requires a greater learning effort than simpler technologies such as Velocity.

Further Reading on XMLC

See the following resources for further information about XMLC:

  • http://xmlc.enhydra.org/software/documentation/xmlcSlides/xmlcSlides.html: A simple introduction to XMLC

  • http://staff.plugged.net.au/dwood/xmlc-tutorial/index.html: The XMLC Tutorial

  • http://xmlc.enhydra.org/software/documentation/doc/xmlc/user-manual/index.html: The XMLC user manual

  • http://www.java-zone.com/free/articles/Rogers01/Rogers01-1.asp: Overview of XMLC and comparison with JSP



Expert One-on-One J2EE Design and Development
Microsoft Office PowerPoint 2007 On Demand
ISBN: B0085SG5O4
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net