/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2013, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core.encoder; import static ch.qos.logback.core.CoreConstants.BYTES_PER_INT; import static ch.qos.logback.core.encoder.ObjectStreamEncoder.START_PEBBLE; import static ch.qos.logback.core.encoder.ObjectStreamEncoder.STOP_PEBBLE; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List; /** * Restitute the contents of an input stream as java objects. * * @author Ceki Gülcü * * @param <E> type of log event object */ public class EventObjectInputStream<E> extends InputStream { NonClosableInputStream ncis; List<E> buffer = new ArrayList<E>(); int index = 0; EventObjectInputStream(InputStream is) throws IOException { this.ncis = new NonClosableInputStream(is); } @Override public int read() throws IOException { throw new UnsupportedOperationException( "Only the readEvent method is supported."); } /** * Returns the number of bytes available */ public int available() throws IOException { return ncis.available(); } public E readEvent() throws IOException { E event = getFromBuffer(); if (event != null) { return event; } internalReset(); int count = readHeader(); if(count == -1) { return null; } readPayload(count); readFooter(count); return getFromBuffer(); } private void internalReset() { index = 0; buffer.clear(); } E getFromBuffer() { if (index >= buffer.size()) { return null; } return buffer.get(this.index++); } int readHeader() throws IOException { byte[] headerBA = new byte[4 * BYTES_PER_INT]; //System.out.println("available="+ncis.available()); int bytesRead = ncis.read(headerBA); if(bytesRead == -1) { return -1; } //System.out.println("**bytesRead="+bytesRead); //System.out.println(ByteArrayUtil.toHexString(headerBA)); int offset = 0; int startPebble = ByteArrayUtil.readInt(headerBA, offset); if (startPebble != START_PEBBLE) { throw new IllegalStateException( "Does not look like data created by ObjectStreamEncoder"); } offset += BYTES_PER_INT; int count = ByteArrayUtil.readInt(headerBA, offset); offset += BYTES_PER_INT; //int endPointer = ByteArrayUtil.readInt(headerBA, offset); offset += BYTES_PER_INT; int checksum = ByteArrayUtil.readInt(headerBA, offset); if (checksum != (START_PEBBLE ^ count)) { throw new IllegalStateException("Invalid checksum"); } return count; } @SuppressWarnings("unchecked") E readEvents(ObjectInputStream ois) throws IOException { E e = null; try { e = (E) ois.readObject(); buffer.add(e); } catch (ClassNotFoundException e1) { // FIXME Auto-generated catch block e1.printStackTrace(); } return e; } void readFooter(int count) throws IOException { byte[] headerBA = new byte[2 * BYTES_PER_INT]; if (ncis.read(headerBA) == -1) { throw new IllegalStateException( "Looks like a corrupt stream"); } int offset = 0; int stopPebble = ByteArrayUtil.readInt(headerBA, offset); if (stopPebble != STOP_PEBBLE) { throw new IllegalStateException( "Looks like a corrupt stream"); } offset += BYTES_PER_INT; int checksum = ByteArrayUtil.readInt(headerBA, offset); if (checksum != (STOP_PEBBLE ^ count)) { throw new IllegalStateException("Invalid checksum"); } } void readPayload(int count) throws IOException { List<E> eventList = new ArrayList<E>(count); ObjectInputStream ois = new ObjectInputStream(ncis); for (int i = 0; i < count; i++) { E e = (E) readEvents(ois); eventList.add(e); } ois.close(); } public void close() throws IOException { ncis.realClose(); } }