1 | // Copyright 2004-2007 Jean-Francois Poilpret |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | package net.sourceforge.hiveutils.service.impl; |
16 | |
17 | import java.io.ByteArrayInputStream; |
18 | import java.io.ByteArrayOutputStream; |
19 | import java.io.File; |
20 | import java.io.FileInputStream; |
21 | import java.io.FileOutputStream; |
22 | import java.io.IOException; |
23 | import java.io.ObjectInputStream; |
24 | import java.io.ObjectOutputStream; |
25 | import java.io.Serializable; |
26 | import java.util.ArrayList; |
27 | import java.util.List; |
28 | import java.util.zip.GZIPInputStream; |
29 | import java.util.zip.GZIPOutputStream; |
30 | |
31 | import org.apache.commons.logging.Log; |
32 | |
33 | import net.sourceforge.hiveutils.service.ObjectTools; |
34 | |
35 | /** |
36 | * Default implementation of ObjectTools service. |
37 | * |
38 | * @author Jean-Francois Poilpret |
39 | */ |
40 | public class ObjectToolsImpl implements ObjectTools |
41 | { |
42 | public ObjectToolsImpl(Log logger, int uncompressBufferSize, boolean useTempFiles) |
43 | { |
44 | _logger = logger; |
45 | _uncompressBufferSize = uncompressBufferSize; |
46 | _useTempFiles = useTempFiles; |
47 | } |
48 | |
49 | public byte[] serialize(Serializable obj) |
50 | { |
51 | try |
52 | { |
53 | ByteArrayOutputStream output = new ByteArrayOutputStream(); |
54 | ObjectOutputStream stream = new ObjectOutputStream(output); |
55 | stream.writeObject(obj); |
56 | stream.flush(); |
57 | stream.close(); |
58 | byte[] buffer = output.toByteArray(); |
59 | output.close(); |
60 | return buffer; |
61 | } |
62 | catch (IOException e) |
63 | { |
64 | _logger.error("serialize", e); |
65 | return null; |
66 | } |
67 | } |
68 | |
69 | public Object deserialize(byte[] buffer) |
70 | { |
71 | try |
72 | { |
73 | ByteArrayInputStream input = new ByteArrayInputStream(buffer); |
74 | ObjectInputStream stream = new ObjectInputStream(input); |
75 | return stream.readObject(); |
76 | } |
77 | catch (IOException e) |
78 | { |
79 | _logger.error("deserialize", e); |
80 | return null; |
81 | } |
82 | catch (ClassNotFoundException e) |
83 | { |
84 | _logger.error("deserialize", e); |
85 | return null; |
86 | } |
87 | } |
88 | |
89 | public byte[] compress(byte[] buffer) |
90 | { |
91 | _logger.debug("compress input size = " + buffer.length); |
92 | try |
93 | { |
94 | ByteArrayOutputStream output = new ByteArrayOutputStream(); |
95 | GZIPOutputStream stream = new GZIPOutputStream(output); |
96 | stream.write(buffer, 0, buffer.length); |
97 | stream.finish(); |
98 | stream.close(); |
99 | byte[] compressedBuffer = output.toByteArray(); |
100 | output.close(); |
101 | _logger.debug("compress output size = " + compressedBuffer.length); |
102 | return compressedBuffer; |
103 | } |
104 | catch (IOException e) |
105 | { |
106 | _logger.error("compress", e); |
107 | return null; |
108 | } |
109 | } |
110 | |
111 | // CSOFF: IllegalCatchCheck |
112 | public byte[] uncompress(byte[] buffer) |
113 | { |
114 | _logger.debug("uncompress input size = " + buffer.length); |
115 | try |
116 | { |
117 | ByteArrayInputStream input = new ByteArrayInputStream(buffer); |
118 | GZIPInputStream stream = new GZIPInputStream(input); |
119 | |
120 | TrunkAssembler assembler; |
121 | if (_useTempFiles) |
122 | { |
123 | assembler = new FileTrunkAssembler(_uncompressBufferSize); |
124 | } |
125 | else |
126 | { |
127 | assembler = new MemoryTrunkAssembler(_uncompressBufferSize); |
128 | } |
129 | |
130 | while (true) |
131 | { |
132 | byte[] trunk = assembler.createTrunk(); |
133 | int read = stream.read(trunk, 0, trunk.length); |
134 | if (read < 0) |
135 | { |
136 | break; |
137 | } |
138 | assembler.addTrunk(trunk, read); |
139 | } |
140 | stream.close(); |
141 | input.close(); |
142 | |
143 | // Reconstruct the full contents |
144 | byte[] contents = assembler.getContent(); |
145 | _logger.debug("uncompress output size = " + contents.length); |
146 | return contents; |
147 | } |
148 | catch (Exception e) |
149 | { |
150 | _logger.error("uncompress", e); |
151 | return null; |
152 | } |
153 | } |
154 | // CSON: IllegalCatchCheck |
155 | |
156 | private interface TrunkAssembler |
157 | { |
158 | public byte[] createTrunk(); |
159 | public void addTrunk(byte[] trunk, int size) throws Exception; |
160 | public byte[] getContent() throws Exception; |
161 | } |
162 | |
163 | static private class FileTrunkAssembler implements TrunkAssembler |
164 | { |
165 | public FileTrunkAssembler(int trunkSize) throws IOException |
166 | { |
167 | _trunk = new byte[trunkSize]; |
168 | _file = File.createTempFile("uncompress", null); |
169 | _stream = new FileOutputStream(_file); |
170 | } |
171 | |
172 | public byte[] createTrunk() |
173 | { |
174 | return _trunk; |
175 | } |
176 | |
177 | public void addTrunk(byte[] trunk, int size) throws IOException |
178 | { |
179 | _size += size; |
180 | _stream.write(trunk, 0, size); |
181 | _stream.flush(); |
182 | } |
183 | |
184 | public byte[] getContent() throws IOException |
185 | { |
186 | try |
187 | { |
188 | _stream.close(); |
189 | byte[] contents = new byte[_size]; |
190 | FileInputStream stream = new FileInputStream(_file); |
191 | stream.read(contents); |
192 | stream.close(); |
193 | return contents; |
194 | } |
195 | finally |
196 | { |
197 | _file.delete(); |
198 | } |
199 | } |
200 | |
201 | private final byte[] _trunk; |
202 | private int _size = 0; |
203 | private final File _file; |
204 | private final FileOutputStream _stream; |
205 | } |
206 | |
207 | static private class MemoryTrunkAssembler implements TrunkAssembler |
208 | { |
209 | public MemoryTrunkAssembler(int trunkSize) |
210 | { |
211 | _trunkSize = trunkSize; |
212 | } |
213 | |
214 | public byte[] createTrunk() |
215 | { |
216 | return new byte[_trunkSize]; |
217 | } |
218 | |
219 | public void addTrunk(byte[] trunk, int size) |
220 | { |
221 | _size += size; |
222 | _trunks.add(new Trunk(trunk, size)); |
223 | } |
224 | |
225 | public byte[] getContent() |
226 | { |
227 | byte[] contents = new byte[_size]; |
228 | int index = 0; |
229 | for (Trunk trunk: _trunks) |
230 | { |
231 | System.arraycopy(trunk.getContent(), 0, contents, index, trunk.getSize()); |
232 | index += trunk.getSize(); |
233 | } |
234 | return contents; |
235 | } |
236 | |
237 | private final List<Trunk> _trunks = new ArrayList<Trunk>(); |
238 | private final int _trunkSize; |
239 | private int _size = 0; |
240 | } |
241 | |
242 | static private final class Trunk |
243 | { |
244 | public Trunk(byte[] content, int size) |
245 | { |
246 | _content = content; |
247 | _size = size; |
248 | } |
249 | |
250 | /** |
251 | * @return Returns the content. |
252 | */ |
253 | public byte[] getContent() |
254 | { |
255 | return _content; |
256 | } |
257 | |
258 | /** |
259 | * @return Returns the size. |
260 | */ |
261 | public int getSize() |
262 | { |
263 | return _size; |
264 | } |
265 | |
266 | private final byte[] _content; |
267 | private final int _size; |
268 | } |
269 | |
270 | final private Log _logger; |
271 | final private int _uncompressBufferSize; |
272 | final private boolean _useTempFiles; |
273 | } |