Frage

I am currently trying to setup a webservice endpoint (within an JBoss AS 6.1.0.FINAL enviroment) to enable clients to long-poll for serverside events without blocking listener threads at the serverside.

Since there does not seem to be a standard solution I found this blog post about CXF continuations (which beside is the WS-Impl. in JBoss).

I could transfer the example as JAX-WS

import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.servlet.annotation.WebServlet;
import javax.xml.ws.BindingType;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import org.apache.cxf.continuations.Continuation;
import org.apache.cxf.continuations.ContinuationProvider;

@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
@WebServlet(asyncSupported = true, urlPatterns = "/LongpollWebservice")
@WebService(targetNamespace = "http://longpoll.edu/", name = "LongpollWebservice", serviceName = "LongpollWebservice", portName = "LongpollWebservice")
public class LongpollWebserviceImpl implements LongpollWebservice {

    @Resource
    WebServiceContext ctx;

    @Override
    @WebMethod
    public List<EventBase> getEvents(String topic, Date since) {
        final ContinuationProvider cp = (ContinuationProvider) ctx.getMessageContext().get(ContinuationProvider.class.getName());
        final Continuation c = cp.getContinuation();
        if (c.isNew()) {
            c.suspend(10000);
            return null;
        } else {
            return Collections.emptyList();
        }
    }
}

The Continuation API comes from

<dependency>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-api</artifactId>
    <version>2.3.1</version>
    <scope>provided</scope>
</dependency>

This is a reduced example. The invocation of c.suspend(10000); should mark the current servlet invocation as State.SUSPENDED. After ten seconds, the suspension should timeout and the request should be reinvoked with c.isNew() == false. (In a real world example the Continuation could be passed to an JMS-Listener Bean or stateful CDI-Eventlistener and c.setObject(event); c.resume(); would be called by the event-dispatcher once an event is available and ready to be delivered)

The CXF interceptor chain should interrupt the executing thread with an SuspendedInvocationException and reschedule the webservice invocation. It compiles and deploys fine on a JBoss 6.1.0 FINAL so far. The wsdl is perfectly delivered.

BUT: when I call getEvents() from a Webservice-Client, the SuspendedInvocationException does not seem to be caught correctly. The whole invocation crashes with the following stacktrace:

14:39:59,578 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/longpoll-warfacade].[edu.hsos.dwe.wss.longpoll.warfacade.LongpollWebserviceImpl]] Servlet.service() for servlet edu.hsos.dwe.wss.longpoll.warfacade.LongpollWebserviceImpl threw exception: org.apache.cxf.continuations.SuspendedInvocationException
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:258) [:2.3.1-patch-01]
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:113) [:2.3.1-patch-01]
at org.apache.cxf.transport.servlet.ServletDestination.invoke(ServletDestination.java:97) [:2.3.1-patch-01]
at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:461) [:2.3.1-patch-01]
at org.jboss.wsf.stack.cxf.ServletControllerExt.invoke(ServletControllerExt.java:172) [:3.4.1.GA]
at org.jboss.wsf.stack.cxf.RequestHandlerImpl.handleHttpRequest(RequestHandlerImpl.java:57) [:3.4.1.GA]
at org.jboss.wsf.stack.cxf.transport.ServletHelper.callRequestHandler(ServletHelper.java:156) [:3.4.1.GA]
at org.jboss.wsf.stack.cxf.CXFNonSpringServletExt.invoke(CXFNonSpringServletExt.java:90) [:3.4.1.GA]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:179) [:2.3.1-patch-01]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:103) [:2.3.1-patch-01]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [:1.0.0.Final]
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:159) [:2.3.1-patch-01]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:324) [:6.1.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.1.0.Final]
at org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:63) [:6.1.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:274) [:6.1.0.Final]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:242) [:6.1.0.Final]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [:6.1.0.Final]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [:6.1.0.Final]
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:181) [:6.1.0.Final]
at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.1.0.Final]
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.1.0.Final]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:159) [:6.1.0.Final]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.1.0.Final]
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.1.0.Final]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.1.0.Final]
at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.1.0.Final]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.1.0.Final]
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.1.0.Final]
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.1.0.Final]
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.1.0.Final]
at java.lang.Thread.run(Thread.java:619) [:1.6.0_18]

So finally my question: Is there anyone who has experience with CXF Continuation and WS and can give me a hint what could be wrong with this attemp?

I do not really get why the Exception is rethrown in PhaseInterceptorChain.doIntercept.

Kind regards, avithan

War es hilfreich?

Lösung

Solved:

  1. Install CXF 2.3.4 to jboss/common/lib (we need this issue fixed: https://issues.apache.org/jira/browse/CXF-3362).

  2. JBossWS-CXF does not catch SuspendedInvocationException. This seems to just been left out in jbossws-cxf-server. I filed an issue at https://issues.jboss.org/browse/JBWS-3409. The attached patch can easily be applied to a checkout of jbossws-cxf-3.4.1.GA (module jbossws-cxf-server) and recompiled with mvn package.

Kind regards

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top