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

org.coos.messaging.transport.NioTCPTransportManager 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.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.coos.messaging.LinkManager;
import org.coos.messaging.util.Log;
import org.coos.messaging.util.LogFactory;

/**
 * Nio tcp server implementation.
 * @author Morten Versvik, Tellu AS
 *
 */
public class NioTCPTransportManager extends DefaultChannelServer {

	private static final String PROPERTY_LISTEN_PORT = "port";

	private int listenPort = 15666;
	private ServerSocket serverSocket;
	private Map transports = new HashMap();
	private static final Log logger = LogFactory.getLog(NioTCPTransportManager.class.getName());
	private boolean running = true;

	private Selector selector;

	private List readyWriters = new ArrayList(100);
	private List emptyWriters = new ArrayList(100);
	private Object lock = "";
	
	public NioTCPTransportManager() {

	}

	public NioTCPTransportManager(int listenPort, LinkManager linkManager) {
		this.listenPort = listenPort;
		setLinkManager(linkManager);
	}


	void readyWrite(SocketChannel sc) {
		synchronized (lock) {
			readyWriters.add(sc);
		}
		selector.wakeup();
	}

	void doneWrite(SocketChannel sc) {
		synchronized (lock) {
			emptyWriters.add(sc);
		}
	}

	public int getListenPort() {
		return listenPort;
	}

	ServerSocketChannel ssc;

	public void start() throws Exception {
		if (properties.get(PROPERTY_LISTEN_PORT) != null) {
			listenPort = Integer.valueOf((String) properties.get(PROPERTY_LISTEN_PORT));
		}

		ssc = ServerSocketChannel.open();
		ssc.configureBlocking(false);

		InetSocketAddress isa = new InetSocketAddress(listenPort);
		ssc.socket().bind(isa, 100);
        listenPort = isa.getPort();
		logger.info(" Listening on port " + listenPort);

		new Thread(new WorkerThread()).start();
	}

	public void stop() throws Exception {
		if (running) {
			running = false;
			serverSocket.close();
			stopTransports();
			ssc.close();
		}
	}

	public void stopTransports() throws Exception {
		for (SocketChannel sc : transports.keySet()) {
			sc.close();
		}
		transports.clear();
	}

	public void socketConnected(SocketChannel sc) {
		logger.debug("Establishing transport to " + sc.socket().getInetAddress());
		try {
			// We should reduce the size of the TCP buffers or else we will
			// easily run out of memory when accepting several thousands of
			// connections
			sc.socket().setReceiveBufferSize(2048);
			sc.socket().setSendBufferSize(2048);
			sc.configureBlocking(false);

			NioTCPTransport ntt = new NioTCPTransport(this, selector, sc);
			initializeChannel(ntt);

			transports.put(sc, ntt);
		} catch (IOException e) {
			logger.error("Exception ignored", e);
		}
	}

	public void socketDisconnected(SocketChannel sc) {
		transports.remove(sc);
		logger.debug("Closing transport to " + sc.socket().getInetAddress());
	}

	class WorkerThread implements Runnable {		
		WorkerThread() {
		}

		@Override
		public void run() {
			try {
				selector = Selector.open();
				ssc.register(selector, SelectionKey.OP_ACCEPT);
			} catch (IOException e1) {
				logger.error("Error opening selector!", e1);
			}

			while (running) {
				try {
					int selected = 0;

					// Blocks waiting for events or selector.wakeup() when message is added to mailbox
					selected = selector.select();

					if (selected > 0) {
						Set readyKeys = selector.selectedKeys();
						Iterator it = readyKeys.iterator();

						while (it.hasNext()) {
							SelectionKey key = it.next();
							it.remove();

							if (key.isAcceptable()) { // Add new connection
								ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
								SocketChannel socket = ssc.accept();
								socket.configureBlocking(false);

								socket.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
								socketConnected(socket);
							} else if (key.isReadable()) {
								NioTCPTransport ntt = transports.get(key.channel());
								try {
								ntt.decodeFromSocket();
								} catch (IOException e) {
									logger.error("IOException " + e.toString() + " from socketchannel: " + key.channel());
								}
							}
							if (key.isValid() && key.isWritable()) {
								NioTCPTransport ntt = transports.get(key.channel());
								ntt.handleWrite();
							}
						}
					}
					
					// Add/remove event notifications for writing to connections
					synchronized (lock) {
						for (SocketChannel sc : emptyWriters) {
							SelectionKey sk = sc.keyFor(selector);
							if (sk != null)
								sk.interestOps(SelectionKey.OP_READ);
						}
						emptyWriters.clear();
						for (SocketChannel sc : readyWriters) {
							SelectionKey sk = sc.keyFor(selector);
							if (sk != null)
								sk.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
						}
						readyWriters.clear();
					}					

				} catch (IOException e) {
	                logger.error("IOException ignored.", e);
					e.printStackTrace();
				} catch (Exception e) {
                    logger.error("Exception ignored.", e);
				}
			}
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy