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