package org.prevayler.foundation;
import org.prevayler.foundation.serialization.JavaSerializer;
import org.prevayler.foundation.serialization.Serializer;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class DeepCopier {
/**
* Same as deepCopy(original, new JavaSerializer()).
* @throws ClassNotFoundException
* @throws IOException
*/
public static Object deepCopy( Object original){
return deepCopy(original,new JavaSerializer());
}
/**
* Produce a deep copy of the given object. Serializes the entire object to a byte array in memory. Recommended for
* relatively small objects, such as individual transactions.
*/
public static Object deepCopy( Object original, Serializer serializer){
try {
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
serializer.writeObject(byteOut,original);
ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());
return serializer.readObject(byteIn);
}
catch ( Exception e) {
Cool.unexpected(e);
return null;
}
}
/**
* Produce a deep copy of the given object. Serializes the object through a pipe between two threads. Recommended for
* very large objects, such as an entire prevalent system. The current thread is used for serializing the original
* object in order to respect any synchronization the caller may have around it, and a new thread is used for
* deserializing the copy.
*/
public static Object deepCopyParallel( Object original, Serializer serializer) throws IOException, ClassNotFoundException {
PipedOutputStream outputStream=new PipedOutputStream();
PipedInputStream inputStream=new PipedInputStream(outputStream);
Receiver receiver=new Receiver(inputStream,serializer);
try {
serializer.writeObject(outputStream,original);
}
finally {
outputStream.close();
}
return receiver.getResult();
}
private static class Receiver extends Thread {
private InputStream _inputStream;
private Serializer _serializer;
private Object _result;
private IOException _ioException;
private ClassNotFoundException _classNotFoundException;
private RuntimeException _runtimeException;
private Error _error;
public Receiver( InputStream inputStream, Serializer serializer){
_inputStream=inputStream;
_serializer=serializer;
start();
}
public void run(){
try {
_result=_serializer.readObject(_inputStream);
}
catch ( IOException e) {
_ioException=e;
}
catch ( ClassNotFoundException e) {
_classNotFoundException=e;
}
catch ( RuntimeException e) {
_runtimeException=e;
}
catch ( Error e) {
_error=e;
throw e;
}
try {
while (_inputStream.read() != -1) {
}
}
catch ( IOException e) {
}
}
public Object getResult() throws ClassNotFoundException, IOException {
try {
join();
}
catch ( InterruptedException e) {
throw new RuntimeException("Unexpected InterruptedException",e);
}
if (_error != null) throw new RuntimeException("Error during deserialization",_error);
if (_runtimeException != null) throw _runtimeException;
if (_classNotFoundException != null) throw _classNotFoundException;
if (_ioException != null) throw _ioException;
if (_result == null) throw new RuntimeException("Deep copy failed in an unknown way");
return _result;
}
}
}