11package io .ably .lib .types ;
22
3- import java .io .ByteArrayOutputStream ;
4- import java .io .IOException ;
5- import java .io .UnsupportedEncodingException ;
6- import java .lang .reflect .Type ;
7- import java .util .regex .Matcher ;
8- import java .util .regex .Pattern ;
9-
10- import org .msgpack .core .MessageFormat ;
11- import org .msgpack .core .MessagePacker ;
12- import org .msgpack .core .MessageUnpacker ;
13-
143import com .davidehrmann .vcdiff .VCDiffDecoder ;
154import com .davidehrmann .vcdiff .VCDiffDecoderBuilder ;
165import com .google .gson .JsonElement ;
6+ import com .google .gson .JsonNull ;
177import com .google .gson .JsonObject ;
188import com .google .gson .JsonParseException ;
19- import com .google .gson .JsonSerializationContext ;
20-
9+ import com .google .gson .JsonPrimitive ;
2110import io .ably .lib .util .Base64Coder ;
2211import io .ably .lib .util .Crypto .ChannelCipher ;
2312import io .ably .lib .util .Log ;
2413import io .ably .lib .util .Serialisation ;
14+ import org .msgpack .core .MessageFormat ;
15+ import org .msgpack .core .MessagePacker ;
16+ import org .msgpack .core .MessageUnpacker ;
17+
18+ import java .io .ByteArrayOutputStream ;
19+ import java .io .IOException ;
20+ import java .io .UnsupportedEncodingException ;
21+ import java .util .regex .Matcher ;
22+ import java .util .regex .Pattern ;
2523
2624public class BaseMessage implements Cloneable {
2725 /**
@@ -54,6 +52,13 @@ public class BaseMessage implements Cloneable {
5452 */
5553 public Object data ;
5654
55+ private static final String TIMESTAMP = "timestamp" ;
56+ private static final String ID = "id" ;
57+ private static final String CLIENT_ID = "clientId" ;
58+ private static final String CONNECTION_ID = "connectionId" ;
59+ private static final String ENCODING = "encoding" ;
60+ private static final String DATA = "data" ;
61+
5762 /**
5863 * Generate a String summary of this BaseMessage
5964 * @return string
@@ -75,7 +80,7 @@ public void decode(ChannelOptions opts) throws MessageDecodeException {
7580
7681 this .decode (opts , new DecodingContext ());
7782 }
78-
83+
7984 private final static VCDiffDecoder vcdiffDecoder = VCDiffDecoderBuilder .builder ().buildSimple ();
8085
8186 private static byte [] vcdiffApply (byte [] delta , byte [] base ) throws MessageDecodeException {
@@ -190,44 +195,88 @@ private String join(String[] elements, char separator, int start, int end) {
190195 return result .toString ();
191196 }
192197
193- /* Gson Serializer */
194- public static class Serializer {
195- public JsonElement serialize (BaseMessage message , Type typeOfMessage , JsonSerializationContext ctx ) {
196- JsonObject json = new JsonObject ();
197- Object data = message .data ;
198- String encoding = message .encoding ;
199- if (data != null ) {
200- if (data instanceof byte []) {
201- byte [] dataBytes = (byte [])data ;
202- json .addProperty ("data" , new String (Base64Coder .encode (dataBytes )));
203- encoding = (encoding == null ) ? "base64" : encoding + "/base64" ;
204- } else {
205- json .addProperty ("data" , data .toString ());
206- }
207- if (encoding != null ) json .addProperty ("encoding" , encoding );
198+ /**
199+ * Base for gson serialisers.
200+ */
201+ public static JsonObject toJsonObject (final BaseMessage message ) {
202+ JsonObject json = new JsonObject ();
203+ Object data = message .data ;
204+ String encoding = message .encoding ;
205+ if (data != null ) {
206+ if (data instanceof byte []) {
207+ byte [] dataBytes = (byte [])data ;
208+ json .addProperty ("data" , new String (Base64Coder .encode (dataBytes )));
209+ encoding = (encoding == null ) ? "base64" : encoding + "/base64" ;
210+ } else {
211+ json .addProperty ("data" , data .toString ());
208212 }
209- if (message .id != null ) json .addProperty ("id" , message .id );
210- if (message .clientId != null ) json .addProperty ("clientId" , message .clientId );
211- if (message .connectionId != null ) json .addProperty ("connectionId" , message .connectionId );
212- return json ;
213+ if (encoding != null ) json .addProperty ("encoding" , encoding );
214+ }
215+ if (message .id != null ) json .addProperty ("id" , message .id );
216+ if (message .clientId != null ) json .addProperty ("clientId" , message .clientId );
217+ if (message .connectionId != null ) json .addProperty ("connectionId" , message .connectionId );
218+ return json ;
219+ }
220+
221+ /**
222+ * Populate fields from JSON.
223+ */
224+ protected void read (final JsonObject map ) throws MessageDecodeException {
225+ final Long optionalTimestamp = readLong (map , TIMESTAMP );
226+ if (null != optionalTimestamp ) {
227+ timestamp = optionalTimestamp ; // unbox
228+ }
229+
230+ id = readString (map , ID );
231+ clientId = readString (map , CLIENT_ID );
232+ connectionId = readString (map , CONNECTION_ID );
233+ encoding = readString (map , ENCODING );
234+ data = readString (map , DATA );
235+ }
236+
237+ /**
238+ * Read an optional textual value.
239+ * @return The value, or null if the key was not present in the map.
240+ * @throws ClassCastException if an element exists for that key and that element is not a {@link JsonPrimitive}
241+ * or is not a valid string value.
242+ */
243+ protected String readString (final JsonObject map , final String key ) {
244+ final JsonElement element = map .get (key );
245+ if (null == element || element instanceof JsonNull ) {
246+ return null ;
247+ }
248+ return element .getAsString ();
249+ }
250+
251+ /**
252+ * Read an optional numerical value.
253+ * @return The value, or null if the key was not present in the map.
254+ * @throws ClassCastException if an element exists for that key and that element is not a {@link JsonPrimitive}
255+ * or is not a valid long value.
256+ */
257+ protected Long readLong (final JsonObject map , final String key ) {
258+ final JsonElement element = map .get (key );
259+ if (null == element || element instanceof JsonNull ) {
260+ return null ;
213261 }
262+ return element .getAsLong ();
214263 }
215264
216265 /* Msgpack processing */
217266 boolean readField (MessageUnpacker unpacker , String fieldName , MessageFormat fieldType ) throws IOException {
218267 boolean result = true ;
219268 switch (fieldName ) {
220- case "timestamp" :
269+ case TIMESTAMP :
221270 timestamp = unpacker .unpackLong (); break ;
222- case "id" :
271+ case ID :
223272 id = unpacker .unpackString (); break ;
224- case "clientId" :
273+ case CLIENT_ID :
225274 clientId = unpacker .unpackString (); break ;
226- case "connectionId" :
275+ case CONNECTION_ID :
227276 connectionId = unpacker .unpackString (); break ;
228- case "encoding" :
277+ case ENCODING :
229278 encoding = unpacker .unpackString (); break ;
230- case "data" :
279+ case DATA :
231280 if (fieldType .getValueType ().isBinaryType ()) {
232281 byte [] byteData = new byte [unpacker .unpackBinaryHeader ()];
233282 unpacker .readPayload (byteData );
@@ -256,27 +305,27 @@ protected int countFields() {
256305
257306 void writeFields (MessagePacker packer ) throws IOException {
258307 if (timestamp > 0 ) {
259- packer .packString ("timestamp" );
308+ packer .packString (TIMESTAMP );
260309 packer .packLong (timestamp );
261310 }
262311 if (id != null ) {
263- packer .packString ("id" );
312+ packer .packString (ID );
264313 packer .packString (id );
265314 }
266315 if (clientId != null ) {
267- packer .packString ("clientId" );
316+ packer .packString (CLIENT_ID );
268317 packer .packString (clientId );
269318 }
270319 if (connectionId != null ) {
271- packer .packString ("connectionId" );
320+ packer .packString (CONNECTION_ID );
272321 packer .packString (connectionId );
273322 }
274323 if (encoding != null ) {
275- packer .packString ("encoding" );
324+ packer .packString (ENCODING );
276325 packer .packString (encoding );
277326 }
278327 if (data != null ) {
279- packer .packString ("data" );
328+ packer .packString (DATA );
280329 if (data instanceof byte []) {
281330 byte [] byteData = (byte [])data ;
282331 packer .packBinaryHeader (byteData .length );
0 commit comments