javaspringservletsjettycometd

Cometd, Jetty : Cometd wont start, abstract error :javax.servlet.ServletOutputStream.setWriteListener


I am trying to run our Spring-MVC application which has Cometd(3.0.9) on Jetty 9.2. Currently it's working perfectly with Tomcat7, but we are checking out Jetty as another application container for some other requirements. However, Cometd won't start, and throws a 500. Here is the only error we get in backend again and again :

2017-09-29 12:48:17.137:WARN:oejs.HttpInput:qtp717356484-66: java.lang.AbstractMethodError: javax.servlet.ServletOutputStream.setWriteListener(Ljavax/servlet/WriteListener;)V

web.xml :

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
         http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
 <servlet>
        <servlet-name>cometd</servlet-name>
        <servlet-class>org.cometd.server.CometDServlet</servlet-class>
        <init-param>
            <param-name>maxSessionsPerBrowser</param-name>
            <param-value>10</param-value>
        </init-param>
        <init-param>
            <param-name>allowMultiSessionsNoBrowser</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>timeout</param-name>
            <param-value>60000</param-value>
        </init-param>
        <init-param>
            <param-name>long-polling.jsonp.timeout</param-name>
            <param-value>30000</param-value>
        </init-param>
        <init-param>
            <param-name>long-polling.timeout</param-name>
            <param-value>40000</param-value>
        </init-param>
        <init-param>
            <param-name>interval</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>maxInterval</param-name>
            <param-value>300000</param-value>
        </init-param>
        <init-param>
            <param-name>long-polling.multiSessionInterval</param-name>
            <param-value>2000</param-value>
        </init-param>
        <init-param>
            <param-name>multiFrameInterval</param-name>
            <param-value>1000</param-value>
        </init-param>
        <init-param>
            <param-name>logLevel</param-name>
            <param-value>3</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>


    <servlet-mapping>
        <servlet-name>cometd</servlet-name>
        <url-pattern>/cometd/*</url-pattern>
    </servlet-mapping>


    <filter>
        <filter-name>cross-origin</filter-name>
        <filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
        <async-supported>true</async-supported>

    </filter>
    <filter-mapping>
        <filter-name>cross-origin</filter-name>
        <url-pattern>/cometd/*</url-pattern>
    </filter-mapping>

Console error :

POST /cometd/handshake HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 201
Accept: */*
Origin: http://localhost:8080
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/61.0.3163.79 Chrome/61.0.3163.79 Safari/537.36
Content-Type: application/json;charset=UTF-8
DNT: 1
Referer: http://localhost:8080/canvaslisting
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Cookie: BAYEUX_BROWSER=1ul0bye0whhe511o; language=de; express_sid=s%3APCZq7dlCE8SlD6Iz86erUOv9tzSY3ByZ.4I%2BjSqnjONlhbuZOW90xM%2BeVjDnGQv0h0faztPBGan8; token=t.acvNouIKHegdIIFTjUjV; io=UiTHlpSm-T0vFYL1AAAA; JSESSIONID=1xktmtvfdgw5qtfqsf4et10g; _gat=1; sessionID=s.0dd75393a703ba234388cc605b84b790%2Cs.6fd7622c942a1808476c55355c46c8e4%2Cs.0dd75393a703ba234388cc605b84b790%2Cs.6fd7622c942a1808476c55355c46c8e4; _ga=GA1.1.1967903258.1505904823; _gid=GA1.1.1406412351.1506495950

HTTP/1.1 500 Server Error
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: 
Content-Type: application/json;charset=UTF-8
Content-Length: 0
Server: Jetty(9.2.22.v20170606)

Cometd dependencies :

<!-- Cometd dependencies -->
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>bayeux-api</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <dependency>
            <groupId>org.cometd.javascript</groupId>
            <artifactId>cometd-javascript-jquery</artifactId>
            <version>${cometd-version}</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-server</artifactId>
            <version>${cometd-version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-client</artifactId>
            <version>9.2.9.v20150224</version>
        </dependency>

        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-client</artifactId>
            <version>${cometd-version}</version>
        </dependency>

        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-annotations</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-servlets -->
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlets</artifactId>
        </dependency>

BayeuxInitializer :

@Component
public class BayeuxInitializer implements DestructionAwareBeanPostProcessor, ServletContextAware {
    private BayeuxServer bayeuxServer;
    private ServerAnnotationProcessor processor;

    @Inject
    private void setBayeuxServer(BayeuxServer bayeuxServer) {
        this.bayeuxServer = bayeuxServer;
    }

    @PostConstruct
    private void init(){

        this.processor = new ServerAnnotationProcessor(bayeuxServer);
    }

    @PreDestroy
    private void destroy() {
    }

    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        processor.processDependencies(bean);
        processor.processConfigurations(bean);
        processor.processCallbacks(bean);

        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
        return bean;
    }

    public void postProcessBeforeDestruction(Object bean, String name) throws BeansException {
        processor.deprocessCallbacks(bean);
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    public BayeuxServer bayeuxServer() {

        return new BayeuxServerImpl();
    }

    public void setServletContext(ServletContext servletContext) {
        servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer);
    }
}



 @Listener(value = "/service/online")
    public void OnlineNotifications(ServerSession remote, ServerMessage.Mutable message) {
        Person person = this.personService.getCurrentlyAuthenticatedUser();

// This person is always null in Jetty, but not on Apache tomcat.
}

Solution

  • Your web.xml declared the web application to be Servlet 3.1.

    ServletOutputStream.setWriteListener(WriteListener) is a method that has been added to Servlet 3.1.

    The error you get:

    java.lang.AbstractMethodError: javax.servlet.ServletOutputStream.setWriteListener(Ljavax/servlet/WriteListener;)V
    

    says that you have compiled your application against a Servlet 3.1 jar, but you are running it in an environment that does not provide such jar, probably just a Servlet 3.0 jar.

    Jetty 9.2.x, out of the box, supports Servlet 3.1.

    I suspect that you have a bad classpath where you reference old jars that cause you that error, so I would double check that first.

    If you're deploying your web application in a standalone Jetty 9.2.x server, please make sure that the jars in your web application's WEB-INF/lib are correct.