Hi Yuji,
thanks for the patch - it fixes the issue and looks ok to me. I'll integrate it to standalone JAX-WS repo and it will be integrated into openjdk during next syncup.

Thanks
Miran



On 01/12/15 11:11, KUBOTA Yuji wrote:
Hi Miroslav and all,

Could you please review the below issue and patch?

I got the advice by Alan at net-dev. So I want to ask you.
http://mail.openjdk.java.net/pipermail/net-dev/2015-December/009361.html

----
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();
---

Thanks,
Yuji

Reply via email to