View Javadoc
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 &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) 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 }