package de.skuzzle.polly.core.internal.irc;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import de.skuzzle.polly.sdk.eventlistener.IrcUser;
import de.skuzzle.polly.sdk.eventlistener.MessageEvent;
import de.skuzzle.polly.sdk.exceptions.DisposingException;
/*
* ISSUE: 0000049
*/
public class RoundRobinScheduler extends Thread implements MessageScheduler {
private Lock lock;
private IrcManagerImpl ircManager;
private Semaphore sema;
private Map<Object, LinkedList<MessageEvent>> messageQueue;
private int messageDelay;
private AtomicBoolean shutdownFlag;
public RoundRobinScheduler(IrcManagerImpl ircManager, int messageDelay) {
super("IRC_MESSAGE_SCHEDULER");
this.ircManager = ircManager;
this.messageQueue = new HashMap<Object, LinkedList<MessageEvent>>();
this.sema = new Semaphore(0);
this.messageDelay = messageDelay;
this.shutdownFlag = new AtomicBoolean(false);
this.lock = new ReentrantLock(true);
}
public void addMessage(String channel, String message, Object source) {
try {
this.lock.lock();
LinkedList<MessageEvent> msgs = this.messageQueue.get(source);
if (msgs == null) {
msgs = new LinkedList<MessageEvent>();
this.messageQueue.put(source, msgs);
}
msgs.add(new MessageEvent(this.ircManager, new IrcUser("DEBUGGER",
"", ""), null, channel, message));
this.sema.release();
} finally {
this.lock.unlock();
}
}
@Override
public void run() {
while (!this.shutdownFlag.get() && !this.isInterrupted()) {
try {
this.sema.acquire();
} catch (InterruptedException e) {
return;
}
if (this.lock.tryLock()) {
try {
Iterator<Entry<Object, LinkedList<MessageEvent>>> it =
this.messageQueue.entrySet().iterator();
while (it.hasNext()) {
Entry<Object, LinkedList<MessageEvent>> entry = it
.next();
LinkedList<MessageEvent> msgs = entry.getValue();
if (msgs.isEmpty()) {
continue;
}
MessageEvent next = msgs.pollFirst();
this.ircManager.sendMessage(next.getChannel(),
next.getMessage());
// CONSIDER: Remove iterator entry if the message list
// for the current source is empty.
// Not removing it should be slightly faster but
// will require more memory
if (msgs.isEmpty()) {
it.remove();
}
}
} finally {
this.lock.unlock();
}
} else {
// put back permit if we could not get the lock in this run
this.sema.release();
}
try {
Thread.sleep(this.messageDelay);
} catch (InterruptedException e) {
return;
}
}
}
@Override
public boolean isDisposed() {
return !this.shutdownFlag.get();
}
@Override
public synchronized void dispose() throws DisposingException {
this.shutdownFlag.set(true);
this.interrupt();
}
@Override
public void setMessageDelay(int delay) {
this.messageDelay = delay;
}
}