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