package org.xmpp.jnodes.nio;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SelDatagramChannel {
private final static ExecutorService executorService = Executors.newFixedThreadPool(10);
private static Selector selector;
// Instance Properties
protected final DatagramChannel channel;
private DatagramListener datagramListener;
private final static Object obj = new Object();
private static void init() {
try {
selector = Selector.open();
while (!selector.isOpen()) {
Thread.yield();
}
final Runnable task = new Runnable() {
public void run() {
while (true) {
try {
final int n;
synchronized (obj) {
}
n = selector.select();
if (n == 0) {
Thread.sleep(50);
Thread.yield();
continue;
}
final Set keys = selector.selectedKeys();
// Iterate through the Set of keys.
for (Iterator i = keys.iterator(); i.hasNext();) {
// Get a key from the set, and remove it from the set
final SelectionKey key = (SelectionKey) i.next();
i.remove();
// Get the channel associated with the key
final DatagramChannel c = (DatagramChannel) key.channel();
if (key.isValid() && key.isReadable()) {
final SelDatagramChannel sdc = (SelDatagramChannel) key.attachment();
if (sdc == null) {
// Discard Packet
c.receive(ByteBuffer.allocate(0));
continue;
}
final ByteBuffer b = ByteBuffer.allocateDirect(1450);
final SocketAddress clientAddress;
synchronized (sdc) {
clientAddress = sdc.channel.receive(b);
}
// If we got the datagram successfully, broadcast the Event
if (clientAddress != null) {
// Execute in a different Thread avoid serialization
if (sdc.datagramListener != null) {
executorService.submit(new Runnable() {
public void run() {
sdc.datagramListener.datagramReceived(sdc, b, clientAddress);
}
});
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
};
executorService.submit(task);
} catch (IOException e) {
e.printStackTrace();
}
}
protected SelDatagramChannel(final DatagramChannel channel, final DatagramListener datagramListener) {
this.channel = channel;
this.datagramListener = datagramListener;
}
public static SelDatagramChannel open(final DatagramListener datagramListener, final SocketAddress localAddress) throws IOException {
synchronized (executorService) {
if (selector == null) {
init();
}
}
final DatagramChannel dc = DatagramChannel.open();
dc.configureBlocking(false);
dc.socket().bind(localAddress);
final SelDatagramChannel c = new SelDatagramChannel(dc, datagramListener);
synchronized (obj) {
selector.wakeup();
dc.register(selector, SelectionKey.OP_READ, c);
}
return c;
}
public int send(final ByteBuffer src, final SocketAddress target) throws IOException {
return this.channel.send(src, target);
}
public void close() throws IOException {
final SelectionKey k = channel.keyFor(selector);
if (k != null) {
synchronized (obj) {
selector.wakeup();
k.cancel();
}
}
synchronized (this) {
channel.close();
}
}
public void setDatagramListener(DatagramListener listener) {
this.datagramListener = listener;
}
}