blob: 5d89606c11d5c2a89f2b2477a1c4a6da8ba06d19 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
/*
* Copyright 2011 gitblit.com.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.gitblit.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class DeepCopier {
/**
* Produce a deep copy of the given object. Serializes the entire object to
* a byte array in memory. Recommended for relatively small objects.
*/
@SuppressWarnings("unchecked")
public static <T> T copy(T original) {
T o = null;
try {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(byteOut);
oos.writeObject(original);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream ois = new ObjectInputStream(byteIn);
try {
o = (T) ois.readObject();
} catch (ClassNotFoundException cex) {
// actually can not happen in this instance
}
} catch (IOException iox) {
// doesn't seem likely to happen as these streams are in memory
throw new RuntimeException(iox);
}
return o;
}
/**
* This conserves heap memory!!!!! Produce a deep copy of the given object.
* Serializes the object through a pipe between two threads. Recommended for
* very large objects. 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 <T> T copyParallel(T original) {
try {
PipedOutputStream outputStream = new PipedOutputStream();
PipedInputStream inputStream = new PipedInputStream(outputStream);
ObjectOutputStream ois = new ObjectOutputStream(outputStream);
Receiver<T> receiver = new Receiver<T>(inputStream);
try {
ois.writeObject(original);
} finally {
ois.close();
}
return receiver.getResult();
} catch (IOException iox) {
// doesn't seem likely to happen as these streams are in memory
throw new RuntimeException(iox);
}
}
private static class Receiver<T> extends Thread {
private final InputStream inputStream;
private volatile T result;
private volatile Throwable throwable;
public Receiver(InputStream inputStream) {
this.inputStream = inputStream;
start();
}
@Override
@SuppressWarnings("unchecked")
public void run() {
try {
ObjectInputStream ois = new ObjectInputStream(inputStream);
try {
result = (T) ois.readObject();
try {
// Some serializers may write more than they actually
// need to deserialize the object, but if we don't
// read it all the PipedOutputStream will choke.
while (inputStream.read() != -1) {
}
} catch (IOException e) {
// The object has been successfully deserialized, so
// ignore problems at this point (for example, the
// serializer may have explicitly closed the inputStream
// itself, causing this read to fail).
}
} finally {
ois.close();
}
} catch (Throwable t) {
throwable = t;
}
}
public T getResult() throws IOException {
try {
join();
} catch (InterruptedException e) {
throw new RuntimeException("Unexpected InterruptedException", e);
}
// join() guarantees that all shared memory is synchronized between
// the two threads
if (throwable != null) {
if (throwable instanceof ClassNotFoundException) {
// actually can not happen in this instance
}
throw new RuntimeException(throwable);
}
return result;
}
}
}
|