This project has retired. For details please refer to its Attic page.
Source code
001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.webserver;
020
021import org.apache.reef.tang.annotations.Parameter;
022import org.apache.reef.util.logging.LoggingScope;
023import org.apache.reef.util.logging.LoggingScopeFactory;
024import org.apache.reef.wake.remote.address.LocalAddressProvider;
025import org.apache.reef.wake.remote.ports.TcpPortProvider;
026import org.apache.reef.wake.remote.ports.parameters.TcpPortRangeBegin;
027import org.mortbay.jetty.Connector;
028import org.mortbay.jetty.Server;
029import org.mortbay.jetty.bio.SocketConnector;
030
031import javax.inject.Inject;
032import java.net.BindException;
033import java.util.Iterator;
034import java.util.logging.Level;
035import java.util.logging.Logger;
036
037/**
038 * HttpServer. It manages Jetty Server and Event Handlers
039 */
040public final class HttpServerImpl implements HttpServer {
041  /**
042   * Standard Java logger.
043   */
044  private static final Logger LOG = Logger.getLogger(HttpServerImpl.class.getName());
045
046  /**
047   *  JettyHandler injected in the constructor.
048   */
049  private JettyHandler jettyHandler;
050
051  /**
052   * Jetty server.
053   */
054  private final Server server;
055
056  /**
057   * port number used in Jetty Server.
058   */
059  private final int port;
060
061  /**
062   * Logging scope factory.
063   */
064  private final LoggingScopeFactory loggingScopeFactory;
065
066  /**
067   * The address provider for the HTTPServer.
068   */
069  private final LocalAddressProvider addressProvider;
070
071  /**
072   * Constructor of HttpServer that wraps Jetty Server.
073   *
074   * @param jettyHandler
075   * @param portNumber
076   * @throws Exception
077   */
078  @Inject
079  HttpServerImpl(final JettyHandler jettyHandler,
080                 final LocalAddressProvider addressProvider,
081                 @Parameter(TcpPortRangeBegin.class)final int portNumber,
082                 final TcpPortProvider tcpPortProvider,
083                 final LoggingScopeFactory loggingScopeFactory) throws Exception {
084    this.addressProvider = addressProvider;
085    this.loggingScopeFactory = loggingScopeFactory;
086    this.jettyHandler = jettyHandler;
087    int availablePort = portNumber;
088    Server srv = null;
089
090    try (final LoggingScope ls = this.loggingScopeFactory.httpServer()) {
091
092      final Iterator<Integer> ports = tcpPortProvider.iterator();
093      while (ports.hasNext() && srv  == null) {
094        availablePort = ports.next();
095        srv = tryPort(availablePort);
096      }
097
098      if (srv  != null) {
099        this.server = srv;
100        this.port = availablePort;
101        this.server.setHandler(jettyHandler);
102        LOG.log(Level.INFO, "Jetty Server started with port: {0}", availablePort);
103      } else {
104        throw new RuntimeException("Could not find available port for http");
105      }
106    }
107  }
108
109  private Server tryPort(final int portNumber) throws Exception {
110    Server srv = new Server();
111    final Connector connector = new SocketConnector();
112    connector.setHost(addressProvider.getLocalAddress());
113    connector.setPort(portNumber);
114    srv.addConnector(connector);
115    try {
116      srv.start();
117      LOG.log(Level.INFO, "Jetty Server started with port: {0}", portNumber);
118    } catch (final BindException ex) {
119      srv = null;
120      LOG.log(Level.FINEST, "Cannot use port: {0}. Will try another", portNumber);
121    }
122    return srv;
123  }
124
125  /**
126   * get a random port number in min and max range.
127   *
128   * @return
129   */
130  private int getNextPort(final int maxPort, final int minPort) {
131    return minPort + (int) (Math.random() * ((maxPort - minPort) + 1));
132  }
133
134  /**
135   * It will be called from RuntimeStartHandler.
136   * As the Jetty server has been started at initialization phase, no need to start here.
137   *
138   * @throws Exception
139   */
140  @Override
141  public void start() throws Exception {
142  }
143
144  /**
145   * stop Jetty Server. It will be called from RuntimeStopHandler
146   *
147   * @throws Exception
148   */
149  @Override
150  public void stop() throws Exception {
151    server.stop();
152  }
153
154  @Override
155  public int getPort() {
156    return port;
157  }
158
159  /**
160   * Add a HttpHandler to Jetty Handler.
161   *
162   * @param httpHandler
163   */
164  @Override
165  public void addHttpHandler(final HttpHandler httpHandler) {
166    LOG.log(Level.INFO, "addHttpHandler: {0}", httpHandler.getUriSpecification());
167    jettyHandler.addHandler(httpHandler);
168  }
169}