5

I have a stateful web service deployed onto Tomcat. It consists of factory service and main API service, and works just fine. Factory service returns a W3CEndpointReference to main API instance, and client uses the session.

Now, I'm trying to run the very same service as a standalone application. In this case, the W3CEndpointReference returned by the factory suddenly starts to point to factory URI, not to main service one.

When references from runs against Tomcat and standalone are compared, it becomes clear that standalone reference has a wrong URI. Specifically, it points to factory URI, not main API one.

Here's correct reference:

...
<ns3:Address>http://localhost:8080/td2ws/api</ns3:Address> 
...

Here's references when factory is called on standalone process:

<Address>http://localhost:9009/td2ws/factory</Address>

My understanding that some code under servlet context has a knowledge of correspondence between service class (Td2Ws) and it's URI, and adjusts the references accordingly. That piece of code is not in effect under standalone process though. I can even suspect that code uses sun-jaxws.xml, but I don't know how to "turn it on".

How can I make stateful web service in standalone application work?

Here are relevant parts of the code:

Factory service (stateless):

@WebService(targetNamespace="http://server.td2ws.sf.net/") 
public class Td2WsFactory {
    @WebMethod(operationName="StartSession", action="urn:StartSession")
    @WebResult(name="Reference")
    public W3CEndpointReference startSession() {
        StatefulWebServiceManager<Td2Ws> manager = Td2Ws.getManager();

        // for standalone execution only
        if( manager == null ) {
            manager = new StatefulInstanceResolver<Td2Ws>(Td2Ws.class);
            Td2Ws.setManager(manager);
        }

        Td2Ws session = new Td2Ws();
        return manager.export(W3CEndpointReference.class,session);
    }
}

Stateful API:

@Stateful
@WebService(targetNamespace="http://server.td2ws.sf.net/") 
@Addressing
public class Td2Ws {
    private static StatefulWebServiceManager<Td2Ws> manager;

    public static void setManager(StatefulWebServiceManager<Td2Ws> manager ) {
        Td2Ws.manager = manager;
    }

    public static StatefulWebServiceManager<Td2Ws> getManager() {
        return Td2Ws.manager;
    }

    @WebMethod(operationName="Login", action="urn:Login")
    public void login(
            @WebParam(name="Username") String username,
            @WebParam(name="Password") String password,
            @WebParam(name="Domain") String domain,
            @WebParam(name="Project") String project
            ) throws Td2WsException {

Client code (targeted to standalone):

public static void main(String[] args) throws Exception {
    Endpoint epf = Endpoint.publish("http://localhost:9009/td2ws/factory", new net.sf.td2ws.server.Td2WsFactory());
    Endpoint eps = Endpoint.publish("http://localhost:9009/td2ws/api", new net.sf.td2ws.server.Td2Ws());

    URL factoryUrl = new URL("http://localhost:9009/td2ws/factory?wsdl");
    QName factoryQname = new QName("http://server.td2ws.sf.net/", "Td2WsFactoryService");

    URL sessionUrl = new URL("http://localhost:9009/td2ws/api?wsdl");
    QName sessionQname = new QName("http://server.td2ws.sf.net/", "Td2WsService");

    Td2WsFactory factory = new Td2WsFactoryService(factoryUrl,factoryQname).getTd2WsFactoryPort();
    System.out.println("factory: "+factory);

    W3CEndpointReference session = factory.startSession();
    System.out.println("session: "+session);

    Td2WsService service = new Td2WsService(sessionUrl,sessionQname);
    System.out.println("service: "+service);

    Td2Ws port = service.getPort(session,Td2Ws.class);
    System.out.println("port: "+port);

    port.login(
            Config.get("td.user"), 
            Config.get("td.pass"),
            Config.get("td.domain"),
            Config.get("td.project"));
    System.out.println("logged in...");

That code fails on login() as the target object has no Login operation (it's wrongly targeted to factory URI, after all):

Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: 
Cannot find dispatch method for {http://server.td2ws.sf.net/}Login
Vladimir Dyuzhev
  • 18,130
  • 10
  • 48
  • 62

1 Answers1

0

I haven't done this in awhile, but I took a look at a functional stateful web service that I built some time ago. My Annotations are very similar to yours, except I have this at the top of my class:

public class MyService {

  @Resource
  WebServiceContext wsCtx;

  ...

}

Notice there is no modifier, if anything else I think it needs to be public, but I'm not positive. How the container knows to set this beats me, but it works. It must just look for any @Resource of type WebServiceContext and set it. You can access session information like so:

HttpServletRequest hRequest =  (HttpServletRequest)ctx.getMessageContext().get(MessageContext.SERVLET_REQUEST);

Session s = hRequest.getSession();
slambeth
  • 887
  • 5
  • 17