All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.unboundid.util.TeeOutputStream Maven / Gradle / Ivy

/*
 * Copyright 2011-2020 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2011-2020 Ping Identity Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * Copyright (C) 2011-2020 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.util;



import java.io.OutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;



/**
 * This class provides an {@code OutputStream} implementation that can cause
 * everything provided to it to be written to multiple output streams (e.g.,
 * to both a file and to standard output, or to both a file and a network
 * socket).  Any number of destination streams (including zero, if desired) may
 * be specified.
 */
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class TeeOutputStream
       extends OutputStream
{
  // The set of target output streams to which any data received will be
  // written.
  @NotNull private final List streams;



  /**
   * Creates a new instance of this output stream that will write any data
   * received to each of the provided target streams.
   *
   * @param  targetStreams  The set of output streams to which any data received
   *                        will be written.  If it is {@code null} or empty,
   *                        then any data received will simply be discarded.
   */
  public TeeOutputStream(@Nullable final OutputStream... targetStreams)
  {
    if (targetStreams == null)
    {
      streams = Collections.emptyList();
    }
    else
    {
      streams = Collections.unmodifiableList(
           new ArrayList<>(Arrays.asList(targetStreams)));
    }
  }



  /**
   * Creates a new instance of this output stream that will write any data
   * received to each of the provided target streams.
   *
   * @param  targetStreams  The set of output streams to which any data received
   *                        will be written.  If it is {@code null} or empty,
   *                        then any data received will simply be discarded.
   */
  public TeeOutputStream(
              @Nullable final Collection targetStreams)
  {
    if (targetStreams == null)
    {
      streams = Collections.emptyList();
    }
    else
    {
      streams = Collections.unmodifiableList(new ArrayList<>(targetStreams));
    }
  }



  /**
   * Writes the provided byte of data to each of the target output streams.
   *
   * @param  b  The byte of data to be written.  Only the lower eight bits
   *            of the provided value will be written.
   *
   * @throws  IOException  If a problem occurs while writing the provided byte
   *                       to any of the target output streams.
   */
  @Override()
  public void write(final int b)
         throws IOException
  {
    for (final OutputStream s : streams)
    {
      s.write(b);
    }
  }



  /**
   * Writes the entire contents of the provided byte array to each of the target
   * output streams.
   *
   * @param  b  The byte array containing the data to be written.
   *
   * @throws  IOException  If a problem occurs while writing the provided data
   *                       to any of the target output streams.
   */
  @Override()
  public void write(@NotNull final byte[] b)
         throws IOException
  {
    for (final OutputStream s : streams)
    {
      s.write(b);
    }
  }



  /**
   * Writes a portion of the contents of the provided byte array to each of the
   * target output streams.
   *
   * @param  b    The byte array containing the data to be written.
   * @param  off  The offset within the array at which the data should start
   *              being written.
   * @param  len  The number of bytes from the array that should be written.
   *
   * @throws  IOException  If a problem occurs while writing the provided data
   *                       to any of the target output streams.
   */
  @Override()
  public void write(@NotNull final byte[] b, final int off, final int len)
         throws IOException
  {
    for (final OutputStream s : streams)
    {
      s.write(b, off, len);
    }
  }



  /**
   * Flushes each of the target output streams to force any buffered content to
   * be written out.
   *
   * @throws  IOException  If a problem occurs while flushing any of the target
   *                       output streams.
   */
  @Override()
  public void flush()
         throws IOException
  {
    for (final OutputStream s : streams)
    {
      s.flush();
    }
  }



  /**
   * Closes each of the target output streams.
   *
   * @throws  IOException  If a problem occurs while closing any of the target
   *                       output streams.  Note that even if an exception is
   *                       thrown, an attempt will be made to close all target
   *                       streams.  If multiple target streams throw an
   *                       exception, then the first exception encountered will
   *                       be thrown.
   */
  @Override()
  public void close()
         throws IOException
  {
    IOException exceptionToThrow = null;

    for (final OutputStream s : streams)
    {
      try
      {
        s.close();
      }
      catch (final IOException ioe)
      {
        Debug.debugException(ioe);
        if (exceptionToThrow == null)
        {
          exceptionToThrow = ioe;
        }
      }
    }

    if (exceptionToThrow != null)
    {
      throw exceptionToThrow;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy