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      @SuppressWarnings("resource") // Fluent API.
81      @Override
82      public Writer append(final char c) throws IOException {
83          try {
84              beforeWrite(1);
85              super.append(c);
86              afterWrite(1);
87          } catch (final IOException e) {
88              handleIOException(e);
89          }
90          return this;
91      }
92  
93      /**
94       * Invokes the delegates' {@code append(CharSequence)} methods.
95       *
96       * @param csq The character sequence to write
97       * @return this writer
98       * @throws IOException if an I/O error occurs.
99       */
100     @SuppressWarnings("resource") // Fluent API.
101     @Override
102     public Writer append(final CharSequence csq) throws IOException {
103         try {
104             final int len = IOUtils.length(csq);
105             beforeWrite(len);
106             super.append(csq);
107             afterWrite(len);
108         } catch (final IOException e) {
109             handleIOException(e);
110         }
111         return this;
112     }
113 
114     /**
115      * Invokes the delegates' {@code append(CharSequence, int, int)} methods.
116      *
117      * @param csq   The character sequence to write
118      * @param start The index of the first character to write
119      * @param end   The index of the first character to write (exclusive)
120      * @return this writer
121      * @throws IOException if an I/O error occurs.
122      */
123     @SuppressWarnings("resource") // Fluent API.
124     @Override
125     public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
126         try {
127             beforeWrite(end - start);
128             super.append(csq, start, end);
129             afterWrite(end - start);
130         } catch (final IOException e) {
131             handleIOException(e);
132         }
133         return this;
134     }
135 
136     /**
137      * Invoked by the write methods before the call is proxied. The number of chars to be written (1 for the
138      * {@link #write(int)} method, buffer length for {@link #write(char[])}, etc.) is given as an argument.
139      * <p>
140      * Subclasses can override this method to add common pre-processing functionality without having to override all the
141      * write methods. The default implementation does nothing.
142      * </p>
143      *
144      * @param n number of chars to be written
145      * @throws IOException if the pre-processing fails
146      */
147     @SuppressWarnings("unused") // Possibly thrown from subclasses.
148     protected void beforeWrite(final int n) throws IOException {
149         // noop
150     }
151 
152     /**
153      * Invokes the delegate's {@code close()} method.
154      *
155      * @throws IOException if an I/O error occurs.
156      */
157     @Override
158     public void close() throws IOException {
159         try {
160             super.close();
161         } catch (final IOException e) {
162             handleIOException(e);
163         }
164     }
165 
166     /**
167      * Invokes the delegate's {@code flush()} method.
168      *
169      * @throws IOException if an I/O error occurs.
170      */
171     @Override
172     public void flush() throws IOException {
173         try {
174             super.flush();
175         } catch (final IOException e) {
176             handleIOException(e);
177         }
178     }
179 
180     /**
181      * Handle any IOExceptions thrown.
182      * <p>
183      * This method provides a point to implement custom exception handling. The default behavior is to re-throw the
184      * exception.
185      * </p>
186      *
187      * @param e The IOException thrown
188      * @throws IOException if an I/O error occurs.
189      */
190     protected void handleIOException(final IOException e) throws IOException {
191         throw e;
192     }
193 
194     /**
195      * Invokes the delegate's {@code write(char[])} method.
196      *
197      * @param cbuf the characters to write
198      * @throws IOException if an I/O error occurs.
199      */
200     @Override
201     public void write(final char[] cbuf) throws IOException {
202         try {
203             final int len = IOUtils.length(cbuf);
204             beforeWrite(len);
205             super.write(cbuf);
206             afterWrite(len);
207         } catch (final IOException e) {
208             handleIOException(e);
209         }
210     }
211 
212     /**
213      * Invokes the delegate's {@code write(char[], int, int)} method.
214      *
215      * @param cbuf the characters to write
216      * @param off  The start offset
217      * @param len  The number of characters to write
218      * @throws IOException if an I/O error occurs.
219      */
220     @Override
221     public void write(final char[] cbuf, final int off, final int len) throws IOException {
222         try {
223             beforeWrite(len);
224             super.write(cbuf, off, len);
225             afterWrite(len);
226         } catch (final IOException e) {
227             handleIOException(e);
228         }
229     }
230 
231     /**
232      * Invokes the delegate's {@code write(int)} method.
233      *
234      * @param c the character to write
235      * @throws IOException if an I/O error occurs.
236      */
237     @Override
238     public void write(final int c) throws IOException {
239         try {
240             beforeWrite(1);
241             super.write(c);
242             afterWrite(1);
243         } catch (final IOException e) {
244             handleIOException(e);
245         }
246     }
247 
248     /**
249      * Invokes the delegate's {@code write(String)} method.
250      *
251      * @param str the string to write
252      * @throws IOException if an I/O error occurs.
253      */
254     @Override
255     public void write(final String str) throws IOException {
256         try {
257             final int len = IOUtils.length(str);
258             beforeWrite(len);
259             super.write(str);
260             afterWrite(len);
261         } catch (final IOException e) {
262             handleIOException(e);
263         }
264     }
265 
266     /**
267      * Invokes the delegate's {@code write(String)} method.
268      *
269      * @param str the string to write
270      * @param off The start offset
271      * @param len The number of characters to write
272      * @throws IOException if an I/O error occurs.
273      */
274     @Override
275     public void write(final String str, final int off, final int len) throws IOException {
276         try {
277             beforeWrite(len);
278             super.write(str, off, len);
279             afterWrite(len);
280         } catch (final IOException e) {
281             handleIOException(e);
282         }
283     }
284 
285 }