blob: 67dce8b8088652b1c666057dcf6a8a2bcfcce637 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.reef.webserver;
import org.apache.reef.tang.annotations.Parameter;
import org.apache.reef.util.logging.LoggingScope;
import org.apache.reef.util.logging.LoggingScopeFactory;
import org.apache.reef.wake.remote.address.LocalAddressProvider;
import org.apache.reef.wake.remote.ports.TcpPortProvider;
import org.apache.reef.wake.remote.ports.parameters.TcpPortRangeBegin;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.bio.SocketConnector;
import javax.inject.Inject;
import java.net.BindException;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* HttpServer. It manages Jetty Server and Event Handlers
*/
public final class HttpServerImpl implements HttpServer {
/**
* Standard Java logger.
*/
private static final Logger LOG = Logger.getLogger(HttpServerImpl.class.getName());
/**
* JettyHandler injected in the constructor.
*/
private JettyHandler jettyHandler;
/**
* Jetty server.
*/
private final Server server;
/**
* port number used in Jetty Server.
*/
private final int port;
/**
* Logging scope factory.
*/
private final LoggingScopeFactory loggingScopeFactory;
/**
* The address provider for the HTTPServer.
*/
private final LocalAddressProvider addressProvider;
/**
* Constructor of HttpServer that wraps Jetty Server.
*
* @param jettyHandler
* @param portNumber
* @throws Exception
*/
@Inject
HttpServerImpl(final JettyHandler jettyHandler,
final LocalAddressProvider addressProvider,
@Parameter(TcpPortRangeBegin.class)final int portNumber,
final TcpPortProvider tcpPortProvider,
final LoggingScopeFactory loggingScopeFactory) throws Exception {
this.addressProvider = addressProvider;
this.loggingScopeFactory = loggingScopeFactory;
this.jettyHandler = jettyHandler;
int availablePort = portNumber;
Server srv = null;
try (final LoggingScope ls = this.loggingScopeFactory.httpServer()) {
final Iterator<Integer> ports = tcpPortProvider.iterator();
while (ports.hasNext() && srv == null) {
availablePort = ports.next();
srv = tryPort(availablePort);
}
if (srv != null) {
this.server = srv;
this.port = availablePort;
this.server.setHandler(jettyHandler);
LOG.log(Level.INFO, "Jetty Server started with port: {0}", availablePort);
} else {
throw new RuntimeException("Could not find available port for http");
}
}
}
private Server tryPort(final int portNumber) throws Exception {
Server srv = new Server();
final Connector connector = new SocketConnector();
connector.setHost(addressProvider.getLocalAddress());
connector.setPort(portNumber);
srv.addConnector(connector);
try {
srv.start();
LOG.log(Level.INFO, "Jetty Server started with port: {0}", portNumber);
} catch (final BindException ex) {
srv = null;
LOG.log(Level.FINEST, "Cannot use port: {0}. Will try another", portNumber);
}
return srv;
}
/**
* get a random port number in min and max range.
*
* @return
*/
private int getNextPort(final int maxPort, final int minPort) {
return minPort + (int) (Math.random() * ((maxPort - minPort) + 1));
}
/**
* It will be called from RuntimeStartHandler.
* As the Jetty server has been started at initialization phase, no need to start here.
*
* @throws Exception
*/
@Override
public void start() throws Exception {
}
/**
* stop Jetty Server. It will be called from RuntimeStopHandler
*
* @throws Exception
*/
@Override
public void stop() throws Exception {
server.stop();
}
@Override
public int getPort() {
return port;
}
/**
* Add a HttpHandler to Jetty Handler.
*
* @param httpHandler
*/
@Override
public void addHttpHandler(final HttpHandler httpHandler) {
LOG.log(Level.INFO, "addHttpHandler: {0}", httpHandler.getUriSpecification());
jettyHandler.addHandler(httpHandler);
}
}