Page 2 of 5
Entity implementation creates a bidirectional map between the data entity it represents and a MapperRecord -- mandated by the Entity interface. It should know how to marshal (or translate) data from its data source into a MapperRecord, as well as write a MapperRecord's contents to its respective data store.
MapperRecord object are placed in an XML file that the entity parses at runtime.
Entity implementation has a two-parameter constructor: the name of the map to use and the operation to perform (Entity.READ or Entity.WRITE). All other object variables should be accessible via getter and setter methods. (I will clarify later why this rule is necessary):protected String fileName;
//Constructor that creates a file entity
public FileEntity(String entityAlias, int operation) {
this.fileMapName = entityAlias;
this.operation = operation;
}
public void setFileName(String fName) { //Sets filename
this.fileName = fName;
}
public String getFileName() { //Gets filename
return this.fileName;
}
Once all the framework's entities can successfully create and store MapperRecords based on XML metadata, you can effortlessly create execution paths to map data from one to another:
Entity readEntity = new FileEntity("from_map",Entity.READ);
readEntity.setFileName("/tmp/from.txt");
Entity writeEntity = new TableEntity("table_map",Entity.WRITE);
//Open entities for reading and writing
readEntity.open();
writeEntity.open();
//For each read record, write record to write entity
MapperRecord record;
while ((record = (MapperRecord)readEntity.readRecord()) != null) {
if (record.isEmpty()) {
continue;
}
writeEntity.writeRecord(record);
}
//Close entities
writeEntity.close();
readEntity.close();
I originally designed this framework to reliably parse and create transaction-laden text files for exchange with business affiliates. Creating a custom Perl script for each affiliate's incoming (and outgoing) file formats is an arduous task for any development team, without even considering the testing and maintenance nightmares. As an alternative to Perl scripting, this reusable and extendable application pattern reduces the time spent on the development lifecycle's latter stages.
So let's start with the classic example of reading records from a text file and writing them to a database to show how well
the design works. Creating the two entities, FileEntity and TableEntity, which implement the Entity interface, is fairly simple.
The FileEntity class parses an XML file, like the following, to load different file formats into memory (using Apache's Xerces SAX parser):
<!-- FileEntityList.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<filemaps>
<map name="from_map" delimiter="," > <!-- comma-delimited file
format -->
<field name="id" />
<field name="amount" />
<field name="date" />
</map>
<map name="to_map" delimiter="|" > <!-- pipe-delimited file format
-->
<field name="date" />
<field name="amount" />
<field name="id" />
</map>
<map name="fixed_map"> <!--fixed-length file format -->
<field name="id" start="1" end="2" />
<field name="amount" start="3" end="32" />
<field name="date" start="33" end="62" />
</map>
</filemaps>
The from_map map describes a comma-delimited file format while the fixed_map map describes a fixed-length file format. Armed with the my_map file format, the READ operation, and a filename, FileEntity's readRecord() method can marshal the file's comma-delimited records into a MapperRecord keyed by the field names in the XML file: