FilterCollectionWriter.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.io.output;

  18. import java.io.FilterWriter;
  19. import java.io.IOException;
  20. import java.io.Writer;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Objects;
  25. import java.util.stream.Stream;

  26. import org.apache.commons.io.IOExceptionList;
  27. import org.apache.commons.io.IOIndexedException;
  28. import org.apache.commons.io.function.IOConsumer;

  29. /**
  30.  * Abstract class for writing filtered character streams to a {@link Collection} of writers. This is in contrast to
  31.  * {@link FilterWriter} which is backed by a single {@link Writer}.
  32.  * <p>
  33.  * This abstract class provides default methods that pass all requests to the contained writers. Subclasses should
  34.  * likely override some of these methods.
  35.  * </p>
  36.  * <p>
  37.  * The class {@link Writer} defines method signatures with {@code throws} {@link IOException}, which in this class are
  38.  * actually {@link IOExceptionList} containing a list of {@link IOIndexedException}.
  39.  * </p>
  40.  *
  41.  * @since 2.7
  42.  */
  43. public class FilterCollectionWriter extends Writer {

  44.     /**
  45.      * Empty and immutable collection of writers.
  46.      */
  47.     protected final Collection<Writer> EMPTY_WRITERS = Collections.emptyList();

  48.     /**
  49.      * The underlying writers.
  50.      */
  51.     protected final Collection<Writer> writers;

  52.     /**
  53.      * Constructs a new filtered collection writer.
  54.      *
  55.      * @param writers Writers to provide the underlying targets.
  56.      */
  57.     protected FilterCollectionWriter(final Collection<Writer> writers) {
  58.         this.writers = writers == null ? EMPTY_WRITERS : writers;
  59.     }

  60.     /**
  61.      * Constructs a new filtered collection writer.
  62.      *
  63.      * @param writers Writers to provide the underlying targets.
  64.      */
  65.     protected FilterCollectionWriter(final Writer... writers) {
  66.         this.writers = writers == null ? EMPTY_WRITERS : Arrays.asList(writers);
  67.     }

  68.     @Override
  69.     public Writer append(final char c) throws IOException {
  70.         return forAllWriters(w -> w.append(c));
  71.     }

  72.     @Override
  73.     public Writer append(final CharSequence csq) throws IOException {
  74.         return forAllWriters(w -> w.append(csq));
  75.     }

  76.     @Override
  77.     public Writer append(final CharSequence csq, final int start, final int end) throws IOException {
  78.         return forAllWriters(w -> w.append(csq, start, end));
  79.     }

  80.     @SuppressWarnings("resource") // no allocation
  81.     @Override
  82.     public void close() throws IOException {
  83.         forAllWriters(Writer::close);
  84.     }

  85.     /**
  86.      * Flushes the stream.
  87.      *
  88.      * @throws IOException If an I/O error occurs
  89.      */
  90.     @SuppressWarnings("resource") // no allocation
  91.     @Override
  92.     public void flush() throws IOException {
  93.         forAllWriters(Writer::flush);
  94.     }

  95.     private FilterCollectionWriter forAllWriters(final IOConsumer<Writer> action) throws IOExceptionList {
  96.         IOConsumer.forAll(action, writers());
  97.         return this;
  98.     }

  99.     @SuppressWarnings("resource") // no allocation
  100.     @Override
  101.     public void write(final char[] cbuf) throws IOException {
  102.         forAllWriters(w -> w.write(cbuf));
  103.     }

  104.     /**
  105.      * Writes a portion of an array of characters.
  106.      *
  107.      * @param cbuf Buffer of characters to be written
  108.      * @param off  Offset from which to start reading characters
  109.      * @param len  Number of characters to be written
  110.      * @throws IOException If an I/O error occurs
  111.      */
  112.     @SuppressWarnings("resource") // no allocation
  113.     @Override
  114.     public void write(final char[] cbuf, final int off, final int len) throws IOException {
  115.         forAllWriters(w -> w.write(cbuf, off, len));
  116.     }

  117.     /**
  118.      * Writes a single character.
  119.      *
  120.      * @throws IOException If an I/O error occurs
  121.      */
  122.     @SuppressWarnings("resource") // no allocation
  123.     @Override
  124.     public void write(final int c) throws IOException {
  125.         forAllWriters(w -> w.write(c));
  126.     }

  127.     @SuppressWarnings("resource") // no allocation
  128.     @Override
  129.     public void write(final String str) throws IOException {
  130.         forAllWriters(w -> w.write(str));
  131.     }

  132.     /**
  133.      * Writes a portion of a string.
  134.      *
  135.      * @param str String to be written
  136.      * @param off Offset from which to start reading characters
  137.      * @param len Number of characters to be written
  138.      * @throws IOException If an I/O error occurs
  139.      */
  140.     @SuppressWarnings("resource") // no allocation
  141.     @Override
  142.     public void write(final String str, final int off, final int len) throws IOException {
  143.         forAllWriters(w -> w.write(str, off, len));
  144.     }

  145.     private Stream<Writer> writers() {
  146.         return writers.stream().filter(Objects::nonNull);
  147.     }

  148. }