1

The client calls a web service at http://localhost:8080/soap/v1/myservice

This maps nicely to my service class, and my method gets called.

In some situations I'd like to have access within that method to information from the http request. What I just can't get is the path (or the full url).

There is information available in the injectable WebServiceContext, like so:

@WebService @Service
public class MySoapService {

  @Resource
  private WebServiceContext webServiceContext;

  @WebMethod
  public String requestInfo() {
    MessageContext mc = webServiceContext.getMessageContext();
    return makeMsg(mc);
  }

  private String makeMsg(MessageContext messageContext) {
    StringBuilder sb = new StringBuilder();
    sb.append("Request method: "+messageContext.get(MessageContext.HTTP_REQUEST_METHOD));
    sb.append(", Path: "+messageContext.get(MessageContext.PATH_INFO));
    sb.append(", Query string: "+messageContext.get(MessageContext.QUERY_STRING));
    sb.append(", User agent: "+((Map)messageContext.get(MessageContext.HTTP_REQUEST_HEADERS)).get("user-agent"));
    sb.append(", Content type: "+((Map)messageContext.get(MessageContext.HTTP_REQUEST_HEADERS)).get("content-type"));
    sb.append(", Http accept: "+((Map)messageContext.get(MessageContext.HTTP_REQUEST_HEADERS)).get("accept"));
    sb.append(", Http host: "+((Map)messageContext.get(MessageContext.HTTP_REQUEST_HEADERS)).get("host"));
    sb.append(", Connection: "+((Map)messageContext.get(MessageContext.HTTP_REQUEST_HEADERS)).get("connection"));
    System.out.println(messageContext);
    return sb.toString();
  }

}

However, the path requested by messageContext.get(MessageContext.PATH_INFO)) is null.

Example result:

Request method: POST, Path: null, Query string: null, User agent: [JAX-WS RI 2.2.4-b01], Content type: [text/xml; charset=utf-8], Http accept: [text/xml, multipart/related], Http host: [localhost], Connection: [keep-alive]

I am also able to get the info whether it was https or not, but it requires an ugly cast and field access:

((AbstractWebServiceContext) webServiceContext).getRequestPacket().wasTransportSecure

In the debugger I can see the url's path, but without reflection I can't get to it. There just has to be a clean way to get it, no?

intellij debugger shows url

Since SO resized my screenshot without adding a click-to-enlarge, here is the important part: enter image description here

My dependencies:

    <dependency>
        <groupId>org.glassfish.grizzly</groupId>
        <artifactId>grizzly-http-server-jaxws</artifactId>
        <version>2.3.18</version>
    </dependency>

which itself uses

    <dependency>
        <groupId>javax.xml.ws</groupId>
        <artifactId>jaxws-api</artifactId>
        <version>2.2.5</version>
    </dependency>

There are some similar questions on SO, but none helps me.

mc.get(MessageContext.SERVLET_REQUEST) returns null as for this person wsContext.getMessageContext().get(MessageContext.SERVLET_REQUEST) returns null on Jetty? or this Geting the IP Address Of A client For a webservice or this How can I access the ServletContext from within a JAX-WS web service?

To reproduce, this code is available on GitHub https://github.com/optimaize/soapworks at first run (debug) the Boot class, then the RequestInfoServiceImplTest.

Community
  • 1
  • 1
Fabian Kessler
  • 804
  • 11
  • 12

2 Answers2

3

Please check WebServiceContext.getMessageContext().get( "org.apache.cxf.request.url" ).toString()

Jack
  • 193
  • 11
0

Here is a way to extract the URI using reflection. I'm using it as a temporary hack.

import com.sun.xml.ws.api.server.WebServiceContextDelegate;
import com.sun.xml.ws.server.AbstractWebServiceContext;
import org.jetbrains.annotations.NotNull;
import javax.xml.ws.WebServiceContext;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 */
public class RequestUrlExtractor {

    /**
     * Best effort. Uses reflection.
     * See http://stackoverflow.com/questions/28234303/how-do-i-get-the-full-request-url-in-a-java-jax-ws-webservice-webmethod
     * @return starting with a slash, eg "/my/service/url"
     * @throws RuntimeException in case of failure (api change)
     */
    @NotNull
    public String extractUri(@NotNull WebServiceContext webServiceContext) {
        WebServiceContextDelegate webServiceContextDelegate = ((AbstractWebServiceContext) webServiceContext).getRequestPacket().webServiceContextDelegate;
        Class<?> c = webServiceContextDelegate.getClass();
        Field field;
        try {
            field = c.getDeclaredField("request");
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        field.setAccessible(true);
        Object result;
        try {
            result = field.get(webServiceContextDelegate);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        c = result.getClass();
        try {
            field = c.getDeclaredField("request");
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
        field.setAccessible(true);
        Object request;
        try {
            request = field.get(result);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        java.lang.reflect.Method method;
        try {
            method = request.getClass().getMethod("getRequestURI");
        } catch (SecurityException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        Object uri;
        try {
            uri = method.invoke(request);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        if (!(uri instanceof String)) {
            throw new RuntimeException("Not a string!");
        }
        return (String)uri;
    }

}
Fabian Kessler
  • 804
  • 11
  • 12