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 * https://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 }