XSP Internals
http://xml.apache.org/http://www.apache.org/http://www.w3.org/

Main
User Documentation

XSP
Overview
XSP Guide
XSP Internals
XSP Logicsheets
Sessions

Logicsheets
Request
Session
ESQL
Forms

Index

This document presents Apache Cocoon's dynamic markup language framework and its use in implementing XSP:

Markup-to-code Transformation

XSP is based on a general-purpose markup-to-code transformation engine built around three key abstractions:

  • Dynamic Markup Language. An namespace-qualified XML vocabulary providing code embedding directives. An associated dynamic markup language processor transforms static markup interspersed with code embedding directives into an equivalent source program string written in a target programming language. Upon execution, the generated program will rebuild the original XML document as augmented by dynamic content emitted by the embedded code.
  • Programming Language. A procedural language in which the dynamic markup processor generates source code from an input XML document. Its associated programming language processor is responsible for compiling, loading and executing the generated code within the boundaries of its calling environment.
  • Program Generator. A component that integrates markup and programming language processors to build and execute markup-generating programs derived from XML documents. Beyond this "glue" role, this component is responsible for persistently storing generated programs as well as automatically rebuilding them should their source XML documents change on disk after program generation.

Note Despite its particular usage for XSP, ProgramGenerator is not restricted to run in a server pages environment.

XSP and Cocoon Generators

As a rule, XSP pages are translated into Cocoon Generator's.

Server Pages Generator Proxy

Generator's created by XSP are invoked exclusively through ServerPagesGenerator, a proxy that uses Cocoon's ProgramGenerator component to load pages and subsequently delegates actual SAX event generation to them.

Note The terms Generator and ProgramGenerator are somewhat confusing. Here, Generator refers to a Cocoon org.apache.cocoon.generation.Generator instance responsible for the initial feeding of Cocoon's SAX pipeline. ProgramGenerator, on the other hand, refers to a Cocoon component responsible for building and executing programs derived from XML documents containing dynamic markup: org.apache.cocoon.components.language.generator.ProgramGenerator

ServerPagesGenerator attempts to cope with a not unlikely possibility: premature termination of proxied generator execution. "Premature" here means that the invoked generator may return after starting one or more SAX events but without properly ending them.

While this not an expected scenario in "manual" SAX programming, server pages may well need to terminate in the middle of document production:

  <page>
    <title>For Your Eyes Only</title>

    <xsp:logic>
      if (!request.getParameter("pet").equals("Cheetah")) {
        <p>
          Hey, you're not Tarzan!
        </p>

        /*** Unclosed SAX events here! ***/
        return;
      }
    </xsp:logic>
    <!-- Multi-racial Jane affair description follows -->
    . . .
  </page>

The server pages generator proxy is defined in the sitemap as follows:

. . .
<map:generator
  name="serverpages"
  src="org.apache.cocoon.generation.ServerPagesGenerator"/>
. . .
<map:pipelines>
  <map:pipeline>
    . . .
    <map:match pattern="/samples/*.xsp">
      <map:generate type="serverpages" src="../samples/documents/{1}.xsp">
        <!--
          <parameter name="markup-language" value="xsp"/>
          <parameter name="programming-language" value="java"/>
        -->
      </map:generate>
      <map:transform type="xslt" src="../samples/stalemates/simple-page.xsl"/>
      <map:serialize type="html" mime-type="text/html"/>
    </map:match>
    . . .
  </map:pipeline>
</map:pipelines>

Note that parameters markup-language and programming-language default to xsp and java respectively.

The complete XSP sitemap configuration is explained below.

XSP Generators and Compiled Languages

For the Java language (and other compiled languages like Rhino Javascript), XSP pages are translated into classes extending AbstractServerPage . This class, in turn, extends ComposerGenerator , which gives it access to commonly used components such as parser or cocoon itself (typically used as EntityResolver for request URI's).

AbstractServerPage implements org.apache.arch.Modifiable. This is tested by ProgramGenerator to assert whether the page has been invalidated as a result of files it depends on having changed on disk. These files are typically logicsheets and template files included by means of XInclude.

Note As of this writing, XInclude support is still unimplemented but will be based on Donald Ball's (possibly extended) XIncludeTransformer.

AbstractServerPage implements Modifiable by means of two static variables: dateCreated and dependencies (a, possibly empty, array of File's pointing to logicsheets and other files included during the code generation stage).

AbstractServerPage also provides a boolean hasContentChanged() method that is tested by ServerPagesGenerator to assert whether dynamic content should not be regenerated for a given request. The default implementation unconditionally returns true, but can be overridden by XSP pages based on their interpretation of the Cocoon request object. This is an experimental feature that will become meaningful only when a SAX-event caching mechanism is added to Cocoon.

Finally, AbstractServerPage also provides a number of utility methods used to shorten the generation of SAX events not requiring a namespace.

The Programming Language Processor

A Cocoon's ProgrammingLanguage processor exposes the following methods:

  • load. Load a program from a file in a given directory, compiling it, if necessary, using a given encoding.
  • instantiate Create a new instance of a previously loaded program
  • unload Discard a previously loaded program performing any necessary cleanup
  • getSourceExtension Return the canonical source file extension used by this programming language
  • getCodeFormatter Return an (optional) instance of CodeFormatter used to beautify source code written in this programming language
  • quoteString Escape a string constant according to the programming language rules

A default implementation ( AbstractProgrammingLanguage ) is provided that extends org.apache.arch.named.AbstractNamedComponent and retrieves language-related sitemap parameters.

Filenames and Encoding

load and unload are passed a file/directory pair used to locate the program.

The baseDirectory should be an absolute pathname pointing to the top-level directory (also known as repository) containing the program file.

The filename is a path, relative to the baseDirectory, pointing to the program file.

Source program filenames are built by concatenating the repository's baseDirectory name, the given filename, the dot extension separator and the language-specific source or object extensions. The cross-platform File.separator is used to ensure portability.

Note The filename must not contain any source or object extension. It may, though, contain subdirectories depending on its position within the repository tree. Also, programming languages must define a source extension even when their actual compilers/interpreters do not enforce this. This is also true of object extensions for compiled languages. Furthermore, the dot character is always used as the extension separator.

Finally, the (optional) encoding argument specifies the how the source program file contents are encoded. This argument can be null to specify the platform's default encoding.

Loading Programs

Currently, programs returned by the load operation are "plain" Java Object's and are not required to implement any interface or to extend any particular class.

Note This may change in the future so that the loaded program may be required to provide dependency information (for automatic reloading) as well as source code information (for debugging purposes).

Compiled programs attempt to locate the object program first. If found, it's loaded in a language-specific way and then returned to the calling environment. Failing that, the source file is located and the language-specific compiler is invoked prior to actual program loading.

Of course, it is an error for the source program file not to exist as a readable, regular operating system file.

Unloading Programs

When a previously loaded program is no longer needed (or becomes "outdated" as explained below) the language processor may need to perform cleanup actions, such as releasing memory or (in the case of Java-like compiled languages) reinstantiating the class loader.

Loaded programs may become outdated as a consequence of events external to the programming language processor. In a server pages environment, this is the result of the source XML document (or any of the files it depends on) having changed on disk.

The base class AbstractProgrammingLanguage implements this method as final to delete the unloaded source program file and delegate actual unloading to method doUnload.

Method doUnload is not defined as abstract in order to relieve interpreted subclasses from having to implement an empty method when no cleanup is required.

Note Currently, only the program object is being passed to unload. It may be possible for some interpreted languages to also require knowing what file the program was originally loaded from. In this case, instantiation should take place through the program object itself, rather than through the language processor (see Program Instantiation below)

Instantiating Programs

The program object returned by load must act as an factory capable of creating program instance objects on demand.

Currently, instantiation is performed by the language processor given a previously loaded program.

Compiled programs use a language-specified class loader to create a new program instance.

Note For compiled languages, it is possible to guarantee that a generated program implements a given interface or extends a given class. For interpreted languages, though, it may be necessary to pass an additional prototype object to load as to ensure that created instances conform to a given Java type expected behavior.

Source Extensions

All languages are required to return a source extension. This extension is used to locate source files for subsequent interpretation or compilation.

Code Formatting

Programming languages may provide a CodeFormatter instance used by code generators to beautify source code.

Interface CodeFormatter exposes a single method: formatCode. formatCode takes as arguments a String containing the source code to be beautified and an encoding to be preserved during string conversions.

Code formatters can be associated with a programming language by specifying a code-formatter parameter in its sitemap configuration:

<parameter name="code-formatter"
  value="org.apache.cocoon.components.language.programming.java.JstyleFormatter"/>

Note Currently, Jstyle is being used for Java source formatting. This open source project appears to be stagnated and lacks advanced formatting options present in other (unfortunately, not open-sourced) products like Jindent .

String Quoting

Method quoteString applies the programming language string constant escaping rules to its input argument.

This method exists to assist markup language code generators in escaping Text XML nodes.

Compiled Languages

Compiled languages extend the ProgrammingLanguage abstraction by introducing the notions of compilation and object extension.

A base implementation (CompiledProgrammingLanguage) is provided that adds the following protected variables and abstract/overridable methods:

  • Variable compilerClass. Used to create instances of the language's compiler.
  • Variable deleteSources. Used to state whether intermediate source files should be deleted after successful compilation
  • Method getObjectExtension. Used to build object filenames
  • Method loadProgram. Used to perform actual program load after source and (possibly) object files have been located
  • Method doUnload. Used to perform cleanup after program unloading

Note Object files are not required to be Java class files. It's up the the compiled programming language processor to handle object files.

Compiled programming languages must specify their preferred compiler as a sitemap parameter:

<component-instance name="java"
  class="org.apache.cocoon.components.language.programming.java.JavaLanguage">
  . . .
  <parameter name="compiler"
    value="org.apache.cocoon.components.language.programming.java.Jikes"/>
  . . .
</component-instance>
Object Extensions

All compiled languages are required to return a source extension. This extension is used to locate object files for subsequent loading.

Object Program Loading

Concrete compiled programming languages must implement the abstract method loadProgram to actually load an object program resulting from compilation.

Program Compilation

Compilation is delegated to a sitemap-specified LanguageCompiler instance, as explained below.

Compilers

Interface LanguageCompiler defines the initialization and behavior for all compilers.

Methods exposed by this interface are:

  • setFile. Used to specify the source file to be compiled. This should be an absolute filename
  • setSource. Used to specify the directory where dependent source files (if any) are stored
  • setDestination. Used to specify the directory where the generated object files should be placed
  • setClasspath. Used to specify the class loading path used by the compiler. While this option is named after Java's classpath system variable, its semantics are language-independent
  • setEncoding. Used to specify the encoding used by the input source file
  • compile. The compiler's workhorse (boolean)
  • getErrors. Used to retrieve a list of compilation error messages should compilation fail
Compiler Errors

Error message producer by the compiler must be collected and massaged by the LanguageCompiler in order to wrap each of them as a CompilerError instance.

Class CompilerError exposes the following methods:

  • getFile. Returns the program filename originating the error
  • isError. Asserts whether the error is a server error or simply a warning
  • getStartLine. Returns the starting line of the offending code
  • getStartColumn. Returns the starting column (within the starting line) of the offending code
  • getEndLine. Returns the ending line of the offending code
  • getEndColumn. Returns the ending column (within the ending line) of the offending code
  • getMessage. Returns the actual error message text
Java Compilers

For the Java language, 2 pluggable compilers are available:

  • Javac. A wrapper to Sun's builtin compiler
  • Jikes. A wrapper to IBM's Jikes compiler

Both of these compilers are based on AbstractJavaCompiler.

Other Compilers

Since Rhino Javascript provides its own, only compiler (jsc), class JavascriptLanguage doesn't use the compiler class initialized by CompiledProgrammingLanguage.

Object Program Unloading

CompiledProgrammingLanguage extends the default implementation provided by AbstractProgrammingLanguage by deleting the object program file and delegating actual unloading to the doUnload method.

Method doUnload provides an empty default implementation that can be overridden by derived compiled languages should unloading cleanup be actually required.

For Java-based compiled languages (i.e., those using class files as their object format, unloading implies reinstantiating their class loader such that it "forgets" about previously loaded classes thus becoming able to refresh class files updates since their last load.

This is a commonly-used workaround for the (somewhat buggy) standard Java class loader, which doesn't provide for an explicit method for reloading class files.

The Cocoon Class Loader

To circumvent standard Java class loaders limitation, Cocoon provides a simple customized class loader (RepositoryClassLoader) that features:

  • A directory-based extensible classpath that can grow at execution time
  • Class reloading by means of reinstantiation

RepositoryClassLoader extends java.lang.ClassLoader adding an addDirectory method that adds the directory pointed to by its String argument to its local classpath.

Access to protected RepositoryClassLoader class is proxied through interface ClassLoaderManager. This interface exposes the following methods:

  • addDirectory. Passed to the proxied RepositoryClassLoader
  • loadClass. Passed to the proxied RepositortyClassLoader
  • reinstantiate. Used to discard the previous class loader and create a new one

Class ClassLoaderManagerImpl implements ClassLoaderManager in a singleton-like fashion that ensures that only one instance of this class loader exists, thus ensuring the reinstantiation mechanism works properly.

The class loader can be specified in the sitemap on a per-language basis:

<component-instance name="java"
  class="org.apache.cocoon.components.language.programming.java.JavaLanguage">
  . . .
  <parameter name="class-loader"
    value="org.apache.cocoon.components.classloader.ClassLoaderManagerImpl"/>
</component-instance>

Alternatively, the class loader can be specified in the sitemap as a global component:

<component
  role="class-loader"
  class="org.apache.cocoon.components.classloader.ClassLoaderManagerImpl"/>
Interpreted Languages

Interpreted languages for which a Java-based interpreter exists are supported by means of IBM's outstanding Bean Scripting Framework (BSF).

Currently, BSF supports:

  • Mozilla Rhino
  • NetRexx
  • Jacl
  • JPython
  • VBScript (Win32 only)
  • JScript (Win32 only)
  • PerlScript (Win32 only)
  • BML (Not applicable to server pages)
  • LotusXSL (Not applicable to server pages)

Note Interpreted language support is still unimplemented!
While BSF is extremely easy to use and very stable, there's still a challenge in writing code-generation logicsheets for each of this languages; this task requires familiarity with XSP internals, XSLT and, above all, the programming language at hand...

Note Despite being supported by BSF, Rhino Javascript is separately supported by Cocoon as a compiled language in order to take advantage of automatic class reloading and persistent class file storage.

Note Since ProgramGenerator clients will typically require that program instances implement a given interface or extend a given class, method instantiate in interface ProgrammingLanguage may need to be augmented with a prototype interface that can be used by each language processor to ensure that the program instance can act as a Java object of the given type.

The Markup Language Processor

A Cocoon's MarkupLanguage processor exposes the following methods:

  • getEncoding. Return the encoding to be used in program generation and compilation or null to use the platform's default encoding
  • generateCode. Given a DOM Document written in a given markup language, generate an equivalent program in a given programming language)

A base markup language processor implementation is provided in class AbstractMarkupLanguage. This class extends org.apache.arch.named.AbstractNamedComponent to set the markup language's associated namespace using the following required parameters:

  • prefix. The markup language's namespace prefix
  • uri. The markup language's namespace URI
<component-instance name="xsp"
  class="org.apache.cocoon.components.language.markup.xsp.XSPMarkupLanguage">
  <parameter name="prefix" value="xsp"/>
  <parameter name="uri" value="http://xml.apache.org/xsp"/>
</component-instance>

AbstractMarkupLanguage adds a number of abstract/overridable methods that must be implemented by concrete markup language processors:

  • preprocessDocument. Augment the input DOM Document to prepare it for simpler, faster logicsheet-based code generation
  • getLogicsheets. Return the list of logicsheets declared in the input document according to the syntax of the markup language at hand
  • addDependency. Add a dependency on an external file. This is used to inform the concrete markup language processor about XML documents included by means of XInclude as well as any intervening logicsheet

Note AbstractMarkupLanguage is currently tied to logicsheets as the only means of generating source code. While logicsheets provide a very powerful means for code generation, good design dictates that the actual code generation mechanism should be decoupled from the dynamic markup language abstraction.

Note The current code generation strategy is DOM-based. In principle, this is adequate because document preprocessing may need random access to document nodes. Code generation is being reconsidered, however, to overcome this and make it possible to reuse Cocoon's SAX-based filtering pipeline.

Markup Encoding

All markup languages must provide a way to declare the XML document's encoding so that it is preserved during code generation, beautifying and compilation.

This is required for proper i18n support, where the default encoding usually replaces "exotic" characters with question marks.

Note Ideally, it should be possible to determine the source XML document's encoding from its declaring <?xml?> processing instruction. Unfortunately, XML parsers (both DOM and SAX) don't seem to provide access to it, thus forcing server pages authors to redundantly specify it.

The Logicsheet class

A logicsheet is an XML filter used to translate user-defined dynamic markup into equivalent code embedding directives for a given markup language.

Logicsheets lie at the core of XSP's promise to separate logic from content and presentation: they make dynamic content generation capabilities available to content authors not familiar with (and not interested in) programming.

For a detailed description of logicsheets, see Logicsheet Concepts.

Logicsheets are represented in class Logicsheet. This class exposes the following methods:

  • setInputSource. Set the InputSource pointing to the XSLT stylesheet to be used for dynamic tag transformation
  • apply. Apply the stylesheet to a given document

Logicsheet takes care of preserving all namespaces defined in the input document. This is necessary when multiple logicsheets are applied and multiple namespaces are used in the input document.

Note Currently, Logicsheet is a concrete class. It should be redefined as an interface in order to decouple it from the use of XSLT stylesheets. Again, while stylesheets are the "obvious" way to implement logicsheets, a user-supplied XML filter may also be used in some cases. The current implementation uses an ugly hack where a Xalan stylesheet processor is used to perform the transformation without an intervening stylesheet processor wrapping abstraction.

Named Logicsheets

As explained in Logicsheet Concepts, logicsheets are typically associated with a single object type whose methods it wraps to make them available as markup commands.

Markup commands related to a given object type are grouped under a single namespace.

Class NamedLogicsheet extends Logicsheet to associate it with a namespace. This class exposes the following additional methods:

  • setPrefix. To set the logicsheet's namespace prefix
  • getPrefix. To retrieve the logicsheet's namespace prefix
  • setUri. To set the logicsheet's namespace URI
  • getUri. To retrieve the logicsheet's namespace URI

Named logicsheets are used as builtin logicsheets by AbstractMarkupLanguage to preload logicsheets and make them accessible to dynamic XML documents without explicit declaration.

This feature relieves page authors from the need to explicitly declare commonly used logicsheets in their documents. Builtin logicsheets are automatically applied if the document declares their same namespace URI.

Note The current AbstractMarkupLanguage implementation wrongly binds named logicsheets based on their namespace prefix instead of their URI!

Logicsheet Code Generators

Logicsheets translate dynamic tags to equivalent code-embedding directives expressed in the markup language at hand. They do not, however, actually emit the final source code program.

Code generation as such (i.e., the final production of a string containing a source program written in a programming language) is the responsibility of class LogicsheetCodeGenerator.

Class LogicsheetCodeGenerator exposes the following methods:

  • addLogicsheet. Add a logicsheet to the generator's logicsheet list. Logicsheets are applied in the order of their addition.
  • generateCode. Return a string containing a source program resulting from successively applying added logicsheets.

Though "regular" logicsheets as such do not emit source code, LogicsheetCodeGenerator expects its last stylesheet to produce a single element containing only a text node.

This final, programming language-specific logicsheet is responsible for actually expanding code-embedding directives into source code.

For each supported target programming language, markup languages must provide a core logicsheet.

Note LogicsheetCodeGenerator is currently implemented as a class. It should be defined as an interface in order to the decouple the code generator abstraction from its logicsheet-based implementation. This would allow for alternative code-generation strategies to be plugged.

Markup Language Definition

Markup languages are defined in the sitemap as follows:

<component-type name="markup-language">
  <component-instance name="xsp"
    class="org.apache.cocoon.components.language.markup.xsp.XSPMarkupLanguage">
    <parameter name="prefix" value="xsp"/>
    <parameter name="uri" value="http://xml.apache.org/xsp"/>

    <target-language name="java">
      <parameter name="core-logicsheet"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/xsp.xsl"/>

      <builtin-logicsheet>
        <parameter name="prefix" value="xsp-request"/>
        <parameter name="uri" value="http://xml.apache.org/xsp/request/2.0"/>
        <parameter name="href"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/request.xsl"/>
      </builtin-logicsheet>

      <builtin-logicsheet>
        <parameter name="prefix" value="xsp-response"/>
        <parameter name="uri"
          value="http://xml.apache.org/xsp/response/2.0"/>
        <parameter name="href"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/request.xsl"/>
      </builtin-logicsheet>
    </target-language>
  </component-instance>
</component-type>

Here, the markup language prefix and uri are defined together with one or more supported programming languages.

For each supported programming language, a corresponding core logicsheet is defined as a URL pointing to its code-generation stylesheet.

Optionally, each supported programming language may define one or more namespace-mapped builtin logicsheets.

The XSP Markup Language

So far, programming and markup languages have been described in general, without explicitly referring to the XSP language.

This section describes how the above described framework is used to implement XSP in particular. For a description of logicsheet authoring requirements for XSP in Java, see XSLT Logicsheets and XSP for Java.

Note The XSP syntax is being revised to allow for the omission of the root <xsp:page> element. This is convenient for the (typical) case in which all logic has been conveniently placed in logicsheets so that XSP pages do not need to embed any code. In this case, there should be no need for the <xsp:page> element.

Markup Encoding

Method getEncoding is implemented by class XSPMarkupLanguage by retrieving the attribute named encoding in the root <xsp:page> element.

Note In absence of a <xsp:page> root element, the encoding will be retrieved from an attribute named xsp:encoding present in the "user" root element.

Document Preprocessing

XSPMarkupLanguage preprocesses its input document by:

  • Setting the root element file-name attribute to the base filename of its input source.
  • Setting the root element file-path attribute to the base directory name of its input source.
  • Setting the root element creation-date attribute to the current system time
  • Escaping text nodes according to the rules dictated by the target programming language. This excludes text nodes enclosed in <xsp:logic> and <xsp:expr> elements, as they are to be output as code.

Note A feature to be added is collecting all text nodes under the document's root element and replacing them by references to their relative index position. This will allow for the generation of contentHandler.characters method calls that reference char arrays instead of constant String's. In addition to saving execution time, this will result in decreased program size because common substrings can be output by "reusing" their containing character arrays along with their corresponding offsets and lengths.

Dependency Tracking

File dependencies passed to XSPMarkupLanguage by its AbstractMarkupLanguage superclass are stored in top-level <xsp:dependency> elements.

These elements are used by XSP code-generation logicsheets to populate the File array defined by the generated classes' AbstractServerPage superclass.

XSP Builtin Logicsheets

XSP for Java currently provides only 2 builtin logicsheets: request and response, associated with their corresponding Cocoon counterparts.

Note A mechanism is needed for Cocoon to pass additional objects to XSP pages. In particular, for the servlet execution environment, access to servlet objects is a must.

The DOM-XSP Markup Language

The new, SAX-based XSP version for Cocoon is not backwards compatible with its DOM-based former self.

In order to protect the existing DOM-based XSP code base, a "new" markup language will be added that simply wraps existing XSP version 1 pages, postprocessing their generated documents to convert them into SAX events.

While this solution implies additional overhead, it provides a simple path for migrating existing XSP pages.

In addition to this straight-forward mechanism, the new, SAX-based XSP version will overload the xspExpr method to accept as argument a Node expression and transform it to equivalent SAX events.

For the long run, though, developers are strongly encouraged to replace their "legacy" DOM pages and classes with equivalent, faster SAX counterparts.

The Program Generator

The ProgramGenerator interface exposes a single load method that takes as arguments a File pointing to a source XML document, as well as a markup and programming language name pair.

This method is responsible for locating, loading and instantiating a program derived from the given source document. Failing this, the program is generated and stored in an external, persistent repository.

Once instantiated, the program is kept in an in-memory cache for speeding up subsequent requests.

For each request, the source XML document is checked for changes and the program instance is queried for dependency changes so that the program can be automatically regenerated and reloaded if needed. This default behavior can be disabled by means of a sitemap parameter.

Note Currently, the program instance (as opposed to the program object itself) is queried for invalidating changes. This should change as a consequence of defining a separate Program abstraction as part of the upcoming addition of debugging support.

A default implementation of ProgramGenerator is provided that uses a FilesystemStore as repository: ProgramGeneratorImpl.

Program Repository

FilesystemStore is an implementation of the Store interface that uses a filesystem, hierarchical directory as its persistence mechanism.

Note FilesystemStore implements Store directly. A higher-level interface (PersistentStore) should be defined to accommodate other sensible persistent storage mechanisms such as relational databases or object databases like Ozone.

FilesystemStore expects the String representation of its key's to be filenames relative to its directory root.

Objects returned by FilesystemStore's get method are File's pointing to their corresponding entries (or null if their associated file doesn't exit).

FilesystemStore stores Java objects according to the following rules:

  • null values generate empty directories
  • String values are dumped to text files
  • All other Object's are serialized
Program Reloading

Unless the auto-reload sitemap option is in effect, ProgramGeneratorImpl will check whether program instances implement interface Modifiable in order to assert whether they should be regenerated and reloaded.

Method load uses its markupLanguageName and programmingLanguage arguments to retrieve the corresponding NamedComponent instances.

In server pages mode, these parameters are set by the calling ServerPagesGenerator from parameters passed via the sitemap <process> section.

The appropriate MarkupLanguage and ProgrammingLanguage instances are used to generate and load a program for which an instance is created and then returned to the calling environment.

Named Components

In order to support pluggable markup and programming languages, a new abstraction was added to Cocoon's arch core interfaces: org.apache.arch.named.NamedComponent.

Interface NamedComponent is simply an extension to org.apache.arch.Component that exposes a getName() method.

NamedComponent's belong to a collection of components sharing the same Java type and are individually identified by a name unique within each collection.

A org.apache.arch.named.NamedComponentManager is a component responsible for storing and locating NamedComponent instances. This interface exposes the following methods:

  • getComponent. Retrieve a NamedComponent instance given its type and name.
  • getTypes. Return an Enumeration of all known NamedComponent types.
  • getComponents. Return an Enumeration of all NamedComponents within a given type.

A default implementation is provided for this interface: org.apche.arch.named.NamedComponentManagerImpl.

Class org.apache.arch.named.AbstractNamedComponent provides a base implementation for NamedComponent that extends org.apache.arch.Configurable. This class exposes the following methods:

  • setConfiguration. Retrieve named-component sitemap configuration values converting parameter name/value pairs into Parameters passed to subclasses for easier initialization
  • setParameters. An empty method to be overridden by subclasses for parameter-based initialization
  • setAdditionalConfiguration. An empty method to be overridden by subclasses when parameter-based initialization is not sufficient because there are nested configuration elements in the corresponding sitemap entry
  • getRequiredParameter. A static convenience method that returns a named parameter as a String throwing an IllegalArgumentException if the parameter was not specified in the sitemap configuration
XSP Sitemap Configuration

Note The sitemap configuration shown here is likely to change in the near future.

A (rather verbose) sitemap definition for XSP follows:

<component role="factory"
           class="org.apache.avalon.NamedComponentManagerImpl">

  <component-type name="programming-language">
    <component-instance name="java"
    class="org.apache.cocoon.components.language.programming.java.JavaLanguage">
      <parameter name="compiler"
      value="org.apache.cocoon.components.language.programming.java.Javac"/>
      <parameter name="code-formatter"
      value="org.apache.cocoon.components.language.programming.java.JstyleFormatter"/>
      <parameter name="class-loader"
      value="org.apache.cocoon.components.classloader.ClassLoaderManagerImpl"/>
      <parameter name="delete-sources" value="false"/>
    </component-instance>
  </component-type>

  <component-type name="markup-language">
    <component-instance name="xsp"
    class="org.apache.cocoon.components.language.markup.xsp.XSPMarkupLanguage">
      <parameter name="prefix" value="xsp"/>
      <parameter name="uri" value="http://xml.apache.org/xsp"/>

      <target-language name="java">
        <parameter name="core-logicsheet"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/xsp.xsl"/>

        <builtin-logicsheet>
          <parameter name="prefix" value="xsp-request"/>
          <parameter name="uri" value="http://xml.apache.org/xsp/request/2.0"/>
          <parameter name="href"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/request.xsl"/>
        </builtin-logicsheet>

        <builtin-logicsheet>
          <parameter name="prefix" value="xsp-response"/>
          <parameter name="uri"
          value="http://xml.apache.org/xsp/response/2.0"/>
          <parameter name="href"
value="resource://org/apache/cocoon/components/language/markup/xsp/java/request.xsl"/>
        </builtin-logicsheet>
      </target-language>
    </component-instance>
  </component-type>
</component>

<component role="program-generator"
  class="org.apache.cocoon.components.language.generator.ProgramGeneratorImpl">
  <parameter name="repository" value="/tmp/repository"/>
  <parameter name="auto-reload" value="true"/>
</component>

<generator  name="serverpages"
            class="org.apache.cocoon.generation.ServerPagesGenerator"/>

<!--
<component
  role="class-loader"
  class="org.apache.cocoon.components.classloader.ClassLoaderManagerImpl"
/>
-->

<sitemap>
  <partition>
    <process uri="simple-page.xsp" source="../samples/documents/simple-page.xsp">
      <generator name="serverpages">
        <!--
        <parameter name="markup-language" value="xsp"/>
        <parameter name="programming-language" value="java"/>
        -->
      </generator>
      <filter name="xslt">
        <parameter name="stylesheet" value="../samples/documents/simple-page.xsl"/>
      </filter>
      <serializer name="html">
        <parameter name="contentType" value="text/html"/>
      </serializer>
    </process>
  </partition>
</sitemap>
Copyright © 1999-2002 The Apache Software Foundation. All Rights Reserved.