    1   /*
    2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/test/org/apache/commons/httpclient/server/SimpleHttpServer.java,v 1.15 2004/12/11 22:35:26 olegk Exp $
    3    * $Revision: 480424 $
    4    * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
    5    *
    6    * ====================================================================
    7    *
    8    *  Licensed to the Apache Software Foundation (ASF) under one or more
    9    *  contributor license agreements.  See the NOTICE file distributed with
    10   *  this work for additional information regarding copyright ownership.
    11   *  The ASF licenses this file to You under the Apache License, Version 2.0
    12   *  (the "License"); you may not use this file except in compliance with
    13   *  the License.  You may obtain a copy of the License at
    14   *
    15   *      http://www.apache.org/licenses/LICENSE-2.0
    16   *
    17   *  Unless required by applicable law or agreed to in writing, software
    18   *  distributed under the License is distributed on an "AS IS" BASIS,
    19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    20   *  See the License for the specific language governing permissions and
    21   *  limitations under the License.
    22   * ====================================================================
    23   *
    24   * This software consists of voluntary contributions made by many
    25   * individuals on behalf of the Apache Software Foundation.  For more
    26   * information on the Apache Software Foundation, please see
    27   * <http://www.apache.org/>.
    28   *
    29   */
    30
    31  package org.apache.commons.httpclient.server;
    32
    33  import java.io.IOException;
    34  import java.net.InetAddress;
    35  import java.net.ServerSocket;
    36  import java.net.Socket;
    37
    38  import org.apache.commons.logging.Log;
    39  import org.apache.commons.logging.LogFactory;
    40
    41  /**
    42   * A simple, but extensible HTTP server, mostly for testing purposes.
    43   *
    44   * @author Christian Kohlschuetter
    45   * @author Oleg Kalnichevski
    46   */
    47  public class SimpleHttpServer implements Runnable {
    48      private static final Log LOG = LogFactory.getLog(SimpleHttpServer.class);
    49
    50      private String testname = "Simple test";
    51      private long count = 0;
    52      private ServerSocket listener = null;
    53      private Thread t;
    54      private ThreadGroup tg;
    55      private boolean stopped = false;
    56
    57      private SimpleConnSet connections = new SimpleConnSet();
    58
    59      private HttpRequestHandler requestHandler = null;
    60
    61      /**
    62       * Creates a new HTTP server instance, using an arbitrary free TCP port
    63       *
    64       * @throws IOException  if anything goes wrong during initialization
    65       */
    66      public SimpleHttpServer() throws IOException {
    67          this(null, 0);
    68      }
    69
    70      /**
    71       * Creates a new HTTP server instance, using the specified socket
    72       * factory and the TCP port
    73       *
    74       * @param   port    Desired TCP port
    75       * @throws IOException  if anything goes wrong during initialization
    76       */
    77      public SimpleHttpServer(SimpleSocketFactory socketfactory, int port)
    78          throws IOException {
    79          if (socketfactory == null) {
    80          	socketfactory = new SimplePlainSocketFactory();
    81          }
    82          listener = socketfactory.createServerSocket(port);
    83          if(LOG.isDebugEnabled()) {
    84              LOG.debug("Starting test HTTP server on port " + getLocalPort());
    85          }
    86          tg = new ThreadGroup("SimpleHttpServer thread group");
    87          t = new Thread(tg, this, "SimpleHttpServer listener");
    88          t.setDaemon(true);
    89          t.start();
    90      }
    91
    92      /**
    93       * Creates a new HTTP server instance, using the specified TCP port
    94       *
    95       * @param   port    Desired TCP port
    96       * @throws IOException  if anything goes wrong during initialization
    97       */
    98      public SimpleHttpServer(int port) throws IOException {
    99          this(null, port);
    100     }
    101
    102     public String getTestname() {
    103         return this.testname;
    104     }
    105
    106     public void setTestname(final String testname) {
    107         this.testname = testname;
    108     }
    109
    110     /**
    111      * Returns the TCP port that this HTTP server instance is bound to.
    112      *
    113      * @return  TCP port, or -1 if not running
    114      */
    115     public int getLocalPort() {
    116         return listener.getLocalPort();
    117     }
    118
    119     /**
    120      * Returns the IP address that this HTTP server instance is bound to.
    121      * @return String representation of the IP address or <code>null</code> if not running
    122      */
    123     public String getLocalAddress() {
    124         InetAddress address = listener.getInetAddress();
    125         // Ugly work-around for older JDKs
    126         byte[] octets = address.getAddress();
    127         if ((octets[0] == 0)
    128          && (octets[1] == 0)
    129          && (octets[2] == 0)
    130          && (octets[3] == 0)) {
    131             return "localhost";
    132         } else {
    133             return address.getHostAddress();
    134         }
    135     }
    136
    137     /**
    138      * Checks if this HTTP server instance is running.
    139      *
    140      * @return  true/false
    141      */
    142     public boolean isRunning() {
    143         if(t == null) {
    144             return false;
    145         }
    146         return t.isAlive();
    147     }
    148
    149     /**
    150      * Stops this HTTP server instance.
    151      */
    152     public synchronized void destroy() {
    153         if (stopped) {
    154             return;
    155         }
    156
    157         this.stopped = true;
    158         if(LOG.isDebugEnabled()) {
    159             LOG.debug("Stopping test HTTP server on port " + getLocalPort());
    160         }
    161         tg.interrupt();
    162
    163         if (listener != null) {
    164             try {
    165                 listener.close();
    166             } catch(IOException e) {
    167
    168             }
    169         }
    170         this.connections.shutdown();
    171     }
    172
    173     /**
    174      * Returns the currently used HttpRequestHandler by this SimpleHttpServer
    175      *
    176      * @return The used HttpRequestHandler, or null.
    177      */
    178     public HttpRequestHandler getRequestHandler() {
    179         return requestHandler;
    180     }
    181
    182     /**
    183      * Sets the HttpRequestHandler to be used for this SimpleHttpServer.
    184      *
    185      * @param rh    Request handler to be used, or null to disable.
    186      */
    187     public void setRequestHandler(HttpRequestHandler rh) {
    188         this.requestHandler = rh;
    189     }
    190
    191     public void setHttpService(HttpService service) {
    192         setRequestHandler(new HttpServiceHandler(service));
    193     }
    194
    195     public void run() {
    196         try {
    197             while (!this.stopped && !Thread.interrupted()) {
    198                 Socket socket = listener.accept();
    199                 try {
    200                     if (this.requestHandler == null) {
    201                         socket.close();
    202                         break;
    203                     }
    204                     SimpleHttpServerConnection conn = new SimpleHttpServerConnection(socket);
    205                     this.connections.addConnection(conn);
    206
    207                     Thread t = new SimpleConnectionThread(
    208                             tg,
    209                             this.testname + " thread " + this.count,
    210                             conn,
    211                             this.connections,
    212                             this.requestHandler);
    213                     t.setDaemon(true);
    214                     t.start();
    215                 } catch (IOException e) {
    216                     LOG.error("I/O error: " + e.getMessage());
    217                 }
    218                 this.count++;
    219                 Thread.sleep(100);
    220             }
    221         } catch (InterruptedException accept) {
    222         } catch (IOException e) {
    223             if (!stopped) {
    224                 LOG.error("I/O error: " + e.getMessage());
    225             }
    226         } finally {
    227             destroy();
    228         }
    229     }
    230 }