package com.netifera.platform.internal.model.sync;
import java.util.ArrayList;
import java.util.List;
import com.netifera.platform.api.dispatcher.IMessenger;
import com.netifera.platform.api.dispatcher.MessengerException;
import com.netifera.platform.api.events.IEvent;
import com.netifera.platform.api.events.IEventHandler;
import com.netifera.platform.api.log.ILogger;
import com.netifera.platform.internal.model.Workspace;
import com.netifera.platform.model.IUpdateRecord;
import com.netifera.platform.model.ModelUpdate;
/*
* Handles synchronization for a single connection to the probe.
*/
public class ChannelSynchronizer extends Thread {
private final static int MAX_UPDATES_PER_MESSAGE = 25;
final private ModelSynchronizer synchronizer;
final private Workspace workspace;
final private IMessenger messenger;
final private ILogger logger;
private long currentUpdateIndex;
private long nextSendIndex;
private volatile boolean done;
ChannelSynchronizer(ModelSynchronizer synchronizer, IMessenger messenger, ILogger logger, long startIndex) {
this.synchronizer = synchronizer;
this.messenger = messenger;
this.logger = logger;
this.done = false;
this.nextSendIndex = startIndex;
this.workspace = synchronizer.getWorkspace();
workspace.addEntityUpdateListener(new IEventHandler() {
public void handleEvent(IEvent event) {
event();
}
});
}
private synchronized void event() {
logger.debug("Event! update index = " + synchronizer.getWorkspace().getCurrentUpdateIndex());
currentUpdateIndex = synchronizer.getWorkspace().getCurrentUpdateIndex();
notifyAll();
}
public void kill() {
done = true;
notifyAll();
}
public void run() {
currentUpdateIndex = synchronizer.getWorkspace().getCurrentUpdateIndex();
logger.debug("Starting Channel Synchronizer");
while(!done) {
try {
sendUpdates();
} catch (InterruptedException e) {
interrupt();
done = true;
}
}
synchronizer.removeChannelSynchronizer(messenger);
}
private void sendUpdates() throws InterruptedException {
synchronized(this) {
logger.debug("CurrentUpdateIndex: " + currentUpdateIndex + " nextSendIndex: " + nextSendIndex);
while(!done && currentUpdateIndex <= nextSendIndex) {
wait();
}
}
sendUpdateRecords(currentUpdateIndex);
}
private void sendUpdateRecords(long current) {
final List<IUpdateRecord> updates = new ArrayList<IUpdateRecord>(MAX_UPDATES_PER_MESSAGE);
while(!done && nextSendIndex < current) {
updates.clear();
for(int i = 0; i < MAX_UPDATES_PER_MESSAGE && nextSendIndex < current; i++) {
IUpdateRecord record = workspace.getEntityByUpdateIndex(nextSendIndex);
if(record == null)
break;
updates.add(record);
nextSendIndex++;
}
sendUpdateMessage(updates);
}
}
private void sendUpdateMessage(List<IUpdateRecord> updates) {
if(updates.isEmpty())
return;
final ModelUpdate updateMessage = new ModelUpdate(updates);
try {
messenger.emitMessage(updateMessage);
} catch (MessengerException e) {
interrupt();
done = true;
}
}
}