Java Processor
- 1. Rationale
- 2. Benefits and Drawbacks
- 3. Usage
- 4. Compilation
- 5. Compilation Class Path
- 6. Runtime Class Loading
- 7. Limitations
- 8. Properties
- 9. Example
1. Rationale
Orbeon Forms comes with a number of pre-built processors. However, in some
cases, it makes sense for the developer to write a new processor in Java. For the
purpose of this discussion, let's assume that the processor is implemented in a file
called MyProcessor.java
. Custom processors can essentially be deployed
in two ways:
- "Manually":
-
Compile
MyProcessor.java
. -
Place the compiled class in
WEB-INF/classes
(or in any other location where it can be found by the classloader used to load the classes inorbeon.jar
). -
Declare the new processor in
/config/custom-processors.xml
(i.e. mapping an URI to this new processor). The syntax of/config/custom-processors.xml
is as described here. -
Use the newly declared processor in an XPL (Orbeon Forms Pipeline Definition Language) file using the URI declared in the
processors.xml
.
-
- Using the Java processor:
-
Place
MyProcessor.java
with the other resources. -
Use the new processor in an XPL file through the Java processor. (We'll see below how this processor works in detail.)
-
2. Benefits and Drawbacks
The main advantages of using the Java processor versus manually compiling and deploying the compiled processor are:
- Easy deployment: the Java file is placed with the other resources and one does not need to worry about compilation, packaging and deployment.
- Immediate visibility upon modifications: one can change the Java file, save it and instantly see the result in the browser (no need to compile, redeploy the application).
However, one should also note the drawbacks that come with the Java processor. In
particular, the XML code needed in the XPL file to call a custom processor using the
Java processor is a bit more complex than the XML code used to call a processor
declared in processors.xml
.
3. Usage
config input | The config element has two attributes:
Let's assume you place your Java source files in your resources
directory under the |
---|---|
Other inputs and outputs | The processor implemented in Java can take an
arbitrary number of inputs and outputs. The only
restriction on the inputs/outputs is that no input
can be named config as this input is
already used to configure the Java processor.
|
4. Compilation
Before it can run a custom processor, the Java processor must
compile the source code to generate the class
files
from the java
files, and load those
class
files in the Java VM.
By default, the Java processor uses Sun's compiler
(com.sun.tools.javac.Main
) to produce class
files. See the
compiler-class
and compiler-jar
properties for more information about specifying the compiler to use.
The class
files are stored in the temporary directory, as defined by
the Java system property java.io.tmpdir
. Since compilation is a time
consuming process, it is performed only when necessary. The Java processor compiles
a custom processor when one of these conditions is met:
- The source of the custom processor has never been compiled before.
-
The last modified date of the source file for the custom processor is prior
to the last modified date of the corresponding
class
file.
Note that Sun's javac
automatically compiles all the files that the
custom processor depends on, but that the Java processor only runs
javac
by comparing the dates of the .java
and
class
of the custom processor itself. So if only one of the classes
used by the custom processor has changed since the last compilation, the Java
processor will not run the compiler. You should be aware of this limitation and
"touch" the source of the custom processor when such a case occurs to force a
compilation.
5. Compilation Class Path
Before invoking the Java compiler, Orbeon Forms builds a classpath using two properties. The following list summaries the complete classpath order.
-
The class path defined by the
classpath
property. -
The
WEB-INF/classes
directory, if found and Presentation Server runs in an application server. - The JAR and ZIP files used by the classloader hierarchy that loaded the Java processor. This automatically puts on the compilation class path the classes that the Java processor can use.
-
The JAR path defined by the
jarpath
property. -
All the JAR and ZIP files under the
WEB-INF/lib
directory, if found and Orbeon Forms runs in an application server. -
If the
WEB-INF/lib
directory is not found, all the JAR and ZIP files in the same directory as the JAR file containing the Java processor. Typically, when running from a command line, this is theorbeon.jar
JAR file. Iforbeon.jar
is stored in a directory with all the JAR files it depends on, those will automatically be added to the compilation class path.
6. Runtime Class Loading
The compiled files are loaded by a class loader created by the Java processor. A different class loader is created for each source path, and all the classes in the same source path are loaded in the same class loader. For a given source path, a new class loader is created if one of these conditions is met:
- No class loader has been previously created for this source path.
- One of the classes in this source path has been compiled since the class loader has been created.
When a new class loader is created, the previous one, if it exists, is discarded with all the loaded classes, and all the classes are re-loaded in the new class loader.
7. Limitations
- A custom processor used with the Java processor cannot use its
config
input, as this input is used to configure the Java processor. - Java source files must be stored on the file system, i.e. the
resources can only be loaded with the Filesystem or Web App resource managers. This is due to a
limitation of Sun's
javac
which can only compile source files stored on disk. - The Java processor will recompile a custom processor only if the Java source of the processor itself has changed. If only one of the classes (that the custom processor depends on) has changed since the last compilation, the source of the customer processor must be "touched" to force a re-compilation.
8. Properties
Several global properties are relevant to the Java processor. Refer to the Properties section for more information.
9. Example
The processor below declares a single output data
and no inputs. It
will always send the same XML content to its data
output, namely an
answer
element containing the text "42". For more details on how to
implement processors in Java, please refer to the Processors API.
import org.orbeon.oxf.pipeline.api.PipelineContext; import org.orbeon.oxf.processor.ProcessorInputOutputInfo; import org.orbeon.oxf.processor.SimpleProcessor; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; public class DeepThoughtProcessor extends SimpleProcessor { public DeepThoughtProcessor() { addOutputInfo(new ProcessorInputOutputInfo(OUTPUT_DATA)); } public void generateData(PipelineContext context, ContentHandler contentHandler) throws SAXException { String answer = "42"; contentHandler.startDocument(); contentHandler.startElement("", "answer", "answer", new AttributesImpl()); contentHandler.characters(answer.toCharArray(), 0, answer.length()); contentHandler.endElement("", "answer", "answer"); contentHandler.endDocument(); } }