The extension mechanism used in EGE is based on the Java Plugin Framework (JPF). More information about which can be found at: http://jpf.sourceforge.net. This section explains how to create sample implementation of a converter.
Currently the EGE project has to offer implementations of extensions :
Important: EGE API assumes conversion of the data by usage of the streams - one input stream for the input data and one output stream for the output data. In order to make it possible to provide input data and output data consisting of multiple files/directories, EGE implementation requires that every EGE converter accepts data and outputs data by means of a ZIP archive. This requirement is crucial not only for appropriate conversion of data consisting of multiple files/directories, but also for conversion results consisting of multiple files/directories. To have a simple rules for EGE converter creation, EGE implementation requires every converter to obey this requirement. Additionally, for developers convenience EGE implementation provides functionality for compressing multiple files into a ZIP archive and decompressing ZIP archive. These functions are provided by the ZipIOResolver class. An instance of this class is returned by the getStandardIOResolver() method of the EGEConfigurationManager instance. Please, note that this requirement is stated by this specific EGE implementation and not by the EGE API itself.
Each extension project has to import at least the EGE API and EGE framework libraries (ege-api-X.jar,ege-framework-x.jar where X is the library version) in order to be able to use the EGE interfaces, data types and extensions mechanism.
In this case the implemented class, named SampleConverter, will implement the pl.psnc.dl.ege.Converter interface. Implementing every method of this interface should result in code that looks like this:
package com.myapp.converter; import java.io.InputStream; import java.io.OutputStream; import pl.psnc.dl.ege.component.Converter; import pl.psnc.dl.ege.exception.ConverterException; import pl.psnc.dl.ege.types.ConversionActionArguments; import pl.psnc.dl.ege.types.DataType; public class SampleConverter implements Converter { public void convert(InputStream input, OutputStream output, ConversionActionArguments conversionArguments) throws ConverterException, IOException { // if conversionArguments are correct // perform proper conversion: // handle properties (if they were defined) taken from conversionArguments // read data from input stream // transform data according to implemented logic // write data into output stream } public List<ConversionActionArguments> getPossibleConversions() { // return the list of ConversionActionArguments // that describes possibilities // of this particular converter implementation. return .........; } }
Through the getPossibleConversions() method the converter informs the external application in which it is embedded about the possibilities of the converter. It is done by returning a list of pairs of data types and conversion properties definitions (instances of ConversionActionArguments). Method convert() should contain the necessary conversion logic, which checks the specific ConversionActionArguments, handles received parameters, performs conversion on data from the input stream and writes the result of conversion to a given output stream.
IMPORTANT: The input and output streams will be opened and closed by EGE. Therefore the plug-in code should not try to open or close those streams.
Creating converter with input and output data compression.
EGE implementation requires that every EGE converter accepts data and outputs data in form of a ZIP archive. In order to obey this requirement EGE converter may use functions available in the EGE implementation package. These functions are provided by the ZipIOResolver class. An instance of this class is returned by the getStandardIOResolver() method of the EGEConfigurationManager instance. IOResolver provides two simple methods for compression and decompression of data :
Example code showing the usage of EGE IOResolver is presented below:
package com.myapp.converter; import java.io.InputStream; import java.io.OutputStream; import pl.psnc.dl.ege.component.Converter; import pl.psnc.dl.ege.exception.ConverterException; import pl.psnc.dl.ege.types.ConversionActionArguments; import pl.psnc.dl.ege.types.DataType; public class SampleConverter implements Converter { private final IOResolver ior = EGEConfigurationManager.getInstance().getStandardIOResolver(); public void convert(InputStream input, OutputStream output, ConversionActionArguments conversionArguments) throws ConverterException, IOException { File inputTempDir = new File("in_foobar"); File outputTempDir = new File("out_foobar"); try{ ior.decompressStream(input, inputTempDir); // unpack transferred data into temporary directory // if conversionArguments are correct // perform proper conversion: // handle properties (if they were defined) taken from conversionArguments // read data from temporary directory // transform data according to implemented logic // write data into output temporary directory ior.compressData(outputTempDir, output); // compress converted data from output temporary directory and transferr it to output stream. }finally{ // cleanup temporary data } } public List<ConversionActionArguments> getPossibleConversions() { // return the list of ConversionActionArguments // that describes possibilities // of this particular converter implementation. return .........; } }
Before creating a .jar file with the plug-in, it is necessary to create the JPF plug-in descriptor to mark the converter class as a JPF plug-in.
Descriptor file name is plugin.xml and it should look like this:
<?xml version="1.0" ?> <!DOCTYPE plugin PUBLIC "-//JPF//Java Plug-in Manifest 0.4" "http://jpf.sourceforge.net/plugin_0_7.dtd"> (1) <plugin id="com.mycompany.converter" version="1.0"> (2) <requires> (3) <import plugin-id="pl.psnc.dl.ege.root"/> (4) </requires> (5) <extension plugin-id="pl.psnc.dl.ege.root" point-id="Converter" id="SampleConverter"> (6) <parameter id="class" value="com.myapp.converter.SampleConverter"/> (7) <parameter id="name" value="Sample Converter"/> (8) </extension> (9) </plugin>
Every plug-in in JPF has its unique id, which is defined in the plug-in element by an id attribute (in our case it is "com.mycompany.converter", see line 1). Every JPF extension is connected to a specified extension point, which in this case is "Converter" (described by a point-id attribute of the extension element in line 5, imported in lines 2 to 4). Extension points are defined within the JPF descriptor of EGE API and they are: Converter, Validator and Recognizer. More information about the JPF plug-in descriptors are available at http://jpf.sourceforge.net.
The extension element (lines 5 - 8) contains two additional parameters:
This descriptor has to be inserted in the root directory of extension .jar file or in its direct sub-directory named "META-INF". Finally to use the created example converter in EGE client application, its .jar file(s) has to be added to the classpath of the EGE client.
The process of creating Recognizer and Validator extensions is very similar. First of all we need to create a class that implements one of the chosen interfaces - Reconizer or Validator and secondly change few things in the plugin.xml file:
<?xml version="1.0" ?> <!DOCTYPE plugin PUBLIC "-//JPF//Java Plug-in Manifest 0.4" "http://jpf.sourceforge.net/plugin_0_7.dtd"> (1) <plugin id="com.mycompany.validator" version="1.0"> (2) <requires> (3) <import plugin-id="pl.psnc.dl.ege.root"/> (4) </requires> (5) <extension plugin-id="pl.psnc.dl.ege.root" point-id="Validator" id="SampleValidator"> (6) <parameter id="class" value="com.myapp.validator.SampleValidator"/> (7) <parameter id="name" value="Sample Validator"/> (8) </extension> (9) </plugin>
This example shows the extension of Validator. First line shows that the id attribute of plugin element has changed into different name - every plugin must have a unique name. Line (5) shows the differences within extension element : point-id parameter is now of "Validator" value and the id parameter has changed into 'SampleValidator'. Finally, it is necessary to change the parameter with id "class" in (6) line, where in the attribute value we have to point to our class name - that implements the Validator interface and also change the value attribute of the next parameter - name in line (7). Creating the Recognizer extension is almost the same. The difference is that we need to create the class that implements the Recognizer interface and particular attributes have to be changed in plugin.xml :
<?xml version="1.0" ?> <!DOCTYPE plugin PUBLIC "-//JPF//Java Plug-in Manifest 0.4" "http://jpf.sourceforge.net/plugin_0_7.dtd"> (1) <plugin id="com.mycompany.recognizer" version="1.0"> (2) <requires> (3) <import plugin-id="pl.psnc.dl.ege.root"/> (4) </requires> (5) <extension plugin-id="pl.psnc.dl.ege.root" point-id="Recognizer" id="SampleRecognizer"> (6) <parameter id="class" value="com.myapp.recognizer.SampleRecognizer"/> (7) <parameter id="name" value="Sample Recognizer"/> (8) </extension> (9) </plugin>
Once again it is necessary to change the following attributes :