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       * 
45       * @param id     identifier string for the client
46       * @param socket socket to which logging events will be written
47       */
48      public RemoteReceiverStreamClient(String id, Socket socket) {
49          this.clientId = "client " + id + ": ";
50          this.socket = socket;
51          this.outputStream = null;
52      }
53  
54      /**
55       * Constructs a new client.
56       * <p>
57       * This constructor exists primarily to support unit tests where it is
58       * inconvenient to have to create a socket for the test.
59       * 
60       * @param id           identifier string for the client
61       * @param outputStream output stream to which logging Events will be written
62       */
63      RemoteReceiverStreamClient(String id, OutputStream outputStream) {
64          this.clientId = "client " + id + ": ";
65          this.socket = null;
66          this.outputStream = outputStream;
67      }
68  
69      /**
70       * {@inheritDoc}
71       */
72      public void setQueue(BlockingQueue<Serializable> queue) {
73          this.queue = queue;
74      }
75  
76      /**
77       * {@inheritDoc}
78       */
79      public boolean offer(Serializable event) {
80          if (queue == null) {
81              throw new IllegalStateException("client has no event queue");
82          }
83          return queue.offer(event);
84      }
85  
86      /**
87       * {@inheritDoc}
88       */
89      public void close() {
90          if (socket == null)
91              return;
92          CloseUtil.closeQuietly(socket);
93      }
94  
95      /**
96       * {@inheritDoc}
97       */
98      public void run() {
99          addInfo(clientId + "connected");
100 
101         ObjectOutputStream oos = null;
102         try {
103             int counter = 0;
104             oos = createObjectOutputStream();
105             while (!Thread.currentThread().isInterrupted()) {
106                 try {
107                     Serializable event = queue.take();
108                     oos.writeObject(event);
109                     oos.flush();
110                     if (++counter >= CoreConstants.OOS_RESET_FREQUENCY) {
111                         // failing to reset the stream periodically will result in a
112                         // serious memory leak (as noted in AbstractSocketAppender)
113                         counter = 0;
114                         oos.reset();
115                     }
116                 } catch (InterruptedException ex) {
117                     Thread.currentThread().interrupt();
118                 }
119             }
120         } catch (SocketException ex) {
121             addInfo(clientId + ex);
122         } catch (IOException ex) {
123             addError(clientId + ex);
124         } catch (RuntimeException ex) {
125             addError(clientId + ex);
126         } finally {
127             if (oos != null) {
128                 CloseUtil.closeQuietly(oos);
129             }
130             close();
131             addInfo(clientId + "connection closed");
132         }
133     }
134 
135     private ObjectOutputStream createObjectOutputStream() throws IOException {
136         if (socket == null) {
137             return new ObjectOutputStream(outputStream);
138         }
139         return new ObjectOutputStream(socket.getOutputStream());
140     }
141 }