View Javadoc

1   package com.atlassian.plugin.webresource.transformer;
2   
3   import java.io.IOException;
4   import java.io.OutputStream;
5   import java.io.Writer;
6   import java.nio.ByteBuffer;
7   import java.nio.CharBuffer;
8   import java.nio.charset.Charset;
9   import java.nio.charset.CharsetDecoder;
10  import java.nio.charset.CoderResult;
11  import java.nio.charset.CodingErrorAction;
12  
13  /**
14   * This class is taken from CommonsIO 2.0.1 and usage should be replaced with that class when the dependency is updated
15   */
16  class WriterOutputStream extends OutputStream
17  {
18      private final Writer writer;
19      private final CharsetDecoder decoder;
20      private final boolean writeImmediately;
21      private final ByteBuffer decoderIn;
22      private final CharBuffer decoderOut;
23  
24      WriterOutputStream(final Writer writer, final Charset charset, final int bufferSize, final boolean writeImmediately)
25      {
26          decoderIn = ByteBuffer.allocate(128);
27  
28          this.writer = writer;
29          decoder = charset.newDecoder();
30          decoder.onMalformedInput(CodingErrorAction.REPLACE);
31          decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
32          decoder.replaceWith("?");
33          this.writeImmediately = writeImmediately;
34          decoderOut = CharBuffer.allocate(bufferSize);
35      }
36  
37      WriterOutputStream(final Writer writer, final Charset charset)
38      {
39          this(writer, charset, 1024, false);
40      }
41  
42      WriterOutputStream(final Writer writer, final String charsetName, final int bufferSize, final boolean writeImmediately)
43      {
44          this(writer, Charset.forName(charsetName), bufferSize, writeImmediately);
45      }
46  
47      WriterOutputStream(final Writer writer, final String charsetName)
48      {
49          this(writer, charsetName, 1024, false);
50      }
51  
52      WriterOutputStream(final Writer writer)
53      {
54          this(writer, Charset.defaultCharset(), 1024, false);
55      }
56  
57      @Override
58      public void write(final byte[] b, int off, int len) throws IOException
59      {
60          while (len > 0)
61          {
62              final int c = Math.min(len, decoderIn.remaining());
63              decoderIn.put(b, off, c);
64              processInput(false);
65              len -= c;
66              off += c;
67          }
68          if (writeImmediately)
69          {
70              flushOutput();
71          }
72      }
73  
74      @Override
75      public void write(final byte[] b) throws IOException
76      {
77          write(b, 0, b.length);
78      }
79  
80      @Override
81      public void write(final int b) throws IOException
82      {
83          write(new byte[] { (byte) b }, 0, 1);
84      }
85  
86      @Override
87      public void flush() throws IOException
88      {
89          flushOutput();
90          writer.flush();
91      }
92  
93      @Override
94      public void close() throws IOException
95      {
96          processInput(true);
97          flushOutput();
98          writer.close();
99      }
100 
101     private void processInput(final boolean endOfInput) throws IOException
102     {
103         decoderIn.flip();
104         CoderResult coderResult;
105         while (true)
106         {
107             coderResult = decoder.decode(decoderIn, decoderOut, endOfInput);
108             if (!(coderResult.isOverflow()))
109             {
110                 break;
111             }
112             flushOutput();
113         }
114         if (!(coderResult.isUnderflow()))
115         {
116             throw new IOException("Unexpected coder result");
117         }
118 
119         decoderIn.compact();
120     }
121 
122     private void flushOutput() throws IOException
123     {
124         if (decoderOut.position() > 0)
125         {
126             writer.write(decoderOut.array(), 0, decoderOut.position());
127             decoderOut.rewind();
128         }
129     }
130 }