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