/**
* $RCSfile$
* $Revision: $
* $Date: $
*
* Copyright (C) 2006 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.multiplexer.net;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.util.Log;
import org.jivesoftware.multiplexer.ServerPort;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
* Accepts new socket connections using a non-blocking model. A single selector is
* used for all connected clients and also for accepting new connections.
*
* @author Daniele Piras
*/
class NonBlockingAcceptingMode extends SocketAcceptingMode {
// Time (in ms) to sleep from a reading-cycle to another
private static final long CYCLE_TIME = 10;
// Selector to collect messages from client connections.
private Selector selector;
protected NonBlockingAcceptingMode(ServerPort serverPort,
InetAddress bindInterface) throws IOException {
super(serverPort);
// Chaning server to use NIO
// Open selector...
selector = Selector.open();
// Create a new ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// Retrieve socket and bind socket with specified address
this.serverSocket = serverSocketChannel.socket();
this.serverSocket.bind(new InetSocketAddress(bindInterface, serverPort.getPort()));
// Configure Blocking to unblocking
serverSocketChannel.configureBlocking(false);
// Registering connection with selector.
SelectionKey sk = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
AcceptConnection acceptConnection = new AcceptConnection();
sk.attach(acceptConnection);
}
/**
* DANIELE:
* This thread use the selector NIO features to retrieve client connections
* and messages.
*/
public void run() {
while (notTerminated && !Thread.interrupted()) {
try {
selector.select();
Set selected = selector.selectedKeys();
Iterator it = selected.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
it.remove();
SelectorAction action = (SelectorAction) key.attachment();
if (action == null) {
continue;
}
if (key.isAcceptable()) {
action.connect(key);
}
else if (key.isReadable()) {
action.read(key);
}
}
Thread.sleep(CYCLE_TIME);
}
catch (IOException ie) {
if (notTerminated) {
Log.error(LocaleUtils.getLocalizedString("admin.error.accept"),
ie);
}
}
catch (Exception e) {
Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), e);
}
}
}
/*
* InnerClass that is use when a new client arrive.
* It's use the reactor pattern to register an abstract action
* to the selector.
*/
class AcceptConnection implements SelectorAction {
public void read(SelectionKey key) throws IOException {
}
/*
* A client arrive...
*/
public void connect(SelectionKey key) throws IOException {
// Retrieve the server socket channel...
ServerSocketChannel sChannel = (ServerSocketChannel) key.channel();
// Accept the connection
SocketChannel socketChannel = sChannel.accept();
// Retrieve socket for incoming connection
Socket sock = socketChannel.socket();
socketChannel.configureBlocking(false);
// Registering READING operation into the selector
SelectionKey sockKey = socketChannel.register(selector, SelectionKey.OP_READ);
if (sock != null) {
System.out.println("Connect " + sock.toString());
Log.debug("Connect " + sock.toString());
try {
SocketReader reader =
SocketReaderFactory.createSocketReader(sock, false, serverPort, false);
SelectorAction action = new ReadAction(reader);
sockKey.attach(action);
}
catch (Exception e) {
// There is an exception...
Log.error(LocaleUtils.getLocalizedString("admin.error.accept"), e);
}
}
}
}
class ReadAction implements SelectorAction {
SocketReader reader;
public ReadAction(SocketReader reader) {
this.reader = reader;
}
public void read(SelectionKey key) throws IOException {
// Socket reader (using non-blocking mode) will read the stream and process, in
// another thread, any number of stanzas found in the stream.
reader.run();
}
public void connect(SelectionKey key) throws IOException {
}
}
}