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

org.coos.messaging.transport.TCPTransport Maven / Gradle / Ivy

There is a newer version: 1.3.1
Show newest version
/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * 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 program 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 program.  If not, see .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.messaging.transport;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import org.coos.messaging.Channel;
import org.coos.messaging.Message;
import org.coos.messaging.Processor;
import org.coos.messaging.ProcessorException;
import org.coos.messaging.Service;
import org.coos.messaging.Transport;
import org.coos.messaging.impl.DefaultMessage;
import org.coos.messaging.impl.DefaultProcessor;
import org.coos.messaging.util.Log;
import org.coos.messaging.util.LogFactory;


/**
 * @author Knut Eilif Husa, Tellu AS
 *
 * A TCP transport
 */
public class TCPTransport extends DefaultProcessor implements Transport, Service {

    static final String PROPERTY_HOST = "host";
    static final String PROPERTY_PORT = "port";
    static final String PROPERTY_RETRY = "retry";
    static final String PROPERTY_RETRY_TIME = "retryTime";
    static final int CONNECT_TIMEOUT = 4000;
    
    protected static final Log logger = LogFactory.getLog(TCPTransport.class.getName());
    
    protected String hostName;
    protected int hostPort = 15656;
    protected int retryTime = 10000;
    protected boolean retry = false;
    protected Socket socket;
    private Reader reader;
    private Writer writer;

    protected List mailbox = Collections.synchronizedList(new LinkedList());
    protected Processor transportProcessor;
    protected boolean running = true;
    protected Channel channel;
    TCPTransportManager tm;

    public TCPTransport() {
    }

    public TCPTransport(String hostIP, int hostPort) {
        this.hostName = hostIP;
        this.hostPort = hostPort;
    }

    TCPTransport(Socket socket, TCPTransportManager tm) {
        this.socket = socket;
        this.tm = tm;
    }

    public Processor getTransportProcessor() {
        return transportProcessor;
    }

    public void setChainedProcessor(Processor transportProcessor) {
        this.transportProcessor = transportProcessor;
    }

    public Reader getReader() {
        return reader;
    }

    public Writer getWriter() {
        return writer;
    }

    public void processMessage(Message msg) throws ProcessorException {

        if (!running) {
            return;
        }

        String priStr = msg.getHeader(Message.PRIORITY);

        if (priStr != null) {
            int pri = Integer.valueOf(priStr);
            int idx = 0;

            for (Message message : mailbox) {
                String pr = message.getHeader(Message.PRIORITY);

                if (pr != null) {
                    int p = Integer.valueOf(pr);

                    if (pri < p) {
                        mailbox.add(idx, msg);

                        synchronized (this) {
                            this.notify();
                        }

                        break;
                    }
                }

                idx++;
            }
        } else {
            mailbox.add(msg);

            synchronized (this) {
                this.notify();
            }
        }
    }

    public void start() throws Exception {
        running = true;

        if (socket != null) {

            // Socket already exist, Start reader and writer
            reader = new Reader();
            writer = new Writer();

            return;

        }

        // socket does not exist, must be established before starting reader and
        // writer
        if (hostName == null) {
            hostName = (String) properties.get(PROPERTY_HOST);
        }

        if (properties.get(PROPERTY_PORT) != null) {
            hostPort = Integer.valueOf((String) properties.get(PROPERTY_PORT));
        }

        String retryStr = (String) properties.get(PROPERTY_RETRY);

        if ((retryStr != null) && retryStr.equals("true")) {
            retry = true;
        } else {
            retry = false;
        }

        if (properties.get(PROPERTY_RETRY_TIME) != null) {
            retryTime = Integer.valueOf((String) properties.get(PROPERTY_RETRY_TIME));
        }

        logger.info("Establishing transport to " + hostName + ":" + hostPort);

        if (retry) { // must retry in a separate thread

            Thread t = new Thread(new Runnable() {

                        public void run() {
                            boolean connecting = true;

                            while (connecting && running) {

                                try {
                                    socket = new Socket();
                                    socket.connect(new InetSocketAddress(hostName, hostPort), CONNECT_TIMEOUT);
                                    connecting = false;
                                } catch (IOException e) {
                                    logger.warn(
                                        "Establishing transport to " + hostName + ":" + hostPort + " failed. Retrying in " + retryTime +
                                        " millisec.");

                                    try {
                                        Thread.sleep(retryTime);
                                    } catch (InterruptedException e1) {
                                        logger.warn("Interrupted while waiting for retry.", e);
                                    }
                                }

                                if (!connecting && running) {
                                    logger.info(
                                        "Transport from " + socket.getLocalSocketAddress() + " to " + socket.getRemoteSocketAddress() +
                                        " established.");
                                }
                            }

                            if (running) {
                                reader = new Reader();
                                writer = new Writer();
                            }
                        }
                    });

            t.start();

        } else {

            try {
                socket = new Socket();
                socket.connect(new InetSocketAddress(hostName, hostPort), CONNECT_TIMEOUT);
            } catch (IOException e) {
                running = false;
                logger.warn("Establishing transport to " + hostName + ":" + hostPort + " failed.");
                throw e;
            }

            if (running) {
                reader = new Reader();
                writer = new Writer();
            }
        }
    }

    public void stop() throws Exception {
        logger.info("Closing transport: " + hostName + ":" + hostPort);
        running = false;

        if (reader != null) {
            reader.stop();
        }

        if (writer != null) {
            writer.stop();
        }

        if (socket != null) {
            socket.close();
        }

        socket = null;

        if (tm != null)
            tm.disconnected(this);
    }

    public int getQueueSize() {
        return mailbox.size();
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    class Reader implements Runnable {
        Thread readerThread;
        InputStream is;
        boolean running = true, failed;

        Reader() {
            readerThread = new Thread(this);
            readerThread.start();
            logger.info("Reader started on :" + socket.getLocalSocketAddress());
            failed = false;
        }

        public void stop() {
            running = false;

            if (!failed)
                retry = false;
        }

        public void run() {

            try {
                is = socket.getInputStream();

                DataInputStream din = new DataInputStream(is);

                while (running) {
                    Message msg = null;

                    try {
                        msg = new DefaultMessage(din);
                    } catch (SocketException e) {
                        logger.info("Connection closing");
                        running = false;
                        failed = true;
                    } catch (EOFException e) {
                        logger.info("Error in Message deserialization. Connection closing EOF", e); //-brudd
                        running = false;
                        failed = true;
                    } catch (Exception e) {
                        logger.error("Error in Message deserialization. Aborting", e);
                        running = false;
                        failed = true;
                    }
                    
                    try {
                        if (running) {
                            transportProcessor.processMessage(msg);
                        }
                    } catch (ProcessorException e) {
                        logger.error("ProcessorException caught when processing message " + msg.getName() + " Ignored.", e);
                    } catch (Exception e) {
                        logger.error("Unknown Exception caught when processing message " + msg.getName() + " Ignored.", e);
                    }
                }

                is.close();

                if (channel != null) {
                    channel.disconnect();

                    if (retry) {
                        Thread.sleep(retryTime);
                        channel.connect(channel.getLinkManager());
                    }
                }

            } catch (Exception e) {
                logger.error("Unknown Error in Reader", e);
            }
        }
    }

    class Writer implements Runnable {
        Thread writerThread;
        OutputStream os;
        boolean running = true;

        Writer() {
            writerThread = new Thread(this);
            writerThread.start();
            logger.info("Writer started on :" + socket.getLocalSocketAddress());
        }

        public void stop() {
            running = false;
            writerThread.interrupt();
        }

        public void run() {

            try {
                os = socket.getOutputStream();

                while (running) {

                    if (mailbox.isEmpty()) {

                        synchronized (TCPTransport.this) {

                            try {
                                TCPTransport.this.wait();
                            } catch (InterruptedException e) {

                                if (!running)
                                    return;
                            }
                        }
                    } else {
                        Message msg = mailbox.remove(0);

                        try {
                            os.write(msg.serialize());
                            os.flush();
                        } catch (SocketException e) {

                            running = false;
                            if (e.getMessage().equals("Socket closed")) {
                                logger.info("Connection closing");
                            } else {
                                logger.error("Error in Message writing. Aborting", e);
                            }
                        } catch (Exception e) {
                            logger.error("Error in Message writing. Aborting", e);
                            running = false;
                        }
                    }
                }

                os.close();

                if (!mailbox.isEmpty()) {
                    logger.warn("Discarding " + mailbox.size() + " messages");
                }

                mailbox.clear();
            } catch (Exception e) {
                logger.error("Unknown Error in Writer", e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy