package org.prevayler.foundation.network;
import java.io.IOException;
/**
* Stubborn Network Proxies are bound to each Service instance in
* a Prevayler providing Server services for Replication.
* This allows the binding to be dynamically connected to a Client
* replicator, thereby facilitating reconnection after failure.
* A failed receive causes the proxy to capture the thread until
* the replication client (network) reconnects.
* The Proxy never invokes "close" on the service layer.
*/
public class StubbornNetworkProxy implements ObjectReceiver {
private ObjectReceiver _network;
private ObjectReceiver _client;
private StubbornNetworkClientConnector _inboundChannel;
public StubbornNetworkProxy(){
}
protected synchronized void connect( ObjectReceiver network, StubbornNetworkClientConnector inboundChannel){
_network=network;
_inboundChannel=inboundChannel;
openClientChannel();
}
protected synchronized void disconnect(){
_inboundChannel=null;
_network=null;
}
protected void setClient( ObjectReceiver client){
_client=client;
}
public ObjectReceiver getClient(){
return _client;
}
public void receive( Object object){
if (isOpen()) {
attemptToForward(object);
}
else {
waitTillOpen();
attemptToForward(object);
}
}
private synchronized boolean forwarded( Object object){
try {
if (_network == null) {
return false;
}
_network.receive(object);
return true;
}
catch ( IOException handle) {
return false;
}
}
private void attemptToForward( Object object){
while (!forwarded(object)) {
closeClientChannel();
waitTillOpen();
}
}
private synchronized void waitTillOpen(){
try {
wait();
}
catch ( InterruptedException unexpected) {
}
}
private synchronized boolean isOpen(){
return (_network != null);
}
public void close() throws IOException {
closeClientChannel();
_client=null;
}
private synchronized void openClientChannel(){
notify();
}
private void closeClientChannel(){
try {
if (_inboundChannel != null) _inboundChannel.disconnect();
if (_network != null) _network.close();
}
catch ( IOException ignorable) {
}
finally {
_network=null;
_inboundChannel=null;
}
}
}