    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.IOException;
    020import java.io.Writer;
    021import java.util.Objects;
    022
    023/**
    024 * Writer implementation that writes the data to an {@link Appendable}
    025 * Object.
    026 * <p>
    027 * For example, can be used with a {@link java.lang.StringBuilder}
    028 * or {@link java.lang.StringBuffer}.
    029 * </p>
    030 *
    031 * @since 2.7
    032 * @see java.lang.Appendable
    033 *
    034 * @param <T> The type of the {@link Appendable} wrapped by this AppendableWriter.
    035 */
    036public class AppendableWriter <T extends Appendable> extends Writer {
    037
    038    private final T appendable;
    039
    040    /**
    041     * Constructs a new instance with the specified appendable.
    042     *
    043     * @param appendable the appendable to write to
    044     */
    045    public AppendableWriter(final T appendable) {
    046        this.appendable = appendable;
    047    }
    048
    049    /**
    050     * Appends the specified character to the underlying appendable.
    051     *
    052     * @param c the character to append
    053     * @return this writer
    054     * @throws IOException upon error
    055     */
    056    @Override
    057    public Writer append(final char c) throws IOException {
    058        appendable.append(c);
    059        return this;
    060    }
    061
    062    /**
    063     * Appends the specified character sequence to the underlying appendable.
    064     *
    065     * @param csq the character sequence to append
    066     * @return this writer
    067     * @throws IOException upon error
    068     */
    069    @Override
    070    public Writer append(final CharSequence csq) throws IOException {
    071        appendable.append(csq);
    072        return this;
    073    }
    074
    075    /**
    076     * Appends a subsequence of the specified character sequence to the underlying appendable.
    077     *
    078     * @param csq the character sequence from which a subsequence will be appended
    079     * @param start the index of the first character in the subsequence
    080     * @param end the index of the character following the last character in the subsequence
    081     * @return this writer
    082     * @throws IOException upon error
    083     */
    084    @Override
    085    public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
    086        appendable.append(csq, start, end);
    087        return this;
    088    }
    089
    090    /**
    091     * Closes the stream. This implementation does nothing.
    092     *
    093     * @throws IOException upon error
    094     */
    095    @Override
    096    public void close() throws IOException {
    097        // noop
    098    }
    099
    100    /**
    101     * Flushes the stream. This implementation does nothing.
    102     *
    103     * @throws IOException upon error
    104     */
    105    @Override
    106    public void flush() throws IOException {
    107        // noop
    108    }
    109
    110    /**
    111     * Return the target appendable.
    112     *
    113     * @return the target appendable
    114     */
    115    public T getAppendable() {
    116        return appendable;
    117    }
    118
    119    /**
    120     * Writes a portion of an array of characters to the underlying appendable.
    121     *
    122     * @param cbuf an array with the characters to write
    123     * @param off offset from which to start writing characters
    124     * @param len number of characters to write
    125     * @throws IOException upon error
    126     */
    127    @Override
    128    public void write(final char[] cbuf, final int off, final int len) throws IOException {
    129        Objects.requireNonNull(cbuf, "Character array is missing");
    130        if (len < 0 || (off + len) > cbuf.length) {
    131            throw new IndexOutOfBoundsException("Array Size=" + cbuf.length +
    132                    ", offset=" + off + ", length=" + len);
    133        }
    134        for (int i = 0; i < len; i++) {
    135            appendable.append(cbuf[off + i]);
    136        }
    137    }
    138
    139    /**
    140     * Writes a character to the underlying appendable.
    141     *
    142     * @param c the character to write
    143     * @throws IOException upon error
    144     */
    145    @Override
    146    public void write(final int c) throws IOException {
    147        appendable.append((char)c);
    148    }
    149
    150    /**
    151     * Writes a portion of a String to the underlying appendable.
    152     *
    153     * @param str a string
    154     * @param off offset from which to start writing characters
    155     * @param len number of characters to write
    156     * @throws IOException upon error
    157     */
    158    @Override
    159    public void write(final String str, final int off, final int len) throws IOException {
    160        // appendable.append will add "null" for a null String; add an explicit null check
    161        Objects.requireNonNull(str, "String is missing");
    162        appendable.append(str, off, off + len);
    163    }
    164
    165}