How to (Java)
There are few entry points in 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
- Use files
- Use XML parsers
- Implement an active tag
- Change the implementation of an active tag
- Write to the standard output
- Deal with collections
- Test your module
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 ; 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 ; 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 :
- The list of built-in modules in .
- The specification of the Extensible XML Processor
Plug the module definition to the engine
Once a module has been designed, it must be known by the 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 specifications have enhanced XML catalogs concepts in the Active Catalog specification.
uses a built-in catalog to supply its own resources, but users should use an to add custom resources ; the tutorial section shows how such a catalog could be written.
Then, the 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 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 :
- 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 , some objects are X-operable objects, like #io:x-file. Moreover, some X-operable objects are sensible to 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 , 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
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 :
- offers the ability to parse XML fragments (documents that have several root elements or text content around the root element(s))
- 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 , 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>
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 jar file.
For example, lets' consider that the implementation used for parsing HTML file doesn't suit your needs. uses Neko HTML but you might prefer TagSoup or any other for that job.
If you don't want to recompile , 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 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 layer. If System.out.println() is use in your Java code, the redirection at the 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 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 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 .
Please refer to the XUnit cookbook.
Since 0.3.1, Web applications can also be tested with
Please refer to the WUnit documentation.

