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.nio.bootstrap;
28
29 import java.io.IOException;
30 import java.net.InetAddress;
31 import java.net.InetSocketAddress;
32 import java.util.concurrent.ExecutorService;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.TimeUnit;
35 import java.util.concurrent.atomic.AtomicReference;
36
37 import org.apache.http.ExceptionLogger;
38 import org.apache.http.impl.nio.DefaultHttpServerIODispatch;
39 import org.apache.http.impl.nio.DefaultNHttpServerConnection;
40 import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
41 import org.apache.http.impl.nio.reactor.IOReactorConfig;
42 import org.apache.http.nio.NHttpConnectionFactory;
43 import org.apache.http.nio.NHttpServerEventHandler;
44 import org.apache.http.nio.reactor.IOEventDispatch;
45 import org.apache.http.nio.reactor.IOReactorException;
46 import org.apache.http.nio.reactor.IOReactorExceptionHandler;
47 import org.apache.http.nio.reactor.ListenerEndpoint;
48
49
50
51
52 public class HttpServer {
53
54 enum Status { READY, ACTIVE, STOPPING }
55
56 private final int port;
57 private final InetAddress ifAddress;
58 private final IOReactorConfig ioReactorConfig;
59 private final NHttpServerEventHandler serverEventHandler;
60 private final NHttpConnectionFactory<? extends DefaultNHttpServerConnection> connectionFactory;
61 private final ExceptionLogger exceptionLogger;
62 private final ExecutorService listenerExecutorService;
63 private final ThreadGroup dispatchThreads;
64 private final AtomicReference<Status> status;
65 private final DefaultListeningIOReactor ioReactor;
66
67 private volatile ListenerEndpoint endpoint;
68
69 HttpServer(
70 final int port,
71 final InetAddress ifAddress,
72 final IOReactorConfig ioReactorConfig,
73 final NHttpServerEventHandler serverEventHandler,
74 final NHttpConnectionFactory<? extends DefaultNHttpServerConnection> connectionFactory,
75 final ExceptionLogger exceptionLogger) {
76 this.port = port;
77 this.ifAddress = ifAddress;
78 this.ioReactorConfig = ioReactorConfig;
79 this.serverEventHandler = serverEventHandler;
80 this.connectionFactory = connectionFactory;
81 this.exceptionLogger = exceptionLogger;
82 this.listenerExecutorService = Executors.newSingleThreadExecutor(
83 new ThreadFactoryImpl("HTTP-listener-" + this.port));
84 this.dispatchThreads = new ThreadGroup("I/O-dispatchers");
85 try {
86 this.ioReactor = new DefaultListeningIOReactor(
87 this.ioReactorConfig,
88 new ThreadFactoryImpl("I/O-dispatch", this.dispatchThreads));
89 } catch (final IOReactorException ex) {
90 throw new IllegalStateException(ex);
91 }
92 this.ioReactor.setExceptionHandler(new IOReactorExceptionHandler() {
93 @Override
94 public boolean handle(final IOException ex) {
95 exceptionLogger.log(ex);
96 return false;
97 }
98
99 @Override
100 public boolean handle(final RuntimeException ex) {
101 exceptionLogger.log(ex);
102 return false;
103 }
104 });
105 this.status = new AtomicReference<Status>(Status.READY);
106 }
107
108 public ListenerEndpoint getEndpoint() {
109 return this.endpoint;
110 }
111
112 public void start() throws IOException {
113 if (this.status.compareAndSet(Status.READY, Status.ACTIVE)) {
114 this.endpoint = this.ioReactor.listen(new InetSocketAddress(this.ifAddress, this.port > 0 ? this.port : 0));
115 final IOEventDispatch ioEventDispatch = new DefaultHttpServerIODispatch(
116 this.serverEventHandler, this.connectionFactory);
117 this.listenerExecutorService.execute(new Runnable() {
118
119 @Override
120 public void run() {
121 try {
122 ioReactor.execute(ioEventDispatch);
123 } catch (final Exception ex) {
124 exceptionLogger.log(ex);
125 }
126 }
127
128 });
129 }
130 }
131
132 public void awaitTermination(final long timeout, final TimeUnit timeUnit) throws InterruptedException {
133 this.listenerExecutorService.awaitTermination(timeout, timeUnit);
134 }
135
136 public void shutdown(final long gracePeriod, final TimeUnit timeUnit) {
137 if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPING)) {
138 try {
139 this.ioReactor.shutdown(timeUnit.toMillis(gracePeriod));
140 } catch (final IOException ex) {
141 this.exceptionLogger.log(ex);
142 }
143 this.listenerExecutorService.shutdown();
144 }
145 }
146
147 }