Hi all, Please review this issue and patch.
Thanks, Yuji 2015-10-29 3:22 GMT+09:00 KUBOTA Yuji <kubota.y...@gmail.com>: > Hi all, > > I'm at the HackerGarten @ JavaOne15, and write a patch for OpenJDK > community. This's second times from JavaOne14. :) > > We find an unexpected exception in JAX-WS, so I write a patch to fix it. > We think that this issue may block the migration to JDK9 from JDK7. > > If we bind 0.0.0.0 ( using as wildcard ) to publish multiple as the > following test code, JDK9 (and JDK8) returns "java.net.BindException: > Address already in use.” as the below. But JDK7 does NOT return the > exception. > > - Test code for reproduce > --- > import javax.jws.*; > import javax.xml.ws.*; > > public class WSTest{ > > @WebService > public static class Method1{ > @WebMethod > public String getMethod1Value(){ > return "from Method1"; > } > } > > @WebService > public static class Method2{ > @WebMethod > public String getMethod2Value(){ > return "from Method2"; > } > } > > public static void main(String[] args) throws Exception{ > Endpoint endPoint1 = Endpoint.publish("http://0.0.0.0:8081/method1", > new > Method1()); > Endpoint endPoint2 = Endpoint.publish("http://0.0.0.0:8081/method2", > new > Method2()); > > System.out.println("Sleep 3 secs..."); > > Thread.sleep(3000); > > endPoint2.stop(); > endPoint1.stop(); > } > > } > --- > > - StackTrace > --- > Exception in thread "main" > com.sun.xml.internal.ws.server.ServerRtException: Server Runtime > Error: java.net.BindException: Address already in use > at > com.sun.xml.internal.ws.transport.http.server.ServerMgr.createContext(ServerMgr.java:117) > at > com.sun.xml.internal.ws.transport.http.server.HttpEndpoint.publish(HttpEndpoint.java:64) > at > com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:232) > at > com.sun.xml.internal.ws.spi.ProviderImpl.createAndPublishEndpoint(ProviderImpl.java:126) > at javax.xml.ws.Endpoint.publish(Endpoint.java:240) > at wstest.WSTest.main(WSTest.java:27) > Caused by: java.net.BindException: Address already in use > at sun.nio.ch.Net.bind0(Native Method) > at sun.nio.ch.Net.bind(Net.java:432) > at sun.nio.ch.Net.bind(Net.java:424) > at > sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:223) > at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74) > at sun.net.httpserver.ServerImpl.<init>(ServerImpl.java:102) > at sun.net.httpserver.HttpServerImpl.<init>(HttpServerImpl.java:50) > at > sun.net.httpserver.DefaultHttpServerProvider.createHttpServer(DefaultHttpServerProvider.java:35) > at com.sun.net.httpserver.HttpServer.create(HttpServer.java:130) > at > com.sun.xml.internal.ws.transport.http.server.ServerMgr.createContext(ServerMgr.java:86) > ... 5 more > ----- > > To publishes the Endpoint, JAX-WS checks whether the HttpContext has > been created by given address, then creates a HttpContext if do not > exist. > If we sets 0.0.0.0 as given address, JAX-WS checks by > ServerSocket#getLocalSocketAddress() (server local address), so > returns BindException when 0.0.0.0 has been blinded already. > > Why so? JAX_WS-941[1] fixes NPE in Endpoint.stop but do not think > about above situation. And JAX_WS-941 does not back port to JDK7. > > So I write a patch which is based jdk9/dev/jaxws (changeset: > 637:2d84c6f4cbba) to fix the BindException with JAX_WS-941. > Please review this patch :) > > [1]: https://java.net/jira/browse/JAX_WS-941 > > - Patch > --- > diff -r 2d84c6f4cbba > src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java > --- > a/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java > Thu Oct 22 08:47:47 2015 -0700 > +++ > b/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/ServerMgr.java > Tue Oct 27 19:48:35 2015 +0900 > @@ -38,6 +38,7 @@ > import java.util.concurrent.ExecutorService; > import java.util.concurrent.Executors; > import java.util.logging.Logger; > +import java.util.Optional; > > /** > * Manages all the WebService HTTP servers created by JAXWS runtime. > @@ -81,24 +82,38 @@ > synchronized(servers) { > state = servers.get(inetAddress); > if (state == null) { > - logger.fine("Creating new HTTP Server at "+inetAddress); > - // Creates server with default socket backlog > - server = HttpServer.create(inetAddress, 0); > - server.setExecutor(Executors.newCachedThreadPool()); > - String path = url.toURI().getPath(); > - logger.fine("Creating HTTP Context at = "+path); > - HttpContext context = server.createContext(path); > - server.start(); > + final int finalPortNum = port; > + Optional<ServerState> stateOpt = > + servers.values() > + .stream() > + .filter(s -> s.getServer() > + .getAddress() > + .getPort() == > finalPortNum) > + .findAny(); > > - // we have to get actual inetAddress from server, > which can differ from the original in some cases. > - // e.g. A port number of zero will let the system > pick up an ephemeral port in a bind operation, > - // or IP: 0.0.0.0 - which is used to monitor > network traffic from any valid IP address > - inetAddress = server.getAddress(); > + if (inetAddress.getAddress().isAnyLocalAddress() && > + stateOpt.isPresent()) { > + state = stateOpt.get(); > + } else { > + logger.fine("Creating new HTTP Server at > "+inetAddress); > + // Creates server with default socket backlog > + server = HttpServer.create(inetAddress, 0); > + server.setExecutor(Executors.newCachedThreadPool()); > + String path = url.toURI().getPath(); > + logger.fine("Creating HTTP Context at = "+path); > + HttpContext context = server.createContext(path); > + server.start(); > > - logger.fine("HTTP server started = "+inetAddress); > - state = new ServerState(server, path); > - servers.put(inetAddress, state); > - return context; > + // we have to get actual inetAddress from > server, which can differ from the original in some cases. > + // e.g. A port number of zero will let the > system pick up an ephemeral port in a bind operation, > + // or IP: 0.0.0.0 - which is used to monitor > network traffic from any valid IP address > + inetAddress = server.getAddress(); > + > + logger.fine("HTTP server started = "+inetAddress); > + state = new ServerState(server, path); > + servers.put(inetAddress, state); > + return context; > + } > } > } > server = state.getServer(); > ---