001/*
002 * The MIT License
003 * Copyright (c) 2012 Microsoft Corporation
004 *
005 * Permission is hereby granted, free of charge, to any person obtaining a copy
006 * of this software and associated documentation files (the "Software"), to deal
007 * in the Software without restriction, including without limitation the rights
008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
009 * copies of the Software, and to permit persons to whom the Software is
010 * furnished to do so, subject to the following conditions:
011 *
012 * The above copyright notice and this permission notice shall be included in
013 * all copies or substantial portions of the Software.
014 *
015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
021 * THE SOFTWARE.
022 */
023
024package microsoft.exchange.webservices.data.misc;
025
026import microsoft.exchange.webservices.data.core.ExchangeService;
027import microsoft.exchange.webservices.data.core.request.HangingServiceRequestBase;
028import microsoft.exchange.webservices.data.core.enumeration.misc.TraceFlags;
029import org.apache.commons.logging.Log;
030import org.apache.commons.logging.LogFactory;
031
032import javax.xml.stream.XMLStreamException;
033
034import java.io.ByteArrayOutputStream;
035import java.io.IOException;
036import java.io.InputStream;
037
038/**
039 * A stream that traces everything it returns from its Read() call.
040 * That trace may be retrieved at the end of the stream.
041 */
042public class HangingTraceStream extends InputStream {
043
044  private static final Log LOG = LogFactory.getLog(HangingTraceStream.class);
045
046  private final InputStream underlyingStream;
047  private final ExchangeService service;
048  private ByteArrayOutputStream responseCopy;
049
050  /**
051   * Initializes a new instance of the HangingTraceStream class.
052   *
053   * @param stream  The stream.
054   * @param service the service.
055   */
056  public HangingTraceStream(final InputStream stream, final ExchangeService service) {
057    this.underlyingStream = stream;
058    this.service = service;
059  }
060
061  /**
062   * Gets a value indicating whether the current stream supports reading.
063   *
064   * @return true
065   */
066  public boolean getCanRead() {
067    return true;
068  }
069
070  /**
071   * Gets a value indicating whether the current stream supports seeking.
072   *
073   * @return false
074   */
075  public boolean getCanSeek() {
076    return false;
077  }
078
079  /**
080   * Gets a value indicating whether the current stream supports writing.
081   *
082   * @return false
083   */
084  public boolean getCanWrite() {
085    return false;
086  }
087
088  /**
089   * When overridden in a derived class, clears all buffers
090   * for this stream and causes any buffered data to be
091   *  written to the underlying device.
092   *@exception An I/O error occurs.
093   */
094        /*
095         * @Override public void close() { // no-op }
096         */
097
098  /**
099   * When overridden in a derived class, reads a sequence of
100   * bytes from the current stream and advances the
101   * position within the stream by the number of bytes read.
102   *
103   * @param buffer An array of bytes. When this method returns, the buffer
104   *               contains the specified byte array with the values between
105   * @param offset The zero-based byte offset in at which to
106   *               begin storing the data read from the current stream.
107   * @param count  The maximum number of bytes to be read from the current stream.
108   * @return The total number of bytes read into the buffer.
109   * This can be less than the number of bytes requested if that
110   * many bytes are not currently available, or zero (0)
111   * if the end of the stream has been reached.
112   * @throws IOException The sum of offset and count is larger than the buffer length.
113   */
114  @Override
115  public int read(byte[] buffer, int offset, int count) throws IOException {
116    count = HangingServiceRequestBase.BUFFER_SIZE;
117    final int retVal = underlyingStream.read(buffer, offset, count);
118
119    if (HangingServiceRequestBase.isLogAllWireBytes()) {
120      final String readString = new String(buffer, offset, count, "UTF-8");
121      final String logMessage = String.format(
122          "HangingTraceStream ID [%d] returned %d bytes. Bytes returned: [%s]",
123          hashCode(), retVal, readString);
124
125      try {
126        service.traceMessage(TraceFlags.DebugMessage, logMessage);
127      } catch (final XMLStreamException e) {
128        LOG.error(e);
129      }
130    }
131
132    if (responseCopy != null) {
133      responseCopy.write(buffer, offset, retVal);
134    }
135
136    return retVal;
137  }
138
139  /**
140   * Sets the response copy.
141   *
142   * @param responseCopy a copy of response
143   */
144  public void setResponseCopy(final ByteArrayOutputStream responseCopy) {
145    this.responseCopy = responseCopy;
146  }
147
148  @Override
149  public int read() throws IOException {
150    return 0;
151  }
152
153}
154