package org.prevayler.implementation.publishing;
import org.prevayler.Clock;
import org.prevayler.foundation.Cool;
import org.prevayler.foundation.Turn;
import org.prevayler.implementation.Capsule;
import org.prevayler.implementation.TransactionGuide;
import org.prevayler.implementation.TransactionTimestamp;
import org.prevayler.implementation.clock.PausableClock;
import org.prevayler.implementation.journal.Journal;
import java.io.IOException;
public class CentralPublisher extends AbstractPublisher {
private final PausableClock _pausableClock;
private final Journal _journal;
private volatile int _pendingPublications=0;
private final Object _pendingPublicationsMonitor=new Object();
private Turn _nextTurn=Turn.first();
private long _nextTransaction;
private final Object _nextTurnMonitor=new Object();
public CentralPublisher( Clock clock, Journal journal){
super(new PausableClock(clock));
_pausableClock=(PausableClock)_clock;
_journal=journal;
}
public void publish( Capsule capsule){
synchronized (_pendingPublicationsMonitor) {
if (_pendingPublications == 0) _pausableClock.pause();
_pendingPublications++;
}
try {
publishWithoutWorryingAboutNewSubscriptions(capsule);
}
finally {
synchronized (_pendingPublicationsMonitor) {
_pendingPublications--;
if (_pendingPublications == 0) {
_pausableClock.resume();
_pendingPublicationsMonitor.notifyAll();
}
}
}
}
private void publishWithoutWorryingAboutNewSubscriptions( Capsule capsule){
TransactionGuide guide=approve(capsule);
_journal.append(guide);
notifySubscribers(guide);
}
private TransactionGuide approve( Capsule capsule){
synchronized (_nextTurnMonitor) {
TransactionTimestamp timestamp=new TransactionTimestamp(capsule,_nextTransaction,_pausableClock.realTime());
this.hook79(timestamp);
Turn turn=_nextTurn;
_nextTurn=_nextTurn.next();
_nextTransaction++;
return new TransactionGuide(timestamp,turn);
}
}
private void notifySubscribers( TransactionGuide guide){
guide.startTurn();
try {
_pausableClock.advanceTo(guide.executionTime());
notifySubscribers(guide.timestamp());
}
finally {
guide.endTurn();
}
}
public void subscribe( TransactionSubscriber subscriber, long initialTransaction) throws IOException, ClassNotFoundException {
synchronized (_pendingPublicationsMonitor) {
while (_pendingPublications != 0) Cool.wait(_pendingPublicationsMonitor);
_journal.update(subscriber,initialTransaction);
synchronized (_nextTurnMonitor) {
_nextTransaction=_journal.nextTransaction();
}
super.addSubscriber(subscriber);
}
}
public void close() throws IOException {
_journal.close();
}
protected void hook79( TransactionTimestamp timestamp){
}
}