/* * Copyright 2013-2015 EMC Corporation. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://www.apache.org/licenses/LICENSE-2.0.txt * * or in the "license" file accompanying this file. This file 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 com.emc.ecs.sync.rest; import com.sun.jersey.api.container.ContainerFactory; import com.sun.jersey.api.core.PackagesResourceConfig; import com.sun.jersey.api.core.ResourceConfig; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.core.UriBuilder; import java.net.BindException; import java.net.InetSocketAddress; import java.net.URI; import java.util.concurrent.Executors; public class RestServer { private static final Logger log = LoggerFactory.getLogger(RestServer.class); public static final String DEFAULT_HOST_NAME = "localhost"; public static final int DEFAULT_PORT = 9200; public static final int MAX_BIND_ATTEMPTS = 5; private String hostName; private int port; private HttpServer httpServer; private boolean autoPortEnabled = false; public RestServer() { this(DEFAULT_HOST_NAME, DEFAULT_PORT); } public RestServer(String hostName, int port) { this.hostName = hostName; this.port = port > 0 ? port : DEFAULT_PORT; } public void start() { log.info("starting REST server..."); URI serverUri; int bindAttempts = 0; try { do { serverUri = createUri(); log.debug("Binding REST server to {}", serverUri); InetSocketAddress socket = new InetSocketAddress(serverUri.getPort()); if (serverUri.getHost() != null && serverUri.getHost().length() > 0) socket = new InetSocketAddress(serverUri.getHost(), serverUri.getPort()); try { bindAttempts++; httpServer = HttpServer.create(socket, 0); } catch (BindException e) { log.info("Could not bind to {}: {}", serverUri, e); if (!autoPortEnabled) throw e; if (bindAttempts >= MAX_BIND_ATTEMPTS) throw new RuntimeException("Exceeded maximum bind attempts", e); port++; } } while (httpServer == null); httpServer.setExecutor(Executors.newCachedThreadPool()); httpServer.createContext(serverUri.getPath(), ContainerFactory.createContainer(HttpHandler.class, createResourceConfig())); httpServer.start(); log.warn("REST server listening at {}", serverUri); } catch (Throwable t) { log.error("REST server failed to start: {}", (Object) t); throw new RuntimeException("REST server failed to start", t); } } public void stop(int maxWaitSeconds) { log.info("stopping REST server..."); httpServer.stop(maxWaitSeconds); } protected URI createUri() { return UriBuilder.fromUri("http://" + hostName + "/").port(port).build(); } protected ResourceConfig createResourceConfig() { return new PackagesResourceConfig(RestServer.class.getPackage().getName()); } public String getHostName() { return hostName; } public int getPort() { return port; } public boolean isAutoPortEnabled() { return autoPortEnabled; } public void setAutoPortEnabled(boolean autoPortEnabled) { this.autoPortEnabled = autoPortEnabled; } }