001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.impl.bootstrap; 028 029import java.io.IOException; 030import java.net.InetAddress; 031import java.net.ServerSocket; 032import java.util.Set; 033import java.util.concurrent.SynchronousQueue; 034import java.util.concurrent.ThreadPoolExecutor; 035import java.util.concurrent.TimeUnit; 036import java.util.concurrent.atomic.AtomicReference; 037 038import javax.net.ServerSocketFactory; 039import javax.net.ssl.SSLServerSocket; 040 041import org.apache.http.ExceptionLogger; 042import org.apache.http.HttpConnectionFactory; 043import org.apache.http.HttpServerConnection; 044import org.apache.http.config.SocketConfig; 045import org.apache.http.impl.DefaultBHttpServerConnection; 046import org.apache.http.protocol.HttpService; 047 048/** 049 * @since 4.4 050 */ 051public class HttpServer { 052 053 enum Status { READY, ACTIVE, STOPPING } 054 055 private final int port; 056 private final InetAddress ifAddress; 057 private final SocketConfig socketConfig; 058 private final ServerSocketFactory serverSocketFactory; 059 private final HttpService httpService; 060 private final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory; 061 private final SSLServerSetupHandler sslSetupHandler; 062 private final ExceptionLogger exceptionLogger; 063 private final ThreadPoolExecutor listenerExecutorService; 064 private final ThreadGroup workerThreads; 065 private final WorkerPoolExecutor workerExecutorService; 066 private final AtomicReference<Status> status; 067 068 private volatile ServerSocket serverSocket; 069 private volatile RequestListener requestListener; 070 071 HttpServer( 072 final int port, 073 final InetAddress ifAddress, 074 final SocketConfig socketConfig, 075 final ServerSocketFactory serverSocketFactory, 076 final HttpService httpService, 077 final HttpConnectionFactory<? extends DefaultBHttpServerConnection> connectionFactory, 078 final SSLServerSetupHandler sslSetupHandler, 079 final ExceptionLogger exceptionLogger) { 080 this.port = port; 081 this.ifAddress = ifAddress; 082 this.socketConfig = socketConfig; 083 this.serverSocketFactory = serverSocketFactory; 084 this.httpService = httpService; 085 this.connectionFactory = connectionFactory; 086 this.sslSetupHandler = sslSetupHandler; 087 this.exceptionLogger = exceptionLogger; 088 this.listenerExecutorService = new ThreadPoolExecutor( 089 1, 1, 0L, TimeUnit.MILLISECONDS, 090 new SynchronousQueue<Runnable>(), 091 new ThreadFactoryImpl("HTTP-listener-" + this.port)); 092 this.workerThreads = new ThreadGroup("HTTP-workers"); 093 this.workerExecutorService = new WorkerPoolExecutor( 094 0, Integer.MAX_VALUE, 1L, TimeUnit.SECONDS, 095 new SynchronousQueue<Runnable>(), 096 new ThreadFactoryImpl("HTTP-worker", this.workerThreads)); 097 this.status = new AtomicReference<Status>(Status.READY); 098 } 099 100 public InetAddress getInetAddress() { 101 final ServerSocket localSocket = this.serverSocket; 102 if (localSocket != null) { 103 return localSocket.getInetAddress(); 104 } else { 105 return null; 106 } 107 } 108 109 public int getLocalPort() { 110 final ServerSocket localSocket = this.serverSocket; 111 if (localSocket != null) { 112 return localSocket.getLocalPort(); 113 } else { 114 return -1; 115 } 116 } 117 118 public void start() throws IOException { 119 if (this.status.compareAndSet(Status.READY, Status.ACTIVE)) { 120 this.serverSocket = this.serverSocketFactory.createServerSocket( 121 this.port, this.socketConfig.getBacklogSize(), this.ifAddress); 122 this.serverSocket.setReuseAddress(this.socketConfig.isSoReuseAddress()); 123 if (this.socketConfig.getRcvBufSize() > 0) { 124 this.serverSocket.setReceiveBufferSize(this.socketConfig.getRcvBufSize()); 125 } 126 if (this.sslSetupHandler != null && this.serverSocket instanceof SSLServerSocket) { 127 this.sslSetupHandler.initialize((SSLServerSocket) this.serverSocket); 128 } 129 this.requestListener = new RequestListener( 130 this.socketConfig, 131 this.serverSocket, 132 this.httpService, 133 this.connectionFactory, 134 this.exceptionLogger, 135 this.workerExecutorService); 136 this.listenerExecutorService.execute(this.requestListener); 137 } 138 } 139 140 public void stop() { 141 if (this.status.compareAndSet(Status.ACTIVE, Status.STOPPING)) { 142 this.listenerExecutorService.shutdown(); 143 this.workerExecutorService.shutdown(); 144 final RequestListener local = this.requestListener; 145 if (local != null) { 146 try { 147 local.terminate(); 148 } catch (final IOException ex) { 149 this.exceptionLogger.log(ex); 150 } 151 } 152 this.workerThreads.interrupt(); 153 } 154 } 155 156 public void awaitTermination(final long timeout, final TimeUnit timeUnit) throws InterruptedException { 157 this.workerExecutorService.awaitTermination(timeout, timeUnit); 158 } 159 160 public void shutdown(final long gracePeriod, final TimeUnit timeUnit) { 161 stop(); 162 if (gracePeriod > 0) { 163 try { 164 awaitTermination(gracePeriod, timeUnit); 165 } catch (final InterruptedException ex) { 166 Thread.currentThread().interrupt(); 167 } 168 } 169 final Set<Worker> workers = this.workerExecutorService.getWorkers(); 170 for (final Worker worker: workers) { 171 final HttpServerConnection conn = worker.getConnection(); 172 try { 173 conn.shutdown(); 174 } catch (final IOException ex) { 175 this.exceptionLogger.log(ex); 176 } 177 } 178 } 179 180}