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