package org.prevayler.implementation;
import org.prevayler.foundation.Chunk;
import org.prevayler.foundation.serialization.Serializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.util.Date;
public abstract class Capsule implements Serializable {
private final byte[] _serialized;
protected Capsule( Object transaction, Serializer journalSerializer){
try {
ByteArrayOutputStream bytes=new ByteArrayOutputStream();
journalSerializer.writeObject(bytes,transaction);
_serialized=bytes.toByteArray();
}
catch ( Exception exception) {
throw new Error("Unable to serialize transaction",exception);
}
}
protected Capsule( byte[] serialized){
_serialized=serialized;
}
/**
* Get the serialized representation of the transaction. Callers must not modify the returned array.
*/
public byte[] serialized(){
return _serialized;
}
/**
* Deserialize the contained Transaction or TransactionWithQuery.
*/
public Object deserialize( Serializer journalSerializer){
try {
return journalSerializer.readObject(new ByteArrayInputStream(_serialized));
}
catch ( Exception exception) {
throw new Error("Unable to deserialize transaction",exception);
}
}
/**
* Execute a freshly deserialized copy of the transaction. This method will synchronize on the prevalentSystem
* while running the transaction but after deserializing it.
*/
public void executeOn( Object prevalentSystem, Date executionTime, Serializer journalSerializer){
Object transaction=deserialize(journalSerializer);
synchronized (prevalentSystem) {
justExecute(transaction,prevalentSystem,executionTime);
}
}
/**
* Actually execute the Transaction or TransactionWithQuery. The caller
* is responsible for synchronizing on the prevalentSystem.
*/
protected abstract void justExecute( Object transaction, Object prevalentSystem, Date executionTime);
/**
* Make a clean copy of this capsule that will have its own query result fields.
*/
public abstract Capsule cleanCopy();
Chunk toChunk(){
Chunk chunk=new Chunk(_serialized);
chunk.setParameter("withQuery",String.valueOf(this instanceof TransactionWithQueryCapsule));
return chunk;
}
static Capsule fromChunk( Chunk chunk){
boolean withQuery=Boolean.valueOf(chunk.getParameter("withQuery")).booleanValue();
if (withQuery) {
return new TransactionWithQueryCapsule(chunk.getBytes());
}
else {
return new TransactionCapsule(chunk.getBytes());
}
}
}