ohair@286: /* alanb@368: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.xml.internal.ws.transport.http.server; ohair@286: ohair@286: import com.sun.net.httpserver.HttpContext; ohair@286: import com.sun.net.httpserver.HttpServer; ohair@286: import com.sun.xml.internal.ws.server.ServerRtException; ohair@286: ohair@286: import java.net.InetSocketAddress; ohair@286: import java.net.URL; ohair@286: import java.util.HashMap; ohair@286: import java.util.HashSet; ohair@286: import java.util.Map; ohair@286: import java.util.Set; ohair@286: import java.util.concurrent.ExecutorService; ohair@286: import java.util.concurrent.Executors; ohair@286: import java.util.logging.Logger; ohair@286: ohair@286: /** ohair@286: * Manages all the WebService HTTP servers created by JAXWS runtime. ohair@286: * ohair@286: * @author Jitendra Kotamraju ohair@286: */ ohair@286: final class ServerMgr { ohair@286: ohair@286: private static final ServerMgr serverMgr = new ServerMgr(); ohair@286: private static final Logger logger = ohair@286: Logger.getLogger( ohair@286: com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".server.http"); ohair@286: private final Map servers = new HashMap(); ohair@286: ohair@286: private ServerMgr() {} ohair@286: ohair@286: /** ohair@286: * Gets the singleton instance. ohair@286: * @return manager instance ohair@286: */ ohair@286: static ServerMgr getInstance() { ohair@286: return serverMgr; ohair@286: } ohair@286: ohair@286: /* ohair@286: * Creates a HttpContext at the given address. If there is already a server ohair@286: * it uses that server to create a context. Otherwise, it creates a new ohair@286: * HTTP server. This sever is added to servers Map. ohair@286: */ ohair@286: /*package*/ HttpContext createContext(String address) { ohair@286: try { ohair@286: HttpServer server; ohair@286: ServerState state; ohair@286: URL url = new URL(address); ohair@286: int port = url.getPort(); ohair@286: if (port == -1) { ohair@286: port = url.getDefaultPort(); ohair@286: } ohair@286: InetSocketAddress inetAddress = new InetSocketAddress(url.getHost(), ohair@286: port); ohair@286: synchronized(servers) { ohair@286: state = servers.get(inetAddress); ohair@286: if (state == null) { ohair@286: logger.fine("Creating new HTTP Server at "+inetAddress); ohair@286: // Creates server with default socket backlog ohair@286: server = HttpServer.create(inetAddress, 0); ohair@286: server.setExecutor(Executors.newCachedThreadPool()); ohair@286: String path = url.toURI().getPath(); ohair@286: logger.fine("Creating HTTP Context at = "+path); ohair@286: HttpContext context = server.createContext(path); ohair@286: server.start(); ohair@286: ohair@286: // we have to get actual inetAddress from server, which can differ from the original in some cases. ohair@286: // e.g. A port number of zero will let the system pick up an ephemeral port in a bind operation, ohair@286: // or IP: 0.0.0.0 - which is used to monitor network traffic from any valid IP address ohair@286: inetAddress = server.getAddress(); ohair@286: ohair@286: logger.fine("HTTP server started = "+inetAddress); ohair@286: state = new ServerState(server, path); ohair@286: servers.put(inetAddress, state); ohair@286: return context; ohair@286: } ohair@286: } ohair@286: server = state.getServer(); ohair@286: ohair@286: if (state.getPaths().contains(url.getPath())) { ohair@286: String err = "Context with URL path "+url.getPath()+ " already exists on the server "+server.getAddress(); ohair@286: logger.fine(err); ohair@286: throw new IllegalArgumentException(err); ohair@286: } ohair@286: ohair@286: logger.fine("Creating HTTP Context at = "+url.getPath()); ohair@286: HttpContext context = server.createContext(url.getPath()); ohair@286: state.oneMoreContext(url.getPath()); ohair@286: return context; ohair@286: } catch(Exception e) { ohair@286: throw new ServerRtException("server.rt.err",e ); ohair@286: } ohair@286: } ohair@286: ohair@286: /* ohair@286: * Removes a context. If the server doesn't have anymore contexts, it ohair@286: * would stop the server and server is removed from servers Map. ohair@286: */ ohair@286: /*package*/ void removeContext(HttpContext context) { ohair@286: InetSocketAddress inetAddress = context.getServer().getAddress(); ohair@286: synchronized(servers) { ohair@286: ServerState state = servers.get(inetAddress); ohair@286: int instances = state.noOfContexts(); ohair@286: if (instances < 2) { ohair@286: ((ExecutorService)state.getServer().getExecutor()).shutdown(); ohair@286: state.getServer().stop(0); ohair@286: servers.remove(inetAddress); ohair@286: } else { ohair@286: state.getServer().removeContext(context); ohair@286: state.oneLessContext(context.getPath()); ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: private static final class ServerState { ohair@286: private final HttpServer server; ohair@286: private int instances; ohair@286: private Set paths = new HashSet(); ohair@286: ohair@286: ServerState(HttpServer server, String path) { ohair@286: this.server = server; ohair@286: this.instances = 1; ohair@286: paths.add(path); ohair@286: } ohair@286: ohair@286: public HttpServer getServer() { ohair@286: return server; ohair@286: } ohair@286: ohair@286: public void oneMoreContext(String path) { ohair@286: ++instances; ohair@286: paths.add(path); ohair@286: } ohair@286: ohair@286: public void oneLessContext(String path) { ohair@286: --instances; ohair@286: paths.remove(path); ohair@286: } ohair@286: ohair@286: public int noOfContexts() { ohair@286: return instances; ohair@286: } ohair@286: ohair@286: public Set getPaths() { ohair@286: return paths; ohair@286: } ohair@286: } ohair@286: }