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(); } }