Cocoon Documentation

# Dynamic XML in Cocoon

# Introduction

Web publishing is very limited without the ability to create dynamic content. By dynamic XML we mean the content that is created as a function of request parameters or state of the requested resource. For this reason, a lot of work and design has been put into Cocoon to allow dynamic XML content to be generated.

# The Servlet/JSP model

People are used to writing small Java programs to create their dynamic web content. Servlets, and Java in general, are very powerful, easy to write and fast to debug, but they impose (like any other pure-logic solution) a significant management cost. This is due to the fact that programmable components like servlets must include both the logic to generate the dynamic code as well as all static elements (such as static content and style). The need for a more useful solution soon appeared.

To fill the gap between Java programmers and web engineers (groups that rarely overlap), Sun proposed the Java Server Pages (JSP) specification, a markup language (today with both SGML and XML syntax) that allows web engineers to include code in their pages, rather than include pages in their code. The impact of this strategy was significant: servlets were written directly in Java code if very little static content was to be used, otherwise JSP or other compiled server pages technologies were used.

This said, it would seem that using servlets/JSPs to create dynamic XML content would be the perfect choice. Unfortunately, design issues indicate that we should take a second look at the technology, and understand why this isn't so.

# Servlet Chaining Vs. Servlet Nesting

Java Servlets were introduced by the Java Web Server team as a way to allow users to create their own web plug-ins. They were designed to handle the HTTP protocol and all possible dynamic web content (including HTML, XML, images, etc. - both text and binary streams). Unfortunately, the need for a componentized request handler was not taken into serious consideration in the design phase but only later, when at an implementation phase.

In fact, the Java Web Server provided the ability to chain multiple servlets, one becoming the filter of the other. Unfortunately, since the API doesn't include such a possibility in its design, such a servlet chain is very limited in its behavior and puts significant restrictions on the API use. Something that forced the Servlet API architects to come up with better solutions.

The solution was servlet nesting: the ability for a servlet to include another servlet's output inside its own transparently. This allowed programmers to separate different logic on different servlets, thus removing the need for servlet chaining.

# The limitations of Servlet Nesting

While servlet nesting was a major advantage over servlet chaining because it allowed servlets to be somewhat modular without losing the full API power, a common design pattern applies to the Servlet model in general: no servlet is allowed to modify the output of another servlet. This holds true for all servlet API versions up to today (version 2.2).

This limitation is the key: if no further XML processing is needed on the server side, using servlets/JSP for creating XML is a perfect choice, but if this output requires some server side processing (for example XSLT transformations), the Servlet API does not allow another servlet to post-process it's output. This other servlet is, in our case, Cocoon.

In a few words, the Servlet API doesn't support Servlet Piping.

# The Cocoon Model

Rather than turning Cocoon into a servlet engine, thus limiting its portability, this document outlines some solutions that allow Cocoon users to get the servlet-equivalent functionality with internal Cocoon design ideas.

The Cocoon processing model is based on the separation of

- Production - where XML content is generated based on Request parameters (servlet equivalent)
- Processing - where the produced XML content is transformed/evaluated
- Formatting - where the XML content is finally formatted into the desired output format for client use.

This separation of working contexts allows Cocoon users to implement their own internal modules to add the functionality they require to the whole publishing system. In fact, while a few of these components are already shipped with Cocoon, the highly modular structure allows you to build your own to fit your particular needs.

# Writing Producers

Producers initiate the request handling phase. They are responsible for evaluating the HttpServletRequest parameters provided and create XML content that is fed into the processing reactor. Servlet logic should be translated into a producer if the request parameters can be used directly to generate the XML content (for example the FileProducer which loads the requested file from disk).

Here follows the code for an example producer distributed with Cocoon:

    public class DummyProducer
      extends AbstractProducer
      implements Status
    {

      String dummy = "<?xml version=\"1.0\"?>"
          + "<?cocoon-format type=\"text/html\"?>"
          + "<html><body>"
          + "<h1 align=\"center\">"
              + "Hello from a dummy page"
          + "</h1>"
          + "</body></html>";

      public Reader getStream(HttpServletRequest request)
        throws IOException
      {
        return new StringReader(dummy);
      }

      public String getPath(HttpServletRequest request) {
        return "";
      }

      public String getStatus() {
        return "Dummy Producer";
      }
    }

The key method is `getStream()` which is responsible for processing the given servlet request and provide a Reader for reading the generated XML document.

Note that AbstractProducer has also another method, `getDocument(request)`, which is responsible for directly returning a DOM tree. In case you need to render your servlet code Cocoon-aware, the above example should tell you what to do.

Please look at the shipped producers' source code for example code and look at the user guide for how to install and use your own producers.

# Writing Processors

If your servlet needs many parameters to work, it is more reasonable that you write a Processor instead. A Processor transforms a given XML document (which, in this case should contain the needed static parameters) into something else, driven both by the input document and by the request object which is also available.

Here is a simple processor example that should show you what the above means. Suppose you have the following document as input (note that it may have been produced from a file, from other sources or dynamically - see the above paragraph):

    <?xml version="1.0"?>
    <page>
     <p>Current time is <time/></p>
    </page>

Our simple example processor will look for the <time/> tags and will expand them to the current local time, creating this result document:

    <?xml version="1.0"?>
    <page>
     <p>Current time is 6:48PM</p>
    </page>

Please look at the shipped processors' source code for example code and look at the user guide for how to install and use your own processors.

# Using Cocoon processors

The above example shows a very simple situation but needs non-trivial code to implement it. For this reason, the Cocoon distribution includes a number of processors that implement common needs and situations. These are:

- The XSLT processor - Applies XSLT transformations to the input document. XSLT allows you to solve your transformation needs as well as simple tag evaluation/processing due to its extensible and programmable nature. XSLT is a W3C Recommendation.
- The XSP processor - Evaluates XSP pages and compiles them into producers. This processor allows you include programmatic logic into your pages as well as to separate the logic from the content. See the XSP user guide for more information. Note that the XSP Processor assumes that it is getting its input from a static file, so it will not work well with pre-processing. Its design means that it should really have been a Producer in the first place, instead of a Processor. This change has been made in Cocoon 2.
- The DCP processor (Deprecated) - Evaluates XML processing instructions with multi-language (Java and EcmaScript) logic. This processor allows you to do programmatic substitution and inclusion eliminating the need for complex processing logic. See the DCP user guide for more information. Note: This is deprecated - users are advised to use the more powerful XSP processor instead.
- The SQL processor (Deprecated) - Evaluates simple tags describing SQL queries to JDBC drivers and formats their result-set in XML depending on given parameters. See the SQL processor user guide for more information. Note: This is deprecated - users are advised to use the XSP SQL taglib, or the more powerful Extended SQL taglib instead. The latter (ESQL taglib) allows easy post-processing of output within XSP, amongst other things, whilst the former taglib is mainly provided for backward compatability.
- The LDAP processor - the LDAP processor that evaluates simple tags describing LDAP queries to directory services and formats their result-set in XML depending on given parameters. See the LDAP processor user guide for more information.

Copyright © 1999-2001 The Apache Software Foundation.
All rights reserved.