-
Notifications
You must be signed in to change notification settings - Fork 6
SerializedMessages
Messages are disseminated in your ASAP P2P system. The actual message structure is opaque to the system. Your message content is of type byte[]. It is your task to produce this byte array and to deserialize received messages. You can implement both methods as you please. Nevertheless, there are some experiences we have made after implementing several apps. We want to share this best practise.
public class YourMessage {
public static YourMessage produceYourMessage(/* your message parts */) { ... }
public static YourMessage produceYourMessage(byte[] serializedMessage) { ... }
public byte[] serialize() { ..}
}
This code sketches a message class. It provides two static factory methods: one produces a message object by your parameters. The other one produces a message object from its serialized format. The third – and only non static – method serializes this message.
Lets assume we implement a messenger. A message my contain a string (message content) and a timestamp. Their would be code somewhere in your application:
...
CharSequence message = ... // message e.g. from GUI
long timestamp = System.currentTimeMillis();
...
Your message object could look like this:
public class YourMessage {
private CharSequence message;
private long timestamp;
public static YourMessage produceYourMessage(CharSequence message, long timestamp) {
this.message = message, this.timestamp = timestamp;
}
public static YourMessage produceYourMessage(byte[] serializedMessage) { ... }
public byte[] serialize() { .. }
}
Now, we have got a structure. How would we serialize those two message parts into a byte array. You might think of libraries which produce e.g. a JSON String which can be transformed into byte[]. Any JSON like format has git an overhead, though. XML is worse. There is a very simple way which produces a very compact byte array.
public class YourMessage {
...
public byte[] serialize() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream daos = new DataOutputStream(baos);
daos.writeUTF(this.message.toString());
daos.writeLong(this.timestamp);
return baos.toByteArray();
}
public static YourMessage produceYourMessage(byte[] serializedMessage) {
ByteArrayInputStream bais = new ByteArrayInputStream(serializedMessage);
DataInputStream dais = new DataInputStream (bais);
String message = dais.readUTF();
long timeStamp = dais.readLong();
return new YourMessage(message, timeStamp);
}
}
The result is very compact. Take care to write and read all parts of your message in the same order. (We talk from experience. Finding those kinds of bugs is time consuming and frustrating if found.)
ASAP is a protocol. We also had to serialize and deserialize messages. There is a public class ASAPSerialization. It works very similar to this previous examples. There are write and read methods for different data types. There is always an InputStream or OutputStream expected. Use an ByteArrayInputStream and ByteArrayOutputStream and replace e.g. dais.readUTF()
with readCharSequenceParameter(bais);
public class YourMessage {
...
public byte[] serialize() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ASAPSerialization.writeCharSequenceParameter(this.message, baos);
ASAPSerialization.writeLongParameter(this.timestamp, baos);
return baos.toByteArray();
}
public static YourMessage produceYourMessage(byte[] serializedMessage) {
ByteArrayInputStream bais = new ByteArrayInputStream(serializedMessage);
CharSequence message = ASAPSerialization.readCharSequenceParameter(bais);
long timeStamp = ASAPSerialization.readLongParameter(bais);
return new YourMessage(message, timeStamp);
}
}
Our ASAPSerialization class also offers methods to handle sets of CharSequences (Set<java.lang.CharSequence>
) and two-dimensional byte arrays (byte[][]
).
Whatever you decide - please do not even think of using XML and produce a byte array. The overhead is immense.
A more complex example can be found in our SharkMessenger component: SharkMessage makes the described job. It also provides end-to-end encryption and signing.
It is a good point to talk about cryptography. This library supports E2E encryption.