1 /*
2 * #%L
3 * BufferingBsonOutputStream.java - mongodb-async-driver - Allanbank Consulting, Inc.
4 * %%
5 * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
6 * %%
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * #L%
19 */
20 package com.allanbank.mongodb.bson.io;
21
22 import java.io.FilterOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25
26 import com.allanbank.mongodb.bson.Document;
27 import com.allanbank.mongodb.bson.Visitor;
28
29 /**
30 * {@link BufferingBsonOutputStream} provides a class to write BSON documents
31 * based on the <a href="http://bsonspec.org/">BSON specification</a>.
32 * <p>
33 * Users of this class must make sure that the {@link #flushBuffer()} method is
34 * called after calling any of the {@link #writeInt(int) writeXXX()} methods.
35 * </p>
36 *
37 * @api.yes This class is part of the driver's API. Public and protected members
38 * will be deprecated for at least 1 non-bugfix release (version
39 * numbers are <major>.<minor>.<bugfix>) before being
40 * removed or modified.
41 * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
42 */
43 public class BufferingBsonOutputStream extends FilterOutputStream {
44
45 /** The {@link Visitor} to write the BSON documents. */
46 private final RandomAccessOutputStream myOutput;
47
48 /** The {@link Visitor} to write the BSON documents. */
49 private final BufferingWriteVisitor myVisitor;
50
51 /**
52 * Creates a new {@link BufferingBsonOutputStream}.
53 *
54 * @param output
55 * The stream to write to.
56 */
57 public BufferingBsonOutputStream(final OutputStream output) {
58 super(output);
59
60 myVisitor = new BufferingWriteVisitor();
61 myOutput = myVisitor.getOutputBuffer();
62 }
63
64 /**
65 * Creates a new {@link BufferingBsonOutputStream}.
66 *
67 * @param output
68 * The stream to write to.
69 * @param cache
70 * The cache for encoding strings.
71 */
72 public BufferingBsonOutputStream(final OutputStream output,
73 final StringEncoderCache cache) {
74 super(output);
75
76 myVisitor = new BufferingWriteVisitor(cache);
77 myOutput = myVisitor.getOutputBuffer();
78 }
79
80 /**
81 * Creates a new {@link BufferingBsonOutputStream}.
82 *
83 * @param output
84 * The stream to write to.
85 */
86 public BufferingBsonOutputStream(final RandomAccessOutputStream output) {
87 super(output);
88
89 myVisitor = new BufferingWriteVisitor(output);
90 myOutput = myVisitor.getOutputBuffer();
91 }
92
93 /**
94 * Writes any pending data to the underlying stream.
95 * <p>
96 * Users should call this method after calling any of the
97 * {@link #writeInt(int) writeXXX(...)} methods.
98 * </p>
99 *
100 * @throws IOException
101 * On a failure to write to the underlying document.
102 */
103 public void flushBuffer() throws IOException {
104 if (out != myOutput) {
105 myVisitor.writeTo(out);
106 myVisitor.reset();
107 }
108 }
109
110 /**
111 * Returns the maximum number of strings that may have their encoded form
112 * cached.
113 *
114 * @return The maximum number of strings that may have their encoded form
115 * cached.
116 * @deprecated The cache {@link StringEncoderCache} should be controlled
117 * directory. This method will be removed after the 2.1.0
118 * release.
119 */
120 @Deprecated
121 public int getMaxCachedStringEntries() {
122 return myVisitor.getMaxCachedStringEntries();
123 }
124
125 /**
126 * Returns the maximum length for a string that the stream is allowed to
127 * cache.
128 *
129 * @return The maximum length for a string that the stream is allowed to
130 * cache.
131 * @deprecated The cache {@link StringEncoderCache} should be controlled
132 * directory. This method will be removed after the 2.1.0
133 * release.
134 */
135 @Deprecated
136 public int getMaxCachedStringLength() {
137 return myVisitor.getMaxCachedStringLength();
138 }
139
140 /**
141 * Returns the output buffer.
142 *
143 * @return The output buffer.
144 */
145 public RandomAccessOutputStream getOutput() {
146 return myOutput;
147 }
148
149 /**
150 * Returns the current position in the stream.
151 *
152 * @return The current position in the stream.
153 */
154 public long getPosition() {
155 return myOutput.getPosition();
156 }
157
158 /**
159 * Sets the value of maximum number of strings that may have their encoded
160 * form cached.
161 *
162 * @param maxCacheEntries
163 * The new value for the maximum number of strings that may have
164 * their encoded form cached.
165 * @deprecated The cache {@link StringEncoderCache} should be controlled
166 * directory. This method will be removed after the 2.1.0
167 * release.
168 */
169 @Deprecated
170 public void setMaxCachedStringEntries(final int maxCacheEntries) {
171 myVisitor.setMaxCachedStringEntries(maxCacheEntries);
172 }
173
174 /**
175 * Sets the value of length for a string that the stream is allowed to cache
176 * to the new value. This can be used to stop a single long string from
177 * pushing useful values out of the cache.
178 *
179 * @param maxlength
180 * The new value for the length for a string that the encoder is
181 * allowed to cache.
182 * @deprecated The cache {@link StringEncoderCache} should be controlled
183 * directory. This method will be removed after the 2.1.0
184 * release.
185 */
186 @Deprecated
187 public void setMaxCachedStringLength(final int maxlength) {
188 myVisitor.setMaxCachedStringLength(maxlength);
189
190 }
191
192 /**
193 * Writes <code>b.length</code> bytes to this output stream.
194 * <p>
195 * Calls the write(byte[]) of the underlying stream.
196 * </p>
197 *
198 * @param b
199 * the data to be written.
200 * @exception IOException
201 * if an I/O error occurs.
202 * @see java.io.FilterOutputStream#write(byte[], int, int)
203 */
204 @Override
205 public void write(final byte b[]) throws IOException {
206 out.write(b);
207 }
208
209 /**
210 * Writes <code>len</code> bytes from the specified <code>byte</code> array
211 * starting at offset <code>off</code> to this output stream.
212 * <p>
213 * Calls the write(byte[],int,int) of the underlying stream.
214 * </p>
215 *
216 * @param b
217 * the data.
218 * @param off
219 * the start offset in the data.
220 * @param len
221 * the number of bytes to write.
222 * @exception IOException
223 * if an I/O error occurs.
224 * @see java.io.FilterOutputStream#write(int)
225 */
226 @Override
227 public void write(final byte b[], final int off, final int len)
228 throws IOException {
229 out.write(b, off, len);
230 }
231
232 /**
233 * Writes the Document in BSON format to the underlying stream.
234 * <p>
235 * This method automatically calls {@link #flushBuffer()}.
236 * </p>
237 *
238 * @param doc
239 * The document to write.
240 * @return The number of bytes written for the document.
241 * @throws IOException
242 * On a failure to write to the underlying document.
243 */
244 public long write(final Document doc) throws IOException {
245
246 doc.accept(myVisitor);
247
248 final long position = myVisitor.getSize();
249
250 flushBuffer();
251
252 return position;
253 }
254
255 /**
256 * Writes a single byte to the output buffer.
257 * <p>
258 * Users of this method must call {@link #flushBuffer()} or the contents
259 * will not be written to the wrapped stream.
260 * </p>
261 *
262 * @param b
263 * The byte to write.
264 */
265 public void writeByte(final byte b) {
266 myOutput.writeByte(b);
267 }
268
269 /**
270 * Writes a sequence of bytes to the output buffer.
271 * <p>
272 * Users of this method must call {@link #flushBuffer()} or the contents
273 * will not be written to the wrapped stream.
274 * </p>
275 *
276 * @param data
277 * The bytes to write.
278 */
279 public void writeBytes(final byte[] data) {
280 myOutput.writeBytes(data);
281 }
282
283 /**
284 * Writes a "Cstring" to the output buffer.
285 * <p>
286 * Users of this method must call {@link #flushBuffer()} or the contents
287 * will not be written to the wrapped stream.
288 * </p>
289 *
290 * @param strings
291 * The CString to write. The strings are concatenated into a
292 * single CString value.
293 */
294 public void writeCString(final String... strings) {
295 myOutput.writeCString(strings);
296 }
297
298 /**
299 * Writes the Document in BSON format to the underlying stream.
300 * <p>
301 * Users of this method must call {@link #flushBuffer()} or the contents
302 * will not be written to the wrapped stream.
303 * </p>
304 *
305 * @param doc
306 * The document to write.
307 * @throws IOException
308 * On a failure to write to the underlying document.
309 */
310 public void writeDocument(final Document doc) throws IOException {
311 doc.accept(myVisitor);
312 }
313
314 /**
315 * Writes the integer value in little-endian byte order to the output
316 * buffer.
317 * <p>
318 * Users of this method must call {@link #flushBuffer()} or the contents
319 * will not be written to the wrapped stream.
320 * </p>
321 *
322 * @param value
323 * The value to write.
324 */
325 public void writeInt(final int value) {
326 myOutput.writeInt(value);
327 }
328
329 /**
330 * Similar to {@link #writeInt(int)} but allows a portion of the already
331 * written buffer to be re-written.
332 * <p>
333 * Users of this method must call {@link #flushBuffer()} or the contents
334 * will not be written to the wrapped stream.
335 * </p>
336 *
337 * @param position
338 * The position to write at. This location should have already
339 * been written.
340 * @param value
341 * The integer value to write.
342 */
343 public void writeIntAt(final long position, final int value) {
344 myOutput.writeIntAt(position, value);
345 }
346
347 /**
348 * Write the long value in little-endian byte order to the output buffer.
349 * <p>
350 * Users of this method must call {@link #flushBuffer()} or the contents
351 * will not be written to the wrapped stream.
352 * </p>
353 *
354 * @param value
355 * The long to write.
356 */
357 public void writeLong(final long value) {
358 myOutput.writeLong(value);
359 }
360
361 /**
362 * Writes a "string" to the output buffer.
363 * <p>
364 * Users of this method must call {@link #flushBuffer()} or the contents
365 * will not be written to the wrapped stream.
366 * </p>
367 *
368 * @param string
369 * The String to write.
370 */
371 public void writeString(final String string) {
372 myOutput.writeString(string);
373 }
374 }