View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.core.net.server;
15  
16  import java.io.IOException;
17  import java.io.ObjectOutputStream;
18  import java.io.OutputStream;
19  import java.io.Serializable;
20  import java.net.Socket;
21  import java.net.SocketException;
22  import java.util.concurrent.BlockingQueue;
23  
24  import ch.qos.logback.core.CoreConstants;
25  import ch.qos.logback.core.spi.ContextAwareBase;
26  import ch.qos.logback.core.util.CloseUtil;
27  
28  /**
29   * A {@link RemoteReceiverClient} that writes serialized logging events to an
30   * {@link OutputStream}.
31   *
32   * @author Carl Harris
33   */
34  class RemoteReceiverStreamClient extends ContextAwareBase implements RemoteReceiverClient {
35  
36      private final String clientId;
37      private final Socket socket;
38      private final OutputStream outputStream;
39  
40      private BlockingQueue<Serializable> queue;
41  
42      /**
43       * Constructs a new client.
44       * @param id identifier string for the client
45       * @param socket socket to which logging events will be written
46       */
47      public RemoteReceiverStreamClient(String id, Socket socket) {
48          this.clientId = "client " + id + ": ";
49          this.socket = socket;
50          this.outputStream = null;
51      }
52  
53      /**
54       * Constructs a new client.
55       * <p> 
56       * This constructor exists primarily to support unit tests where it
57       * is inconvenient to have to create a socket for the test.
58       * 
59       * @param id identifier string for the client
60       * @param outputStream output stream to which logging Events will be written
61       */
62      RemoteReceiverStreamClient(String id, OutputStream outputStream) {
63          this.clientId = "client " + id + ": ";
64          this.socket = null;
65          this.outputStream = outputStream;
66      }
67  
68      /**
69       * {@inheritDoc}
70       */
71      public void setQueue(BlockingQueue<Serializable> queue) {
72          this.queue = queue;
73      }
74  
75      /**
76       * {@inheritDoc}
77       */
78      public boolean offer(Serializable event) {
79          if (queue == null) {
80              throw new IllegalStateException("client has no event queue");
81          }
82          return queue.offer(event);
83      }
84  
85      /**
86       * {@inheritDoc}
87       */
88      public void close() {
89          if (socket == null)
90              return;
91          CloseUtil.closeQuietly(socket);
92      }
93  
94      /**
95       * {@inheritDoc}
96       */
97      public void run() {
98          addInfo(clientId + "connected");
99  
100         ObjectOutputStream oos = null;
101         try {
102             int counter = 0;
103             oos = createObjectOutputStream();
104             while (!Thread.currentThread().isInterrupted()) {
105                 try {
106                     Serializable event = queue.take();
107                     oos.writeObject(event);
108                     oos.flush();
109                     if (++counter >= CoreConstants.OOS_RESET_FREQUENCY) {
110                         // failing to reset the stream periodically will result in a
111                         // serious memory leak (as noted in AbstractSocketAppender)
112                         counter = 0;
113                         oos.reset();
114                     }
115                 } catch (InterruptedException ex) {
116                     Thread.currentThread().interrupt();
117                 }
118             }
119         } catch (SocketException ex) {
120             addInfo(clientId + ex);
121         } catch (IOException ex) {
122             addError(clientId + ex);
123         } catch (RuntimeException ex) {
124             addError(clientId + ex);
125         } finally {
126             if (oos != null) {
127                 CloseUtil.closeQuietly(oos);
128             }
129             close();
130             addInfo(clientId + "connection closed");
131         }
132     }
133 
134     private ObjectOutputStream createObjectOutputStream() throws IOException {
135         if (socket == null) {
136             return new ObjectOutputStream(outputStream);
137         }
138         return new ObjectOutputStream(socket.getOutputStream());
139     }
140 }