PageRenderTime 52ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/org.mwc.asset.comms/docs/restlet_src/org.restlet/org/restlet/engine/http/io/ChunkedOutputStream.java

https://bitbucket.org/haris_peco/debrief
Java | 168 lines | 64 code | 22 blank | 82 comment | 4 complexity | ce35d5ab80b95d2422f426671dbed673 MD5 | raw file
  1. /**
  2. * Copyright 2005-2010 Noelios Technologies.
  3. *
  4. * The contents of this file are subject to the terms of one of the following
  5. * open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
  6. * "Licenses"). You can select the license that you prefer but you may not use
  7. * this file except in compliance with one of these Licenses.
  8. *
  9. * You can obtain a copy of the LGPL 3.0 license at
  10. * http://www.opensource.org/licenses/lgpl-3.0.html
  11. *
  12. * You can obtain a copy of the LGPL 2.1 license at
  13. * http://www.opensource.org/licenses/lgpl-2.1.php
  14. *
  15. * You can obtain a copy of the CDDL 1.0 license at
  16. * http://www.opensource.org/licenses/cddl1.php
  17. *
  18. * You can obtain a copy of the EPL 1.0 license at
  19. * http://www.opensource.org/licenses/eclipse-1.0.php
  20. *
  21. * See the Licenses for the specific language governing permissions and
  22. * limitations under the Licenses.
  23. *
  24. * Alternatively, you can obtain a royalty free commercial license with less
  25. * limitations, transferable or non-transferable, directly at
  26. * http://www.noelios.com/products/restlet-engine
  27. *
  28. * Restlet is a registered trademark of Noelios Technologies.
  29. */
  30. package org.restlet.engine.http.io;
  31. import java.io.IOException;
  32. import java.io.OutputStream;
  33. import org.restlet.engine.http.header.HeaderUtils;
  34. import org.restlet.engine.util.StringUtils;
  35. /**
  36. * OutputStream to write data in the HTTP chunked encoding format to a
  37. * destination OutputStream. See section 3.6.1 of HTTP Protocol for more
  38. * information on chunked encoding.
  39. *
  40. * @author <a href="mailto:kevin.a.conaway@gmail.com">Kevin Conaway</a>
  41. * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html">HTTP/1.1
  42. * Protocol</a>
  43. */
  44. public class ChunkedOutputStream extends OutputStream {
  45. /** Default size of a chunk. */
  46. private static final int DEFAULT_CHUNK_SIZE = 2048;
  47. /** The byte buffer. */
  48. private final byte[] buffer;
  49. /** The number of bytes written. */
  50. private volatile int bytesWritten;
  51. /** Indicate if the stream is closed. */
  52. private volatile boolean closed;
  53. /** The destination output stream. */
  54. private final OutputStream destination;
  55. /**
  56. * Convenience constructor to use a default chunk size size of 2048.
  57. *
  58. * @param destination
  59. * @see #ChunkedOutputStream(OutputStream, int)
  60. */
  61. public ChunkedOutputStream(OutputStream destination) {
  62. this(destination, DEFAULT_CHUNK_SIZE);
  63. }
  64. /**
  65. * @param destination
  66. * Outputstream to write chunked data to
  67. * @param chunkSize
  68. * Chunk size
  69. */
  70. public ChunkedOutputStream(OutputStream destination, int chunkSize) {
  71. this.destination = destination;
  72. this.buffer = new byte[chunkSize];
  73. this.bytesWritten = 0;
  74. this.closed = false;
  75. }
  76. /**
  77. * @return True if the current chunk is full.
  78. */
  79. private boolean chunkFull() {
  80. return this.bytesWritten == this.buffer.length;
  81. }
  82. /**
  83. * Closes this output stream for writing but does not close the wrapped
  84. * stream.
  85. */
  86. @Override
  87. public void close() throws IOException {
  88. if (!this.closed) {
  89. writeChunk();
  90. writeFinalChunk();
  91. super.close();
  92. this.closed = true;
  93. this.destination.flush();
  94. }
  95. }
  96. /**
  97. * Writes the current chunk and flushes the wrapped stream.
  98. */
  99. @Override
  100. public void flush() throws IOException {
  101. writeChunk();
  102. this.destination.flush();
  103. }
  104. /**
  105. * Resets the internal buffer.
  106. */
  107. private void reset() {
  108. this.bytesWritten = 0;
  109. }
  110. @Override
  111. public void write(int b) throws IOException {
  112. if (chunkFull()) {
  113. writeChunk();
  114. }
  115. this.buffer[this.bytesWritten++] = (byte) b;
  116. }
  117. /**
  118. * Write a chunk, starting with its size in hexadecimal, followed by CRLF
  119. * and the actual content.
  120. *
  121. * @throws IOException
  122. */
  123. private void writeChunk() throws IOException {
  124. if (this.bytesWritten > 0) {
  125. // Write the current position in hexadecimal format followed by CRLF
  126. this.destination.write(StringUtils.getAsciiBytes(Integer
  127. .toHexString(this.bytesWritten)));
  128. HeaderUtils.writeCRLF(this.destination);
  129. // Write the chunk content
  130. this.destination.write(this.buffer, 0, this.bytesWritten);
  131. HeaderUtils.writeCRLF(this.destination);
  132. // Reset the position
  133. reset();
  134. }
  135. }
  136. /**
  137. * Write the closing chunk: A zero followed by two CRLF.
  138. *
  139. * @throws IOException
  140. */
  141. private void writeFinalChunk() throws IOException {
  142. this.destination.write((byte) '0');
  143. HeaderUtils.writeCRLF(this.destination);
  144. HeaderUtils.writeCRLF(this.destination);
  145. }
  146. }