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 * @version $Id: ProxyWriter.java 1415850 2012-11-30 20:51:39Z ggregory $
032 */
033public class ProxyWriter extends FilterWriter {
034
035    /**
036     * Constructs a new ProxyWriter.
037     * 
038     * @param proxy  the Writer to delegate to
039     */
040    public ProxyWriter(final Writer proxy) {
041        super(proxy);
042        // the proxy is stored in a protected superclass variable named 'out'
043    }
044
045    /**
046     * Invokes the delegate's <code>append(char)</code> method.
047     * @param c The character to write
048     * @return this writer
049     * @throws IOException if an I/O error occurs
050     * @since 2.0
051     */
052    @Override
053    public Writer append(final char c) throws IOException {
054        try {
055            beforeWrite(1);
056            out.append(c);
057            afterWrite(1);
058        } catch (final IOException e) {
059            handleIOException(e);
060        }
061        return this;
062    }
063
064    /**
065     * Invokes the delegate's <code>append(CharSequence, int, int)</code> method.
066     * @param csq The character sequence to write
067     * @param start The index of the first character to write
068     * @param end  The index of the first character to write (exclusive)
069     * @return this writer
070     * @throws IOException if an I/O error occurs
071     * @since 2.0
072     */
073    @Override
074    public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
075        try {
076            beforeWrite(end - start);
077            out.append(csq, start, end);
078            afterWrite(end - start);
079        } catch (final IOException e) {
080            handleIOException(e);
081        }
082        return this;
083    }
084
085    /**
086     * Invokes the delegate's <code>append(CharSequence)</code> method.
087     * @param csq The character sequence to write
088     * @return this writer
089     * @throws IOException if an I/O error occurs
090     * @since 2.0
091     */
092    @Override
093    public Writer append(final CharSequence csq) throws IOException {
094        try {
095            int len = 0;
096            if (csq != null) {
097                len = csq.length();
098            }
099
100            beforeWrite(len);
101            out.append(csq);
102            afterWrite(len);
103        } catch (final IOException e) {
104            handleIOException(e);
105        }
106        return this;
107    }
108
109    /**
110     * Invokes the delegate's <code>write(int)</code> method.
111     * @param idx the character to write
112     * @throws IOException if an I/O error occurs
113     */
114    @Override
115    public void write(final int idx) throws IOException {
116        try {
117            beforeWrite(1);
118            out.write(idx);
119            afterWrite(1);
120        } catch (final IOException e) {
121            handleIOException(e);
122        }
123    }
124
125    /**
126     * Invokes the delegate's <code>write(char[])</code> method.
127     * @param chr the characters to write
128     * @throws IOException if an I/O error occurs
129     */
130    @Override
131    public void write(final char[] chr) throws IOException {
132        try {
133            int len = 0;
134            if (chr != null) {
135                len = chr.length;
136            }
137
138            beforeWrite(len);
139            out.write(chr);
140            afterWrite(len);
141        } catch (final IOException e) {
142            handleIOException(e);
143        }
144    }
145
146    /**
147     * Invokes the delegate's <code>write(char[], int, int)</code> method.
148     * @param chr the characters to write
149     * @param st The start offset
150     * @param len The number of characters to write
151     * @throws IOException if an I/O error occurs
152     */
153    @Override
154    public void write(final char[] chr, final int st, final int len) throws IOException {
155        try {
156            beforeWrite(len);
157            out.write(chr, st, len);
158            afterWrite(len);
159        } catch (final IOException e) {
160            handleIOException(e);
161        }
162    }
163
164    /**
165     * Invokes the delegate's <code>write(String)</code> method.
166     * @param str the string to write
167     * @throws IOException if an I/O error occurs
168     */
169    @Override
170    public void write(final String str) throws IOException {
171        try {
172            int len = 0;
173            if (str != null) {
174                len = str.length();
175            }
176
177            beforeWrite(len);
178            out.write(str);
179            afterWrite(len);
180        } catch (final IOException e) {
181            handleIOException(e);
182        }
183    }
184
185    /**
186     * Invokes the delegate's <code>write(String)</code> method.
187     * @param str the string to write
188     * @param st The start offset
189     * @param len The number of characters to write
190     * @throws IOException if an I/O error occurs
191     */
192    @Override
193    public void write(final String str, final int st, final int len) throws IOException {
194        try {
195            beforeWrite(len);
196            out.write(str, st, len);
197            afterWrite(len);
198        } catch (final IOException e) {
199            handleIOException(e);
200        }
201    }
202
203    /**
204     * Invokes the delegate's <code>flush()</code> method.
205     * @throws IOException if an I/O error occurs
206     */
207    @Override
208    public void flush() throws IOException {
209        try {
210            out.flush();
211        } catch (final IOException e) {
212            handleIOException(e);
213        }
214    }
215
216    /**
217     * Invokes the delegate's <code>close()</code> method.
218     * @throws IOException if an I/O error occurs
219     */
220    @Override
221    public void close() throws IOException {
222        try {
223            out.close();
224        } catch (final IOException e) {
225            handleIOException(e);
226        }
227    }
228
229    /**
230     * Invoked by the write methods before the call is proxied. The number
231     * of chars to be written (1 for the {@link #write(int)} method, buffer
232     * length for {@link #write(char[])}, etc.) is given as an argument.
233     * <p>
234     * Subclasses can override this method to add common pre-processing
235     * functionality without having to override all the write methods.
236     * The default implementation does nothing.
237     *
238     * @since 2.0
239     * @param n number of chars to be written
240     * @throws IOException if the pre-processing fails
241     */
242    protected void beforeWrite(final int n) throws IOException {
243    }
244
245    /**
246     * Invoked by the write methods after the proxied call has returned
247     * successfully. The number of chars written (1 for the
248     * {@link #write(int)} method, buffer length for {@link #write(char[])},
249     * etc.) is given as an argument.
250     * <p>
251     * Subclasses can override this method to add common post-processing
252     * functionality without having to override all the write methods.
253     * The default implementation does nothing.
254     *
255     * @since 2.0
256     * @param n number of chars written
257     * @throws IOException if the post-processing fails
258     */
259    protected void afterWrite(final int n) throws IOException {
260    }
261
262    /**
263     * Handle any IOExceptions thrown.
264     * <p>
265     * This method provides a point to implement custom exception
266     * handling. The default behaviour is to re-throw the exception.
267     * @param e The IOException thrown
268     * @throws IOException if an I/O error occurs
269     * @since 2.0
270     */
271    protected void handleIOException(final IOException e) throws IOException {
272        throw e;
273    }
274
275}