This article describes how to add new pipeline stages and database interfaces into CTP. It is intended for programmers, and it assumes familiarity with Java and Ant.
1 Obtaining the Source Code
CTP is designed to be extended with pipeline stages of new types. Stages implement one or more Java interfaces. It is useful to obtain the source code and build it in order to obtain the Javadocs, even though in principle you don't need to modify the code itself.
The software for CTP is open source. All the software written by the RSNA for the project is released under the RSNA Public License. It is maintained on a CVS server at RSNA headquarters. To obtain the source code, configure a CVS client as follows:
Protocol: Password server (:pserver) Server: mirc.rsna.org Port: 2401 Repository folder: /RSNA Username: cvs-reader Password: cvs-reader Module: ClinicalTrialProcessor
Together, this results in the following CVSROOT (which is constructed automatically if you use something like Tortoise-CVS on a Windows system):
This account has read privileges, but it cannot write into the repository, so it can check out but not commit. If you wish to be able to commit software to the CVS library, contact the MIRC project manager.
2 Building the Software
When you check out the ClinicalTrialProcessor module from CVS, you obtain a directory tree full of the sources and libraries for building the application. The top of the directory tree is ClinicalTrialProcessor. It contains several subdirectories. The source code is in the source directory, which has two subdirectories, one each for the Java sources and the files required by the application.
Building CTP requires the Java 1.6 JDK and Ant. Running CTP requires the JDK or JRE and the JAI ImageIO Tools.
The Ant build file for CTP is in the ClinicalTrialProcessor directory and is called build.xml. To build the software on a Windows system, launch a command window, navigate to the ClinicalTrialProcessor directory, and enter ant all.
The build file contains several targets. The all target does a clean build of everything, including the Javadocs, which are put into the documentation directory. The Javadocs can be accessed with a browser by opening the file:
The ctp-installer target just builds the application and places the installer in the products directory.
3 The Object Classes
CTP provides four classes to encapsulate files of various types. The classes are located in the org.rsna.ctp.objects package:
- DicomObject - a DICOM dataset
- XmlObject - an XML file containing identifiers relating the data to the trial and the trial subject
- ZipObject - a zip file containing a manifest.xml file providing identifiers relating the zip file's contents to the trial and the trial subject
- FileObject - a generic file of unknown contents and format
Each class provides methods allowing pipeline stages or database adapters to access the internals of an object without having to know how to parse it. See the Javadocs for a list of all the methods provided by these classes.
4 Implementing a Pipeline Stage
To be recognized as a pipeline stage, a class must implement the org.rsna.ctp.pipeline.PipelineStage interface. An abstract class, org.rsna.ctp.pipeline.AbstractPipelineStage, is provided to supply some of the basic methods required by the PipelineStage interface. All the standard stages extend this class.
Each stage type must also implement its own interface. The interfaces are:
The Javadocs explain the methods which must be implemented in each stage type.
Each stage class must have a constructor which takes its configuration file XML Element as its argument. The constructor must obtain any configuration information it requires from the element. While it is not required that all configuration information be placed in attributes of the element, the getConfigHTML method provided by AbstractPipelineStage expects it, and if you choose to encode configuration information in another way, you must override the getConfigHTML method to make that information available to the configuration servlet.
5 Implementing a DatabaseAdapter
The DatabaseExportService pipeline stage provides a queuing mechanism for submitting files to a database interface, relieving the interface from having to manage the queue. It calls the overloaded process method of the interface with one of the four object types. Each of the objects includes methods providing access to the internals of its file, allowing the interface to interrogate objects to obtain some or all of their data to insert into an external system.
The DatabaseExportService dynamically loads the database interface class, obtaining the name of the class from the configuration element's adapterClass attribute.
5.1 The DatabaseAdapter Class
The DatabaseAdapter class, org.rsna.ctp.stdstages.database.DatabaseAdapter, is a base class for building an interface between the DatabaseExportService and an external database. To be recognized and loaded by the DatabaseExportService, an external database interface class must be an extension of DatabaseAdapter.
The DatabaseAdapter class provides a set of methods allowing the DatabaseExportService to perform various functions, all of which are explained in the Javadocs. The basic interaction model is:
- When the DatabaseExportService detects that files are in its queue, it determines whether the database interface class is loaded and loads it if necessary.
- It then calls the database interface’s connect() method.
- For each file in the queue, it instantiates an object matching the file’s contents and calls the database interface’s process() method. There are four overloaded process methods, one for each object class.
- When the queue is empty, it calls the database interface’s disconnect() method.
All the methods of the DatabaseAdapter class return a static instance of the org.rsna.ctp.pipeline.Status class to indicate the result. The values are:
- Status.OK means that the operation succeeded completely.
- Status.FAIL means that the operation failed and trying again will also fail. This status value indicates a problem with the object being processed.
- Status.RETRY means that the operation failed but trying again later may succeed. This status value indicates a temporary problem accessing the external database.
All the methods of the DatabaseAdapter base class return the value Status.OK.
5.2 Extending the DatabaseAdapter Class
To implement a useful interface to an external database, you must extend the DatabaseAdapter class.
Since the DatabaseAdapter class implements dummy methods returning Status.OK, your class that extends DatabaseAdapter only has to override the methods that apply to your application. If, for example, you only care about XML objects, you can just override the process(XmlObject xmlObject) method and let DatabaseAdapter supply the other process() methods, thus ignoring objects of other types.
Although the DatabaseAdapter class includes reset() and shutdown() methods, they are not called by the DatabaseExportService because restarts are not done in CTP and there is no notice of an impending shutdown. You should therefore ensure that the data is protected in the event of, for example, a power failure. Similarly, since one connect() call is made for possibly multiple process() method calls, it is possible that a failure could result in no disconnect() call. Thus, depending on the design of the external system, it may be wise to commit changes in each process() call.
5.3 Connecting Your Database Interface Class to CTP
The easiest way to connect your class into CTP is to create a package for it under the source/java tree and then build the entire application. This will avoid your having to change the manifest declaration in the build.xml file, and it will ensure that the class is included in the installation without having to add a jar file.