OpenEFM has been built to be highly
customizable. Therefore, it has
been built using a great amount of abstraction. Each type of
functionality that the EFM was designed for has been laid out in an
Interface. This allows any implementation of that interface to work
with the rest of the system.
This document will give a brief overview of the architecture of the system. It will then address specific questions through a FAQ-like section. This section will discuss topics in the form of 'How do I do this with OpenEFM?'. Questions such as 'How do I adapt the CMS connector to fit my courts needs?' and 'How do I configure the software for our Verisign account?' will be addressed in this section.
The OpenEFM system built around a number of freely available, open source software projects. Some of the key resources are listed here.
As mentioned before, the OpenEFMController loads all of the necessary pieces for the EFM to operate. Specifically it loads an instance of each of the following objects or interfaces:
Transceiver | Defines methods for transmitting and receiving filing data to and from external systems, such as CMSs and EFSPs, using various protocol including EbXML. There can be multiple transceiver loaded at the same time. |
SecurityManager | This interface is designed to control the authentication of filing
parties. Arrangements will have to be made, between the local court and
the filing parties, as to which methods of authentication are needed.
Currently this security manager is an HTTP cookie-based implementation.
Default is
com.counterclaim.openefm.security.BasicSecurityManager |
Model | This element isolates the data models that are used for the system.
This includes data stores, like databases, data accessing components, and
the implementation of data objects themselves. Currently the system uses
an Ozone-based object model. Ozone is an open source, persistent Java
object data store. This allows all data objects to be stored and accessed
as native java classes, thus eliminating the need for mapping data between
a database and a data object. Default is
com.counterclaim.openefm.model.ozone.OzoneOpenEFMModelImpl.& ; ; ;nbs
p; |
LxmlValidator | This component checks to verify that the received XML is well formed. It can also be used to check for the inclusion of specific data elements and their values. Currently only a simple implementation is used. This implementation checks the validity of all received filings against their Schema . Default is com.counterclaim.openefm.lxml.validator.SchemaLxmlValidator |
AuditLogger | The audit logger is designed to record specific events that the server may encounter. Currently minimal logging is going on. Events are recorded in the standard log files. These log files are stored by default in "/var/OpenEFM/logs/" |
IdFactory | The IdFactory is a singleton with a pubic static getNextId() method
which dispense EFM-unique id's. Default is
com.counterclaim.openefm.model.id.StringIdFactory |
BillingModule | This module handles the payment processing. Currently, the standard
implementation uses the PayFlowPro services available through Verisign.
This allows fees to be collected by the court through processing of Visa,
American Express, Master Card, and all other credit cards currently
accepted by Verisign. Default is
com.counterclaim.openefm.billing.verisign.PayFloBillingModule |
AdminComponent | This is a web component that is loaded into the Jetty web server
at run time. It establishes the web-based GUI for the system.
Default is com.counterclaim.openefm.admin.WebAdminComponent |
CourtPolicy | A wrapper for an xml file specifying
business logic for a particular court. Default is
com.counterclaim.openefm.courtpolicy.CourtPolicyImpl |
VirusScanner | An ICAP compliant client for scanning
incoming filings via a remote server. Initially disabled. Default is
com.counterclaim.openefm.security.VirusScanner |
As stated in the above resource section, OpenEFM uses Jakarta Ant to automate several project tasks. These common tasks should be used to work with the code base more easily. Jakarta Ant works by reading defined tasks from an XML file. The main Jakarta Ant file is located at "openefm/build/build.xml". Several other files referenced from build.xml reside in the same directory. Jakarta Ant commands should be issued from the build directory in order for ant to find the proper build.xml file. Issuing command of "ant -projecthelp" in the "openefm/build" directory will list many of the defined tasks. You should see output like this:
~/openefm/build ant -projecthelp
Buildfile: build.xml
This is the build for OpenEFM.
Main targets:
all Do it all at once (clean, dist).
bin-zip Zip the out/dist executables for deployment.
chelan-dms Create a WAR for the Chelan DMSadapter.
clean Clean up the build directory.
cms-dms-stub Create a WAR for the CMS stub implementation.
compile Compile the source files.
dist Move all files needed for a distribution to ${out.dist.dir}.
doc-zip Zip up all javadoc information.
ear-me-roar Create a complete OpenEFM EAR file.
ejb-jar Create an EJB JAR file containing all EJBs.
jar Create a JAR file of the app classes.
javadoc Generate javadoc files in out/docs.
javaydoc Generate javadoc files with ydoclet class diagrams.
src-zip Zip up all of the source files in the distribution.
test Run a single JUnit test case, and generate a report in ./build/reports.
tests Run all JUnit tests, and generate a report in ./build/reports.
tests-rescan Regenerate the list of test cases in "build-tests-list.xml", then run the 'tests' target.
usage Output a description of this project.
Default target: usage
By running commands such as "ant clean" or "ant
dist"
common development tasks can be automatically managed.
This area is modeled after the standard FAQ (Frequently Asked Questions) layout. Common customization issues will be addressed here.
Customization Questions:
Creating a new distribution from a modified code base can be accomplished in a few basic steps. First, issuing the ant command "ant dist", will create the appropriate directory structure. This structure is the same structure found in the binary distribution that can be downloaded from the OpenEFM homepage. This directory structure will be rooted at "openefm/out/dist".
This distribution directory houses the entire OpenEFM system. At this point the two directories "/var/OpenEFM/data" and "/var/OpenEFM/logs" will need to be created if they have not been already. Next the distribution can be started by running the executable efm script designed to boot strap the server. This executable can be found at "openefm/out/dist/bin/efm.sh".
Running the command "efm.sh restart" will first stop any running version of OpenEFM, then start the new version.
The Transceiver interface separates most of OpenEFM from the problems of transporting e-filing data between OpenEFM and the various external systems with which it talks. These systems include EFSPs, CMSs and DMSs all; and for each of them, the protocols and formats have changed and continue to change with industry demands. Moreoever, transport protocols like HTTP require that a servlet be configured to receive incoming messages. Thus the transport problem is complex.
We use extension (subclassing) to handle the differences in transport-layer standards, since EbXML, for example, is just an extension of SOAP (and we use both). To account for differences among the interfaces to the EFSPs, CMS and DMS, on the other hand, we use a mode. Hence, Transceiver defines a method 'setMode()', which must be called before a Transceiver will be useful. This tells the Transceiver to which remote system it is talking. Other differences in interfaces are accounted for by wrapping messages in standards-specific helper objects, which are found in package com.counterclaim.openefm.transport.wrapper.
If OpenEFM can already function according to the standards your court has adopted, then you should be able to simply edit "config.xml" to specify the appropriate classes, and possibly write a simple adapter for interfacing with your system (see CMSAdapter below. This may not be necessary for SOAP-based implementations). Otherwise, you may need to extend Transceiver or a subclass thereof. Remember that Transceivers operate within OpenEFM. It is the adapter package that facilitates the adapters, which run within your CMS or DMS.
To implement a new Transceiver, follow these steps:
CMSAdapter is the interface for classes which reside on the remote system and perform the actual work of inserting a submitted filing into permanent storage, ostensibly a Case Management System. There are four main tasks involved in the process.
<servlet>
<servlet-name>cms-soap-receiver</servlet-name>
<servlet-class>com.counterclaim.openefm.transport.adapter.soap.SOAPAdapterServlet</servlet-class>
<init-param>
<param-name>adapter-class</param-name>
<param-value>com.counterclaim.openefm.transport.adapter.StubAdapter</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
The LxmlValidator module checks incoming filings to assure that they consist of the proper XML format. This format should adhere to a schema specified by the court. Many courts have chosen to use the XML available through OASIS Legal XML available at http://www.legalxml.com. The OASIS standards group has worked towards defining the industry standard XML format for transmitting legal filings and documents.
The interface that defines an LxmlValidator is
openefm/src/com/counterclaim/lxml/validator/LxmlValidator.java
A simple implementation has been provided at:
com.counterclaim.openefm.lxml.validator.SchemaLxmlValidator
The most common change here would be the inclusion of a different schema to validate against. This could be accomplished by placing the schema in an accessible directory, ( we use 'openefm/web/admin/WEB-INF/schema' ), and changing the 'filingSchemaFile' attribute in the lxml-validator element of the config.xml file located at 'openefm/web/admin/WEB-INF/config.xml'.
Another common change to the Legal XML validator might be to check for specific data elements and values in the XML filing. This could be accomplished in a number of ways. Most likely the easiest solution would be to add some custom XPath queries to the end of the validateFiling(LxmlFiling filing) method in SchemaLxmlValidator.java..
However, if one had a need, a new LxmlValidator class could be written that extends the interface and is used in place of the SimpleLxmlValidator. The new class would need to be specified in the openefm/web/admin/WEB-INF/config.xml file's lxml-validator element.
The data model interfaces define what types of information the objects used by OpenEFM need to contain. The data model also defines the object factory and object manager interfaces. The overall data model is therefore responsible for storage, retrieval, and implementation of all data objects used by OpenEFM.
The data model can generally
be viewed as a collection of interfaces and implementations, which handle all
types of data used by the system. Currently the data used by the system has been
divided into three categories. The first category is the Legal XML modeling
objects. Then there is a court model object set which handles the processing of
court, user, and EFSP data elements. Finally a small ID section also exists for managing unique object id values. These interfaces can be
found under "src/com/counterclaim/openefm/model/".
The class which ties all of the object model classes together is the OpenEFMModel. The OpenEFMModel is used by the code base to get object managers when they are needed. The configuration file (config.xml) for OpenEFM specifies which OpenEFMModel implementation should be used.
Currently counterclaim has implemented an Ozone-based data model system. Ozone is a persistent object database. Therefore the Ozone object managers handle all instantiation of objects.
If a new database needed to be used, a developer would need to first create implementations of all model related classes. Then the config file would need to be updated in order to point at the new OpenEFMModel implementation.
One neat side effect of the Ozone model implementation stems from the fact that it is a persistent object database. This means that Java objects are saved to disk and are re-instantiated later on when they are needed. So, if the actual definition of the Java object type changes, then objects will fail to be re-instantiated when they are read from disk. This should be accounted for when making developmental changes to an installation. Therefore developers should understand that if they change database object models while using the current Ozone model implementation they will lose access to all saved data in the database. When database object model changes are made to the system it is generally easiest to overcome instantiation errors by deleting the '/var/OpenEFM/data' directory. This will cause a new database to be built from the ground up using the new object definitions. This will however cause a loss of all data in the system.
The Verisign Billing Module requires several configuration parameters be defined. These parameters are specified in the EFM configuration file, typically located at "openefm/web/admin/WEB-INF". The parameters that must be included for the Verisign billing to function properly are:
A sample filing client is provided with OpenEFM. This is a Java implementation of a client. The client can be found at "openefm/src/com/counterclaim/openefm/client/filing/FilingTest.java". A script which allows this client to be run easily from the command line can be found in the bin directory of any distribution. Simply executing this script, "./filing-client.sh" will display instructions for proper usage.
This client is intended to make a connection tothe EFM's filing transceiver. The filing transceivers receiveincoming electronic filings. The client expects to be passed a wellformed Legal XML document that will be filed. It does not construct this document.
The client can be embedded into any Java based application by firstcreating a jar of the OpenEFM project. This can be done by executing the "ant jar" build task. Then including this jar in the classpath of the application that it will be embedded in. The application will then need to instantiate and use a FilingClient object. More information is available about the FilingClient object by browsing the JavaDoc API for this project.
OpenEFM is built around the Struts and Tiles, Java Server Page (JSP) architecture. Developers already familiar with these resources should have no problem discovering the layout of OpenEFM and adding to it. Developers who are new to Java Server Pages or to Struts and Tiles are strongly encouraged to explore some basic Struts and Tiles tutorials. Tutorials are available from the Struts and Tiles homepage listed in the framework section above.
However, a simple example will be outlined here. Lets assume that we want to add a new feature to the manage-filings page. Maybe we would like to add a button entitled 'Destroy' which has an associated action of purging all filings from the system.
First we can add the button to the manage-filings page by editing the jsp file used to generate the page. In this case the file is located at "openefm/web/admin/content/manage-filings.jsp". Near the top of the JSP file we see the tags which specify the current buttons displayed on the page. These tags are standard HTML tags loaded from a standard Struts taglib. An example of one of these lines is as follows:
<html:submitproperty="<%= Constants.ACTION_KEY%>"value="<%=Constants.REJECT_ACTION%>" styleClass="button" />
Inserting a new tag formatted in a similar way can allow us to insert a new 'purge' button. For example:
<html:submitproperty="<%= Constants.ACTION_KEY%>"value="<%=Constants.DESTROY_ACTION%>" styleClass="button" />
Notice that this button's value property is set to be a pre-defined constant. These constants should be set in "openefm/src/com/counterclaim/openefm/admin/Constants.java". This file should be edited to include the new DESTROY_ACTION constant. This constant should be a String type, whose contents will appear as the text of the button. Once these changes have been made this new button will appear on the user interface when we recompile, rebuild and restart OpenEFM.
Right now you are probably thinking, "Well this is exciting but the button doesn't do anything!!". Which is very true, and next we should specify the action that should take place when the button is pressed. Notice that the HTML tag, which specifies the form information, also sets the action. In this particular JSP file it looks like this:
<html:form action= "manageFilings.do"method="<%= method %>">
The "manageFilings.do" part is the important bit of information here. *.do actions get mapped to servlets. These mapping happen in the struts-config file. This file is located at "openefm/web/admin/WEB-INF/struts-config.xml". Specific attention should be paid to the action mapping section. In this file we see the following action mapping for manageFilings:
<action path="/manageFilings"
type="com.counterclaim.openefm.admin.actions.ManageFilingsAction"
name="manageFilingsForm"
scope="request"
input="page.manage-filings">
<forward name="success" path="page.manage-filings"/>
<forward name="detail" path="page.filing-detail"/>
<forward name="remove" path="page.remove-filings"/>
<forward name="receipt" path="page.billing-receipt"/>
</action>
From this we can see a few important pieces of information. First off, the class specified to deal with these actions is located at "openefm/src/com/counterclaim/admin/actions/ManageFilingsAction.java". Second of all, some forward information seems to be presented. This will be examined more closely later.
If we open up this file we will find that the execute method simply checks the action string's value against the action string that is contained in the constants file. The class includes a method for handling each action internally. To implement our new action we could simply create a purgeAllFilings() method, which we can call once the action has been determined.
So having implemented the body of the method that will purge all filings, we now need to set the return type for the method. The return types of these methods are all defined to be ActionForwards. ActionForwards are Struts and Tiles actions that help determine which page should be loaded. Since we can just stay on the manageFilings page after our method has executed we want to make sure the manage-filings page is loaded. Jumping back up to the action definitions above we see that a number of defined forward points exist. Here we can see that "success" is mapped to the manage-filings page. Therefore, once our new purging method has deleted all filings, we can give it following return statement:
return mapping.findForward("success");
Or, like many of the other methods contained in this action class we could simply have our return statement call the "listFilings()" method. This would likely be the best solution since this method handles configuration of the data objects needed for generating the list.
One item of note is that in the struts-config.xml file we see that many of the path elements map to "page.*". These mappings are actually referring to even more mappings. The actual mapping of a page.something to the actual JSP page is done in tiles-config.xml. If you wish to add new pages or content sections to OpenEFM then they will need to be defined in the struts configuration file located at "openefm/web/admin/WEB-INF/tiles-config.xml".
After examining the EFM configuration file, "openefm/web/admin/WEB-INF/config.xml", you may have noticed that many component modules load configuration parameters as attributes. Adding more configuration parameters to modules is an easy task due to the way the modules are instantiated. As an example we will discuss adding a dbLocation attribute to the model module. For each additional attribute three things must be defined by the module. First, a protected String variable, then a getter and setter for that variable. For example, to change
<model className="com.counterclaim.openefm.model.ozone.OzoneOpenEFMModelImpl"
dataDir="/var/OpenEFM/data/ozone" />
to
<model className="com.counterclaim.openefm.model.ozone.OzoneOpenEFMModelImpl"
dataDir="/var/OpenEFM/data/ozone"
dbLocation="/var/db/somedata" />
One would only need to add the following lines toOzoneOpenEFMModelImpl.java:
protected String dbLocation = null;
public void setDbLocation(String db) { this.dbLocation = db; }
public String getDbLocation() { return this.dbLocation; }
Now as long as the attribute is added to the config.xml file this variable value will automatically be set when the module is loaded. This process is intended to allow for easy customization of existing modules and ease of configuration of future and existing modules.
Now you should be comfortable with the basics of building new functionality into OpenEFM. Go nuts! And if you build new functionality that you think everyone should be using, then by all means please feel free to share the additions with the whole OpenEFM community! This process is discussed in the next section on upstream contributions.
Objects that are represented in the ozone object model can be a little tricky to update. The classes that are actually used to implement the persistent state structure are generated by Ozone. These files are generated from the java classes that are contained in the model implementations. Ozone looks at comments in these files to determine which methods change the state of an object to the point where the stored model should be updated. For example, the file:
com/counterclaim/openefm/model/lxml/ozone/OzoneLxmlFiling.java
is an interface defining the OzoneLxmlFiling class.
This file contains the line:
public void setId(Id id) throws ModelException; //update
The "//update" comment informs ozone that this method,when called, should update the persistent model object.
Before new XPath helper methods are added to the InternalLxmlFiling object, it is a good idea to reconsider the necessity of such a change. It is obviously much more convenient for a programmer to simply make calls to helper methods designed to get specific information, however, InternalLxmlFiling already contain the method 'public List queryXPath(String query)'. This method allows for any arbitrary XPath query to be used on the filing. Accessing data this way can however be cumbersome, since dom4j object types will be contained in the list returned from the query.
To add a XPath helper method to the InternalLxmlFiling object four files
must be modified:
com/counterclaim/openefm/model/lxml/InternalLxmlFiling.java
This
file is then interface which defines which methods will be implemented in the
filing object. The new method signature should be included in this file.
com/counterclaim/openefm/model/lxml/InternalLxmlFilingImpl.java
Here the method should actually be implemented. However the XPath queries are all handled through private helper methods which in turn use the a few more files to make the query. An example of a pre-existing XPath helper methods follows:
public String getLeadDocumentId() {
return queryForString("xpath.lead-document-id", new String[]{});
}
The 'xpath.lead-document-id' string
references a querystored in a different file which we will edit shortly. The
'newString[]{}' string array that is passed as a parameter to the
'queryForString'method should contain any parameters that might need to be
expected in the XPath query.
com/counterclaim/openefm/model/lxml/ozone/OzoneLxmlFilingImpl.java
The Ozone filing implementation contains an instance of anInternalLxmlFilingImpl as a private instance variable. All of the XPathhelper methods called on the Ozone filing object are implemented bysimply calling the same method in the Internal Filing. An example ofthis is shown below:
public String getDocumentTitle(String docId) {
return filing.getDocumentTitle(docId);
}
Finally the file which contains the XPath queries must bemodified. The location of this file is specified in com/counterclaim/openefm/model/lxml/XPathHelper.java.( This is marked in the code as a Hack! It needs to be specified in a config file probably and not source code! ) Currently the file used is
com/counterclaim/openefm/model/lxml/XPathQueries_GeorgiaCourtFiling_2001_08_08.properties.
This file contains many different
XPath queries. Some require arguments while others do not. An example of an
XPath query, ready to be executed once the arguments have been filled in follows:
# public String getActorRoleName(String actorId);
xpath.actor-role-name=//Actor[@ID='?']/Role/RoleName
The XPathHelper class inserts the arguments into the query and performs
the search.
One item worth mentioning is the existence of a main method in the InternalLxmlFilingImpl class. This method can be run by executing the run-main.sh script located in the build directory. This method is intended to help test the correctness of the XPath queries. It is intended to be used only by developers and to be re-written ( hacked up ) in order to test newer queries.
The OpenEFM project is housed and maintained using SourceForge.net resources. Therefore the latest version is always accessible. The project home page is here at http://sourceforge.net/project/openefm At this site the very latest code version can be obtained, mailing lists can be accessed, including update and release notification lists.
Anyone wishing to contribute ideas or code changes to the project is highly encouraged to do so. A developers email list is maintained at the project homepage, and is a great place to start getting involved.
Update Author: Andrew McFarland
Version: 04.12.2004
Original Author: Jim Beard
Version: 22.05.2002