org.jboss.aerogear.simplepush.protocol.impl.json.JsonUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.jboss.aerogear.simplepush.protocol.impl.json.JsonUtil.java

Source

/**
 * JBoss, Home of Professional Open Source
 * Copyright Red Hat, Inc., and individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.aerogear.simplepush.protocol.impl.json;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.jboss.aerogear.simplepush.protocol.Ack;
import org.jboss.aerogear.simplepush.protocol.AckMessage;
import org.jboss.aerogear.simplepush.protocol.HelloMessage;
import org.jboss.aerogear.simplepush.protocol.HelloResponse;
import org.jboss.aerogear.simplepush.protocol.MessageType;
import org.jboss.aerogear.simplepush.protocol.NotificationMessage;
import org.jboss.aerogear.simplepush.protocol.PingMessage;
import org.jboss.aerogear.simplepush.protocol.RegisterMessage;
import org.jboss.aerogear.simplepush.protocol.RegisterResponse;
import org.jboss.aerogear.simplepush.protocol.UnregisterMessage;
import org.jboss.aerogear.simplepush.protocol.UnregisterResponse;
import org.jboss.aerogear.simplepush.protocol.impl.AckImpl;
import org.jboss.aerogear.simplepush.protocol.impl.AckMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.HelloMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.HelloResponseImpl;
import org.jboss.aerogear.simplepush.protocol.impl.NotificationMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.PingMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.RegisterMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.RegisterResponseImpl;
import org.jboss.aerogear.simplepush.protocol.impl.StatusImpl;
import org.jboss.aerogear.simplepush.protocol.impl.UnregisterMessageImpl;
import org.jboss.aerogear.simplepush.protocol.impl.UnregisterResponseImpl;

import java.io.IOException;
import java.io.StringWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

/**
 * JSON utility class for transforming SimplePush messages to and from JSON.
 *
 */
public final class JsonUtil {

    private static ObjectMapper om = createObjectMapper();

    private static ObjectMapper createObjectMapper() {
        om = new ObjectMapper();
        final SimpleModule module = new SimpleModule("MyModule",
                new Version(0, 10, 0, null, "org.jboss.aerogear", "aerogear-simplepush-server"));
        module.addDeserializer(MessageType.class, new MessageTypeDeserializer());

        module.addDeserializer(RegisterMessageImpl.class, new RegisterDeserializer());
        module.addSerializer(RegisterMessageImpl.class, new RegisterSerializer());
        module.addDeserializer(RegisterResponseImpl.class, new RegisterResponseDeserializer());
        module.addSerializer(RegisterResponseImpl.class, new RegisterResponseSerializer());

        module.addDeserializer(HelloMessageImpl.class, new HelloDeserializer());
        module.addSerializer(HelloMessageImpl.class, new HelloSerializer());
        module.addDeserializer(HelloResponseImpl.class, new HelloResponseDeserializer());
        module.addSerializer(HelloResponseImpl.class, new HelloResponseSerializer());

        module.addDeserializer(AckMessageImpl.class, new AckDeserializer());
        module.addSerializer(AckMessageImpl.class, new AckSerializer());

        module.addDeserializer(PingMessageImpl.class, new PingDeserializer());
        module.addSerializer(PingMessageImpl.class, new PingSerializer());

        module.addDeserializer(NotificationMessageImpl.class, new NotificationDeserializer());
        module.addSerializer(NotificationMessageImpl.class, new NotificationSerializer());

        module.addDeserializer(UnregisterMessageImpl.class, new UnregisterDeserializer());
        module.addSerializer(UnregisterMessageImpl.class, new UnregisterMessageSerializer());
        module.addDeserializer(UnregisterResponseImpl.class, new UnregisterResponseDeserializer());
        module.addSerializer(UnregisterResponseImpl.class, new UnregisterResponseSerializer());

        om.registerModule(module);
        return om;
    }

    private JsonUtil() {
    }

    /**
     * Transforms from JSON to the type specified.
     *
     * @param json the json to be transformed.
     * @param type the Java type that the JSON should be transformed to.
     * @return T an instance of the type populated with data from the json message.
     */
    public static <T> T fromJson(final String json, final Class<T> type) {
        try {
            return om.readValue(json, type);
        } catch (final Exception e) {
            throw new RuntimeException("error trying to parse json [" + json + "]", e);
        }
    }

    /**
     * Transforms from Java object notation to JSON.
     *
     * @param obj the Java object to transform into JSON.
     * @return {@code String} the json representation for the object.
     */
    public static String toJson(final Object obj) {
        final StringWriter stringWriter = new StringWriter();
        try {
            om.writeValue(stringWriter, obj);
            return stringWriter.toString();
        } catch (final Exception e) {
            throw new RuntimeException("error trying to parse json [" + obj + "]", e);
        }
    }

    /**
     * A convenience method for transforming a SimplePush message frame into an instance
     * of {@link MessageType}.
     *
     * @param json the JSON representing a message in the SimplePush protocol
     * @return {@link MessageType} an instance of MessageType for the passed in json.
     */
    public static MessageType parseFrame(final String json) {
        return fromJson(json, MessageType.class);
    }

    private static class RegisterDeserializer extends JsonDeserializer<RegisterMessageImpl> {

        @Override
        public RegisterMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            return new RegisterMessageImpl(node.get(RegisterMessage.CHANNEL_ID_FIELD).asText());
        }
    }

    private static class RegisterSerializer extends JsonSerializer<RegisterMessage> {

        @Override
        public void serialize(final RegisterMessage register, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(RegisterMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(register.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(RegisterMessage.CHANNEL_ID_FIELD);
            jgen.writeString(register.getChannelId());
            jgen.writeEndObject();
        }
    }

    private static class RegisterResponseDeserializer extends JsonDeserializer<RegisterResponseImpl> {

        @Override
        public RegisterResponseImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            return new RegisterResponseImpl(node.get(RegisterMessage.CHANNEL_ID_FIELD).asText(),
                    new StatusImpl(node.get(RegisterResponseImpl.STATUS_FIELD).asInt(), "N/A"),
                    node.get(RegisterResponseImpl.PUSH_ENDPOINT__FIELD).asText());
        }
    }

    private static class RegisterResponseSerializer extends JsonSerializer<RegisterResponse> {

        @Override
        public void serialize(final RegisterResponse registerResponse, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(RegisterResponse.MESSSAGE_TYPE_FIELD);
            jgen.writeString(registerResponse.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(RegisterResponse.CHANNEL_ID_FIELD);
            jgen.writeString(registerResponse.getChannelId());
            jgen.writeFieldName(RegisterResponse.STATUS_FIELD);
            jgen.writeNumber(registerResponse.getStatus().getCode());
            jgen.writeFieldName(RegisterResponse.PUSH_ENDPOINT__FIELD);
            jgen.writeString(registerResponse.getPushEndpoint());
            jgen.writeEndObject();
        }
    }

    private static class HelloDeserializer extends JsonDeserializer<HelloMessageImpl> {

        @Override
        public HelloMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode channelIdsNode = node.get(HelloMessage.CHANNEL_IDS_FIELD);
            final Set<String> channelIds = new HashSet<String>();
            if (channelIdsNode != null && channelIdsNode.isArray()) {
                for (JsonNode channelIdNode : channelIdsNode) {
                    channelIds.add(channelIdNode.asText());
                }
            }
            final JsonNode uaid = node.get(HelloMessage.UAID_FIELD);
            if (uaid != null) {
                return new HelloMessageImpl(node.get(HelloMessage.UAID_FIELD).asText(), channelIds);
            } else {
                return new HelloMessageImpl();
            }
        }
    }

    private static class HelloSerializer extends JsonSerializer<HelloMessage> {

        @Override
        public void serialize(final HelloMessage hello, final JsonGenerator jgen, final SerializerProvider provider)
                throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(HelloMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(hello.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(HelloMessage.UAID_FIELD);
            jgen.writeString(hello.getUAID());
            jgen.writeArrayFieldStart(HelloMessage.CHANNEL_IDS_FIELD);
            for (String channelId : hello.getChannelIds()) {
                jgen.writeString(channelId);
            }
            jgen.writeEndArray();
            jgen.writeEndObject();
        }
    }

    private static class HelloResponseDeserializer extends JsonDeserializer<HelloResponseImpl> {

        @Override
        public HelloResponseImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode uaid = node.get(HelloMessage.UAID_FIELD);
            return new HelloResponseImpl(UUID.fromString(uaid.asText()).toString());
        }
    }

    private static class HelloResponseSerializer extends JsonSerializer<HelloResponse> {

        @Override
        public void serialize(final HelloResponse helloResponse, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(HelloMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(helloResponse.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(HelloMessage.UAID_FIELD);
            jgen.writeString(helloResponse.getUAID());
            jgen.writeEndObject();
        }
    }

    private static class AckDeserializer extends JsonDeserializer<AckMessageImpl> {

        @Override
        public AckMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode acksNode = node.get(AckMessage.UPDATES_FIELD);
            final Set<Ack> acks = new HashSet<Ack>();
            if (acksNode.isArray()) {
                for (JsonNode ackNode : acksNode) {
                    acks.add(new AckImpl(ackNode.get("channelID").asText(), ackNode.get("version").asLong()));
                }
            }
            return new AckMessageImpl(acks);
        }
    }

    private static class AckSerializer extends JsonSerializer<AckMessage> {

        @Override
        public void serialize(final AckMessage ackMessage, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(AckMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(ackMessage.getMessageType().toString().toLowerCase());
            jgen.writeArrayFieldStart(AckMessage.UPDATES_FIELD);
            for (Ack ack : ackMessage.getAcks()) {
                jgen.writeStartObject();
                jgen.writeFieldName("channelID");
                jgen.writeString(ack.getChannelId());
                jgen.writeFieldName(AckMessage.VERSION_FIELD);
                jgen.writeNumber(ack.getVersion());
                jgen.writeEndObject();
            }
            jgen.writeEndArray();
            jgen.writeEndObject();
        }
    }

    private static class NotificationDeserializer extends JsonDeserializer<NotificationMessageImpl> {

        @Override
        public NotificationMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode updatesNode = node.get(NotificationMessage.UPDATES_FIELD);
            final Set<Ack> acks = new HashSet<Ack>();
            if (updatesNode.isArray()) {
                for (JsonNode channelNode : updatesNode) {
                    final JsonNode versionNode = channelNode.get(NotificationMessage.VERSION_FIELD);
                    final JsonNode channelIdNode = channelNode.get(RegisterMessage.CHANNEL_ID_FIELD);
                    acks.add(new AckImpl(channelIdNode.asText(), versionNode.asLong()));
                }
            }
            return new NotificationMessageImpl(acks);
        }
    }

    private static class NotificationSerializer extends JsonSerializer<NotificationMessage> {

        @Override
        public void serialize(final NotificationMessage notification, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(NotificationMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(notification.getMessageType().toString().toLowerCase());
            jgen.writeArrayFieldStart(NotificationMessage.UPDATES_FIELD);
            for (Ack ack : notification.getAcks()) {
                jgen.writeStartObject();
                jgen.writeFieldName(RegisterMessage.CHANNEL_ID_FIELD);
                jgen.writeString(ack.getChannelId());
                jgen.writeFieldName(NotificationMessage.VERSION_FIELD);
                jgen.writeNumber(ack.getVersion());
                jgen.writeEndObject();
            }
            jgen.writeEndArray();
            jgen.writeEndObject();
        }
    }

    private static class UnregisterDeserializer extends JsonDeserializer<UnregisterMessageImpl> {

        @Override
        public UnregisterMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode channelIdNode = node.get(RegisterMessage.CHANNEL_ID_FIELD);
            return new UnregisterMessageImpl(channelIdNode.asText());
        }
    }

    private static class UnregisterMessageSerializer extends JsonSerializer<UnregisterMessage> {

        @Override
        public void serialize(final UnregisterMessage unregister, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(UnregisterMessage.MESSSAGE_TYPE_FIELD);
            jgen.writeString(unregister.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(RegisterMessage.CHANNEL_ID_FIELD);
            jgen.writeString(unregister.getChannelId());
            jgen.writeEndObject();
        }
    }

    private static class MessageTypeDeserializer extends JsonDeserializer<MessageType> {

        @Override
        public MessageType deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode messageTypeNode = node.get(MessageType.MESSSAGE_TYPE_FIELD);
            return new MessageType() {
                @Override
                public Type getMessageType() {
                    if (messageTypeNode == null) {
                        return MessageType.Type.PING;
                    }
                    return MessageType.Type.valueOf(messageTypeNode.asText().toUpperCase());
                }
            };
        }
    }

    private static class UnregisterResponseDeserializer extends JsonDeserializer<UnregisterResponseImpl> {

        @Override
        public UnregisterResponseImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            final JsonNode channelIdNode = node.get(RegisterResponse.CHANNEL_ID_FIELD);
            return new UnregisterResponseImpl(channelIdNode.asText(),
                    new StatusImpl(node.get(UnregisterResponse.STATUS_FIELD).asInt(), "N/A"));
        }
    }

    private static class UnregisterResponseSerializer extends JsonSerializer<UnregisterResponse> {

        @Override
        public void serialize(final UnregisterResponse unregisterResponse, final JsonGenerator jgen,
                final SerializerProvider provider) throws IOException {
            jgen.writeStartObject();
            jgen.writeFieldName(RegisterResponse.MESSSAGE_TYPE_FIELD);
            jgen.writeString(unregisterResponse.getMessageType().toString().toLowerCase());
            jgen.writeFieldName(RegisterResponse.CHANNEL_ID_FIELD);
            jgen.writeString(unregisterResponse.getChannelId());
            jgen.writeFieldName(RegisterResponse.STATUS_FIELD);
            jgen.writeNumber(unregisterResponse.getStatus().getCode());
            jgen.writeEndObject();
        }
    }

    private static class PingDeserializer extends JsonDeserializer<PingMessageImpl> {

        @Override
        public PingMessageImpl deserialize(final JsonParser jp, final DeserializationContext ctxt)
                throws IOException {
            final ObjectCodec oc = jp.getCodec();
            final JsonNode node = oc.readTree(jp);
            if (node.isObject() && node.size() == 0) {
                return new PingMessageImpl(node.toString());
            }
            throw new RuntimeException("Invalid Ping message format : [" + node.toString() + "]");
        }
    }

    private static class PingSerializer extends JsonSerializer<PingMessage> {

        @Override
        public void serialize(final PingMessage ping, final JsonGenerator jgen, final SerializerProvider provider)
                throws IOException {
            jgen.writeStartObject();
            jgen.writeEndObject();
        }
    }

}