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 }