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.FilterOutputStream;
020    import java.io.IOException;
021    import java.io.OutputStream;
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 FilterOutputStream
027     * to increase reusability.
028     * <p>
029     * See the protected methods for ways in which a subclass can easily decorate
030     * a stream with custom pre-, post- or error processing functionality.
031     * 
032     * @version $Id: ProxyOutputStream.java 1304052 2012-03-22 20:55:29Z ggregory $
033     */
034    public class ProxyOutputStream extends FilterOutputStream {
035    
036        /**
037         * Constructs a new ProxyOutputStream.
038         * 
039         * @param proxy  the OutputStream to delegate to
040         */
041        public ProxyOutputStream(OutputStream proxy) {
042            super(proxy);
043            // the proxy is stored in a protected superclass variable named 'out'
044        }
045    
046        /**
047         * Invokes the delegate's <code>write(int)</code> method.
048         * @param idx the byte to write
049         * @throws IOException if an I/O error occurs
050         */
051        @Override
052        public void write(int idx) throws IOException {
053            try {
054                beforeWrite(1);
055                out.write(idx);
056                afterWrite(1);
057            } catch (IOException e) {
058                handleIOException(e);
059            }
060        }
061    
062        /**
063         * Invokes the delegate's <code>write(byte[])</code> method.
064         * @param bts the bytes to write
065         * @throws IOException if an I/O error occurs
066         */
067        @Override
068        public void write(byte[] bts) throws IOException {
069            try {
070                int len = bts != null ? bts.length : 0;
071                beforeWrite(len);
072                out.write(bts);
073                afterWrite(len);
074            } catch (IOException e) {
075                handleIOException(e);
076            }
077        }
078    
079        /**
080         * Invokes the delegate's <code>write(byte[])</code> method.
081         * @param bts the bytes to write
082         * @param st The start offset
083         * @param end The number of bytes to write
084         * @throws IOException if an I/O error occurs
085         */
086        @Override
087        public void write(byte[] bts, int st, int end) throws IOException {
088            try {
089                beforeWrite(end);
090                out.write(bts, st, end);
091                afterWrite(end);
092            } catch (IOException e) {
093                handleIOException(e);
094            }
095        }
096    
097        /**
098         * Invokes the delegate's <code>flush()</code> method.
099         * @throws IOException if an I/O error occurs
100         */
101        @Override
102        public void flush() throws IOException {
103            try {
104                out.flush();
105            } catch (IOException e) {
106                handleIOException(e);
107            }
108        }
109    
110        /**
111         * Invokes the delegate's <code>close()</code> method.
112         * @throws IOException if an I/O error occurs
113         */
114        @Override
115        public void close() throws IOException {
116            try {
117                out.close();
118            } catch (IOException e) {
119                handleIOException(e);
120            }
121        }
122    
123        /**
124         * Invoked by the write methods before the call is proxied. The number
125         * of bytes to be written (1 for the {@link #write(int)} method, buffer
126         * length for {@link #write(byte[])}, etc.) is given as an argument.
127         * <p>
128         * Subclasses can override this method to add common pre-processing
129         * functionality without having to override all the write methods.
130         * The default implementation does nothing.
131         *
132         * @since 2.0
133         * @param n number of bytes to be written
134         * @throws IOException if the pre-processing fails
135         */
136        protected void beforeWrite(int n) throws IOException {
137        }
138    
139        /**
140         * Invoked by the write methods after the proxied call has returned
141         * successfully. The number of bytes written (1 for the
142         * {@link #write(int)} method, buffer length for {@link #write(byte[])},
143         * etc.) is given as an argument.
144         * <p>
145         * Subclasses can override this method to add common post-processing
146         * functionality without having to override all the write methods.
147         * The default implementation does nothing.
148         *
149         * @since 2.0
150         * @param n number of bytes written
151         * @throws IOException if the post-processing fails
152         */
153        protected void afterWrite(int n) throws IOException {
154        }
155    
156        /**
157         * Handle any IOExceptions thrown.
158         * <p>
159         * This method provides a point to implement custom exception
160         * handling. The default behaviour is to re-throw the exception.
161         * @param e The IOException thrown
162         * @throws IOException if an I/O error occurs
163         * @since 2.0
164         */
165        protected void handleIOException(IOException e) throws IOException {
166            throw e;
167        }
168    
169    }