Package org.prevayler.implementation.replication

Source Code of org.prevayler.implementation.replication.ClientPublisher

//Prevayler(TM) - The Free-Software Prevalence Layer.
//Copyright (C) 2001-2003 Klaus Wuestefeld
//This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

package org.prevayler.implementation.replication;

import org.prevayler.Clock;
import org.prevayler.foundation.network.ObjectSocket;
import org.prevayler.foundation.network.OldNetworkImpl;
import org.prevayler.implementation.Capsule;
import org.prevayler.implementation.TransactionTimestamp;
import org.prevayler.implementation.clock.BrokenClock;
import org.prevayler.implementation.publishing.TransactionPublisher;
import org.prevayler.implementation.publishing.TransactionSubscriber;

import java.io.IOException;
import java.util.Date;


/**
* Reserved for future implementation.
*/
public class ClientPublisher implements TransactionPublisher {

  private final BrokenClock _clock = new BrokenClock();

  private TransactionSubscriber _subscriber;
  private final Object _upToDateMonitor = new Object();

  private Capsule _myCapsule;
  private final Object _myCapsuleMonitor = new Object();
  private RuntimeException _myTransactionRuntimeException;
  private Error _myTransactionError;

  private final ObjectSocket _server;


  public ClientPublisher(OldNetworkImpl network, String serverIpAddress, int serverPort) throws IOException {
    System.out.println("The replication logic is still under development.");
    _server = network.openSocket(serverIpAddress, serverPort);
    startListening();
  }


  private void startListening() {
    Thread listener = new Thread() {
      public void run() {
        try {
          while (true) receiveTransactionFromServer();
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    };
    listener.setDaemon(true);
    listener.start();
  }


  public synchronized void subscribe(TransactionSubscriber subscriber, long initialTransaction) throws IOException, ClassNotFoundException {
    if (_subscriber != null)
      throw new UnsupportedOperationException("The current implementation can only support one subscriber. Future implementations will support more.");
    _subscriber = subscriber;
    synchronized (_upToDateMonitor) {
      _server.writeObject(new Long(initialTransaction));
      wait(_upToDateMonitor);
    }
  }


  public void cancelSubscription(TransactionSubscriber subscriber) {
    throw new UnsupportedOperationException("Removing subscribers is not yet supported by the current implementation.");
  }


  //TODO Remove synchronized allowing multiple transactions to be sent at a time.
  public synchronized void publish(Capsule capsule) {
    if (_subscriber == null)
      throw new IllegalStateException("To publish a transaction, this ClientPublisher needs a registered subscriber.");
    synchronized (_myCapsuleMonitor) {
      _myCapsule = capsule;

      try {
        _server.writeObject(capsule);
      } catch (IOException iox) {
        iox.printStackTrace();
        while (true) Thread.yield()//Remove all exceptions when using StubbornNetwork.
      }
      wait(_myCapsuleMonitor);

      throwEventualErrors();
    }
  }


  private void throwEventualErrors() throws RuntimeException, Error {
    try {
      if (_myTransactionRuntimeException != null) throw _myTransactionRuntimeException;
      if (_myTransactionError != null) throw _myTransactionError;
    } finally {
      _myTransactionRuntimeException = null;
      _myTransactionError = null;
    }
  }


  private void receiveTransactionFromServer() throws IOException, ClassNotFoundException {
    Object transactionCandidate = _server.readObject();

    if (transactionCandidate.equals(ServerConnection.SUBSCRIBER_UP_TO_DATE)) {
      synchronized (_upToDateMonitor) {
        _upToDateMonitor.notify();
      }
      return;
    }

    if (transactionCandidate instanceof Date) {
      Date clockTick = (Date) transactionCandidate;
      _clock.advanceTo(clockTick);
      return;
    }

    if (transactionCandidate instanceof RuntimeException) {
      _myTransactionRuntimeException = (RuntimeException) transactionCandidate;
      notifyMyTransactionMonitor();
      return;
    }
    if (transactionCandidate instanceof Error) {
      _myTransactionError = (Error) transactionCandidate;
      notifyMyTransactionMonitor();
      return;
    }

    TransactionTimestamp transactionTimestamp = (TransactionTimestamp) transactionCandidate;
    Date timestamp = transactionTimestamp.executionTime();
    long systemVersion = transactionTimestamp.systemVersion();

    _clock.advanceTo(timestamp);

    if (transactionTimestamp.capsule() == null) {
      _subscriber.receive(new TransactionTimestamp(_myCapsule, systemVersion, timestamp));
      notifyMyTransactionMonitor();
      return;
    }

    _subscriber.receive(new TransactionTimestamp(transactionTimestamp.capsule(), systemVersion, timestamp));
  }


  private static void wait(Object monitor) {
    try {
      monitor.wait();
    } catch (InterruptedException ix) {
      throw new RuntimeException("Unexpected InterruptedException.");
    }
  }


  private void notifyMyTransactionMonitor() {
    synchronized (_myCapsuleMonitor) {
      _myCapsuleMonitor.notify();
    }
  }


  public Clock clock() {
    return _clock;
  }


  public void close() throws IOException {
    _server.close();
  }

}
TOP

Related Classes of org.prevayler.implementation.replication.ClientPublisher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.