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.Serializable;
18  import java.net.InetAddress;
19  import java.net.ServerSocket;
20  import java.net.UnknownHostException;
21  import java.util.concurrent.Executor;
22  
23  import javax.net.ServerSocketFactory;
24  
25  import ch.qos.logback.core.AppenderBase;
26  import ch.qos.logback.core.net.AbstractSocketAppender;
27  import ch.qos.logback.core.spi.PreSerializationTransformer;
28  
29  /**
30   * 
31   * This is the super class for module specific ServerSocketAppender
32   * implementations can derive from.
33   * 
34   * @author Carl Harris
35   */
36  public abstract class AbstractServerSocketAppender<E> extends AppenderBase<E> {
37  
38      /**
39       * Default {@link ServerSocket} backlog
40       */
41      public static final int DEFAULT_BACKLOG = 50;
42  
43      /**
44       * Default queue size used for each client
45       */
46      public static final int DEFAULT_CLIENT_QUEUE_SIZE = 100;
47  
48      private int port = AbstractSocketAppender.DEFAULT_PORT;
49      private int backlog = DEFAULT_BACKLOG;
50      private int clientQueueSize = DEFAULT_CLIENT_QUEUE_SIZE;
51  
52      private String address;
53  
54      private ServerRunner<RemoteReceiverClient> runner;
55  
56      @Override
57      public void start() {
58          if (isStarted())
59              return;
60          try {
61              ServerSocket socket = getServerSocketFactory().createServerSocket(getPort(), getBacklog(),
62                      getInetAddress());
63              ServerListener<RemoteReceiverClient> listener = createServerListener(socket);
64  
65              runner = createServerRunner(listener, getContext().getScheduledExecutorService());
66              runner.setContext(getContext());
67              getContext().getScheduledExecutorService().execute(runner);
68              super.start();
69          } catch (Exception ex) {
70              addError("server startup error: " + ex, ex);
71          }
72      }
73  
74      protected ServerListener<RemoteReceiverClient> createServerListener(ServerSocket socket) {
75          return new RemoteReceiverServerListener(socket);
76      }
77  
78      protected ServerRunner<RemoteReceiverClient> createServerRunner(ServerListener<RemoteReceiverClient> listener,
79              Executor executor) {
80          return new RemoteReceiverServerRunner(listener, executor, getClientQueueSize());
81      }
82  
83      @Override
84      public void stop() {
85          if (!isStarted())
86              return;
87          
88          try {
89              runner.stop();
90              super.stop();
91          } catch (IOException ex) {
92              addError("server shutdown error: " + ex, ex);
93          }
94      }
95  
96      @Override
97      protected void append(E event) {
98          if (event == null)
99              return;
100         postProcessEvent(event);
101         final Serializable serEvent = getPST().transform(event);
102         runner.accept(new ClientVisitor<RemoteReceiverClient>() {
103             public void visit(RemoteReceiverClient client) {
104                 client.offer(serEvent);
105             }
106         });
107     }
108 
109     /**
110      * Postprocess an event received via {@link #append append()}.
111      * 
112      * @param event
113      */
114     protected abstract void postProcessEvent(E event);
115 
116     /**
117      * Gets a transformer that will be used to convert a received event to a
118      * {@link Serializable} form.
119      * 
120      * @return
121      */
122     protected abstract PreSerializationTransformer<E> getPST();
123 
124     /**
125      * Gets the factory used to create {@link ServerSocket} objects.
126      * <p>
127      * The default implementation delegates to
128      * {@link ServerSocketFactory#getDefault()}. Subclasses may override to private
129      * a different socket factory implementation.
130      * 
131      * @return socket factory.
132      */
133     protected ServerSocketFactory getServerSocketFactory() throws Exception {
134         return ServerSocketFactory.getDefault();
135     }
136 
137     /**
138      * Gets the local address for the listener.
139      * 
140      * @return an {@link InetAddress} representation of the local address.
141      * @throws UnknownHostException
142      */
143     protected InetAddress getInetAddress() throws UnknownHostException {
144         if (getAddress() == null)
145             return null;
146         return InetAddress.getByName(getAddress());
147     }
148 
149     /**
150      * Gets the local port for the listener.
151      * 
152      * @return local port
153      */
154     public int getPort() {
155         return port;
156     }
157 
158     /**
159      * Sets the local port for the listener.
160      * 
161      * @param port the local port to set
162      */
163     public void setPort(int port) {
164         this.port = port;
165     }
166 
167     /**
168      * Gets the listener queue depth.
169      * <p>
170      * This represents the number of connected clients whose connections have not
171      * yet been accepted.
172      * 
173      * @return queue depth
174      * @see java.net.ServerSocket
175      */
176     public int getBacklog() {
177         return backlog;
178     }
179 
180     /**
181      * Sets the listener queue depth.
182      * <p>
183      * This represents the number of connected clients whose connections have not
184      * yet been accepted.
185      * 
186      * @param backlog the queue depth to set
187      * @see java.net.ServerSocket
188      */
189     public void setBacklog(int backlog) {
190         this.backlog = backlog;
191     }
192 
193     /**
194      * Gets the local address for the listener.
195      * 
196      * @return a string representation of the local address
197      */
198     public String getAddress() {
199         return address;
200     }
201 
202     /**
203      * Sets the local address for the listener.
204      * 
205      * @param address a host name or a string representation of an IP address
206      */
207     public void setAddress(String address) {
208         this.address = address;
209     }
210 
211     /**
212      * Gets the event queue size used for each client connection.
213      * 
214      * @return queue size
215      */
216     public int getClientQueueSize() {
217         return clientQueueSize;
218     }
219 
220     /**
221      * Sets the event queue size used for each client connection.
222      * 
223      * @param clientQueueSize the queue size to set
224      */
225     public void setClientQueueSize(int clientQueueSize) {
226         this.clientQueueSize = clientQueueSize;
227     }
228 
229 }