cf.nats.DefaultCfNats.java Source code

Java tutorial

Introduction

Here is the source code for cf.nats.DefaultCfNats.java

Source

/*
 *   Copyright (c) 2013 Intellectual Reserve, Inc.  All rights reserved.
 *
 *   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 cf.nats;

import cf.common.JsonObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import nats.NatsException;
import nats.client.Message;
import nats.client.MessageHandler;
import nats.client.Nats;
import nats.client.Registration;
import nats.client.Request;
import nats.client.Subscription;

import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;

/**
 * The default implementation of {@code CfNats}.
 *
 * @author Mike Heath <elcapo@gmail.com>
 */
public class DefaultCfNats implements CfNats {

    private final Nats nats;
    private final ObjectMapper mapper;

    public DefaultCfNats(Nats nats) {
        this.nats = nats;

        // Configure the Jackson JSON mapper
        mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    @Override
    public void publish(MessageBody message) {
        final String subject = getPublishSubject(message);
        final String encoding = encode(message);
        nats.publish(subject, encoding);
    }

    @Override
    public Registration publish(MessageBody message, long period, TimeUnit timeUnit) {
        final String subject = getPublishSubject(message);
        final String encoding = encode(message);
        return nats.publish(subject, encoding, period, timeUnit);
    }

    @Override
    public <R extends MessageBody<Void>> Request request(MessageBody<R> message, long timeout, TimeUnit unit,
            final RequestResponseHandler<R> handler) {
        final String subject = getPublishSubject(message);
        final String encoding = encode(message);
        final Type[] genericInterfaces = message.getClass().getGenericInterfaces();
        final ParameterizedType replyType = (ParameterizedType) genericInterfaces[0];
        final Class<R> messageReplyClass = (Class<R>) replyType.getActualTypeArguments()[0];

        return nats.request(subject, encoding, timeout, unit,
                createMessageHandler(messageReplyClass, new PublicationHandler<R, Void>() {
                    @Override
                    public void onMessage(Publication<R, Void> publication) {
                        handler.onResponse(publication);
                    }
                }));
    }

    private String getPublishSubject(MessageBody message) {
        if (message == null) {
            throw new IllegalArgumentException("message cannot be null");
        }
        final String subject = getSubject(message.getClass());
        if (subject == null) {
            throw new NatsException("Unable to publish message of type " + message.getClass().getName()
                    + ", missing annotation " + NatsSubject.class.getName());
        }
        return subject;
    }

    @Override
    public <T extends MessageBody<R>, R> Subscription subscribe(Class<T> type, PublicationHandler<T, R> handler) {
        return subscribe(type, null, null, handler);
    }

    @Override
    public <T extends MessageBody<R>, R> Subscription subscribe(Class<T> type, Integer maxMessages,
            PublicationHandler<T, R> handler) {
        return subscribe(type, null, maxMessages, handler);
    }

    @Override
    public <T extends MessageBody<R>, R> Subscription subscribe(Class<T> type, String queueGroup,
            PublicationHandler<T, R> handler) {
        return subscribe(type, queueGroup, null, handler);
    }

    @Override
    public <T extends MessageBody<R>, R> Subscription subscribe(Class<T> type, String queueGroup,
            Integer maxMessages, PublicationHandler<T, R> handler) {
        final Subscription subscribe = nats.subscribe(getSubject(type), queueGroup, maxMessages);
        subscribe.addMessageHandler(createMessageHandler(type, handler));
        return subscribe;
    }

    private <T extends MessageBody<R>, R> MessageHandler createMessageHandler(final Class<T> type,
            final PublicationHandler<T, R> handler) {
        final ObjectReader reader = (JsonObject.class.isAssignableFrom(type)) ? mapper.reader(type) : null;
        return new MessageHandler() {
            @Override
            public void onMessage(final Message message) {
                final String body = message.getBody();
                try {
                    final T cfMessage = reader == null ? type.newInstance() : reader.<T>readValue(body);
                    handler.onMessage(new Publication<T, R>() {
                        @Override
                        public Message getNatsMessage() {
                            return message;
                        }

                        @Override
                        public T getMessageBody() {
                            return cfMessage;
                        }

                        @Override
                        public void reply(R replyMessage) {
                            message.reply(encode(replyMessage));
                        }

                        @Override
                        public void reply(R replyMessage, long delay, TimeUnit unit) {
                            message.reply(encode(replyMessage), delay, unit);
                        }
                    });
                } catch (Exception e) {
                    throw new NatsException(e);
                }
            }
        };
    }

    public Nats getNats() {
        return nats;
    }

    private String encode(Object value) {
        if (!(value instanceof JsonObject)) {
            return null;
        }
        try {
            return mapper.writeValueAsString(value);
        } catch (IOException e) {
            throw new NatsException(e);
        }
    }

    private String getSubject(Class<?> type) {
        NatsSubject subject = type.getAnnotation(NatsSubject.class);
        return subject.value();
    }
}