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     */
017    package org.apache.commons.io.output;
018    
019    import java.io.FilterWriter;
020    import java.io.IOException;
021    import 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 1304052 2012-03-22 20:55:29Z ggregory $
032     */
033    public class ProxyWriter extends FilterWriter {
034    
035        /**
036         * Constructs a new ProxyWriter.
037         * 
038         * @param proxy  the Writer to delegate to
039         */
040        public ProxyWriter(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(char c) throws IOException {
054            try {
055                beforeWrite(1);
056                out.append(c);
057                afterWrite(1);
058            } catch (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(CharSequence csq, int start, int end) throws IOException {
075            try {
076                beforeWrite(end - start);
077                out.append(csq, start, end);
078                afterWrite(end - start);
079            } catch (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(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 (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(int idx) throws IOException {
116            try {
117                beforeWrite(1);
118                out.write(idx);
119                afterWrite(1);
120            } catch (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(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 (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(char[] chr, int st, int len) throws IOException {
155            try {
156                beforeWrite(len);
157                out.write(chr, st, len);
158                afterWrite(len);
159            } catch (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(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 (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(String str, int st, int len) throws IOException {
194            try {
195                beforeWrite(len);
196                out.write(str, st, len);
197                afterWrite(len);
198            } catch (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 (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 (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(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(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(IOException e) throws IOException {
272            throw e;
273        }
274    
275    }