de.dfki.kiara.impl.AbstractMessageConnection.java Source code

Java tutorial

Introduction

Here is the source code for de.dfki.kiara.impl.AbstractMessageConnection.java

Source

/* KIARA - Middleware for efficient and QoS/Security-aware invocation of services and exchange of messages
 *
 * Copyright (C) 2014 German Research Center for Artificial Intelligence (DFKI)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */
package de.dfki.kiara.impl;

import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import de.dfki.kiara.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author Dmitri Rubinstein <dmitri.rubinstein@dfki.de>
 */
public abstract class AbstractMessageConnection implements MessageConnection, TransportMessageListener {

    private static final Logger logger = LoggerFactory.getLogger(AbstractMessageConnection.class);
    private final TransportConnection transportConnection;
    private final IdentityHashMap<Message, TransportMessage> messageMap;
    private final List<Dispatcher> dispatchers;

    private static class Dispatcher extends AbstractFuture<Message> {

        private final Object messageId;

        Dispatcher(Object messageId) {
            this.messageId = messageId;
        }

        public boolean process(Message message) throws Exception {
            final Protocol protocol = message.getProtocol();

            if ((message.getMessageKind() == Message.Kind.RESPONSE
                    || message.getMessageKind() == Message.Kind.EXCEPTION)
                    && protocol.equalMessageIds(messageId, message.getMessageId())) {
                set(message);
                return true;
            }
            return false;
        }

    }

    AbstractMessageConnection(TransportConnection transportConnection) {
        this.transportConnection = transportConnection;
        this.transportConnection.addMessageListener(this);
        this.messageMap = new IdentityHashMap<>();
        this.dispatchers = new ArrayList<>();
    }

    @Override
    public ListenableFuture<Void> send(Message message) {
        if (message == null) {
            throw new NullPointerException("message");
        }
        try {
            final TransportMessage tmessage;

            synchronized (messageMap) {
                tmessage = messageMap.remove(message.getRequestMessage());
            }

            final TransportMessage tresponse = transportConnection.createTransportMessage(tmessage);
            tresponse.setPayload(message.getMessageData());
            tresponse.setContentType(message.getProtocol().getMimeType());
            return transportConnection.send(tresponse);
        } catch (Exception ex) {
            logger.error("Could not send message", ex);
            return Futures.immediateFailedFuture(ex);
        }
    }

    @Override
    public ListenableFuture<Message> receive(Object messageId) {
        final Dispatcher dispatcher = new Dispatcher(messageId);
        synchronized (dispatchers) {
            dispatchers.add(dispatcher);
        }
        return dispatcher;
    }

    @Override
    public void close() throws IOException {
        transportConnection.close();
    }

    public TransportConnection getTransportConnection() {
        return transportConnection;
    }

    protected void processMessage(Message message, InvocationEnvironment env,
            ServiceMethodExecutor serviceMethodExecutor) {
        assert message != null;

        try {
            logger.debug("Incoming message: {}", message);

            switch (message.getMessageKind()) {
            case RESPONSE:
            case EXCEPTION:

                // process via pipeline
                boolean processed = false;
                synchronized (dispatchers) {
                    for (Dispatcher handler : dispatchers) {
                        if (handler.process(message)) {
                            dispatchers.remove(handler);
                            processed = true;
                            break;
                        }
                    }
                }
                if (!processed) {
                    logger.warn("Unprocessed transport message: {}: {}", message.getClass(), message);
                }
                break;
            case REQUEST:

                ListenableFuture<Message> fmsg = serviceMethodExecutor.performLocalCall(env, message);

                Futures.addCallback(fmsg, new FutureCallback<Message>() {

                    @Override
                    public void onSuccess(Message resultMessage) {
                        try {
                            send(resultMessage);
                        } catch (Exception ex) {
                            logger.error("Error on callback response", ex);
                        }
                    }

                    @Override
                    public void onFailure(Throwable t) {
                        logger.error("Could not process message", t);
                    }
                }, Global.executor);

                break;
            default:
                logger.warn("Unprocessed message: {}: {}", message.getClass(), message);
                break;
            }
        } catch (Exception ex) {
            logger.error("Message processing failed", ex);
        }
    }

    protected void processMessage(Protocol protocol, InvocationEnvironment env,
            ServiceMethodExecutor serviceMethodBinding, TransportMessage trequest) throws Exception {
        final Message message = protocol.createMessageFromData(trequest.getPayload());

        synchronized (messageMap) {
            messageMap.put(message, trequest);
        }
        processMessage(message, env, serviceMethodBinding);
    }

}