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

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

/**
 * 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 {

	private static final String PROPERTY_HOST = "host";
	private static final String PROPERTY_PORT = "port";
	private static final String PROPERTY_RETRY = "retry";
	private static final String PROPERTY_RETRY_TIME = "retryTime";

	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 static final Log logger = LogFactory.getLog(TCPTransport.class.getName());
	protected boolean running = true;
	protected Channel channel;

	public TCPTransport() {
	}

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

	TCPTransport(Socket socket) {
		this.socket = socket;
	}

	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));
							connecting = false;
						} catch (IOException e) {
							logger.warn("Establishing transport to " + hostName + ":" + hostPort
									+ " failed. Retrying in " + retryTime + " millisec.");
							try {
								Thread.sleep(retryTime);
							} catch (InterruptedException e1) {
								e1.printStackTrace();
							}
						}
						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));
			} 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;

	}

	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;

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

		public void stop() {
			running = false;

		}

		public void run() {
			try {
				is = socket.getInputStream();

				DataInputStream din = new DataInputStream(is);
				while (running) {
					Message msg = null;
					try {
						msg = new DefaultMessage(din);
						transportProcessor.processMessage(msg);
					} catch (ProcessorException e) {
						e.printStackTrace();
					} catch (SocketException e) {
						logger.info("Connection closing");
						running = false;
					} catch (EOFException e) {
						logger.info("Connection closing EOF");
						running = false;
					} catch (Exception e) {
						e.printStackTrace();
						logger.error("Error in Message deserialization. Aborting");
						running = false;
					}
				}
				is.close();
				
				if (channel != null) {
					channel.disconnect();
					if(retry){
						Thread.sleep(retryTime);
						channel.connect(channel.getLinkManager());
					} 
				}
			
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	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) {
							if (e.getMessage().equals("socket closed")) {
								logger.info("Connection closing");
								running = false;
							}
						} catch (Exception e) {
							e.printStackTrace();
							logger.error("Error in Message writing. Aborting");
							running = false;
						}
					}
				}
				os.close();
				mailbox.clear();
				if (channel != null) {
					channel.disconnect();
					if(retry){
						Thread.sleep(retryTime);
						channel.connect(channel.getLinkManager());
					} 
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy