1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.bootstrap;
28
29 import java.io.IOException;
30 import java.net.InetAddress;
31 import java.net.ServerSocket;
32 import java.util.Set;
33 import java.util.concurrent.SynchronousQueue;
34 import java.util.concurrent.ThreadPoolExecutor;
35 import java.util.concurrent.TimeUnit;
36 import java.util.concurrent.atomic.AtomicReference;
37
38 import javax.net.ServerSocketFactory;
39 import javax.net.ssl.SSLServerSocket;
40
41 import org.apache.http.ExceptionLogger;
42 import org.apache.http.HttpConnectionFactory;
43 import org.apache.http.HttpServerConnection;
44 import org.apache.http.config.SocketConfig;
45 import org.apache.http.impl.DefaultBHttpServerConnection;
46 import org.apache.http.protocol.HttpService;
47
48
49
50
51 public class HttpServer {
52
53 enum Status { READY, ACTIVE, STOPPING }
54
55 private final int port;
56 private final InetAddress ifAddress;
57 private final SocketConfig socketConfig;
58 private final ServerSocketFactory serverSocketFactory;
59 private final HttpService httpService;
60 private final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory;
61 private final SSLServerSetupHandler sslSetupHandler;
62 private final ExceptionLogger exceptionLogger;
63 private final ThreadPoolExecutor listenerExecutorService;
64 private final ThreadGroup workerThreads;
65 private final WorkerPoolExecutor workerExecutorService;
66 private final AtomicReference<Status> status;
67
68 private volatile ServerSocket serverSocket;
69 private volatile RequestListener requestListener;
70
71 HttpServer(
72 final int port,
73 final InetAddress ifAddress,
74 final SocketConfig socketConfig,
75 final ServerSocketFactory serverSocketFactory,
76 final HttpService httpService,
77 final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory,
78 final SSLServerSetupHandler sslSetupHandler,
79 final ExceptionLogger exceptionLogger) {
80 this.port = port;
81 this.ifAddress = ifAddress;
82 this.socketConfig = socketConfig;
83 this.serverSocketFactory = serverSocketFactory;
84 this.httpService = httpService;
85 this.connectionFactory = connectionFactory;
86 this.sslSetupHandler = sslSetupHandler;
87 this.exceptionLogger = exceptionLogger;
88 this.listenerExecutorService = new ThreadPoolExecutor(
89 1, 1, 0L, TimeUnit.MILLISECONDS,
90 new SynchronousQueue<Runnable>(),
91 new ThreadFactoryImpl("HTTP-listener-" + this.port));
92 this.workerThreads = new ThreadGroup("HTTP-workers");
93 this.workerExecutorService = new WorkerPoolExecutor(
94 0, Integer.MAX_VALUE, 1L, TimeUnit.SECONDS,
95 new SynchronousQueue<Runnable>(),
96 new ThreadFactoryImpl("HTTP-worker", this.workerThreads));
97 this.status = new AtomicReference<Status>(Status.READY);
98 }
99
100 public InetAddress getInetAddress() {
101 final ServerSocket localSocket = this.serverSocket;
102 return localSocket != null ? localSocket.getInetAddress() : null;
103 }
104
105 public int getLocalPort() {
106 final ServerSocket localSocket = this.serverSocket;
107 return localSocket != null ? localSocket.getLocalPort() : -1;
108 }
109
110 public void start() throws IOException {
111 if (this.status.compareAndSet(Status.READY, Status.ACTIVE)) {
112 this.serverSocket = this.serverSocketFactory.createServerSocket(
113 this.port, this.socketConfig.getBacklogSize(), this.ifAddress);
114 this.serverSocket.setReuseAddress(this.socketConfig.isSoReuseAddress());
115 if (this.socketConfig.getRcvBufSize() > 0) {
116 this.serverSocket.setReceiveBufferSize(this.socketConfig.getRcvBufSize());
117 }
118 if (this.sslSetupHandler != null && this.serverSocket instanceof SSLServerSocket) {
119 this.sslSetupHandler.initialize((SSLServerSocket) this.serverSocket);
120 }
121 this.requestListener = new RequestListener(
122 this.socketConfig,
123 this.serverSocket,
124 this.httpService,
125 this.connectionFactory,
126 this.exceptionLogger,
127 this.workerExecutorService);
128 this.listenerExecutorService.execute(this.requestListener);
129 }
130 }
131
132 public void stop() {
133 if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPING)) {
134 this.listenerExecutorService.shutdown();
135 this.workerExecutorService.shutdown();
136 final RequestListener local = this.requestListener;
137 if (local != null) {
138 try {
139 local.terminate();
140 } catch (final IOException ex) {
141 this.exceptionLogger.log(ex);
142 }
143 }
144 this.workerThreads.interrupt();
145 }
146 }
147
148 public void awaitTermination(final long timeout, final TimeUnit timeUnit) throws InterruptedException {
149 this.workerExecutorService.awaitTermination(timeout, timeUnit);
150 }
151
152 public void shutdown(final long gracePeriod, final TimeUnit timeUnit) {
153 stop();
154 if (gracePeriod > 0) {
155 try {
156 awaitTermination(gracePeriod, timeUnit);
157 } catch (final InterruptedException ex) {
158 Thread.currentThread().interrupt();
159 }
160 }
161 final Set<Worker> workers = this.workerExecutorService.getWorkers();
162 for (final Worker worker: workers) {
163 final HttpServerConnection conn = worker.getConnection();
164 try {
165 conn.shutdown();
166 } catch (final IOException ex) {
167 this.exceptionLogger.log(ex);
168 }
169 }
170 }
171
172 }