package lsr.service;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import lsr.paxos.replica.Replica;
/**
* This class provides skeletal implementation of {@link Service} interface to
* simplify creating services. To create new service using this class programmer
* needs to implement following methods:
* <ul>
* <li><code>execute</code></li>
* <li><code>makeObjectSnapshot</code></li>
* <li><code>updateToSnapshot</code></li>
* </ul>
* <p>
* In most cases this methods will provide enough functionality. Creating
* snapshots is invoked by framework. If more control for making snapshot is
* needed then <code>Service</code> interface should be implemented.
* <p>
* All methods are called from the same thread, so it is not necessary to
* synchronize them.
* <p>
* <b>Note:</b> The clients should use <code>SerializableClient</code> to
* connect to services extending this class.
*
*/
public abstract class SerializableService extends SimplifiedService {
/**
* Executes one command from client on this state machine. This method will
* be called by {@link Replica}.
*
* @param value - command from client to execute on this service
* @return generated reply which will be sent to client
*/
protected abstract Object execute(Object value);
/**
* Updates the current state of <code>Service</code> to state from snapshot.
* This method will be called after recovery to restore previous state, or
* if we received new one from other replica (using catch-up).
* <p>
* Snapshot argument is deserialized version of object created in
* {@link #makeObjectSnapshot()}
*
* @param snapshot - data used to update to new state
*/
protected abstract void updateToSnapshot(Object snapshot);
/**
* Makes snapshot for current state of <code>Service</code>.
* <p>
* The same data created in this method, will be used to update state from
* other snapshot using {@link #updateToSnapshot(Object)} method.
*
* @return the data containing current state
*/
protected abstract Object makeObjectSnapshot();
protected final byte[] execute(byte[] value) {
try {
return byteArrayFromObject(execute(byteArrayToObject(value)));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
protected final byte[] makeSnapshot() {
try {
return byteArrayFromObject(makeObjectSnapshot());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected final void updateToSnapshot(byte[] snapshot) {
try {
updateToSnapshot(byteArrayToObject(snapshot));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
protected Object byteArrayToObject(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
protected byte[] byteArrayFromObject(Object object) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new ObjectOutputStream(bos).writeObject(object);
return bos.toByteArray();
}
}