1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| |
11 |
| |
12 |
| |
13 |
| |
14 |
| |
15 |
| package org.apache.tapestry.util.io; |
16 |
| |
17 |
| import java.io.ByteArrayInputStream; |
18 |
| import java.io.ByteArrayOutputStream; |
19 |
| import java.io.IOException; |
20 |
| import java.io.InputStream; |
21 |
| import java.io.ObjectInputStream; |
22 |
| import java.io.ObjectOutputStream; |
23 |
| import java.io.OutputStream; |
24 |
| import java.io.Serializable; |
25 |
| import java.util.zip.GZIPInputStream; |
26 |
| import java.util.zip.GZIPOutputStream; |
27 |
| |
28 |
| import org.apache.tapestry.Tapestry; |
29 |
| import org.apache.tapestry.services.DataSqueezer; |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| |
41 |
| |
42 |
| |
43 |
| |
44 |
| |
45 |
| |
46 |
| class SerializableAdaptor implements ISqueezeAdaptor |
47 |
| { |
48 |
| private static final String PREFIX = "O"; |
49 |
| |
50 |
| |
51 |
| |
52 |
| |
53 |
| |
54 |
| |
55 |
| |
56 |
| private static final char PAD = '.'; |
57 |
| |
58 |
| |
59 |
| |
60 |
| |
61 |
| |
62 |
| |
63 |
| private static final char CH_62 = '-'; |
64 |
| |
65 |
| |
66 |
| |
67 |
| |
68 |
| |
69 |
| |
70 |
| private static final char CH_63 = '_'; |
71 |
| |
72 |
1
| public String squeeze(DataSqueezer squeezer, Object data) throws IOException
|
73 |
| { |
74 |
1
| ByteArrayOutputStream bos = null;
|
75 |
1
| GZIPOutputStream gos = null;
|
76 |
1
| ObjectOutputStream oos = null;
|
77 |
1
| byte[] byteData = null;
|
78 |
| |
79 |
1
| try
|
80 |
| { |
81 |
1
| bos = new ByteArrayOutputStream();
|
82 |
1
| gos = new GZIPOutputStream(bos);
|
83 |
1
| oos = new ObjectOutputStream(gos);
|
84 |
| |
85 |
1
| oos.writeObject(data);
|
86 |
1
| oos.close();
|
87 |
| } |
88 |
| finally |
89 |
| { |
90 |
1
| close(oos);
|
91 |
1
| close(gos);
|
92 |
1
| close(bos);
|
93 |
| } |
94 |
| |
95 |
1
| byteData = bos.toByteArray();
|
96 |
| |
97 |
1
| StringBuffer encoded = new StringBuffer(2 * byteData.length);
|
98 |
1
| char[] base64 = new char[4];
|
99 |
| |
100 |
1
| encoded.append(PREFIX);
|
101 |
| |
102 |
1
| for (int i = 0; i < byteData.length; i += 3)
|
103 |
| { |
104 |
163
| encodeBlock(byteData, i, base64);
|
105 |
163
| encoded.append(base64);
|
106 |
| } |
107 |
| |
108 |
1
| return encoded.toString();
|
109 |
| } |
110 |
| |
111 |
3
| private void close(OutputStream stream)
|
112 |
| { |
113 |
3
| if (stream != null)
|
114 |
| { |
115 |
3
| try
|
116 |
| { |
117 |
3
| stream.close();
|
118 |
| } |
119 |
| catch (IOException ex) |
120 |
| { |
121 |
| |
122 |
| } |
123 |
| } |
124 |
| } |
125 |
| |
126 |
3
| private void close(InputStream stream)
|
127 |
| { |
128 |
3
| if (stream != null)
|
129 |
| { |
130 |
3
| try
|
131 |
| { |
132 |
3
| stream.close();
|
133 |
| } |
134 |
| catch (IOException ex) |
135 |
| { |
136 |
| |
137 |
| } |
138 |
| } |
139 |
| } |
140 |
1
| public Object unsqueeze(DataSqueezer squeezer, String string) throws IOException
|
141 |
| { |
142 |
1
| ByteArrayInputStream bis = null;
|
143 |
1
| GZIPInputStream gis = null;
|
144 |
1
| ObjectInputStream ois = null;
|
145 |
1
| byte[] byteData;
|
146 |
| |
147 |
| |
148 |
| |
149 |
1
| byteData = decode(string.substring(1));
|
150 |
| |
151 |
1
| try
|
152 |
| { |
153 |
1
| bis = new ByteArrayInputStream(byteData);
|
154 |
1
| gis = new GZIPInputStream(bis);
|
155 |
1
| ois = new ResolvingObjectInputStream(squeezer.getResolver(), gis);
|
156 |
| |
157 |
1
| return ois.readObject();
|
158 |
| } |
159 |
| catch (ClassNotFoundException ex) |
160 |
| { |
161 |
| |
162 |
| |
163 |
0
| throw new IOException(
|
164 |
| Tapestry.format("SerializableAdaptor.class-not-found", ex.getMessage())); |
165 |
| } |
166 |
| finally |
167 |
| { |
168 |
1
| close(ois);
|
169 |
1
| close(gis);
|
170 |
1
| close(bis);
|
171 |
| } |
172 |
| } |
173 |
| |
174 |
37
| public void register(DataSqueezer squeezer)
|
175 |
| { |
176 |
37
| squeezer.register(PREFIX, Serializable.class, this);
|
177 |
| } |
178 |
| |
179 |
163
| private static void encodeBlock(byte[] raw, int offset, char[] base64) throws IOException
|
180 |
| { |
181 |
163
| int block = 0;
|
182 |
163
| int slack = raw.length - offset - 1;
|
183 |
163
| int end = (slack >= 2) ? 2 : slack;
|
184 |
| |
185 |
163
| for (int i = 0; i <= end; i++)
|
186 |
| { |
187 |
488
| byte b = raw[offset + i];
|
188 |
488
| int neuter = (b < 0) ? b + 256 : b;
|
189 |
488
| block += neuter << (8 * (2 - i));
|
190 |
| } |
191 |
| |
192 |
163
| for (int i = 0; i < 4; i++)
|
193 |
| { |
194 |
652
| int sixbit = (block >>> (6 * (3 - i))) & 0x3f;
|
195 |
652
| base64[i] = getChar(sixbit);
|
196 |
| } |
197 |
| |
198 |
163
| if (slack < 1)
|
199 |
0
| base64[2] = PAD;
|
200 |
| |
201 |
163
| if (slack < 2)
|
202 |
1
| base64[3] = PAD;
|
203 |
| } |
204 |
| |
205 |
652
| protected static char getChar(int sixBit) throws IOException
|
206 |
| { |
207 |
652
| if (sixBit >= 0 && sixBit <= 25)
|
208 |
274
| return (char) ('A' + sixBit);
|
209 |
| |
210 |
378
| if (sixBit >= 26 && sixBit <= 51)
|
211 |
261
| return (char) ('a' + (sixBit - 26));
|
212 |
| |
213 |
117
| if (sixBit >= 52 && sixBit <= 61)
|
214 |
94
| return (char) ('0' + (sixBit - 52));
|
215 |
| |
216 |
23
| if (sixBit == 62)
|
217 |
12
| return CH_62;
|
218 |
| |
219 |
11
| if (sixBit == 63)
|
220 |
11
| return CH_63;
|
221 |
| |
222 |
0
| throw new IOException(
|
223 |
| Tapestry.format("SerializableAdaptor.unable-to-convert", Integer.toString(sixBit))); |
224 |
| } |
225 |
| |
226 |
1
| public static byte[] decode(String string) throws IOException
|
227 |
| { |
228 |
1
| int pad = 0;
|
229 |
1
| char[] base64 = string.toCharArray();
|
230 |
| |
231 |
1
| for (int i = base64.length - 1; base64[i] == PAD; i--)
|
232 |
1
| pad++;
|
233 |
| |
234 |
1
| int length = base64.length * 6 / 8 - pad;
|
235 |
1
| byte[] raw = new byte[length];
|
236 |
1
| int rawIndex = 0;
|
237 |
| |
238 |
1
| for (int i = 0; i < base64.length; i += 4)
|
239 |
| { |
240 |
163
| int block =
|
241 |
| (getValue(base64[i]) << 18) |
242 |
| + (getValue(base64[i + 1]) << 12) |
243 |
| + (getValue(base64[i + 2]) << 6) |
244 |
| + (getValue(base64[i + 3])); |
245 |
| |
246 |
163
| for (int j = 0; j < 3 && rawIndex + j < raw.length; j++)
|
247 |
488
| raw[rawIndex + j] = (byte) ((block >> (8 * (2 - j))) & 0xff);
|
248 |
| |
249 |
163
| rawIndex += 3;
|
250 |
| } |
251 |
| |
252 |
1
| return raw;
|
253 |
| } |
254 |
| |
255 |
652
| private static int getValue(char c) throws IOException
|
256 |
| { |
257 |
652
| if (c >= 'A' && c <= 'Z')
|
258 |
273
| return c - 'A';
|
259 |
| |
260 |
379
| if (c >= 'a' && c <= 'z')
|
261 |
261
| return c - 'a' + 26;
|
262 |
| |
263 |
118
| if (c >= '0' && c <= '9')
|
264 |
94
| return c - '0' + 52;
|
265 |
| |
266 |
24
| if (c == CH_62)
|
267 |
12
| return 62;
|
268 |
| |
269 |
12
| if (c == CH_63)
|
270 |
11
| return 63;
|
271 |
| |
272 |
| |
273 |
| |
274 |
1
| if (c == PAD)
|
275 |
1
| return 0;
|
276 |
| |
277 |
0
| throw new IOException(
|
278 |
| Tapestry.format( |
279 |
| "SerializableAdaptor.unable-to-interpret-char", |
280 |
| new String(new char[] { c }))); |
281 |
| } |
282 |
| |
283 |
| } |