tyrus
  1. tyrus
  2. TYRUS-103

WebSocket in GlassFish 4.0 Promoted Build 72: Unable to Inject CDI or EJB beans

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.0-b12
    • Fix Version/s: 1.0
    • Component/s: None
    • Labels:
      None
    • Environment:

      Glassfish Embedded Server Promoted 72 with Gradle

      Description

      I am reviewing the WebSockets bundled in the GlassFish 4.0 promoted
      build 72. I have successfully got a deployed WAR running in GlassFish
      embedded container using Gradle.

      Does the WebSockets implementation in this promoted build work
      currently against CDI?

      I tried the following code:

      @ApplicationScoped
      class SampleBean {
      @PostConstruct public void init() { System.out.printtf("%s.init()
      called\n", getClass().getSimpleName() );
      public getValue()

      { return "whatever"; }

      }

      @WebSockedEndpoint( "/test" )
      class SampleEndPoint {

      @Inject @ApplicationScoped private SampleBean sampleBean;

      @PostConstruct public void init()

      { System.out.printtf("%s.init() called\n", getClass().getSimpleName() ); // sampleBean is null }

      @WebSocketMessage
      public String echo(String message)

      { return "ECHO: " + message + " and CDI injected bean was "+sampleBean; // sampleBean is still null }

      }

      So far, CDI (or the WELD implementation) does not appear to inject any
      type of bean, including Application Scoped beans, in to an Endpoint.
      Is this a limitation of the current Tyrus reference implementation? Or
      is it part of the Web Socket spec?

      In fact, I never see SampleBean being initialised at all in the
      console output. Strange.

      Running the same code with a Servlet instead of a WebSocketEndPoint is successfully.

      I also attempted injecting a @Singleton @Startup EJB instance into the WebSocket that also failed

        Activity

        Hide
        peter_pilgrim added a comment -

        PS: Programmatic JNDI look-up does work with EJB. The Tyrus implementation is missing the appropriate hooks in to CDI and EJB containers for post initialisation of the endpoints.

        Show
        peter_pilgrim added a comment - PS: Programmatic JNDI look-up does work with EJB. The Tyrus implementation is missing the appropriate hooks in to CDI and EJB containers for post initialisation of the endpoints.
        Hide
        Pavel Bucek added a comment -

        can you please retry with newer glassfish version? please make sure it contains latest stable Tyrus (1.0-b11)

        unzip -p ./glassfish4/glassfish/modules/tyrus-core.jar META-INF/MANIFEST.MF | grep ^Bundle-Version

        Show
        Pavel Bucek added a comment - can you please retry with newer glassfish version? please make sure it contains latest stable Tyrus (1.0-b11) unzip -p ./glassfish4/glassfish/modules/tyrus-core.jar META-INF/MANIFEST.MF | grep ^Bundle-Version
        Hide
        peter_pilgrim added a comment -

        I tried with the sample code against the latest GlassFish 4.0 b77
        I am getting know a different error.

        javax.websocket.DeploymentException: Class javax.websocket.server.DefaultServerConfiguration couldn't be instantiated

        The Tyrus container is failing and preventing the webapp being deployed.

        Show
        peter_pilgrim added a comment - I tried with the sample code against the latest GlassFish 4.0 b77 I am getting know a different error. javax.websocket.DeploymentException: Class javax.websocket.server.DefaultServerConfiguration couldn't be instantiated The Tyrus container is failing and preventing the webapp being deployed.
        Hide
        Pavel Bucek added a comment -

        looks like you might have similar problem as described in http://java.net/jira/browse/TYRUS-102

        can you confirm tyrus version as I requested in previous comment? Also can you please make sure that you don't include any related API jar in your war file?

        Show
        Pavel Bucek added a comment - looks like you might have similar problem as described in http://java.net/jira/browse/TYRUS-102 can you confirm tyrus version as I requested in previous comment? Also can you please make sure that you don't include any related API jar in your war file?
        Hide
        peter_pilgrim added a comment -

        You were correct. I had to exclude the Java EE API from the WAR file, for example Gradle

        dependencies

        { providedCompile 'org.glassfish.main.extras:glassfish-embedded-all:4.0-b77' providedCompile 'javax:javaee-api:7.0-b77' ... }

        I checked that b77 of GlassFish embedded server JAR. Indeed, it does refer to Tyrus 1.0-b11

        META-INF/org.glassfish.tyrus.tyrus-client/pom.properties
        #Generated by org.apache.felix.bundleplugin
        #Tue Feb 12 22:34:00 UTC 2013
        version=1.0-b11
        groupId=org.glassfish.tyrus
        artifactId=tyrus-core

        I can confirmed CDI injection is working at last.

        Now here is the thing. EJB injection does not work at all. Is it suppose to in the WebSocket specification?

        Here is a sample endpoint

        @WebSocketEndpoint("/singleton")
        public class SingletonEJBWebSocketEndpoint {

        @EJB
        private SampleSingleton sampleSingleton;

        @WebSocketOpen
        public void open(Session session) {
        System.out.printf("%s.open() called session=%s\n", getClass().getSimpleName(), session );

        // This is a work around
        System.out.printf(" sampleSingleton = %s BEFORE\n", sampleSingleton );
        if ( sampleSingleton == null) {
        // Look up the object
        Context initialContext = null;
        try

        { initialContext = new InitialContext(); Object obj = initialContext.lookup("java:global/mywebapp/SampleSingleton"); System.out.printf(" obj=%s\n", obj); sampleSingleton = (SampleSingleton)obj; }

        catch (NamingException e)

        { e.printStackTrace(); }

        }
        System.out.printf(" sampleSingleton = %s AFTER\n", sampleSingleton );
        }

        @WebSocketClose
        public void close(Session session)

        { System.out.printf("%s.close() called session=%s\n", getClass().getSimpleName(), session); System.out.printf(" sampleSingleton = %s\n", sampleSingleton ); }

        @WebSocketMessage
        public String generateReply( String message )

        { return String.format("%s - name: %s, counter: %d, message:%s", new Date(), sampleSingleton.getFullName(), sampleSingleton.count(), message.toUpperCase()); }

        }

        The singleton EJB is:

        package je7hb.websocket.basic;

        import javax.annotation.PostConstruct;
        import javax.annotation.PreDestroy;
        import javax.ejb.Singleton;
        import javax.ejb.Startup;
        import java.util.concurrent.atomic.AtomicInteger;

        @Singleton
        @Startup
        public class SampleSingleton {
        private AtomicInteger counter = new AtomicInteger(5000);
        @PostConstruct
        public void init()

        { System.out.printf(">>>> %s.init() called\n", getClass().getSimpleName()); }

        @PreDestroy
        public void destroy()

        { System.out.printf(">>>> %s.destroy() called\n", getClass().getSimpleName()); }

        public int count()

        { return counter.getAndAdd(2); }

        public String getFullName()

        { return "Peter Pilgrim"; }

        }

        The output for the standard console is thus:

        NFO: mywebapp was successfully deployed in 2,083 milliseconds.

              • Press the ENTER key to stop the server ****
                No valid EE environment for injection of je7hb.websocket.basic.SingletonEJBWebSocketEndpoint
                SingletonEJBWebSocketEndpoint.open() called session=Session(1280588945, true)
                sampleSingleton = null BEFORE
                obj=je7hb.websocket.basic.SampleSingleton@41849a6a
                sampleSingleton = je7hb.websocket.basic.SampleSingleton@41849a6a AFTER
                SingletonEJBWebSocketEndpoint.close() called session=Session(1280588945, true)
                sampleSingleton = je7hb.websocket.basic.SampleSingleton@41849a6a
                > Building > :run

        The EJB should inject especially if it is running in the same JVM. For Servlets I check that EJB can inject as well.

        @WebServlet("/fake")
        public class FakeServlet extends HttpServlet

        { @EJB SampleSingleton sampleSingleton; ... }
        Show
        peter_pilgrim added a comment - You were correct. I had to exclude the Java EE API from the WAR file, for example Gradle dependencies { providedCompile 'org.glassfish.main.extras:glassfish-embedded-all:4.0-b77' providedCompile 'javax:javaee-api:7.0-b77' ... } I checked that b77 of GlassFish embedded server JAR. Indeed, it does refer to Tyrus 1.0-b11 META-INF/org.glassfish.tyrus.tyrus-client/pom.properties #Generated by org.apache.felix.bundleplugin #Tue Feb 12 22:34:00 UTC 2013 version=1.0-b11 groupId=org.glassfish.tyrus artifactId=tyrus-core I can confirmed CDI injection is working at last. Now here is the thing. EJB injection does not work at all. Is it suppose to in the WebSocket specification? Here is a sample endpoint @WebSocketEndpoint("/singleton") public class SingletonEJBWebSocketEndpoint { @EJB private SampleSingleton sampleSingleton; @WebSocketOpen public void open(Session session) { System.out.printf("%s.open() called session=%s\n", getClass().getSimpleName(), session ); // This is a work around System.out.printf(" sampleSingleton = %s BEFORE \n", sampleSingleton ); if ( sampleSingleton == null) { // Look up the object Context initialContext = null; try { initialContext = new InitialContext(); Object obj = initialContext.lookup("java:global/mywebapp/SampleSingleton"); System.out.printf(" obj=%s\n", obj); sampleSingleton = (SampleSingleton)obj; } catch (NamingException e) { e.printStackTrace(); } } System.out.printf(" sampleSingleton = %s AFTER \n", sampleSingleton ); } @WebSocketClose public void close(Session session) { System.out.printf("%s.close() called session=%s\n", getClass().getSimpleName(), session); System.out.printf(" sampleSingleton = %s\n", sampleSingleton ); } @WebSocketMessage public String generateReply( String message ) { return String.format("%s - name: %s, counter: %d, message:%s", new Date(), sampleSingleton.getFullName(), sampleSingleton.count(), message.toUpperCase()); } } The singleton EJB is: package je7hb.websocket.basic; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.Singleton; import javax.ejb.Startup; import java.util.concurrent.atomic.AtomicInteger; @Singleton @Startup public class SampleSingleton { private AtomicInteger counter = new AtomicInteger(5000); @PostConstruct public void init() { System.out.printf(">>>> %s.init() called\n", getClass().getSimpleName()); } @PreDestroy public void destroy() { System.out.printf(">>>> %s.destroy() called\n", getClass().getSimpleName()); } public int count() { return counter.getAndAdd(2); } public String getFullName() { return "Peter Pilgrim"; } } The output for the standard console is thus: NFO: mywebapp was successfully deployed in 2,083 milliseconds. Press the ENTER key to stop the server **** No valid EE environment for injection of je7hb.websocket.basic.SingletonEJBWebSocketEndpoint SingletonEJBWebSocketEndpoint.open() called session=Session(1280588945, true) sampleSingleton = null BEFORE obj=je7hb.websocket.basic.SampleSingleton@41849a6a sampleSingleton = je7hb.websocket.basic.SampleSingleton@41849a6a AFTER SingletonEJBWebSocketEndpoint.close() called session=Session(1280588945, true) sampleSingleton = je7hb.websocket.basic.SampleSingleton@41849a6a > Building > :run The EJB should inject especially if it is running in the same JVM. For Servlets I check that EJB can inject as well. @WebServlet("/fake") public class FakeServlet extends HttpServlet { @EJB SampleSingleton sampleSingleton; ... }
        Hide
        stepan.kopriva added a comment -

        According to specificitaion: "Websocket endpoints running in the Java EE platform must have full dependency injection support as described in the CDI specification [8]. [WSC-7.1.1-1] Websocket implementations part of the Java EE platform are required to support field, method, and constructor injection using the javax.inject.Inject annotation into all web socket endpoint classes, as well as the use of interceptors for these classes".

        We do currently also support EJB annotations on endpoint, so your endpoint could look like this:

        @ServerEndpoint(value = "/stateful")
        @Stateful
        public class StatefulBean {

        int counter = 0;
        private boolean postConstructCalled = false;

        @OnMessage
        public String echo(String message)

        { return postConstructCalled ? String.format("%s%s", message, counter++) : "PostConstruct not called."; }

        @PostConstruct
        public void postConstruct()

        { postConstructCalled = true; }

        }

        To inject the EJB to an endpoint please use the @Inject annotation.

        Show
        stepan.kopriva added a comment - According to specificitaion: "Websocket endpoints running in the Java EE platform must have full dependency injection support as described in the CDI specification [8] . [WSC-7.1.1-1] Websocket implementations part of the Java EE platform are required to support field, method, and constructor injection using the javax.inject.Inject annotation into all web socket endpoint classes, as well as the use of interceptors for these classes". We do currently also support EJB annotations on endpoint, so your endpoint could look like this: @ServerEndpoint(value = "/stateful") @Stateful public class StatefulBean { int counter = 0; private boolean postConstructCalled = false; @OnMessage public String echo(String message) { return postConstructCalled ? String.format("%s%s", message, counter++) : "PostConstruct not called."; } @PostConstruct public void postConstruct() { postConstructCalled = true; } } To inject the EJB to an endpoint please use the @Inject annotation.

          People

          • Assignee:
            stepan.kopriva
            Reporter:
            peter_pilgrim
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: