View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io.output;
18  
19  import java.io.FilterWriter;
20  import java.io.IOException;
21  import java.io.Writer;
22  import java.util.Collection;
23  
24  import org.apache.commons.io.IOUtils;
25  
26  /**
27   * A Proxy stream collection which acts as expected, that is it passes the method calls on to the proxied streams and
28   * doesn't change which methods are being called. It is an alternative base class to {@link FilterWriter} and
29   * {@link FilterCollectionWriter} to increase reusability, because FilterWriter changes the methods being called, such
30   * as {@code write(char[])} to {@code write(char[], int, int)} and {@code write(String)} to
31   * {@code write(String, int, int)}. This is in contrast to {@link ProxyWriter} which is backed by a single
32   * {@link Writer}.
33   *
34   * @since 2.7
35   */
36  public class ProxyCollectionWriter extends FilterCollectionWriter {
37  
38      /**
39       * Constructs a new proxy collection writer.
40       *
41       * @param writers Writers object to provide the underlying targets.
42       */
43      public ProxyCollectionWriter(final Collection<Writer> writers) {
44          super(writers);
45      }
46  
47      /**
48       * Constructs a new proxy collection writer.
49       *
50       * @param writers Writers to provide the underlying targets.
51       */
52      public ProxyCollectionWriter(final Writer... writers) {
53          super(writers);
54      }
55  
56      /**
57       * Invoked by the write methods after the proxied call has returned successfully. The number of chars written (1 for
58       * the {@link #write(int)} method, buffer length for {@link #write(char[])}, etc.) is given as an argument.
59       * <p>
60       * Subclasses can override this method to add common post-processing functionality without having to override all
61       * the write methods. The default implementation does nothing.
62       * </p>
63       *
64       * @param n number of chars written
65       * @throws IOException if the post-processing fails
66       */
67      @SuppressWarnings("unused") // Possibly thrown from subclasses.
68      protected void afterWrite(final int n) throws IOException {
69          // noop
70      }
71  
72      /**
73       * Invokes the delegates' {@code append(char)} methods.
74       *
75       * @param c The character to write
76       * @return this writer
77       * @throws IOException if an I/O error occurs.
78       * @since 2.0
79       */
80      @Override
81      public Writer append(final char c) throws IOException {
82          try {
83              beforeWrite(1);
84              super.append(c);
85              afterWrite(1);
86          } catch (final IOException e) {
87              handleIOException(e);
88          }
89          return this;
90      }
91  
92      /**
93       * Invokes the delegates' {@code append(CharSequence)} methods.
94       *
95       * @param csq The character sequence to write
96       * @return this writer
97       * @throws IOException if an I/O error occurs.
98       */
99      @Override
100     public Writer append(final CharSequence csq) throws IOException {
101         try {
102             final int len = IOUtils.length(csq);
103             beforeWrite(len);
104             super.append(csq);
105             afterWrite(len);
106         } catch (final IOException e) {
107             handleIOException(e);
108         }
109         return this;
110     }
111 
112     /**
113      * Invokes the delegates' {@code append(CharSequence, int, int)} methods.
114      *
115      * @param csq   The character sequence to write
116      * @param start The index of the first character to write
117      * @param end   The index of the first character to write (exclusive)
118      * @return this writer
119      * @throws IOException if an I/O error occurs.
120      */
121     @Override
122     public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
123         try {
124             beforeWrite(end - start);
125             super.append(csq, start, end);
126             afterWrite(end - start);
127         } catch (final IOException e) {
128             handleIOException(e);
129         }
130         return this;
131     }
132 
133     /**
134      * Invoked by the write methods before the call is proxied. The number of chars to be written (1 for the
135      * {@link #write(int)} method, buffer length for {@link #write(char[])}, etc.) is given as an argument.
136      * <p>
137      * Subclasses can override this method to add common pre-processing functionality without having to override all the
138      * write methods. The default implementation does nothing.
139      * </p>
140      *
141      * @param n number of chars to be written
142      * @throws IOException if the pre-processing fails
143      */
144     @SuppressWarnings("unused") // Possibly thrown from subclasses.
145     protected void beforeWrite(final int n) throws IOException {
146         // noop
147     }
148 
149     /**
150      * Invokes the delegate's {@code close()} method.
151      *
152      * @throws IOException if an I/O error occurs.
153      */
154     @Override
155     public void close() throws IOException {
156         try {
157             super.close();
158         } catch (final IOException e) {
159             handleIOException(e);
160         }
161     }
162 
163     /**
164      * Invokes the delegate's {@code flush()} method.
165      *
166      * @throws IOException if an I/O error occurs.
167      */
168     @Override
169     public void flush() throws IOException {
170         try {
171             super.flush();
172         } catch (final IOException e) {
173             handleIOException(e);
174         }
175     }
176 
177     /**
178      * Handle any IOExceptions thrown.
179      * <p>
180      * This method provides a point to implement custom exception handling. The default behavior is to re-throw the
181      * exception.
182      * </p>
183      *
184      * @param e The IOException thrown
185      * @throws IOException if an I/O error occurs.
186      */
187     protected void handleIOException(final IOException e) throws IOException {
188         throw e;
189     }
190 
191     /**
192      * Invokes the delegate's {@code write(char[])} method.
193      *
194      * @param cbuf the characters to write
195      * @throws IOException if an I/O error occurs.
196      */
197     @Override
198     public void write(final char[] cbuf) throws IOException {
199         try {
200             final int len = IOUtils.length(cbuf);
201             beforeWrite(len);
202             super.write(cbuf);
203             afterWrite(len);
204         } catch (final IOException e) {
205             handleIOException(e);
206         }
207     }
208 
209     /**
210      * Invokes the delegate's {@code write(char[], int, int)} method.
211      *
212      * @param cbuf the characters to write
213      * @param off  The start offset
214      * @param len  The number of characters to write
215      * @throws IOException if an I/O error occurs.
216      */
217     @Override
218     public void write(final char[] cbuf, final int off, final int len) throws IOException {
219         try {
220             beforeWrite(len);
221             super.write(cbuf, off, len);
222             afterWrite(len);
223         } catch (final IOException e) {
224             handleIOException(e);
225         }
226     }
227 
228     /**
229      * Invokes the delegate's {@code write(int)} method.
230      *
231      * @param c the character to write
232      * @throws IOException if an I/O error occurs.
233      */
234     @Override
235     public void write(final int c) throws IOException {
236         try {
237             beforeWrite(1);
238             super.write(c);
239             afterWrite(1);
240         } catch (final IOException e) {
241             handleIOException(e);
242         }
243     }
244 
245     /**
246      * Invokes the delegate's {@code write(String)} method.
247      *
248      * @param str the string to write
249      * @throws IOException if an I/O error occurs.
250      */
251     @Override
252     public void write(final String str) throws IOException {
253         try {
254             final int len = IOUtils.length(str);
255             beforeWrite(len);
256             super.write(str);
257             afterWrite(len);
258         } catch (final IOException e) {
259             handleIOException(e);
260         }
261     }
262 
263     /**
264      * Invokes the delegate's {@code write(String)} method.
265      *
266      * @param str the string to write
267      * @param off The start offset
268      * @param len The number of characters to write
269      * @throws IOException if an I/O error occurs.
270      */
271     @Override
272     public void write(final String str, final int off, final int len) throws IOException {
273         try {
274             beforeWrite(len);
275             super.write(str, off, len);
276             afterWrite(len);
277         } catch (final IOException e) {
278             handleIOException(e);
279         }
280     }
281 
282 }