1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
package com.allanbank.mongodb.bson.io; |
21 | |
|
22 | |
import java.io.IOException; |
23 | |
import java.io.OutputStream; |
24 | |
import java.util.List; |
25 | |
|
26 | |
import com.allanbank.mongodb.bson.Document; |
27 | |
import com.allanbank.mongodb.bson.Element; |
28 | |
import com.allanbank.mongodb.bson.ElementType; |
29 | |
import com.allanbank.mongodb.bson.Visitor; |
30 | |
import com.allanbank.mongodb.bson.element.ObjectId; |
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
class BufferingWriteVisitor implements Visitor { |
43 | |
|
44 | |
|
45 | |
protected final RandomAccessOutputStream myOutputBuffer; |
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
public BufferingWriteVisitor() { |
51 | 7 | this(new StringEncoderCache()); |
52 | 7 | } |
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | 119 | public BufferingWriteVisitor(final RandomAccessOutputStream output) { |
61 | 119 | myOutputBuffer = output; |
62 | 119 | } |
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
public BufferingWriteVisitor(final StringEncoderCache cache) { |
71 | 7 | this(new RandomAccessOutputStream(cache)); |
72 | 7 | } |
73 | |
|
74 | |
|
75 | |
|
76 | |
|
77 | |
|
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
@Deprecated |
85 | |
public int getMaxCachedStringEntries() { |
86 | 0 | return myOutputBuffer.getMaxCachedStringEntries(); |
87 | |
} |
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
|
97 | |
|
98 | |
|
99 | |
@Deprecated |
100 | |
public int getMaxCachedStringLength() { |
101 | 0 | return myOutputBuffer.getMaxCachedStringLength(); |
102 | |
} |
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
public long getSize() { |
110 | 6 | return myOutputBuffer.getPosition(); |
111 | |
} |
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
public void reset() { |
117 | 9 | myOutputBuffer.reset(); |
118 | 9 | } |
119 | |
|
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
@Deprecated |
132 | |
public void setMaxCachedStringEntries(final int maxCacheEntries) { |
133 | 0 | myOutputBuffer.setMaxCachedStringEntries(maxCacheEntries); |
134 | 0 | } |
135 | |
|
136 | |
|
137 | |
|
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
|
143 | |
|
144 | |
|
145 | |
|
146 | |
|
147 | |
|
148 | |
@Deprecated |
149 | |
public void setMaxCachedStringLength(final int maxlength) { |
150 | 0 | myOutputBuffer.setMaxCachedStringLength(maxlength); |
151 | |
|
152 | 0 | } |
153 | |
|
154 | |
|
155 | |
|
156 | |
|
157 | |
@Override |
158 | |
public void visit(final List<Element> elements) { |
159 | 32360 | final long position = myOutputBuffer.getPosition(); |
160 | |
|
161 | 32360 | myOutputBuffer.writeInt(0); |
162 | 32360 | for (final Element element : elements) { |
163 | 64493 | element.accept(this); |
164 | 64493 | } |
165 | 32360 | myOutputBuffer.writeByte((byte) 0); |
166 | |
|
167 | 32360 | final int size = (int) (myOutputBuffer.getPosition() - position); |
168 | 32360 | myOutputBuffer.writeIntAt(position, size); |
169 | 32360 | } |
170 | |
|
171 | |
|
172 | |
|
173 | |
|
174 | |
@Override |
175 | |
public void visitArray(final String name, final List<Element> elements) { |
176 | 4 | myOutputBuffer.writeByte(ElementType.ARRAY.getToken()); |
177 | 4 | myOutputBuffer.writeCString(name); |
178 | 4 | visit(elements); |
179 | 4 | } |
180 | |
|
181 | |
|
182 | |
|
183 | |
|
184 | |
@Override |
185 | |
public void visitBinary(final String name, final byte subType, |
186 | |
final byte[] data) { |
187 | 32012 | myOutputBuffer.writeByte(ElementType.BINARY.getToken()); |
188 | 32012 | myOutputBuffer.writeCString(name); |
189 | 32012 | switch (subType) { |
190 | |
case 2: { |
191 | 6 | myOutputBuffer.writeInt(data.length + 4); |
192 | 6 | myOutputBuffer.writeByte(subType); |
193 | 6 | myOutputBuffer.writeInt(data.length); |
194 | 6 | myOutputBuffer.writeBytes(data); |
195 | 6 | break; |
196 | |
|
197 | |
} |
198 | |
case 0: |
199 | |
default: |
200 | 32006 | myOutputBuffer.writeInt(data.length); |
201 | 32006 | myOutputBuffer.writeByte(subType); |
202 | 32006 | myOutputBuffer.writeBytes(data); |
203 | |
break; |
204 | |
} |
205 | 32012 | } |
206 | |
|
207 | |
|
208 | |
|
209 | |
|
210 | |
@Override |
211 | |
public void visitBoolean(final String name, final boolean value) { |
212 | |
|
213 | 35 | myOutputBuffer.writeByte(ElementType.BOOLEAN.getToken()); |
214 | 35 | myOutputBuffer.writeCString(name); |
215 | 35 | myOutputBuffer.writeByte(value ? (byte) 0x01 : 0x00); |
216 | 35 | } |
217 | |
|
218 | |
|
219 | |
|
220 | |
|
221 | |
@SuppressWarnings("deprecation") |
222 | |
@Override |
223 | |
public void visitDBPointer(final String name, final String databaseName, |
224 | |
final String collectionName, final ObjectId id) { |
225 | 6 | myOutputBuffer.writeByte(ElementType.DB_POINTER.getToken()); |
226 | 6 | myOutputBuffer.writeCString(name); |
227 | 6 | myOutputBuffer.writeString(databaseName + "." + collectionName); |
228 | |
|
229 | 6 | myOutputBuffer.writeInt(EndianUtils.swap(id.getTimestamp())); |
230 | 6 | myOutputBuffer.writeLong(EndianUtils.swap(id.getMachineId())); |
231 | 6 | } |
232 | |
|
233 | |
|
234 | |
|
235 | |
|
236 | |
@Override |
237 | |
public void visitDocument(final String name, final List<Element> elements) { |
238 | 32010 | myOutputBuffer.writeByte(ElementType.DOCUMENT.getToken()); |
239 | 32010 | myOutputBuffer.writeCString(name); |
240 | 32010 | visit(elements); |
241 | 32010 | } |
242 | |
|
243 | |
|
244 | |
|
245 | |
|
246 | |
@Override |
247 | |
public void visitDouble(final String name, final double value) { |
248 | 7 | myOutputBuffer.writeByte(ElementType.DOUBLE.getToken()); |
249 | 7 | myOutputBuffer.writeCString(name); |
250 | 7 | myOutputBuffer.writeLong(Double.doubleToLongBits(value)); |
251 | 7 | } |
252 | |
|
253 | |
|
254 | |
|
255 | |
|
256 | |
@Override |
257 | |
public void visitInteger(final String name, final int value) { |
258 | 297 | myOutputBuffer.writeByte(ElementType.INTEGER.getToken()); |
259 | 297 | myOutputBuffer.writeCString(name); |
260 | 297 | myOutputBuffer.writeInt(value); |
261 | 297 | } |
262 | |
|
263 | |
|
264 | |
|
265 | |
|
266 | |
@Override |
267 | |
public void visitJavaScript(final String name, final String code) { |
268 | 6 | myOutputBuffer.writeByte(ElementType.JAVA_SCRIPT.getToken()); |
269 | 6 | myOutputBuffer.writeCString(name); |
270 | 6 | myOutputBuffer.writeString(code); |
271 | 6 | } |
272 | |
|
273 | |
|
274 | |
|
275 | |
|
276 | |
@Override |
277 | |
public void visitJavaScript(final String name, final String code, |
278 | |
final Document scope) { |
279 | 6 | myOutputBuffer.writeByte(ElementType.JAVA_SCRIPT_WITH_SCOPE.getToken()); |
280 | 6 | myOutputBuffer.writeCString(name); |
281 | |
|
282 | 6 | final long start = myOutputBuffer.getPosition(); |
283 | 6 | myOutputBuffer.writeInt(0); |
284 | 6 | myOutputBuffer.writeString(code); |
285 | |
|
286 | 6 | scope.accept(this); |
287 | |
|
288 | 6 | final int size = (int) (myOutputBuffer.getPosition() - start); |
289 | 6 | myOutputBuffer.writeIntAt(start, size); |
290 | 6 | } |
291 | |
|
292 | |
|
293 | |
|
294 | |
|
295 | |
@Override |
296 | |
public void visitLong(final String name, final long value) { |
297 | 6 | myOutputBuffer.writeByte(ElementType.LONG.getToken()); |
298 | 6 | myOutputBuffer.writeCString(name); |
299 | 6 | myOutputBuffer.writeLong(value); |
300 | 6 | } |
301 | |
|
302 | |
|
303 | |
|
304 | |
|
305 | |
@Override |
306 | |
public void visitMaxKey(final String name) { |
307 | 6 | myOutputBuffer.writeByte(ElementType.MAX_KEY.getToken()); |
308 | 6 | myOutputBuffer.writeCString(name); |
309 | 6 | } |
310 | |
|
311 | |
|
312 | |
|
313 | |
|
314 | |
@Override |
315 | |
public void visitMinKey(final String name) { |
316 | 6 | myOutputBuffer.writeByte(ElementType.MIN_KEY.getToken()); |
317 | 6 | myOutputBuffer.writeCString(name); |
318 | 6 | } |
319 | |
|
320 | |
|
321 | |
|
322 | |
|
323 | |
@Override |
324 | |
public void visitMongoTimestamp(final String name, final long value) { |
325 | 6 | myOutputBuffer.writeByte(ElementType.MONGO_TIMESTAMP.getToken()); |
326 | 6 | myOutputBuffer.writeCString(name); |
327 | 6 | myOutputBuffer.writeLong(value); |
328 | 6 | } |
329 | |
|
330 | |
|
331 | |
|
332 | |
|
333 | |
@Override |
334 | |
public void visitNull(final String name) { |
335 | 6 | myOutputBuffer.writeByte(ElementType.NULL.getToken()); |
336 | 6 | myOutputBuffer.writeCString(name); |
337 | 6 | } |
338 | |
|
339 | |
|
340 | |
|
341 | |
|
342 | |
@Override |
343 | |
public void visitObjectId(final String name, final ObjectId id) { |
344 | 6 | myOutputBuffer.writeByte(ElementType.OBJECT_ID.getToken()); |
345 | 6 | myOutputBuffer.writeCString(name); |
346 | |
|
347 | 6 | myOutputBuffer.writeInt(EndianUtils.swap(id.getTimestamp())); |
348 | 6 | myOutputBuffer.writeLong(EndianUtils.swap(id.getMachineId())); |
349 | 6 | } |
350 | |
|
351 | |
|
352 | |
|
353 | |
|
354 | |
@Override |
355 | |
public void visitRegularExpression(final String name, final String pattern, |
356 | |
final String options) { |
357 | 9 | myOutputBuffer.writeByte(ElementType.REGEX.getToken()); |
358 | 9 | myOutputBuffer.writeCString(name); |
359 | 9 | myOutputBuffer.writeCString(pattern); |
360 | 9 | myOutputBuffer.writeCString(options); |
361 | 9 | } |
362 | |
|
363 | |
|
364 | |
|
365 | |
|
366 | |
@Override |
367 | |
public void visitString(final String name, final String value) { |
368 | 51 | myOutputBuffer.writeByte(ElementType.STRING.getToken()); |
369 | 51 | myOutputBuffer.writeCString(name); |
370 | 51 | myOutputBuffer.writeString(value); |
371 | 51 | } |
372 | |
|
373 | |
|
374 | |
|
375 | |
|
376 | |
@Override |
377 | |
public void visitSymbol(final String name, final String symbol) { |
378 | 6 | myOutputBuffer.writeByte(ElementType.SYMBOL.getToken()); |
379 | 6 | myOutputBuffer.writeCString(name); |
380 | 6 | myOutputBuffer.writeString(symbol); |
381 | 6 | } |
382 | |
|
383 | |
|
384 | |
|
385 | |
|
386 | |
@Override |
387 | |
public void visitTimestamp(final String name, final long timestamp) { |
388 | 8 | myOutputBuffer.writeByte(ElementType.UTC_TIMESTAMP.getToken()); |
389 | 8 | myOutputBuffer.writeCString(name); |
390 | 8 | myOutputBuffer.writeLong(timestamp); |
391 | 8 | } |
392 | |
|
393 | |
|
394 | |
|
395 | |
|
396 | |
|
397 | |
|
398 | |
|
399 | |
|
400 | |
|
401 | |
public void writeTo(final OutputStream out) throws IOException { |
402 | 9 | myOutputBuffer.writeTo(out); |
403 | 9 | } |
404 | |
|
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
|
410 | |
protected RandomAccessOutputStream getOutputBuffer() { |
411 | 119 | return myOutputBuffer; |
412 | |
} |
413 | |
|
414 | |
} |