001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.net.server;
015
016import java.io.IOException;
017import java.io.Serializable;
018import java.net.InetAddress;
019import java.net.ServerSocket;
020import java.net.UnknownHostException;
021import java.util.concurrent.Executor;
022
023import javax.net.ServerSocketFactory;
024
025import ch.qos.logback.core.AppenderBase;
026import ch.qos.logback.core.net.AbstractSocketAppender;
027import ch.qos.logback.core.spi.PreSerializationTransformer;
028
029/**
030 * 
031 * This is the super class for module specific ServerSocketAppender
032 * implementations can derive from.
033 * 
034 * @author Carl Harris
035 */
036public abstract class AbstractServerSocketAppender<E> extends AppenderBase<E> {
037
038    /**
039     * Default {@link ServerSocket} backlog
040     */
041    public static final int DEFAULT_BACKLOG = 50;
042
043    /**
044     * Default queue size used for each client
045     */
046    public static final int DEFAULT_CLIENT_QUEUE_SIZE = 100;
047
048    private int port = AbstractSocketAppender.DEFAULT_PORT;
049    private int backlog = DEFAULT_BACKLOG;
050    private int clientQueueSize = DEFAULT_CLIENT_QUEUE_SIZE;
051
052    private String address;
053
054    private ServerRunner<RemoteReceiverClient> runner;
055
056    @Override
057    public void start() {
058        if (isStarted())
059            return;
060        try {
061            ServerSocket socket = getServerSocketFactory().createServerSocket(getPort(), getBacklog(),
062                    getInetAddress());
063            ServerListener<RemoteReceiverClient> listener = createServerListener(socket);
064
065            runner = createServerRunner(listener, getContext().getScheduledExecutorService());
066            runner.setContext(getContext());
067            getContext().getScheduledExecutorService().execute(runner);
068            super.start();
069        } catch (Exception ex) {
070            addError("server startup error: " + ex, ex);
071        }
072    }
073
074    protected ServerListener<RemoteReceiverClient> createServerListener(ServerSocket socket) {
075        return new RemoteReceiverServerListener(socket);
076    }
077
078    protected ServerRunner<RemoteReceiverClient> createServerRunner(ServerListener<RemoteReceiverClient> listener,
079            Executor executor) {
080        return new RemoteReceiverServerRunner(listener, executor, getClientQueueSize());
081    }
082
083    @Override
084    public void stop() {
085        if (!isStarted())
086            return;
087        
088        try {
089            runner.stop();
090            super.stop();
091        } catch (IOException ex) {
092            addError("server shutdown error: " + ex, ex);
093        }
094    }
095
096    @Override
097    protected void append(E event) {
098        if (event == null)
099            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}