Open Lowcode message is available on Open Lowcode Github. Just head there if you want to see the code first.
Design Rationale
At the beginning of Open Lowcode adventure, I had to plan sending structured information over a network. The standard solution would be sending an XML message, but this is not satisfactory: XML messages are verbose, complex, and slow to code / decode. So I designed a light structured format with the following rationale:
- It should be human readable: this makes dedoding much easier. This means the message is sent as text, which means accepting the 25% overhead of encoding binary files;
- It should be compact
- For normal messages, it should not weight much more than the payload and the message element names.
- It should have a mode to send data in a table, weighting approximately the same thing as a CSV file
- It should have enough information that a desynchronization between message sent and expected received message is detected immediately (wrong structures / wrong field names…)
- It should not require to store the entirety of a message sent in memory.
Message Sample
A sample message in OLc Message (short for Open Lowcode Message) is shown below.
{
[STR1:FLD1="Content of field 1"
[SUBSTR1_1:FLD1_1="Content of field 1.1",FLD1_2=D20190805T171356]
]
}
Basics are:
- Messages are delimited by curly brackets ‘{‘ and ‘}’. After sending a message, it is assumed the other party will be able to conclude an action.
- Messages are made of structures deliminated by square brackets ‘[‘ and ‘]’. The name just after the opening square bracket is the name of the structure. If the structure contains fields, a column ‘:’ is displayed after the name of the structure
- Then, fields are shown with a succession of NAME=VALUE, separated. If Value is a text, it is between double quotes.
Writing a message
A message is written in code in the order it will be printed: opening a message, opening a structure, declaring the fields inside… The code below is creating the message shown above.
messagewriter.startNewMessage();
messagewriter.startStructure("STR1");
messagewriter.addStringField("FLD1","Content of field 1");
messagewriter.startStructure("SUBSTR1_1");
messagewriter.addStringField("FLD1_1","Content of field 1.1");
messagewriter.addDateField("FLD1_2",new Date());
messagewriter.endStructure("SUBSTR1_1");
messagewriter.endStructure("STR1");
Reading a message
You can read a message with a very similar code to the writing. The Reader has convenience method that will check the next element you expect is indeed present, or else throw an exception.
reader.returnNextMessageStart();
reader.returnNextStartStructure("STR1");
System.out.println("Content of Field 1 "+reader.returnNextStringField("FLD1"));
reader.returnNextStartStructure("SUBSTR1_1");
System.out.println("Content of Field 1.1 "+reader.returnNextStringField("FLD1_1"));
System.out.println("Content of Field 1.2 "+reader.returnNextDateField("FLD1_2"));
reader.returnNextEndStructure("SUBSTR1_1");
reader.returnNextEndStructure("STR1");
reader.returnNextEndMessage();
Exception Handling
Errors are managed the following way:
- If ithe writer receives an illogical instruction, a RuntimeException is thrown. An example is trying to close a structure that was not opened. This is a development error that you should catch, as any other similar bug, at a high level in your program.
- If the program reading the message is expecting something else than what is in the message, the framework will throw a RuntimeException.
- If any communication error happens during writing or reading of messages, an IOException is thrown. There should probably be a place in your program where you try to recover IOException and relaunch messages
- If a party processing a request encounters an error, it can send an error message element at any point during the sending of a message. This will generate an OLcRemoteException, that you can also catch at the appropriate level.
Sending of Compact Array
The toolset offers the possibility to send a compact data array in a format similar to CSV, i.e. easy to parse and compact. An array will look as shown in the message sample below
{
((TESTARRAY(FIELD1="O",FIELD2="I",FIELD3="X",FIELD4="S")
(T,123,X12.5,"Line 1 ")
(F,-50,X-123.5,"Line 2 ")
(T,45000,X45.5,"Line 45 --< ") ))
}
The first line is the declaration of the fields present,s and the other lines contain the data. A compact array is delimited by a double bracket ‘((‘ and ‘))’.