org.necsave.NecsaveTransport.java Source code

Java tutorial

Introduction

Here is the source code for org.necsave.NecsaveTransport.java

Source

/*
 * Copyright (c) 2004-2016 Universidade do Porto - Faculdade de Engenharia
 * Laboratrio de Sistemas e Tecnologia Subaqutica (LSTS)
 * All rights reserved.
 * Rua Dr. Roberto Frias s/n, sala I203, 4200-465 Porto, Portugal
 *
 * This file is part of Neptus, Command and Control Framework.
 *
 * Commercial Licence Usage
 * Licencees holding valid commercial Neptus licences may use this file
 * in accordance with the commercial licence agreement provided with the
 * Software or, alternatively, in accordance with the terms contained in a
 * written agreement between you and Universidade do Porto. For licensing
 * terms, conditions, and further information contact lsts@fe.up.pt.
 *
 * European Union Public Licence - EUPL v.1.1 Usage
 * Alternatively, this file may be used under the terms of the EUPL,
 * Version 1.1 only (the "Licence"), appearing in the file LICENSE.md
 * included in the packaging of this file. You may not use this work
 * except in compliance with the Licence. Unless required by applicable
 * law or agreed to in writing, software distributed under the Licence is
 * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF
 * ANY KIND, either express or implied. See the Licence for the specific
 * language governing permissions and limitations at
 * http://ec.europa.eu/idabc/eupl.html.
 *
 * For more information please see <http://lsts.fe.up.pt/neptus>.
 *
 * Author: zp
 * Oct 20, 2015
 */
package org.necsave;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang3.concurrent.ConcurrentUtils;

import info.necsave.msgs.ActionStop;
import info.necsave.msgs.Header.MEDIUM;
import info.necsave.msgs.PlatformInfo;
import info.necsave.proto.Message;
import info.necsave.proto.ProtoDefinition;
import info.necsave.proto.ProtoInputStream;
import info.necsave.proto.ProtoOutputStream;
import pt.lsts.neptus.NeptusLog;
import pt.lsts.neptus.console.ConsoleLayout;
import pt.lsts.neptus.i18n.I18n;
import pt.lsts.neptus.plugins.NeptusProperty;

/**
 * @author zp
 *
 */
public class NecsaveTransport {

    @NeptusProperty(description = "Port where platforms broadcast their state")
    public int broadcastPort = 17650;

    private DatagramSocket serverSocket = null;
    boolean stopped = false;
    private ConsoleLayout console;
    private byte[] receiveData = new byte[64 * 1024];
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    private LinkedHashMap<Integer, String> platformNames = new LinkedHashMap<>();
    private LinkedHashMap<Integer, InetSocketAddress> platformAddrs = new LinkedHashMap<>();

    public NecsaveTransport(ConsoleLayout console) throws Exception {
        this.console = console;
        boolean bound = false;
        for (int port = broadcastPort; port < broadcastPort + 3; port++) {
            try {
                serverSocket = new DatagramSocket(null);
                serverSocket.setReuseAddress(true);
                serverSocket.setBroadcast(true);
                serverSocket.bind(new InetSocketAddress(port));
                NeptusLog.pub().info(I18n.textf("Bound to port %d", port));
                bound = true;
                break;
            } catch (Exception e) {
                e.printStackTrace();
                NeptusLog.pub().error(I18n.textf("Unable to bind to port %port: %error", port, e.getMessage()));
            }
        }
        if (!bound)
            throw new RuntimeException("Unable to bind to any broadcast port.");

        receiverThread.setDaemon(true);
        receiverThread.start();
    }

    private Thread receiverThread = new Thread("NMP Receiver") {
        public void run() {
            while (!stopped) {
                try {
                    Message msg = readMessage();

                    if (console != null)
                        console.post(msg);
                } catch (Exception e) {
                    NeptusLog.pub().error(e);
                }
            }
        };
    };

    private void process(PlatformInfo msg, String host, int port) {
        if (msg.getPlatformId() != msg.getSrc())
            return;
        platformNames.put(msg.getPlatformId(), msg.getPlatformName());
        platformAddrs.put(msg.getPlatformId(), new InetSocketAddress(host, msg.getPort()));
    }

    private Message readMessage() throws Exception {
        DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
        serverSocket.receive(receivePacket);

        ProtoInputStream pis = new ProtoInputStream(new ByteArrayInputStream(receiveData),
                ProtoDefinition.getInstance());

        Message msg = ProtoDefinition.getInstance().nextMessage(pis);

        if (msg instanceof PlatformInfo)
            process((PlatformInfo) msg, receivePacket.getAddress().getHostAddress(), receivePacket.getPort());

        NeptusLog.pub().debug("Received message of type '" + msg.getAbbrev() + "' from "
                + receivePacket.getAddress() + " - Platform " + platformNames.get(msg.getSrc()));

        return msg;
    }

    public void broadcast(Message msg) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ProtoOutputStream pos = new ProtoOutputStream(baos);
        msg.setMedium(MEDIUM.IP_BROADCAST);
        int length = msg.serialize(pos);
        DatagramPacket packet = new DatagramPacket(baos.toByteArray(), length);
        for (int i = 0; i < 3; i++)
            packet.setSocketAddress(new InetSocketAddress("255.255.255.255", broadcastPort + i));
        serverSocket.send(packet);
    }

    public Future<Boolean> sendMessage(final Message msg, final int platf) {

        if (platformAddrs.containsKey(platf)) {
            InetSocketAddress addr = platformAddrs.get(platf);
            return sendMessage(msg, addr.getHostName(), addr.getPort());
        } else
            return ConcurrentUtils.constantFuture(Boolean.FALSE);
    }

    public Future<Boolean> sendMessage(final Message msg, final String platform) {
        int platf = -1;
        if (platformNames.containsValue(platform)) {
            for (Entry<Integer, String> e : platformNames.entrySet()) {
                if (e.getValue().equals(platform)) {
                    platf = e.getKey();
                    break;
                }
            }
        }
        return sendMessage(msg, platf);
    }

    public Future<Boolean> sendMessage(final Message msg, final String host, final int port) {
        return executor.submit(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                msg.setMedium(MEDIUM.IP_RELIABLE);
                try {
                    Socket socket = new Socket(host, port);
                    msg.serialize(new ProtoOutputStream(socket.getOutputStream()));
                    socket.close();
                    return true;
                } catch (Exception e) {
                    NeptusLog.pub().error(e);
                    return false;
                }
            }
        });
    }

    public void stop() {
        stopped = true;
        receiverThread.interrupt();
    }

    public InetSocketAddress addressOf(int id) {
        return platformAddrs.get(id);
    }

    public void clearPlatforms() {
        platformAddrs.clear();
        platformNames.clear();
    }

    public static void main(String[] args) throws Exception {
        NecsaveTransport transport = new NecsaveTransport(null);
        transport.broadcast(new ActionStop());
        Thread.sleep(100000);
    }
}