All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bytex.snamp.cluster.HazelcastCommunicator Maven / Gradle / Ivy

package com.bytex.snamp.cluster;

import com.bytex.snamp.SafeCloseable;
import com.bytex.snamp.core.Communicator;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.ITopic;
import com.hazelcast.core.Message;

import java.io.Serializable;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 *
 * @author Roman Sakno
 * @version 2.0
 * @since 2.0
 */
final class HazelcastCommunicator extends HazelcastSharedObject> implements Communicator {
    private static final class TransferObjectListener implements com.hazelcast.core.MessageListener, SafeCloseable{
        private final String localMemberID;
        private final Predicate filter;
        private final Consumer listener;
        private final ITopic topic;
        private final String subscription;

        private TransferObjectListener(final ITopic topic, final String localMember, final Predicate filter, final MessageListener listener){
            this.localMemberID = localMember;
            this.filter = Objects.requireNonNull(filter);
            this.listener = Objects.requireNonNull(listener);
            this.topic = Objects.requireNonNull(topic);
            this.subscription = topic.addMessageListener(this);
        }

        private void onMessage(final HazelcastIncomingMessage message){
            if(filter.test(message))
                listener.accept(message);
        }

        @Override
        public void onMessage(final Message hzMessage) {
            final HazelcastIncomingMessage msg = new HazelcastIncomingMessage(hzMessage);
            msg.detectRemoteMessage(localMemberID);
            onMessage(msg);
        }

        @Override
        public void close() {
            topic.removeMessageListener(subscription);
        }
    }

    private static class MessageReceiver extends CompletableFuture implements com.hazelcast.core.MessageListener, SafeCloseable{
        private final Predicate filter;
        private final String subscription;
        private final ITopic topic;
        private final String localMemberID;
        private final Function messageParser;

        private MessageReceiver(final ITopic topic,
                                final String localMember,
                                final Predicate filter,
                                final Function messageParser){
            this.filter = Objects.requireNonNull(filter);
            this.topic = Objects.requireNonNull(topic);
            this.localMemberID = localMember;
            this.subscription = topic.addMessageListener(this);
            this.messageParser = Objects.requireNonNull(messageParser);
        }

        private void onMessage(final HazelcastIncomingMessage inputMessage){
            if(filter.test(inputMessage))
                complete(messageParser.apply(inputMessage));
        }

        @Override
        public final void onMessage(final Message hzMessage) {
            final HazelcastIncomingMessage msg = new HazelcastIncomingMessage(hzMessage);
            msg.detectRemoteMessage(localMemberID);
            onMessage(msg);
        }

        @Override
        public void close() {
            topic.removeMessageListener(subscription);
        }
    }

    private static final class LinkedMessageBox extends LinkedBlockingQueue implements MessageBox, com.hazelcast.core.MessageListener{
        private static final long serialVersionUID = 5833889571236077744L;
        private final Predicate filter;
        private final String subscription;
        private final ITopic topic;
        private final String localMemberID;
        private final Function messageParser;

        private LinkedMessageBox(final ITopic topic,
                                 final String localMember,
                                 final Predicate filter,
                                 final Function messageParser) {
            this.filter = Objects.requireNonNull(filter);
            this.topic = Objects.requireNonNull(topic);
            this.subscription = topic.addMessageListener(this);
            this.localMemberID = localMember;
            this.messageParser = Objects.requireNonNull(messageParser);
        }

        private void onMessage(final HazelcastIncomingMessage message){
            if(filter.test(message))
                add(messageParser.apply(message));
        }

        @Override
        public void onMessage(final Message hzMessage) {
            final HazelcastIncomingMessage msg = new HazelcastIncomingMessage(hzMessage);
            msg.detectRemoteMessage(localMemberID);
            onMessage(msg);
        }

        @Override
        public void close() {
            topic.removeMessageListener(subscription);
        }
    }

    private static final class FixedSizeMessageBox extends ArrayBlockingQueue implements MessageBox, com.hazelcast.core.MessageListener, SafeCloseable{
        private static final long serialVersionUID = 2173687138535015363L;
        private final Predicate filter;
        private final String subscription;
        private final transient ITopic topic;
        private final String localMemberID;
        private final Function messageParser;

        private FixedSizeMessageBox(final int capacity,
                                    final ITopic topic,
                                    final String localMember,
                                    final Predicate filter,
                                    final Function messageParser){
            super(capacity);
            this.filter = Objects.requireNonNull(filter);
            this.topic = Objects.requireNonNull(topic);
            this.subscription = topic.addMessageListener(this);
            this.localMemberID = localMember;
            this.messageParser = Objects.requireNonNull(messageParser);
        }

        private void onMessage(final HazelcastIncomingMessage message){
            if(filter.test(message))
                add(messageParser.apply(message));
        }

        @Override
        public void onMessage(final Message message) {
            final HazelcastIncomingMessage msg = new HazelcastIncomingMessage(message);
            msg.detectRemoteMessage(localMemberID);
            onMessage(msg);
        }

        @Override
        public void close() {
            topic.removeMessageListener(subscription);
        }
    }

    private final HazelcastInstance hazelcast;
    private final String localMember;

    HazelcastCommunicator(final HazelcastInstance hazelcast,
                          final String communicatorName){
        super(hazelcast, communicatorName, HazelcastInstance::getTopic);
        this.hazelcast = Objects.requireNonNull(hazelcast);
        localMember = hazelcast.getCluster().getLocalMember().getUuid();
    }

    @Override
    public long newMessageID() {
        return hazelcast.getAtomicLong("MSGID-".concat(getName())).getAndIncrement();
    }

    @Override
    public void sendSignal(final Serializable signal) {
        sendMessage(signal, MessageType.SIGNAL, newMessageID());
    }

    @Override
    public void sendMessage(final Serializable payload, final MessageType type) {
        sendMessage(payload, type, newMessageID());
    }

    @Override
    public void sendMessage(final Serializable payload, final MessageType type, final long messageID) {
        getDistributedObject().publish(new TransferObject(new HazelcastNodeInfo(hazelcast), payload, type, messageID));
    }

    @Override
    public  V receiveMessage(final Predicate filter, final Function messageParser, final Duration timeout) throws InterruptedException, TimeoutException {
        try(final MessageReceiver receiver = receiveMessage(filter, messageParser)) {
            final Callable callable = timeout == null ? receiver::get : () -> receiver.get(timeout.toNanos(), TimeUnit.NANOSECONDS);
            return callable.call();
        } catch (final InterruptedException | TimeoutException e){
            throw e;
        } catch (final Exception e){
            throw new UncheckedExecutionException(e);
        }
    }

    @Override
    public  MessageReceiver receiveMessage(final Predicate filter, final Function messageParser) {
        return new MessageReceiver<>(getDistributedObject(), localMember, filter, messageParser);
    }

    @Override
    public TransferObjectListener addMessageListener(final MessageListener listener, final Predicate filter) {
        return new TransferObjectListener(getDistributedObject(), localMember, filter, listener);
    }

    @Override
    public  FixedSizeMessageBox createMessageBox(final int capacity, final Predicate filter, final Function messageParser) {
        return new FixedSizeMessageBox<>(capacity, getDistributedObject(), localMember, filter, messageParser);
    }

    @Override
    public  LinkedMessageBox createMessageBox(final Predicate filter, final Function messageParser) {
        return new LinkedMessageBox<>(getDistributedObject(), localMember, filter, messageParser);
    }

    @Override
    public  V sendRequest(final Serializable request, final Function messageParser, final Duration timeout) throws InterruptedException, TimeoutException {
        final long messageID = newMessageID();
        try (final MessageReceiver receiver = receiveMessage(Communicator.responseWithMessageID(messageID), messageParser)) {
            sendMessage(request, MessageType.REQUEST, messageID);
            final Callable callable = timeout == null ? receiver::get : () -> receiver.get(timeout.toNanos(), TimeUnit.NANOSECONDS);
            return callable.call();
        } catch (final InterruptedException | TimeoutException e){
            throw e;
        } catch (final Exception e){
            throw new UncheckedExecutionException(e);
        }
    }

    @Override
    public  MessageReceiver sendRequest(final Serializable request, final Function messageParser) {
        final long messageID = newMessageID();
        final MessageReceiver receiver = receiveMessage(Communicator.responseWithMessageID(messageID), messageParser);
        sendMessage(request, MessageType.REQUEST, messageID);
        return receiver;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy