View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
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.List;
33  import java.util.concurrent.ExecutorService;
34  import java.util.concurrent.Executors;
35  import java.util.concurrent.TimeUnit;
36  import java.util.concurrent.atomic.AtomicReference;
37  
38  import javax.net.ServerSocketFactory;
39  
40  import org.apache.http.ExceptionLogger;
41  import org.apache.http.HttpConnectionFactory;
42  import org.apache.http.HttpServerConnection;
43  import org.apache.http.config.SocketConfig;
44  import org.apache.http.impl.DefaultBHttpServerConnection;
45  import org.apache.http.protocol.HttpService;
46  
47  /**
48   * @since 4.4
49   */
50  public class HttpServer {
51  
52      enum Status { READY, ACTIVE, STOPPING }
53  
54      private final int port;
55      private final InetAddress ifAddress;
56      private final SocketConfig socketConfig;
57      private final ServerSocketFactory serverSocketFactory;
58      private final HttpService httpService;
59      private final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory;
60      private final ExceptionLogger exceptionLogger;
61      private final ExecutorService listenerExecutorService;
62      private final ThreadGroup workerThreads;
63      private final ExecutorService workerExecutorService;
64      private final AtomicReference<Status> status;
65  
66      private volatile ServerSocket serverSocket;
67      private volatile RequestListener requestListener;
68  
69      HttpServer(
70              final int port,
71              final InetAddress ifAddress,
72              final SocketConfig socketConfig,
73              final ServerSocketFactory serverSocketFactory,
74              final HttpService httpService,
75              final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory,
76              final ExceptionLogger exceptionLogger) {
77          this.port = port;
78          this.ifAddress = ifAddress;
79          this.socketConfig = socketConfig;
80          this.serverSocketFactory = serverSocketFactory;
81          this.httpService = httpService;
82          this.connectionFactory = connectionFactory;
83          this.exceptionLogger = exceptionLogger;
84          this.listenerExecutorService = Executors.newSingleThreadExecutor(
85                  new ThreadFactoryImpl("HTTP-listener-" + this.port));
86          this.workerThreads = new ThreadGroup("HTTP-workers");
87          this.workerExecutorService = Executors.newCachedThreadPool(
88                  new ThreadFactoryImpl("HTTP-worker", this.workerThreads));
89          this.status = new AtomicReference<Status>(Status.READY);
90      }
91  
92      public InetAddress getInetAddress() {
93          final ServerSocket localSocket = this.serverSocket;
94          if (localSocket != null) {
95              return localSocket.getInetAddress();
96          } else {
97              return null;
98          }
99      }
100 
101     public int getLocalPort() {
102         final ServerSocket localSocket = this.serverSocket;
103         if (localSocket != null) {
104             return localSocket.getLocalPort();
105         } else {
106             return -1;
107         }
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             this.requestListener = new RequestListener(
119                     this.socketConfig,
120                     this.serverSocket,
121                     this.httpService,
122                     this.connectionFactory,
123                     this.exceptionLogger,
124                     this.workerExecutorService);
125             this.listenerExecutorService.execute(this.requestListener);
126         }
127     }
128 
129     public void stop() {
130         if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPING)) {
131             final RequestListener local = this.requestListener;
132             if (local != null) {
133                 try {
134                     local.terminate();
135                 } catch (IOException ex) {
136                     this.exceptionLogger.log(ex);
137                 }
138             }
139             this.workerThreads.interrupt();
140             this.listenerExecutorService.shutdown();
141             this.workerExecutorService.shutdown();
142         }
143     }
144 
145     public void awaitTermination(final long timeout, final TimeUnit timeUnit) throws InterruptedException {
146         this.workerExecutorService.awaitTermination(timeout, timeUnit);
147     }
148 
149     public void shutdown(final long gracePeriod, final TimeUnit timeUnit) {
150         stop();
151         if (gracePeriod > 0) {
152             try {
153                 awaitTermination(gracePeriod, timeUnit);
154             } catch (InterruptedException ex) {
155                 Thread.currentThread().interrupt();
156             }
157         }
158         final List<Runnable> runnables = this.workerExecutorService.shutdownNow();
159         for (Runnable runnable: runnables) {
160             if (runnable instanceof Worker) {
161                 final Worker worker = (Worker) runnable;
162                 final HttpServerConnection conn = worker.getConnection();
163                 try {
164                     conn.shutdown();
165                 } catch (IOException ex) {
166                     this.exceptionLogger.log(ex);
167                 }
168             }
169         }
170     }
171 
172 }