001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2015 ForgeRock AS.
016 */
017package org.opends.server.types;
018
019import org.forgerock.opendj.ldap.ByteString;
020import org.forgerock.opendj.ldap.ByteStringBuilder;
021
022import java.io.InputStream;
023import java.io.IOException;
024
025/**
026 * A wrapper InputStream that will record all reads from an underlying
027 * InputStream. The recorded bytes will append to any previous
028 * recorded bytes until the clear method is called.
029 */
030public class RecordingInputStream extends InputStream
031{
032  private boolean enableRecording;
033  private InputStream parentStream;
034  private ByteStringBuilder buffer;
035
036  /**
037   * Constructs a new RecordingInputStream that will record all reads
038   * from the given input stream.
039   *
040   * @param parentStream The input stream to record.
041   */
042  public RecordingInputStream(InputStream parentStream)
043  {
044    this.enableRecording = false;
045    this.parentStream = parentStream;
046    this.buffer = new ByteStringBuilder(32);
047  }
048
049  /** {@inheritDoc} */
050  @Override
051  public int read() throws IOException {
052    int readByte = parentStream.read();
053    if(enableRecording)
054    {
055      buffer.appendByte(readByte);
056    }
057    return readByte;
058  }
059
060  /** {@inheritDoc} */
061  @Override
062  public int read(byte[] bytes) throws IOException {
063    int bytesRead = parentStream.read(bytes);
064    if(enableRecording)
065    {
066      buffer.appendBytes(bytes, 0, bytesRead);
067    }
068    return bytesRead;
069  }
070
071  /** {@inheritDoc} */
072  @Override
073  public int read(byte[] bytes, int i, int i1) throws IOException {
074    int bytesRead = parentStream.read(bytes, i, i1);
075    if(enableRecording)
076    {
077      buffer.appendBytes(bytes, i, bytesRead);
078    }
079    return bytesRead;
080  }
081
082  /** {@inheritDoc} */
083  @Override
084  public long skip(long l) throws IOException {
085    return parentStream.skip(l);
086  }
087
088  /** {@inheritDoc} */
089  @Override
090  public int available() throws IOException {
091    return parentStream.available();
092  }
093
094  /** {@inheritDoc} */
095  @Override
096  public void close() throws IOException {
097    parentStream.close();
098  }
099
100  /** {@inheritDoc} */
101  @Override
102  public void mark(int i) {
103    parentStream.mark(i);
104  }
105
106  /** {@inheritDoc} */
107  @Override
108  public void reset() throws IOException {
109    parentStream.reset();
110  }
111
112  /** {@inheritDoc} */
113  @Override
114  public boolean markSupported() {
115    return parentStream.markSupported();
116  }
117
118  /**
119   * Retrieve the bytes read from this input stream since the last
120   * clear.
121   *
122   * @return the bytes read from this input stream since the last
123   *         clear.
124   */
125  public ByteString getRecordedBytes() {
126    return buffer.toByteString();
127  }
128
129  /**
130   * Clear the bytes currently recorded by this input stream.
131   */
132  public void clearRecordedBytes() {
133    buffer.clear();
134  }
135
136  /**
137   * Retrieves whether recording is enabled.
138   *
139   * @return whether recording is enabled.
140   */
141  public boolean isRecordingEnabled()
142  {
143    return enableRecording;
144  }
145
146  /**
147   * Set whether if this input stream is recording all reads or not.
148   *
149   * @param enabled <code>true</code> to recording all reads or
150   *                <code>false</code> otherwise.
151   */
152  public void setRecordingEnabled(boolean enabled)
153  {
154    this.enableRecording = enabled;
155  }
156}