From 1653f1d4d769b17312e87ee96523e2c2293b6bd8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Pereira?= <jop@di.uminho.pt>
Date: Sun, 12 Jul 2015 19:12:01 +0100
Subject: [PATCH 2/3] Add ObjectReader and use it from SocketReceiver and
 ServerSocketReceiver.

This provides a mechanism similar to ObjectWriter in socket appenders
and uses in all receivers to allow the serialization mechanism to be
overriden.
---
 .../ch/qos/logback/classic/net/ObjectReader.java   | 33 +++++++++++++++
 .../logback/classic/net/ObjectReaderFactory.java   | 36 +++++++++++++++++
 .../classic/net/SerializationObjectReader.java     | 47 ++++++++++++++++++++++
 .../ch/qos/logback/classic/net/SocketReceiver.java | 11 ++++-
 .../net/server/RemoteAppenderServerListener.java   |  8 +++-
 .../net/server/RemoteAppenderStreamClient.java     | 27 ++++++++-----
 .../classic/net/server/ServerSocketReceiver.java   |  8 +++-
 .../server/InstrumentedServerSocketReceiver.java   |  3 +-
 .../net/server/RemoteAppenderStreamClientTest.java |  3 +-
 9 files changed, 158 insertions(+), 18 deletions(-)
 create mode 100644 logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReader.java
 create mode 100644 logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReaderFactory.java
 create mode 100644 logback-classic/src/main/java/ch/qos/logback/classic/net/SerializationObjectReader.java

diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReader.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReader.java
new file mode 100644
index 0000000..f9c108c
--- /dev/null
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReader.java
@@ -0,0 +1,33 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2015, 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.classic.net;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Reads objects from an input. This class is the reverse of
+ * {@link ch.qos.logback.core.net.ObjectWriter}.
+ */
+public interface ObjectReader extends Closeable {
+
+  /**
+   * Reads an object from an input.
+   *
+   * @returns the {@link Object} read
+   * @throws IOException in case input/output fails, details are defined by the implementation
+   * @throws ClassNotFoundException in case an unknown class is read 
+   */
+  Object read() throws IOException, ClassNotFoundException;
+}
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReaderFactory.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReaderFactory.java
new file mode 100644
index 0000000..1348909
--- /dev/null
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/ObjectReaderFactory.java
@@ -0,0 +1,36 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2015, 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.classic.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+
+/**
+ * Factory for {@link ch.qos.logback.classic.net.ObjectReader} instances. This
+ * class is the reverse of {@link ch.qos.logback.core.net.ObjectWriterFactory}.
+ */
+public class ObjectReaderFactory {
+
+  /**
+   * Creates a new {@link ch.qos.logback.classic.net.SerializationObjectReader} instance.
+   *
+   * @param inputStream the underlying {@link java.io.InputStream} to write from
+   * @return a new {@link ch.qos.logback.classic.net.SerializationObjectReader} instance
+   * @throws IOException if an I/O error occurs while writing stream header
+   */
+  public ObjectReader newObjectReader(InputStream inputStream) throws IOException {
+    return new SerializationObjectReader(new ObjectInputStream(inputStream));
+  }
+}
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/SerializationObjectReader.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/SerializationObjectReader.java
new file mode 100644
index 0000000..b98ddba
--- /dev/null
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/SerializationObjectReader.java
@@ -0,0 +1,47 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2015, 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.classic.net;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * Reads objects from a stream using Java serialization. This class is the
+ * reverse of {@link ch.qos.logback.core.net.AutoFlushingObjectWriter}.
+ */
+public class SerializationObjectReader implements ObjectReader {
+
+  private final ObjectInputStream objectInputStream;
+
+  /**
+   * Creates a new instance for the given {@link java.io.ObjectInputStream}.
+   *
+   * @param objectInputStream the stream to read from
+   */
+  public SerializationObjectReader(ObjectInputStream objectInputStream) {
+    this.objectInputStream = objectInputStream;
+  }
+
+  @Override
+  public Object read() throws IOException, ClassNotFoundException {
+	  return objectInputStream.readObject();
+  }
+  
+  /**
+   * {@inheritDoc}
+   */
+  public void close() throws IOException {
+	  objectInputStream.close();
+  }
+}
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/SocketReceiver.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/SocketReceiver.java
index 223e584..51dfc55 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/SocketReceiver.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/SocketReceiver.java
@@ -54,6 +54,7 @@ public class SocketReceiver extends ReceiverBase
   private String receiverId;
   private volatile Socket socket;
   private Future<Socket> connectorTask;
+  private ObjectReaderFactory objectReaderFactory;
 
   /**
    * {@inheritDoc}
@@ -86,6 +87,8 @@ public class SocketReceiver extends ReceiverBase
     }
 
     if (errorCount == 0) {
+      objectReaderFactory = createObjectReaderFactory();
+
       receiverId = "receiver " + remoteHost + ":" + port + ": ";
     }
 
@@ -160,11 +163,11 @@ public class SocketReceiver extends ReceiverBase
   private void dispatchEvents(LoggerContext lc) {
     try {
       socket.setSoTimeout(acceptConnectionTimeout);
-      ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
+      ObjectReader ois = objectReaderFactory.newObjectReader(socket.getInputStream());
       socket.setSoTimeout(0);
       addInfo(receiverId + "connection established");
       while (true) {
-        ILoggingEvent event = (ILoggingEvent) ois.readObject();
+        ILoggingEvent event = (ILoggingEvent) ois.read();
         Logger remoteLogger = lc.getLogger(event.getLoggerName());
         if (remoteLogger.isEnabledFor(event.getLevel())) {
           remoteLogger.callAppenders(event);
@@ -205,6 +208,10 @@ public class SocketReceiver extends ReceiverBase
   protected SocketFactory getSocketFactory() {
     return SocketFactory.getDefault();
   }
+  
+  protected ObjectReaderFactory createObjectReaderFactory() {
+	  return new ObjectReaderFactory();
+  }
 
   public void setRemoteHost(String remoteHost) {
     this.remoteHost = remoteHost;
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderServerListener.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderServerListener.java
index 0235502..25bfeb5 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderServerListener.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderServerListener.java
@@ -17,6 +17,7 @@ import java.io.IOException;
 import java.net.ServerSocket;
 import java.net.Socket;
 
+import ch.qos.logback.classic.net.ObjectReaderFactory;
 import ch.qos.logback.core.net.server.ServerListener;
 import ch.qos.logback.core.net.server.ServerSocketListener;
 
@@ -28,13 +29,16 @@ import ch.qos.logback.core.net.server.ServerSocketListener;
 class RemoteAppenderServerListener
     extends ServerSocketListener<RemoteAppenderClient>  {
 
+  private ObjectReaderFactory objectReaderFactory;
+	
   /**
    * Constructs a new listener.
    * @param serverSocket the {@link ServerSocket} from which to accept
    *    new client connections
    */
-  public RemoteAppenderServerListener(ServerSocket serverSocket) {
+  public RemoteAppenderServerListener(ServerSocket serverSocket, ObjectReaderFactory objectReaderFactory) {
     super(serverSocket);
+    this.objectReaderFactory = objectReaderFactory;
   }
 
   /**
@@ -43,7 +47,7 @@ class RemoteAppenderServerListener
   @Override
   protected RemoteAppenderClient createClient(String id, Socket socket) 
       throws IOException {
-    return new RemoteAppenderStreamClient(id, socket);
+    return new RemoteAppenderStreamClient(id, socket, objectReaderFactory);
   }
 
 }
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClient.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClient.java
index 07f268f..a4c2f06 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClient.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClient.java
@@ -16,11 +16,12 @@ package ch.qos.logback.classic.net.server;
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.ObjectInputStream;
 import java.net.Socket;
 
 import ch.qos.logback.classic.Logger;
 import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.net.ObjectReader;
+import ch.qos.logback.classic.net.ObjectReaderFactory;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.core.util.CloseUtil;
 
@@ -39,15 +40,18 @@ class RemoteAppenderStreamClient implements RemoteAppenderClient {
   private LoggerContext lc;
   private Logger logger;
   
+  private ObjectReaderFactory objectReaderFactory;
+  
   /**
    * Constructs a new client.  
    * @param id a display name for the client
    * @param inputStream input stream from which events will be read
    */
-  public RemoteAppenderStreamClient(String id, Socket socket) {
+  public RemoteAppenderStreamClient(String id, Socket socket, ObjectReaderFactory objectReaderFactory) {
     this.id = id;
     this.socket = socket;
     this.inputStream = null;
+    this.objectReaderFactory = objectReaderFactory;
   }
 
   /**
@@ -59,10 +63,11 @@ class RemoteAppenderStreamClient implements RemoteAppenderClient {
    * @param id a display name for the client
    * @param inputStream input stream from which events will be read
    */
-  public RemoteAppenderStreamClient(String id, InputStream inputStream) {
+  public RemoteAppenderStreamClient(String id, InputStream inputStream, ObjectReaderFactory objectReaderFactory) {
     this.id = id;
     this.socket = null;
     this.inputStream = inputStream;
+    this.objectReaderFactory = objectReaderFactory;
   }
 
   /**
@@ -86,12 +91,12 @@ class RemoteAppenderStreamClient implements RemoteAppenderClient {
    */
   public void run() {
     logger.info(this + ": connected"); 
-    ObjectInputStream ois = null;
+    ObjectReader or = null;
     try {
-      ois = createObjectInputStream();
+      or = createObjectReader();
       while (true) {
         // read an event from the wire
-        ILoggingEvent event = (ILoggingEvent) ois.readObject();
+        ILoggingEvent event = (ILoggingEvent) or.read();
         // get a logger from the hierarchy. The name of the logger is taken to
         // be the name contained in the event.
         Logger remoteLogger = lc.getLogger(event.getLoggerName());
@@ -116,19 +121,19 @@ class RemoteAppenderStreamClient implements RemoteAppenderClient {
       logger.error(this + ": " + ex);
     }
     finally {
-      if (ois != null) {
-        CloseUtil.closeQuietly(ois);
+      if (or != null) {
+        CloseUtil.closeQuietly(or);
       }
       close();
       logger.info(this + ": connection closed");
     }
   }
 
-  private ObjectInputStream createObjectInputStream() throws IOException {
+  private ObjectReader createObjectReader() throws IOException {
     if (inputStream != null) {
-      return new ObjectInputStream(inputStream);
+      return objectReaderFactory.newObjectReader(inputStream);
     }
-    return new ObjectInputStream(socket.getInputStream());
+    return objectReaderFactory.newObjectReader(socket.getInputStream());
   }
   
   /**
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/ServerSocketReceiver.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/ServerSocketReceiver.java
index 7fd8423..430a6bf 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/server/ServerSocketReceiver.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/server/ServerSocketReceiver.java
@@ -21,8 +21,10 @@ import java.util.concurrent.Executor;
 
 import javax.net.ServerSocketFactory;
 
+import ch.qos.logback.classic.net.ObjectReaderFactory;
 import ch.qos.logback.classic.net.ReceiverBase;
 import ch.qos.logback.core.net.AbstractSocketAppender;
+import ch.qos.logback.core.net.ObjectWriterFactory;
 import ch.qos.logback.core.net.server.ServerListener;
 import ch.qos.logback.core.net.server.ServerRunner;
 import ch.qos.logback.core.util.CloseUtil;
@@ -71,7 +73,7 @@ public class ServerSocketReceiver extends ReceiverBase {
 
   protected ServerListener<RemoteAppenderClient> createServerListener(
       ServerSocket socket) {
-    return new RemoteAppenderServerListener(socket);
+    return new RemoteAppenderServerListener(socket, createObjectReaderFactory());
   }
   
   protected ServerRunner createServerRunner(
@@ -80,6 +82,10 @@ public class ServerSocketReceiver extends ReceiverBase {
     return new RemoteAppenderServerRunner(listener, executor);
   }
   
+  protected ObjectReaderFactory createObjectReaderFactory() {
+	  return new ObjectReaderFactory();
+  }
+  
   @Override
   protected Runnable getRunnableTask() {
     return runner;
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/net/server/InstrumentedServerSocketReceiver.java b/logback-classic/src/test/java/ch/qos/logback/classic/net/server/InstrumentedServerSocketReceiver.java
index 5ec994f..faad837 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/net/server/InstrumentedServerSocketReceiver.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/net/server/InstrumentedServerSocketReceiver.java
@@ -20,6 +20,7 @@ import java.util.concurrent.Executor;
 
 import javax.net.ServerSocketFactory;
 
+import ch.qos.logback.classic.net.ObjectReaderFactory;
 import ch.qos.logback.classic.net.server.RemoteAppenderClient;
 import ch.qos.logback.classic.net.server.RemoteAppenderServerListener;
 import ch.qos.logback.classic.net.server.ServerSocketReceiver;
@@ -41,7 +42,7 @@ public class InstrumentedServerSocketReceiver extends ServerSocketReceiver {
   private ServerListener lastListener;
   
   public InstrumentedServerSocketReceiver(ServerSocket serverSocket) {
-    this(serverSocket, new RemoteAppenderServerListener(serverSocket), null);
+    this(serverSocket, new RemoteAppenderServerListener(serverSocket, new ObjectReaderFactory()), null);
   }
   
   public InstrumentedServerSocketReceiver(ServerSocket serverSocket,
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClientTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClientTest.java
index 98c9696..b6b140c 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClientTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/net/server/RemoteAppenderStreamClientTest.java
@@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
 import ch.qos.logback.classic.Level;
 import ch.qos.logback.classic.Logger;
 import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.net.ObjectReaderFactory;
 import ch.qos.logback.classic.net.mock.MockAppender;
 import ch.qos.logback.classic.spi.ILoggingEvent;
 import ch.qos.logback.classic.spi.LoggingEvent;
@@ -65,7 +66,7 @@ public class RemoteAppenderStreamClientTest {
     oos.close();
    
     ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
-    client = new RemoteAppenderStreamClient("some client ID", bis);
+    client = new RemoteAppenderStreamClient("some client ID", bis, new ObjectReaderFactory());
     client.setLoggerContext(lc);
   }
   
-- 
2.5.0

