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