001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io.output;
018
019import java.io.FilterWriter;
020import java.io.IOException;
021import java.io.Writer;
022
023/**
024 * A Proxy stream which acts as expected, that is it passes the method
025 * calls on to the proxied stream and doesn't change which methods are
026 * being called. It is an alternative base class to FilterWriter
027 * to increase reusability, because FilterWriter changes the
028 * methods being called, such as write(char[]) to write(char[], int, int)
029 * and write(String) to write(String, int, int).
030 *
031 */
032public class ProxyWriter extends FilterWriter {
033
034    /**
035     * Constructs a new ProxyWriter.
036     *
037     * @param proxy  the Writer to delegate to
038     */
039    public ProxyWriter(final Writer proxy) {
040        super(proxy);
041        // the proxy is stored in a protected superclass variable named 'out'
042    }
043
044    /**
045     * Invokes the delegate's <code>append(char)</code> method.
046     * @param c The character to write
047     * @return this writer
048     * @throws IOException if an I/O error occurs
049     * @since 2.0
050     */
051    @Override
052    public Writer append(final char c) throws IOException {
053        try {
054            beforeWrite(1);
055            out.append(c);
056            afterWrite(1);
057        } catch (final IOException e) {
058            handleIOException(e);
059        }
060        return this;
061    }
062
063    /**
064     * Invokes the delegate's <code>append(CharSequence, int, int)</code> method.
065     * @param csq The character sequence to write
066     * @param start The index of the first character to write
067     * @param end  The index of the first character to write (exclusive)
068     * @return this writer
069     * @throws IOException if an I/O error occurs
070     * @since 2.0
071     */
072    @Override
073    public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
074        try {
075            beforeWrite(end - start);
076            out.append(csq, start, end);
077            afterWrite(end - start);
078        } catch (final IOException e) {
079            handleIOException(e);
080        }
081        return this;
082    }
083
084    /**
085     * Invokes the delegate's <code>append(CharSequence)</code> method.
086     * @param csq The character sequence to write
087     * @return this writer
088     * @throws IOException if an I/O error occurs
089     * @since 2.0
090     */
091    @Override
092    public Writer append(final CharSequence csq) throws IOException {
093        try {
094            int len = 0;
095            if (csq != null) {
096                len = csq.length();
097            }
098
099            beforeWrite(len);
100            out.append(csq);
101            afterWrite(len);
102        } catch (final IOException e) {
103            handleIOException(e);
104        }
105        return this;
106    }
107
108    /**
109     * Invokes the delegate's <code>write(int)</code> method.
110     * @param idx the character to write
111     * @throws IOException if an I/O error occurs
112     */
113    @Override
114    public void write(final int idx) throws IOException {
115        try {
116            beforeWrite(1);
117            out.write(idx);
118            afterWrite(1);
119        } catch (final IOException e) {
120            handleIOException(e);
121        }
122    }
123
124    /**
125     * Invokes the delegate's <code>write(char[])</code> method.
126     * @param chr the characters to write
127     * @throws IOException if an I/O error occurs
128     */
129    @Override
130    public void write(final char[] chr) throws IOException {
131        try {
132            int len = 0;
133            if (chr != null) {
134                len = chr.length;
135            }
136
137            beforeWrite(len);
138            out.write(chr);
139            afterWrite(len);
140        } catch (final IOException e) {
141            handleIOException(e);
142        }
143    }
144
145    /**
146     * Invokes the delegate's <code>write(char[], int, int)</code> method.
147     * @param chr the characters to write
148     * @param st The start offset
149     * @param len The number of characters to write
150     * @throws IOException if an I/O error occurs
151     */
152    @Override
153    public void write(final char[] chr, final int st, final int len) throws IOException {
154        try {
155            beforeWrite(len);
156            out.write(chr, st, len);
157            afterWrite(len);
158        } catch (final IOException e) {
159            handleIOException(e);
160        }
161    }
162
163    /**
164     * Invokes the delegate's <code>write(String)</code> method.
165     * @param str the string to write
166     * @throws IOException if an I/O error occurs
167     */
168    @Override
169    public void write(final String str) throws IOException {
170        try {
171            int len = 0;
172            if (str != null) {
173                len = str.length();
174            }
175
176            beforeWrite(len);
177            out.write(str);
178            afterWrite(len);
179        } catch (final IOException e) {
180            handleIOException(e);
181        }
182    }
183
184    /**
185     * Invokes the delegate's <code>write(String)</code> method.
186     * @param str the string to write
187     * @param st The start offset
188     * @param len The number of characters to write
189     * @throws IOException if an I/O error occurs
190     */
191    @Override
192    public void write(final String str, final int st, final int len) throws IOException {
193        try {
194            beforeWrite(len);
195            out.write(str, st, len);
196            afterWrite(len);
197        } catch (final IOException e) {
198            handleIOException(e);
199        }
200    }
201
202    /**
203     * Invokes the delegate's <code>flush()</code> method.
204     * @throws IOException if an I/O error occurs
205     */
206    @Override
207    public void flush() throws IOException {
208        try {
209            out.flush();
210        } catch (final IOException e) {
211            handleIOException(e);
212        }
213    }
214
215    /**
216     * Invokes the delegate's <code>close()</code> method.
217     * @throws IOException if an I/O error occurs
218     */
219    @Override
220    public void close() throws IOException {
221        try {
222            out.close();
223        } catch (final IOException e) {
224            handleIOException(e);
225        }
226    }
227
228    /**
229     * Invoked by the write methods before the call is proxied. The number
230     * of chars to be written (1 for the {@link #write(int)} method, buffer
231     * length for {@link #write(char[])}, etc.) is given as an argument.
232     * <p>
233     * Subclasses can override this method to add common pre-processing
234     * functionality without having to override all the write methods.
235     * The default implementation does nothing.
236     *
237     * @since 2.0
238     * @param n number of chars to be written
239     * @throws IOException if the pre-processing fails
240     */
241    protected void beforeWrite(final int n) throws IOException {
242    }
243
244    /**
245     * Invoked by the write methods after the proxied call has returned
246     * successfully. The number of chars written (1 for the
247     * {@link #write(int)} method, buffer length for {@link #write(char[])},
248     * etc.) is given as an argument.
249     * <p>
250     * Subclasses can override this method to add common post-processing
251     * functionality without having to override all the write methods.
252     * The default implementation does nothing.
253     *
254     * @since 2.0
255     * @param n number of chars written
256     * @throws IOException if the post-processing fails
257     */
258    protected void afterWrite(final int n) throws IOException {
259    }
260
261    /**
262     * Handle any IOExceptions thrown.
263     * <p>
264     * This method provides a point to implement custom exception
265     * handling. The default behaviour is to re-throw the exception.
266     * @param e The IOException thrown
267     * @throws IOException if an I/O error occurs
268     * @since 2.0
269     */
270    protected void handleIOException(final IOException e) throws IOException {
271        throw e;
272    }
273
274}