/*
* StubbornNetworkProxy.java
*
*
*/
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) {
//TODO: Action TBD
}
}
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;
}
}
}