How to (Java)

There are few entry points in RefleX that must be used by developers.
For example, never use java.io.File, use org.inria.ns.reflex.io.XFile instead, which supports many URI schemes and ensures that XPath expressions are applyable on it. If you have to deal with a third party component that do use java.io.File, be sure to convert XFiles to Files at the latest stage ; but if this component is able to deal with InputStreams, use directly those available with XFile.

How to

Design its own module

A module is made of active tags, XPath functions, predefined properties, and foreign attributes. A module definition consists on mapping these active XML materials to their concrete implementations. Each mapping can be done in two different ways :

  • in pure Java ; this is the case for almost all active tags supplied by RefleX ; for example, <xcl:echo> is bound to the org.inria.ns.reflex.processor.xcl.EchoAction Java class, which is done thanks to the module definition of XCL ;
  • in Active Tags ; users can consider that a tag is defined thanks to other tags ; this is the case of the custom tag <po:xml-orders> which is used in the tutorial section ; the tag definition is done thanks to this custom module definition.

Notice that in the same module, pure Java definitions and macro definitions can be encountered, like for the I/O module, which contains Java mappings for almost all active material, and a macro for <io:save> and io:exists().

Read more here :

Plug the module definition to the engine

Once a module has been designed, it must be known by the RefleX engine in order to be active. For this purpose, a catalog must be used ; as XML catalogs are tailored to supply a single resource for a given URI, the Active Tags specifications have enhanced XML catalogs concepts in the Active Catalog specification.

RefleX uses a built-in catalog to supply its own resources, but users should use an Active Catalog to add custom resources ; the tutorial section shows how such a catalog could be written.

Then, the RefleX engine must be launched with the knowledge of this catalog, which can be done from the command line :

 $ java org.inria.ns.reflex.ReflexCLI -c myCatalog.cat run myActiveSheet.xcl

...or in the deployment descriptor of your Web application :

  <init-param>
    <param-name>catalogs</param-name>
    <param-value>web:///WEB-INF/myCatalog.cat</param-value>
  </init-param>

If you embed RefleX in a Java application, you can simply add the catalogs to the processor instance with the relevant method.

See also the command line interface and the servlet.

Use files

Developpers should not use the traditional java.io.File to handle files, but instead the wrapper org.inria.ns.reflex.modules.io.XFile. Actually, in RefleX :

  • XFiles are X-operable objects, that is to say that they behaves like if they were XML objects ; for example, XPath expressions may be applied on a file object, like this : $myFile/@io:length or this : $myFile//*[@io:is-file] ; in Active Tags, some objects are X-operable objects, like #io:x-file. Moreover, some X-operable objects are sensible to Active Update operations.
  • XFiles are backed by VFS, that allow to plug many file systems (VFS comes with numbers of useful file systems).

If you have a reference to a file as a java.lang.String, a java.net.URI, a java.net.URL, a java.io.File, or a org.inria.ns.reflex.modules.io.XFile, you can simply get an XFile like this :

  XFile file = XFile.getXFile( reference );

If the reference is a relative path, it must be resolved regarding a base file :

  XFile file = XFile.getXFile( base, reference );

If the base is missing, the base URI will be those of the caller active sheet if it can be localized, or the base of its parent creator (if any), or by default the current directory.

Use Input and Output streams

The input and output streams of an XFile are available with the getInputStream() and getOutputStream() methods.

Do not close an output stream with its close method ; do use IOHelper#close(java.io.OutputStream) instead. This prevent closing PrintStreams unexpectedly ; PrintStreams can be closed explicitely by the user with the <io:close> element.

In Active Tags, streams of characters and streams of bytes are handled in the same way ; a stream of byte will be turn in a stream of characters if :

  • an encoding is available (for example as an HTTP header),
  • an encoding was set explicitely by the user,
  • an XML parsing is performed.

Further reading avalaible in the I/O module specification.

Use XML parsers

RefleX relies on JAXP for parsing XML files, allowing an application to select which concrete implementation to use.

Developers should not use JAXP classes directly for 2 main reasons :

  • RefleX offers the ability to parse XML fragments (documents that have several root elements or text content around the root element(s))
  • RefleX offers catalog lookup facilities

For this purpose, an interface that represents the configuration of a parser is available : org.inria.ns.reflex.xml.ParserConfiguration ; two implementations are also supplied : org.inria.ns.reflex.xml.ParserConfiguration#NAMESPACEAWARE_PARSER_CONFIGURATION which is a hard-coded namespace aware parser configuration suitable for most common parsings and org.inria.ns.reflex.xml.ParserConfiguration.Impl which provides a basic support for customization.

There are also some classes necessary for URI resolution : org.inria.ns.reflex.xml.ExternalIdentifierResolver, org.inria.ns.reflex.xml.URIReferenceResolver, and org.inria.ns.reflex.xml.FileResolver. The 2 formers are dealing with catalogs, while the latter can be invoked for various file systems.

Once the parser configuration has been choosen and the resolvers have been set, DOM or SAX parsing can be performed with various parsers provided in the org.inria.ns.reflex.xml.dom and the org.inria.ns.reflex.xml.sax packages. The DOMAdaptableParser and SAXAdaptableParser classes are certainly the most usefull parsers that can parse XML fragments safely. SAXSafeParser can be used when an application have to read XML files as well as raw text files.

Implement an active tag

Please read first "how-to design its own module".

There is a simple contract to follow for implementing an active tag, which must have :

  • a method invoked by the engine when unmarshalling,
  • a method invoked at runtime.

For this purpose, any active tag must extend org.inria.ns.reflex.processor.core.AbstractAction or one of its subclass. The method for unmarshalling must have the following signature :

public static AbstractAction unmarshal(
  AbstractAction parent, Element element )

This method is invoked automatically by the engine when the corresponding tag is encountered ; it should create an instance of the expected class. If the tag accept attributes, they have to be processed in this method. In a future release, the engine will check automatically with a schema if a tag is valid. After creating an instance of an active tag class, the unmarshal method MUST tell to the engine that the unmarshall process must go on ; in some rare case, developers can block it, but it is not recommended :

  public static AbstractAction unmarshal(
      AbstractAction parent, Element element )
      throws XMLException {
    // create an instance of my active tag
    MyAction myAction = new MyAction( parent, element );
    // unmarshal inside my element
    AbstractAction.unmarshal( myAction, element );
    // return my instance
    return myAction;
  }

If the class extends directly org.inria.ns.reflex.processor.core.AbstractAction, the custom process should start from the method :

public void runAction(DataSet dataSet)

If the class intend to produce a property to put in the data set, it should extend org.inria.ns.reflex.processor.core.AbstractSetAction and simply implements :

public Object getComputedValue(DataSet dataSet)

Use XPath

XPath always appear in expressions in Active Tags, that is to say an XPath expression surrounded by curly braces. The class that handles expressions is org.inria.ns.reflex.xml.xpath.Expression.

XPaths expressions are used when an object reference must be handled by a tag ; for example, when an attribute value appears as an expression, like this :

  <xcl:transform output="{ value( $web:response/@web:output ) }" source="{ $xml }"/>

As this tag requires an #io:output stream to write to, it uses an attribute that contains an expression. In the unmarshal() method of this tag :

  public static AbstractAction unmarshal(
      AbstractAction parent, Element element )
      throws XMLException {
    // create an expression from @output from the current element
    Expression output = Expression.parseValueTemplate(
      element, "output"
    );
    TransformAction transformAction = new TransformAction(
      output, parent, element
    );
    // ...
  }
  public TransformAction(
      Expression output, AbstractAction parent, Element element ) {
    this(parent, element);
    this.output = output;
  }
  private Expression output;

In the runAction() method :

  public void runAction( DataSet dataSet )
        throws ExecutionException {
    Object output = this.output.compute( dataSet.getXPathVariableResolver() );
    // io:output is either an OutputStream or a Writer
    if ( output instanceof OutputStream ) {
      OutputStream os = (OutputStream) output;
      // ...
    } else if ( output instanceof Writer ) {
      Writer w = (Writer) output;
      // ...
    } else {
      // error ?
    }
  }

If a QName must be computed, the class org.inria.ns.reflex.xml.QExpression can be used to unmarshal attribute values.

Passing parameters

A parameter is a more flexible way to pass a value to a component than using an attribute of an element. Passing parameters can be done thanks to <xcl:param> ; the target component that accept parameters is not necessary from the same module (XCL) ; for example :

  <io:file name="myFile" uri="xmldb:provider://user:pwd@host:port/path/to/resource">
    <xcl:param name="xmldb-resource-type" value="XMLResource"/>
  </io:file>

Additionally, some parameters may be set conditionally :

  <xcl:transform output="/path/to/doc.html" source="/path/to/doc.xml"
stylesheet="/path/to/stylesheet.xsl"> <xcl:param name="date" value="{ $date }"/> <xcl:if test="{ $page }"> <xcl:then> <xcl:param name="page" value="{ $page }"/> </xcl:then> </xcl:if> </xcl:transform>

RefleX provides a ready to use class (org.inria.ns.reflex.processor.core.AbstractAction.ParameterAdapter) that uses callbacks to set parameters to a target component that one can use in one of the runtime method of your active tag :

  SomeComponent myComponent = ...
  // Checking for parameters
  if ( this.actions != null ) {
    AbstractAction.ParameterAdapter adapter =
      new AbstractAction.ParameterAdapter() {
        public void setParameter( Object name, Object value ) {
          if ( myComponent != null ) {
              myComponent.setParameter( name, value );
          }
        }
    }
    // this will set a parameter to the component for each
    // parameter encountered when performing subactions
    adapter.setParameters( dataSet );
  }

Using the context

The context allows more flexibility than passing parameters with <xcl:param>, as any other tag can be used to "feed the context" of a target component ; using the context is a way to make a dynamic assembly of a component.

Each piece of code that push a context, must pop it in any case, as shown below :

  List context = dataSet.pushContext();
  try {
    // subactions will feed the context
    runActions( dataSet );
  } finally {
    dataSet.popContext();
  }
  // use the objects that were stored in the context
  ...

Casting to basic types

Don't try to convert directly to basic types (String, Number, Boolean) : there is a helper class that will do the job ensuring that XPath requirements are steadfast : org.inria.ns.reflex.xml.operator.XMaster thanks to a set of relevant static classes xxxValueOf().

Change the implementation of an active tag

Some tags are using third-party Java tools that are not those you would have choosen. You might prefer use those you know better or that you rely on. Whatever your reason, it is simple to change the implementation of an existing tag : you can even achieve this without recompiling the RefleX jar file.

For example, lets' consider that the implementation used for parsing HTML file doesn't suit your needs. RefleX uses Neko HTML but you might prefer TagSoup or any other for that job.

If you don't want to recompile RefleX, the best way is to edit the XCL module definition (res:///org/inria/ns/reflex/processor/xcl/module.exp), change the binding of the <xcl:parse-html> tag, and repack the jar file. The change should look like this :

<exp:element name="xcl:parse-html" source="res:org.acme.myTags.tagSoup.ParseHTMLAction"/>

Don't forget to write your class ("org.acme.myTags.tagSoup.ParseHTMLAction"), to compile it, and to put it in the classpath before launching the JVM. The simplest way is to make a copy of the source file and make the required changes.

Write to the standard output

Avoid using System.out.println() in your Java implementation. It is better to use the SYSTEM module of RefleX where the predefined property $sys:out is defined. Actually, if an application intend to redirect the standard output to another output it can be done in two ways : either at the Java layer or at the Active Tags layer. If System.out.println() is use in your Java code, the redirection at the Active Tags layer won't be effective.

An example of Java code is given by the <xcl:echo> active tag. Please refer to the source code. Instead of writing directly to System.out, the implementation get the $sys:out property and test if it is a file, a writer, or an output stream.

An exemple of application that redirect the standard output to another output at the Active Tags layer is the XUnit application : XUnit captures everything written directly or indirectly to $sys:out.

Deal with collections

Some classes are using intensively collections (java.util.*) for many purpose ; for example, attributes of X-operable objects are backed by a Map. To keep RefleX as performant as possible, it is necessary to make the collections used as much as dynamic as possible : don't pre-fill the values to put in a collection, prefer to implement a dynamic one that supply the values expected at the latest stage.

Some classes are available for that purpose in the org.inria.ns.reflex.util package, specifically the DeferredMap class.

The DeferredEntryMap class is used intensively for attributes of XOperable objects : the attribute set of such objects is built from a map of attribute prototypes. Many classes are using this facility. Example : the org.inria.ns.reflex.modules.web.XApplication class.

Test your module

Java tests

The Java tests should be achieve with a tool such as JUnit or any method you'd prefer.

XML tests

XML tests are for more complex scenarii that you can achieve with XUnit.

Please refer to the XUnit cookbook.

Since RefleX 0.3.1, Web applications can also be tested with WUnit

Please refer to the WUnit documentation.