Monday, April 07, 2008

TranScope and Xerialize

If you have no idea what XML, Serialization, or if you only think of Java as the coffee, then leave now. Or just continue if you are curious.

I've been working on a Pet Project for some time now. It's written in Java, using NetBeans, Swing and with Scripting done in Groovy. It's a very generic Transaction Reader and Simulator.

Why? It is just Fun! I'm learning a lot by working on it, and its pretty useful, at least for me.

A Transaction is either a specific kind of a message, or a record in a file.

These transactions are Financial transactions (mostly). But the project is generic enough to handle any message or record, as long as you know what the messages are supposed to be like.

Messages can be any kind of format. I am currently working on BASE24 ISO, BASE24 ATM and POS Internal messages, and some ATM native messages. Other messages like VISA, MasterCard, or any Switch can be easily added to the system. More on this later.

Currently, the system can read ACI XPNET Audit Files, and any Tandem Enscribe file. Just transfer the files to the PC in Binary (or use the built-in transparent FTP feature in the program) to read all records and expand them.

So, what can you do with these messages? Well, the main interface displays the expanded messages as a cool looking Tree, XML, or Hex Dump. You can search the files for any text, or any value in any field. You can output the data as nice XML, or CSV. Or even write a script to put the data to an RDBMS. I used it to extract BASE24 TLF fields (including some Tokens) to an RDBMS for analysis.

The Simulator is still in its early stages under development, but so far, it can open TCP sockets and talk back to a BASE24 host in BASE24 ISO-8583 messages. The Simulator is actually a Groovy script that talks in high level using Structures. It does NOT do any of the cumbersome ISO message packing at all. That is all done by the Message Templates. All you need the Groovy Script is something like:

MSG.dump()
if(MSG.MSG_TYP.value == "0800") {
MSG.MSG_TYP.value = "0810";
bits = MSG.BIT_FIELDS;
// Add the response code field
resp = MSG.BIT_FIELDS.add("39.RESP_CDE");
// and set to 00
resp.value = "00";
// then reply
SRC.write(MSG)
// and we are done.
return true;
}

One thing that I'm planning to do is have the program read some file (Audit or Transaction Log) and create messages to send to a receiver. That will be fun! and will be very useful for testing and trouble-shooting.

Literally anything is possible. Really! I used that!

Okay so how do you define a Message? All messages are defined in XML, and human readable XML.

The XML describes what the message looks like. The program will do the conversion in and out. You do not write any line of code to expand any message. A sample XML snippet that describes a message is:

1 <Struct name="B7">
2 <BNumber size="8" name="RBA"/>
3 <FString size="35" name="TLF_NAM"/>
4 <FString size="1" name="TKN_RETRV_OPT"/>
5 <Struct name="ATM_KEY">
6 <Struct name="CRD">
7 <FString size="4" name="LN"/>
8 <FString size="4" name="FIID"/>
9 <FString size="19" name="PAN"/>
10 <FString size="3" name="MBR_NUM"/>
11 </Struct>
12 </Struct>
13 </Struct>
That XML should be readable and maintainable by humans.

I created some utilities in the program itself to convert DDL (the DDLTAL kind) to XML, because Tandem does not give me XML of its data structures. And because I am too lazy to convert it by hand. I'd spend 2 weeks automating something I can manually do in 2 hours. That's just me.


Which brings me to Xerialize. To create and read the XML, I initially worked with JAXB. I also tried XStream and Simple. Those did not give me the flexibility I needed, specially with the constructs I have. JAXB was not pleasant, but it the job. It is very picky about certain things, specially about polymorphic lists, which i heavily rely on. When I sub-classed some base class, some properties where written to XML twice!. But the last straw was when I upgraded to JDK 1.6u5 (I used u3). My XML was not readable at all. Something was broken, and not just for me. I posted an issue on the JAXB list, and some other people had the same issue. And the issue is not even looked at for a month now!

Screw JAXB, I'll create my own XML. And so Xerialize was born. About four days ago. Xerializer is a very generic library for serializing Java objects using Annotations.

You just annotate the getters and setters they way you need them, and XML is written, and read back. Your annotated getters and setters are called as usual when reading and writing. Discover is all done at runtime using Reflection. Anything that is not annotated is skipped.
No XJC, no Schema compiler, no nested XmlElment for XmlElements. Plain and simple. I currently use DOM to do the XML work, but may change that later.

These are the general rules for using Xerialize:
  1. The tag name is the Java class name, except for some nested lists You can qualify the class name's package using XML namespace. So in the above sample, FString is a Java class.
  2. Simple built-in class properties should be XML attributes. Annotate the ones you need.
  3. Object properties are XML Elements. Annotate the ones you need.
  4. Generic or Polymorphic lists should be handled without any extra configuration. If the FStringV is a sub-class of FString, then I can put that XML element and the reading writing just works.
  5. I know what methods to use for getters and setters, so Xerialize will only use what I annotate. You can actually hide an annotated property in a subclass by overriding the getter and setter and not annotate them.
  6. Default values are null during writing XML. Any null element will not be written. If an element is not in the XML, then the setter will not be called.
  7. Must have public default constructor.
  8. All annotated methods must be public. Xerialize does not use magic to look at private fields or methods.
  9. XML must support namespaces and XInlcude.
  10. Xerialize must support an easy to use method for nested Tree like nodes. A node containing a list of other nodes and so on. All these nodes are of one subclass. In the above example, Struct is superclass for both BNumber and FString.
And there you have it. I just opened a Google Code project and will publish the first draft soon.

Just Google it!