scp.targets.vertx.CommunicationManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for scp.targets.vertx.CommunicationManagerImpl.java

Source

/*
 * Authors:
 *   Venkatesh-Prasad Ranganath
 *
 * Copyright (c) 2014, Kansas State University
 * Licensed under Eclipse Public License v1.0
 * http://www.eclipse.org/legal/epl-v10.html
 */

package scp.targets.vertx;

import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.eventbus.DeliveryOptions;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.ReplyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scp.api.*;
import scp.impl.*;
import scp.impl.ExecutorInvoker.ExecutorInvokerStatus;
import scp.impl.ReceiverInvoker.ReceiverInvokerStatus;
import scp.impl.ResponderInvoker.ResponderInvokerStatus;
import scp.util.Pair;
import scp.util.TimestampedBox;

import scp.util.NonNull;

import java.io.*;
import java.util.concurrent.Semaphore;

/**
 * A <a href="http://vertx.io">Vert.x</a> event bus based implementation of communication manager.
 */
public class CommunicationManagerImpl implements CommunicationManager {
    private final static Logger LOGGER = LoggerFactory.getLogger(CommunicationManagerImpl.class);
    private Vertx vertx;
    private EventBus eventBus;

    /**
     * Instantiates a new Communication manager impl based on non-clustered Vertx instance.
     */
    public CommunicationManagerImpl() {
        this.vertx = Vertx.vertx();
    }

    /**
     * Instantiates a new Communication manager impl based on clustered Vertx instance.
     *
     * @param port the port.  If this argument is 0, then the system will pick the port.
     * @param hostname the hostname
     */
    public CommunicationManagerImpl(int port, String hostname) {
        final Semaphore _sem = new Semaphore(0);
        final Handler<AsyncResult<Vertx>> _handler = event -> {
            try {
                if (event.succeeded()) {
                    LOGGER.info("Vertx creation succeeded");
                    CommunicationManagerImpl.this.vertx = event.result();
                } else {
                    LOGGER.error("Vertx creation failed");
                    throw new RuntimeException("Could not initialize Communication manager", event.cause());
                }
            } finally {
                _sem.release();
            }
        };
        final VertxOptions _opt = new VertxOptions();
        _opt.setClustered(true);
        _opt.setClusterHost(hostname);
        _opt.setClusterPort(port);
        Vertx.clusteredVertx(_opt, _handler);

        try {
            _sem.acquire();
        } catch (final InterruptedException _e) {
            final String _msg = "Why did the semaphore encountered InterruptedException?";
            LOGGER.error(_msg, _e);
            throw new RuntimeException(_msg, _e);
        }

        assert this.vertx != null;
    }

    @Override
    public void setUp() {
        this.eventBus = this.vertx.eventBus();

        assert this.eventBus != null;
        LOGGER.info("Done setting up vertx eventbus");
    }

    @Override
    public void tearDown() {
        assert this.vertx != null;

        /*
        TODO: Need to figured out how to call vertx.close without tripping Vertx
            
        final Semaphore _tmp2 = new Semaphore(0);
        this.vertx.close(evt -> {
        LOGGER.info("Vertx closed");
        _tmp2.release();
        });
        try {
        _tmp2.acquire();
        LOGGER.info("Done tearing down vertx");
        } catch (final InterruptedException _e) {
        throw new RuntimeException((_e));
        }
        */
    }

    @Override
    public <T extends Serializable> Pair<Status, Publisher<T>> createPublisher(
            @NonNull PublisherConfiguration<T> configuration) {
        final PublishRequester<T> _publisher = new PublishRequester<>(configuration,
                data -> CommunicationManagerImpl.this.eventBus.publish(configuration.topic, getBytes(data)));
        return new Pair<>(Status.SUCCESS, _publisher);
    }

    @Override
    public <T extends Serializable> Status registerSubscriber(@NonNull SubscriberConfiguration<T> configuration) {
        final SubscriberInvoker<T> _subscriberInvoker = new SubscriberInvoker<>(configuration);
        this.eventBus.consumer(configuration.topic,
                (Message<byte[]> msg) -> _subscriberInvoker.processData(getData(msg.body())));
        return Status.SUCCESS;
    }

    @Override
    public <T extends Serializable> Pair<Status, Requester<T>> createRequester(
            @NonNull RequesterConfiguration<T> configuration) {
        final RequestRequester<T> _requester = new RequestRequester<>(configuration, () -> {
            final Semaphore _sem = new Semaphore(0);
            final Box<Pair<ResponderInvokerStatus, TimestampedBox<T>>> _ret = new Box<>();
            final DeliveryOptions _opt = new DeliveryOptions();
            _opt.setSendTimeout(configuration.maximumLatency);
            CommunicationManagerImpl.this.eventBus.send(configuration.responderIdentifier, new byte[] {}, _opt,
                    new SendHandler<T, Pair<ResponderInvokerStatus, TimestampedBox<T>>>(
                            configuration.maximumLatency, _sem, _ret));
            return waitAndBailOnFailure(_sem, _ret);
        });
        return new Pair<>(Status.SUCCESS, _requester);
    }

    @Override
    public <T extends Serializable> Status registerResponder(@NonNull ResponderConfiguration<T> configuration) {
        final ResponderInvoker<T> _responderInvoker = new ResponderInvoker<>(configuration);
        this.eventBus.consumer(configuration.identifier,
                msg -> msg.reply(CommunicationManagerImpl.getBytes(_responderInvoker.serviceRequest())));
        return Status.SUCCESS;
    }

    @Override
    public <T extends Serializable> Pair<Status, Sender<T>> createSender(
            @NonNull SenderConfiguration<T> configuration) {
        final SendRequester<T> _sender = new SendRequester<>(configuration, (data) -> {
            final Semaphore _sem = new Semaphore(0);
            final Box<ReceiverInvokerStatus> _ret = new Box<>();
            final DeliveryOptions _opt = new DeliveryOptions();
            _opt.setSendTimeout(configuration.maximumLatency);
            CommunicationManagerImpl.this.eventBus.send(configuration.receiverIdentifier, getBytes(data), _opt,
                    new SendHandler<T, ReceiverInvokerStatus>(configuration.maximumLatency, _sem, _ret));
            return waitAndBailOnFailure(_sem, _ret);
        });
        return new Pair<>(Status.SUCCESS, _sender);
    }

    @Override
    public <T extends Serializable> Status registerReceiver(@NonNull ReceiverConfiguration<T> configuration) {
        final ReceiverInvoker<T> _receiverInvoker = new ReceiverInvoker<>(configuration);
        this.eventBus.consumer(configuration.identifier, (Message<byte[]> msg) -> {
            final ReceiverInvokerStatus _status = _receiverInvoker.receive(getData(msg.body()));
            msg.reply(CommunicationManagerImpl.getBytes(_status));
        });
        return Status.SUCCESS;
    }

    @Override
    public <T extends Serializable> Pair<Status, Initiator<T>> createInitiator(
            @NonNull InitiatorConfiguration<T> configuration) {
        final InitiateRequester<T> _sender = new InitiateRequester<>(configuration, (data) -> {
            final Semaphore _sem = new Semaphore(0);
            final Box<ExecutorInvokerStatus> _ret = new Box<>();
            final DeliveryOptions _opt = new DeliveryOptions();
            _opt.setSendTimeout(configuration.maximumLatency);
            CommunicationManagerImpl.this.eventBus.send(configuration.executorIdentifier, getBytes(data), _opt,
                    new SendHandler<T, ExecutorInvokerStatus>(configuration.maximumLatency, _sem, _ret));
            return waitAndBailOnFailure(_sem, _ret);
        });
        return new Pair<>(Status.SUCCESS, _sender);
    }

    @Override
    public <T extends Serializable> Status registerExecutor(@NonNull ExecutorConfiguration<T> configuration) {
        final ExecutorInvoker<T> _receiverInvoker = new ExecutorInvoker<>(configuration);
        this.eventBus.consumer(configuration.identifier, (Message<byte[]> msg) -> {
            final ExecutorInvokerStatus _status = _receiverInvoker.execute(getData(msg.body()));
            msg.reply(CommunicationManagerImpl.getBytes(_status));
        });
        return Status.SUCCESS;
    }

    private static <T extends Serializable> T waitAndBailOnFailure(Semaphore sem, Box<T> ret) {
        try {
            sem.acquire();
            return ret.data;
        } catch (final InterruptedException _e) {
            LOGGER.error("Semaphore interrupted", _e);
            throw new RuntimeException(_e);
        }
    }

    private static <T extends Serializable> byte[] getBytes(T data) {
        try {
            final ByteArrayOutputStream _tmp1 = new ByteArrayOutputStream();
            final ObjectOutputStream _tmp2 = new ObjectOutputStream(_tmp1);
            _tmp2.writeObject(data);
            _tmp2.flush();
            final byte[] _msg = _tmp1.toByteArray();
            _tmp2.close();
            return _msg;
        } catch (final IOException _e) {
            CommunicationManagerImpl.LOGGER.error("Serialization failed", _e);
            throw new RuntimeException(_e);
        }
    }

    private static <T extends Serializable> T getData(byte[] bytes) {
        try {
            final ByteArrayInputStream _tmp2 = new ByteArrayInputStream(bytes);
            final ObjectInputStream _tmp3 = new ObjectInputStream(_tmp2);
            final T _data = (T) _tmp3.readObject();
            _tmp3.close();
            return _data;
        } catch (final ClassNotFoundException | IOException _e) {
            LOGGER.error("Deserialization failed", _e);
            throw new RuntimeException(_e);
        }
    }

    private static class Box<T extends Serializable> {
        /**
         * The Data.
         */
        T data;
    }

    private static class SendHandler<T extends Serializable, S extends Serializable>
            implements Handler<AsyncResult<Message<byte[]>>> {
        private long maximumLatency;
        private Semaphore sem;
        private Box<S> ret;

        public SendHandler(long maximumLatency, Semaphore sem, Box<S> ret) {
            this.maximumLatency = maximumLatency;
            this.sem = sem;
            this.ret = ret;
        }

        @Override
        public void handle(AsyncResult<Message<byte[]>> event) {

            if (event.succeeded()) {
                ret.data = getData(event.result().body());
            } else {
                LOGGER.error("Vertx Send failed: {}", ((ReplyException) event.cause()).failureType());
                //try {
                //Thread.sleep(maximumLatency * 2);
                //} catch (final InterruptedException _e) {
                //    LOGGER.error("This is bad!", _e);
                //    throw new RuntimeException(_e);
                //}
            }
            sem.release();
        }
    }
}