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.ports.TcpPortProvider; 025import org.apache.reef.wake.remote.ports.parameters.TcpPortRangeBegin; 026import org.mortbay.jetty.Server; 027 028import javax.inject.Inject; 029import java.net.BindException; 030import java.util.Iterator; 031import java.util.logging.Level; 032import java.util.logging.Logger; 033 034/** 035 * HttpServer. It manages Jetty Server and Event Handlers 036 */ 037public final class HttpServerImpl implements HttpServer { 038 /** 039 * Standard Java logger. 040 */ 041 private static final Logger LOG = Logger.getLogger(HttpServerImpl.class.getName()); 042 043 /** 044 * JettyHandler injected in the constructor. 045 */ 046 private JettyHandler jettyHandler; 047 048 /** 049 * Jetty server. 050 */ 051 private final Server server; 052 053 /** 054 * port number used in Jetty Server. 055 */ 056 private final int port; 057 058 /** 059 * Logging scope factory. 060 */ 061 private final LoggingScopeFactory loggingScopeFactory; 062 063 /** 064 * Constructor of HttpServer that wraps Jetty Server. 065 * 066 * @param jettyHandler 067 * @param portNumber 068 * @throws Exception 069 */ 070 @Inject 071 HttpServerImpl(final JettyHandler jettyHandler, 072 @Parameter(TcpPortRangeBegin.class) final int portNumber, 073 final TcpPortProvider tcpPortProvider, 074 final LoggingScopeFactory loggingScopeFactory) throws Exception { 075 076 this.loggingScopeFactory = loggingScopeFactory; 077 this.jettyHandler = jettyHandler; 078 int availablePort = portNumber; 079 Server srv = null; 080 081 try (final LoggingScope ls = this.loggingScopeFactory.httpServer()) { 082 083 final Iterator<Integer> ports = tcpPortProvider.iterator(); 084 while (ports.hasNext() && srv == null) { 085 availablePort = ports.next(); 086 srv = tryPort(availablePort); 087 } 088 089 if (srv != null) { 090 this.server = srv; 091 this.port = availablePort; 092 this.server.setHandler(jettyHandler); 093 LOG.log(Level.INFO, "Jetty Server started with port: {0}", availablePort); 094 } else { 095 throw new RuntimeException("Could not find available port for http"); 096 } 097 } 098 } 099 100 private Server tryPort(final int portNumber) throws Exception { 101 Server srv = new Server(portNumber); 102 try { 103 srv.start(); 104 LOG.log(Level.INFO, "Jetty Server started with port: {0}", portNumber); 105 } catch (final BindException ex) { 106 srv = null; 107 LOG.log(Level.FINEST, "Cannot use port: {0}. Will try another", portNumber); 108 } 109 return srv; 110 } 111 112 /** 113 * get a random port number in min and max range. 114 * 115 * @return 116 */ 117 private int getNextPort(final int maxPort, final int minPort) { 118 return minPort + (int) (Math.random() * ((maxPort - minPort) + 1)); 119 } 120 121 /** 122 * It will be called from RuntimeStartHandler. 123 * As the Jetty server has been started at initialization phase, no need to start here. 124 * 125 * @throws Exception 126 */ 127 @Override 128 public void start() throws Exception { 129 } 130 131 /** 132 * stop Jetty Server. It will be called from RuntimeStopHandler 133 * 134 * @throws Exception 135 */ 136 @Override 137 public void stop() throws Exception { 138 server.stop(); 139 } 140 141 @Override 142 public int getPort() { 143 return port; 144 } 145 146 /** 147 * Add a HttpHandler to Jetty Handler. 148 * 149 * @param httpHandler 150 */ 151 @Override 152 public void addHttpHandler(final HttpHandler httpHandler) { 153 LOG.log(Level.INFO, "addHttpHandler: {0}", httpHandler.getUriSpecification()); 154 jettyHandler.addHandler(httpHandler); 155 } 156}