Мы обнаружили эту проблему при реализации логики переподключения для конечной точки WS с использованием стека JAX-WS, развернутого на сервере Glassfishv2.1. Развертываем веб-сервис в кластерной среде. Чтобы упростить развертывание, мы используем 0.0.0.0 в качестве IP-адреса, на котором необходимо опубликовать конечную точку, чтобы к ней можно было получить доступ со всех доступных IP-адресов, относящихся к узлам кластера. Ниже приведен фрагмент кода для инициализации WS (веб-службы):
import javax.xml.ws.Endpoint;
.
.
//Implementor is the corresponding implementation object for the WS
Endpoint receiver = Endpoint.create(new Implementor());
.
receiver.setExecutor(threadPoolExecutor);
receiver.publish ("http://0.0.0.0:9545/context");
Мы вызываем receive.stop (), чтобы прекратить публикацию конечной точки в нашем коде очистки. Вот где мы получаем исключение нулевого указателя со следующей трассировкой стека:
java.lang.NullPointerException
at com.sun.xml.ws.transport.http.server.ServerMgr.removeContext(ServerMgr.java:123)
at com.sun.xml.ws.transport.http.server.HttpEndpoint.stop(HttpEndpoint.java:110)
at com.sun.xml.ws.transport.http.server.EndpointImpl.stop(EndpointImpl.java:167
Пытаясь найти причину NPE, мы обнаружили, что класс ServerMgr зависит от InetSocketAddress HttpServer, который прослушивает ip: порт URL-адреса, где публикуется конечная точка WS, для получения некоторой информации о состоянии из карта. Поскольку адрес inet "inet: /0.0.0.0" интерпретируется как "inet: / 0: 0: 0: 0: 0: 0: 0: 0", он не может найти запись на карте и, следовательно, NPE. Вот исходный код ServerMgr.
Чтобы доказать, что это действительно проблема, мы попытались воспроизвести логику кода ServerMgr, связанного с InetSocketAddress, в виде следующей программы:
import com.sun.net.httpserver.HttpContext;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main {
static final String URL_1 = "http://0.0.0.0:9545/context";
static final String URL_2 = "http://127.0.0.1:9548/context";
static final String URL_3 = "http://10.226.90.217:9549/context";
public void testUrl(String address){
try {
URL url = new URL(address);
Map<InetSocketAddress, Integer> map = new HashMap<InetSocketAddress, Integer>();
InetSocketAddress iaddr = new InetSocketAddress(url.getHost(), url.getPort());
map.put(iaddr, 1);
HttpServer server = HttpServer.create(iaddr, 5);
HttpContext context = server.createContext(url.toURI().getPath());
server.start();
System.out.println("original inet:"+iaddr+" and final inet:"+context.getServer().getAddress());
if(iaddr.equals(context.getServer().getAddress())){
System.out.println("equal");
Integer t = map.get(context.getServer().getAddress());
if( t == null){
System.out.println("You won");
}else{
System.out.println("You lose "+t);
}
}else{
System.out.println("not-equal");
}
server.stop(0);
map.clear();
} catch (URISyntaxException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args)
{
Main d = new Main();
d.testUrl(Main.URL_1);
d.testUrl(Main.URL_2);
d.testUrl(Main.URL_3);
}
}
Достаточно странно, мы получаем следующий результат в моем окне WindowsXP (Java версия 1.6.0_22)
equal--
original inet:/0.0.0.0:9545 and final inet:/0.0.0.0:9545
equal
You lose 1
equal--
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
equal--
original inet:/10.226.92.47:9549 and final inet:/10.226.92.47:9549
equal
You lose 1
и следующий вывод на моем устройстве dev
(Linux Tahoe 2.6.9-67.EL # 1 Ср 7 Ноября 13:43:31 EST 2007 x86_64 x86_64 x86_64 GNU / Linux)
(Java версия 1.6.0_17)
run:
original inet:/0.0.0.0:9545 and final inet:/0:0:0:0:0:0:0:0:9545
not-equal
original inet:/127.0.0.1:9548 and final inet:/127.0.0.1:9548
equal
You lose 1
original inet:/10.226.90.217:9549 and final inet:/10.226.90.217:9549
equal
You lose 1
Исходя из фона - у меня два вопроса:
- а. Почему интерпретируется 0.0.0.0
как адрес IPv6? (Кроме того, это проблема?
с ОС или JRE? Это ошибка
или особенность? и т.д.)
- б. У нас есть способ настроить
JRE интерпретировать 0.0.0.0 как адрес IPv4?
(Мы хотим продолжать использовать 0.0.0.0 в качестве конечной точки
адрес, поскольку это упрощает развертывание
нашего веб-сервиса)