I have an extension of this question. I have that exact code running on a Jetty Server, and other SOAP web services work perfectly. However, on this line:
HttpServletRequest req = (HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST);
System.out.println("Client IP = " + req.getRemoteAddr());
The server crashes with a null pointer exception. mc.get(MessageContext.SERVLET_REQUEST)
is returning null.
By comparison, mc.get(MessageContext.HTTP_REQUEST_METHOD
) returns "POST", so I assume that's working.
What can I do to fix this?
EDIT:
I've tried this fix to no avail.
I've also tried using the @Context annotation instead and got the same issue.
A System.out.println(mc) yields this:
{javax.xml.ws.wsdl.port={http://my.test.namespace.com/}testWSDLPort,
javax.xml.ws.soap.http.soapaction.uri="",
com.sun.xml.internal.ws.server.OneWayOperation=null,
javax.xml.ws.http.request.pathinfo=null,
...
...
and so on, and the list of values does NOT include javax.xml.ws.servlet.request, which is the value of MessageContext.SERVLET_REQUEST. What do I need to do to make sure the MessageContext has this value?
Currently the Jetty HTTP SPI JAX-WS implementation doesn't appear to properly inject the MessageContext into a web service. Try switching to Apache CXF instead. Once you have
- cxf-2.6.2.jar
- neethi-3.0.2.jar
- xmlschema-core-2.0.3.jar
on your project build path, you have to create a servlet class that extends the CXFNonSpringServlet and overrides the loadBus function like so:
public class SOAPServlet extends CXFNonSpringServlet {
private static final long serialVersionUID = 1L;
private Map<String, Object> endpoints;
public SOAPServlet(){
endpoints = new HashMap<String, Object>();
}
@Override
public void loadBus(ServletConfig servletConfig) {
super.loadBus(servletConfig);
// You could add the endpoint publish codes here
Bus bus = getBus();
BusFactory.setDefaultBus(bus);
Set s = endpoints.entrySet();
Iterator p = s.iterator();
while(p.hasNext()){
Map.Entry m = (Map.Entry)p.next();
String address = (String)m.getKey();
Object impl = (Object)m.getValue();
System.out.println("Publishing " + address);
Endpoint.publish(address, impl);
}
}
public void publish(String address, Object impl){
endpoints.put(address, impl);
}
}
And then where you are configuring your server, add these lines:
Server server = new Server(8080);
// Configure SOAP servlet
SOAPServlet servlet = new SOAPServlet();
ServletHolder SOAPServletHolder = new ServletHolder(servlet);
ServletContextHandler SOAPContext = new ServletContextHandler(server,"/",ServletContextHandler.SESSIONS);
SOAPContext.addServlet(SOAPServletHolder, "/*");
// Set server context handlers
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler []{SOAPContext});
server.setHandler(contexts);
// Publish SOAP Web service endpoints
servlet.publish("/MyWebServiceRelativeURL", new MyWebServiceImpl());
server.start();
server.join();
I encountered the same issue - instead of retrieving the SERVLET_REQUEST like that and getting null, I used the following:
com.sun.net.httpserver.HttpExchange server = (com.sun.net.httpserver.HttpExchange) mc.get("com.sun.xml.internal.ws.http.exchange");
System.out.println("Client IP = " + server.getRemoteAddress().toString());
This allows for retrieving of the IP address, port, etc.