roc
roc

Reputation: 41

atmosphere @managedservice class is not invoked in jetty 9

I have a class annotated by @ManagedService, it is not invoked. Servlet container is Jetty9.2.3.v20140905, atmosphere-runtime 2.3.1,AtomsphereServlet. The AtmosphereServlet is loaded successfully, browser side request can reach the AtmosphereServlet but the annotated class is not invoked. The warning is server side:

WARN  org.atmosphere.websocket.DefaultWebSocketProcessor - No AtmosphereHandler or WebSocketHandler installed. Adding a default one.

here is configuration in Jetty web.xml

<servlet>
    <description>AtmosphereServlet</description>
    <servlet-name>AtmosphereServlet</servlet-name>
    <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
    <!-- List of init-param -->
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.shareableThreadPool</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.maxProcessingThreads</param-name>
        <param-value>10</param-value>
    </init-param>
    <init-param>
        <param-name>org.atmosphere.cpr.broadcaster.maxAsyncWriteThreads</param-name>
        <param-value>10</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <!-- If you want to use Servlet 3.0 -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>AtmosphereServlet</servlet-name>
    <!-- Any mapping -->
    <url-pattern>/pusher/*</url-pattern>
</servlet-mapping>

Here is the code: breakpoint here is not invoked:

@ManagedService(path = "/test")

public class SubscribeRequest {
    private Logger log = Logger.getLogger(this.getClass().getName());

    @Get
    public void onGet(AtmosphereResource r) {
        String channel=r.getRequest().getParameter("channel");
        if(channel == null) {
            return;
        }
        if(channel.startsWith("/project/")) {
            BroadcasterFactory f = r.getAtmosphereConfig().getBroadcasterFactory();           
            f.lookup(channel, true).addAtmosphereResource(r);
            log.log(Level.INFO, "Subscribe for " + channel + "\n");
            r.suspend();
        }else{
            //not support other channel yet
            log.log(Level.INFO, "Subscribe for NOT-SUPPORT channel:" + channel + "\n");
        }
    }

    @Message
    public String onMessage(AtmosphereResource r, String message) throws IOException {
        log.log(Level.INFO,message);
        return message;
    }

}

here is JS request:

var request = {
    url: '/pusher/test?channel=/project/201',
    contentType: 'application/json',
    logLevel: 'debug',
    transport: 'websocket',
    trackMessageLength: true,
    reconnectInterval: 5000,
    enableXDR: true,
    timeout: 60000
  };

I use embedded jetty, Here is the function to startjetty:

private void startJetty(String workingDir, String baseDir, String configDir, String contextPath, String warFile) throws Exception {
     Server server = new Server();
     .....
    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath(contextPath);
    if(runInsideIntelliJ) { // Allows running/debugging from within e.g. IntelliJ
      log.fine("Running project from inside IDE environment. Running directly from source web files.");
      webapp.setWar(workingDir+"/web/src/main/webapp/");
      String extraClasspath = workingDir + "/web/target/classes/";
      extraClasspath += ";" + new String(Files.readAllBytes(Paths.get(workingDir + "/web/web.debug.classpath")));
      webapp.setExtraClasspath(extraClasspath);
      webapp.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");

      webapp.addFilter("com.teb.web.CorsDebugFilter", "/protected/rest/*", EnumSet.allOf(DispatcherType.class));
    } else {
      webapp.setWar(warFile);
    }
    ServletHolder defaultServlet = new ServletHolder(DefaultServlet.class);
    defaultServlet.setInitParameter("cacheControl", "max-age=0,public");
    defaultServlet.setName("default");
    webapp.addServlet(defaultServlet, "/");

    org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
    classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");

    webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
            ".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");

    HandlerCollection handlers = new HandlerCollection();
    RequestLogHandler requestLogHandler = new RequestLogHandler();
    handlers.setHandlers(new Handler[]{webapp, /*rootContextHandler,*/ requestLogHandler});
    server.setHandler(handlers);

    ...
    // Start the server
    server.start();
    server.join();
  }

Here is Atmosphere framework startup print log, it looks the annotated managedservice class has been scanned:

2015-05-16 00:04:33,954 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Atmosphere is using org.atmosphere.cpr.DefaultAnnotationProcessor for processing annotation
2015-05-16 00:04:33,955 [main] INFO  org.atmosphere.cpr.DefaultAnnotationProcessor - AnnotationProcessor class org.atmosphere.cpr.DefaultAnnotationProcessor$ServletContainerInitializerAnnotationProcessor being used
2015-05-16 00:04:33,956 [main] WARN  org.atmosphere.cpr.DefaultAnnotationProcessor - Unable to detect annotations. Application may fail to deploy.
2015-05-16 00:04:33,957 [main] INFO  org.atmosphere.cpr.AnnotationHandler - Found Annotation in class com.teb.ea.web.webpush.SubscribeRequest being scanned: interface org.atmosphere.config.service.ManagedService
2015-05-16 00:04:33,959 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Auto detecting atmosphere handlers /WEB-INF/classes/
2015-05-16 00:04:33,960 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Auto detecting WebSocketHandler in /WEB-INF/classes/
2015-05-16 00:04:33,963 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed WebSocketProtocol org.atmosphere.websocket.protocol.SimpleHttpProtocol 
2015-05-16 00:04:34,003 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installing Default AtmosphereInterceptors
2015-05-16 00:04:34,004 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.CorsInterceptor : CORS Interceptor Support
2015-05-16 00:04:34,005 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.CacheHeadersInterceptor : Default Response's Headers Interceptor
2015-05-16 00:04:34,006 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.PaddingAtmosphereInterceptor : Browser Padding Interceptor Support
2015-05-16 00:04:34,007 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.AndroidAtmosphereInterceptor : Android Interceptor Support
2015-05-16 00:04:34,009 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.HeartbeatInterceptor : Heartbeat Interceptor Support
2015-05-16 00:04:34,010 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.SSEAtmosphereInterceptor : SSE Interceptor Support
2015-05-16 00:04:34,011 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.JSONPAtmosphereInterceptor : JSONP Interceptor Support
2015-05-16 00:04:34,012 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.JavaScriptProtocol : Atmosphere JavaScript Protocol
2015-05-16 00:04:34,012 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.WebSocketMessageSuspendInterceptor : org.atmosphere.interceptor.WebSocketMessageSuspendInterceptor
2015-05-16 00:04:34,013 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.OnDisconnectInterceptor : Browser disconnection detection
2015-05-16 00:04:34,013 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   org.atmosphere.interceptor.IdleResourceInterceptor : org.atmosphere.interceptor.IdleResourceInterceptor
2015-05-16 00:04:34,013 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Set org.atmosphere.cpr.AtmosphereInterceptor.disableDefaults to disable them.
2015-05-16 00:04:34,014 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor CORS Interceptor Support with priority FIRST_BEFORE_DEFAULT 
2015-05-16 00:04:34,015 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Default Response's Headers Interceptor with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Browser Padding Interceptor Support with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Android Interceptor Support with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.interceptor.HeartbeatInterceptor - HeartbeatInterceptor configured with padding value 'X', client frequency 60 seconds and server frequency 0 seconds
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Heartbeat Interceptor Support with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor SSE Interceptor Support with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor JSONP Interceptor Support with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Atmosphere JavaScript Protocol with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor org.atmosphere.interceptor.WebSocketMessageSuspendInterceptor with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor Browser disconnection detection with priority AFTER_DEFAULT 
2015-05-16 00:04:34,016 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Installed AtmosphereInterceptor org.atmosphere.interceptor.IdleResourceInterceptor with priority BEFORE_DEFAULT 
2015-05-16 00:04:34,017 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Using EndpointMapper class org.atmosphere.util.DefaultEndpointMapper
2015-05-16 00:04:34,017 [main] WARN  org.atmosphere.cpr.AtmosphereFramework - No BroadcasterCache configured. Broadcasted message between client reconnection will be LOST. It is recommended to configure the org.atmosphere.cache.UUIDBroadcasterCache
2015-05-16 00:04:34,017 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Default Broadcaster Class: org.atmosphere.cpr.DefaultBroadcaster
2015-05-16 00:04:34,017 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Broadcaster Shared List Resources: false
2015-05-16 00:04:34,017 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Broadcaster Polling Wait Time 100
2015-05-16 00:04:34,017 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Shared ExecutorService supported: true
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Messaging Thread Pool Size: 10
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Async I/O Thread Pool Size: 10
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Using BroadcasterFactory: org.atmosphere.cpr.DefaultBroadcasterFactory
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Using AtmosphereResurceFactory: org.atmosphere.cpr.DefaultAtmosphereResourceFactory
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Using WebSocketProcessor: org.atmosphere.websocket.DefaultWebSocketProcessor
2015-05-16 00:04:34,018 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Invoke AtmosphereInterceptor on WebSocket message true
2015-05-16 00:04:34,019 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - HttpSession supported: false
2015-05-16 00:04:34,019 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Atmosphere is using org.atmosphere.inject.InjectableObjectFactory for dependency injection and object creation
2015-05-16 00:04:34,019 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Atmosphere is using async support: org.atmosphere.container.Jetty9AsyncSupportWithWebSocket running under container: jetty/9.2.3.v20140905 with WebSocket enabled.
2015-05-16 00:04:34,020 [main] INFO  org.atmosphere.cpr.AtmosphereFramework - Atmosphere Framework 2.3.1 started.
2015-05-16 00:04:34,020 [main] INFO  org.atmosphere.cpr.AtmosphereFramework -   

So far, tried the follows:

1 add the follow init-param

    <init-param>
        <param-name>org.atmosphere.cpr.packages</param-name>
        <param-value>com.mobilaris.ea.web.webpush</param-value>
    </init-param>

2 set annotated class path same as servlet mapping in web.xml, it is /pusher/test

3 replace @ManagedService with AtmosphereHandler, get the same warning and my Handler is not invoked. It is complete same issue as managedservice annotation.

The strange is the client request doesn't invoke my annotated class, but websocket still connect successfully printed in browser console. It is also proved in wireshark, the websocket connect do established. It looks Atmosphere framework is using something default to deal with the request and establishing the websocket connection which i don't want to have,i want the request should be controlled in my annotated class, so that my class (in onready/on get) can check and decide to conn or not.

Here is the browser side console log:

atmosphere.js:3221 Invoking executeWebSocket
atmosphere.js:3221 Using URL: ws://localhost:9999/pusher/test?channel=201&X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.2.11-javascript&X-Atmosphere-Transport=websocket&X-Atmosphere-TrackMessageSize=true&Content-Type=application/json&X-atmo-protocol=true
...
atmosphere.js:3221 Sat May 16 2015 08:03:50 GMT+0200 (CEST) Atmosphere: websocket.onopen
atmosphere.js:3221 Websocket successfully opened
...
atmosphere.js:3221 Sat May 16 2015 08:04:50 GMT+0200 (CEST) Atmosphere: Firing closedByClient
angular-1.3.14.js:11607 ReferenceError: author is not defined
    at Object.request.onClientTimeout (http://localhost:9999/authedfolder/js/my.js:41:57)
    at http://spyboost.github.io/angular-atmosphere/service/angular-atmosphere-service.js:16:30
    at Scope.$get.Scope.$eval (http://localhost:9999/authedfolder/components/angularjs/angular-1.3.14.js:14401:28)
    at Scope.$get.Scope.$apply (http://localhost:9999/authedfolder/components/angularjs/angular-1.3.14.js:14500:23)
    at Object.subscribe.angular.forEach.result.(anonymous function) [as onClientTimeout] (http://spyboost.github.io/angular-atmosphere/service/angular-atmosphere-service.js:15:28)
    at _f (http://localhost:9999/authedfolder/components/atmosphere/atmosphere.js:2767:31)
    at _invokeFunction (http://localhost:9999/authedfolder/components/atmosphere/atmosphere.js:2721:17)
    at _invokeCallback (http://localhost:9999/authedfolder/components/atmosphere/atmosphere.js:2850:21)
    at _onClientTimeout (http://localhost:9999/authedfolder/components/atmosphere/atmosphere.js:1636:17)
    at http://localhost:9999/authedfolder/components/atmosphere/atmosphere.js:1623:25(anonymous function) @ angular-1.3.14.js:11607$get @ angular-1.3.14.js:8557$get.Scope.$apply @ angular-1.3.14.js:14502subscribe.angular.forEach.result.(anonymous function) @ angular-atmosphere-service.js:15_f @ atmosphere.js:2767_invokeFunction @ atmosphere.js:2721_invokeCallback @ atmosphere.js:2850_onClientTimeout @ atmosphere.js:1636(anonymous function) @ atmosphere.js:1623
atmosphere.js:3221 Sat May 16 2015 08:04:50 GMT+0200 (CEST) Atmosphere: Firing closedByClient
atmosphere.js:3221 Sat May 16 2015 08:04:50 GMT+0200 (CEST) Atmosphere: websocket.onclose
atmosphere.js:3221 Websocket closed, reason: Unknown: no status code was provided even though one was expected.
atmosphere.js:3221 Websocket closed, wasClean: true

Upvotes: 1

Views: 1057

Answers (2)

roc
roc

Reputation: 41

Finally find the reason and solution.

root cause:

atmosphere-runtime.jar is not in WEB-INF/lib folder. If you don't have any problem to put it into WEB-INF/lib folder by adding dependency in your web app pom, just do it.

In my case,i got "slf4j java.lang.LinkageError loader constraint violation",because two pom modules (one of them is webapp module) both put atmosphere dependency in their pom file. Then Jetty classloader and default classloader both load atmosphere class.

Solution:

  1. only put dependency in one pom, if you need change your code,you have to do so.
  2. adding exclusion to atmosphere dependency:

  <dependency>
      <groupId>org.atmosphere</groupId>
      <artifactId>atmosphere-runtime</artifactId>
      <exclusions>
          <exclusion>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-log4j12</artifactId>
          </exclusion>
          <exclusion>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-api</artifactId>
          </exclusion>
          <exclusion>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
          </exclusion>
      </exclusions>
  </dependency>

If you still want to leave atmosphere-runtime.jar in other folder than WEB-INF/lib, you can add the following to your web.xml, it do invoke my annotated class, but i am not sure its a good solution.

<init-param>
    <param-name>org.atmosphere.cpr.AtmosphereHandler</param-name>
    <param-value>com.teb.web.webpush.SubscribeRequest</param-value>
</init-param>

Upvotes: 2

jfarcand
jfarcand

Reputation: 1705

Are you using Jetty 9 embed interface by anay chance? Anyway just add in your web.xml

    <init-param>
        <param-name>org.atmosphere.cpr.packages</param-name>
        <param-value>your package name</param-value>
    </init-param>

And also make sure your class define a package :-)

Upvotes: 0

Related Questions