diff options
Diffstat (limited to 'WordPress/src/main/java/org/xmlrpc/android/LoggedInputStream.java')
-rw-r--r-- | WordPress/src/main/java/org/xmlrpc/android/LoggedInputStream.java | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/WordPress/src/main/java/org/xmlrpc/android/LoggedInputStream.java b/WordPress/src/main/java/org/xmlrpc/android/LoggedInputStream.java new file mode 100644 index 000000000..ad16c40a0 --- /dev/null +++ b/WordPress/src/main/java/org/xmlrpc/android/LoggedInputStream.java @@ -0,0 +1,111 @@ +package org.xmlrpc.android; + +import java.io.IOException; +import java.io.InputStream; + + +/** + * A LoggedInputStream adds logging functionality to another input stream. + * <p>Note that calls on a LoggedInputStream are passed "as-is" to the underlying stream.</p> + * + * + * <p>We're using a LoggedInputStream in {@code XMLRPClient.java} to log the XML-RPC response document in case of parser errors.<br /> + * + * There are plenty of other ways to log the response, but a {@code XmlPullParser} wants an InputStream as input parameter, and + * a LoggedInputStream seems the most reliable solution, with the smallest memory footprint.<br /> + * Below are other examples of logging we tried:</p> + * <ul> + * <li>Read the first 1000 characters from the original input stream, then create a new SequenceInputStream with both the characters just read (a new ByteArrayInputStream), + * and the original input stream.</li> + * <li>Read the whole content in a String and log it, then create an StringInputStream over the string, and pass the new stream to the parser.</li> + * </ul> + */ + +public final class LoggedInputStream extends InputStream { + private final InputStream inputStream; + + private final static int MAX_LOG_SIZE = 1000; + private final byte[] loggedString = new byte[MAX_LOG_SIZE]; + private int loggedStringSize = 0; + + public LoggedInputStream(InputStream input) { + this.inputStream = input; + } + + @Override + public int available() throws IOException { + return inputStream.available(); + } + + @Override + public void close() throws IOException { + inputStream.close(); + } + + @Override + public void mark(int readlimit) { + inputStream.mark(readlimit); + } + + @Override + public boolean markSupported() { + return inputStream.markSupported(); + } + + @Override + public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { + int bytesRead = inputStream.read(buffer, byteOffset, byteCount); + if (bytesRead != -1) { + log(buffer, byteOffset, bytesRead); + } + return bytesRead; + } + + @Override + public int read(byte[] buffer) throws IOException { + return this.read(buffer, 0, buffer.length); + } + + @Override + public int read() throws IOException { + int characterRead = inputStream.read(); + if (characterRead != -1) { + log(characterRead); + } + return characterRead; + } + + @Override + public synchronized void reset() throws IOException { + inputStream.reset(); + } + + @Override + public long skip(long byteCount) throws IOException { + return inputStream.skip(byteCount); + } + + private void log(byte[] inputArray, int byteOffset, int byteCount) { + int availableSpace = MAX_LOG_SIZE - loggedStringSize; + if (availableSpace <= 0) { + return; + } + int bytesLength = Math.min(availableSpace, byteCount); + int startingPosition = MAX_LOG_SIZE - availableSpace; + System.arraycopy(inputArray, byteOffset, loggedString, startingPosition, bytesLength); + loggedStringSize += bytesLength; + } + + private void log(int inputChar) { + byte[] logThis = {(byte) inputChar}; + log(logThis, 0, 1); + } + + public String getResponseDocument() { + if (loggedStringSize == 0) { + return ""; + } else { + return new String(loggedString, 0, loggedStringSize); + } + } +} |