package com.workshare.msnos.core.protocols.ip.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.workshare.msnos.core.Gateway.Listener;
import com.workshare.msnos.core.Message;
import com.workshare.msnos.core.serializers.WireJsonSerializer;
import com.workshare.msnos.core.serializers.WireSerializer;
import com.workshare.msnos.soup.threading.Multicaster;
import com.workshare.msnos.soup.threading.ThreadFactories;
public class UDPServer {
private static Logger logger = Logger.getLogger(UDPServer.class.getName());
private static final String THREAD_NAME = "UDP-Server";
private final ThreadFactory threads;
private final Multicaster<Listener, Message> multicaster;
private final WireSerializer sz;
private Thread thread;
private int maxPacketSize;
private MulticastSocket socket;
public UDPServer() {
this(ThreadFactories.DEFAULT, new Multicaster<Listener, Message>() {
@Override
protected void dispatch(Listener listener, Message message) {
listener.onMessage(message);
}
});
}
public UDPServer(ThreadFactory threads, Multicaster<Listener, Message> caster) {
this.sz = new WireJsonSerializer(); // hard dependency to remove in future?
this.threads = threads;
this.multicaster = caster;
}
public synchronized void start(MulticastSocket socket, int maxPacketSize) {
if (thread != null)
throw new RuntimeException("UDPServer started two times? WTF?");
this.socket = socket;
this.maxPacketSize = maxPacketSize;
thread = threads.newThread(new Runnable() {
@Override
public void run() {
loop();
}
});
thread.setDaemon(true);
thread.setName(THREAD_NAME);
thread.start();
}
public synchronized void stop() {
if (!THREAD_NAME.equals(thread.getName()))
throw new RuntimeException("UDPServer stopped two times or never started? WTF?");
thread.setName("-ghost-");
thread.interrupt();
}
private void loop() {
byte[] buf = new byte[maxPacketSize];
logger.info("Listening loop started on port " + socket.getLocalPort());
while (!thread.isInterrupted()) {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
try {
socket.receive(packet);
} catch (IOException e) {
logger.log(Level.FINEST, "IOException receiving UDP packet", e);
}
if (thread.isInterrupted())
break;
try {
process(packet);
} catch (Exception ex) {
logger.log(Level.WARNING, "Unable to process packet", ex);
}
}
Thread.interrupted();
logger.info("Listening loop ended!");
}
private void process(DatagramPacket packet) {
Message message = (Message) sz.fromBytes(packet.getData(), 0, packet.getLength(), Message.class);
logger.log(Level.FINEST, "Received message {} ", message.toString());
sendToListeners(message);
}
private void sendToListeners(Message message) {
multicaster.dispatch(message);
}
public void addListener(final Listener listener) {
multicaster.addListener(listener);
}
public WireSerializer serializer() {
return sz;
}
}