Search code examples
javagwtatmosphere

AtmosphereResource become null


I'm tryin' to develop a small gwt chat application Atmosphere's gwt extension. The server side part of application take care about incoming AtmosphereResource associating a Broadcaster and suspending it. Here is the code snippet about suspending a new incoming AtmosphereResource:

private void doGet(AtmosphereResource ar, String userId) {
    if(BroadcasterFactory.getDefault().lookup(userId) != null) {
    ar.setBroadcaster(BroadcasterFactory.getDefault().lookup(userId).addAtmosphereResource(ar));
    } else {
            ar.setBroadcaster(BroadcasterFactory.getDefault().get(userId).addAtmosphereResource(ar));
    }
    ar.suspend();
    ...
}

When I look for that AtmosphereResource, using it's previously stored uuid, I always found it null:

...
AtmosphereResource arTarget = AtmosphereResourceFactory.getDefault().find(uuid);            
if (arTarget != null)   {
    arTarget.getBroadcaster().broadcast(msg,arTarget);
} else {
    log.info("handleRawMessage:no broadcaster "+((RawMessage) msg).toString());
}
...

What's wrong? I also notice that AtmosphereResources got rapidly onResume, as they immediately time out, but timeout is set to -1. Did I miss something? This is a snippet of my pom to.

<dependency>
    <groupId>org.atmosphere.extensions</groupId>
    <artifactId>atmosphere-gwt20-client</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.atmosphere.extensions</groupId>
    <artifactId>atmosphere-gwt20-common</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.atmosphere.extensions</groupId>
    <artifactId>atmosphere-gwt20-server</artifactId>
    <version>2.1.1</version>
</dependency>
<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-runtime</artifactId>
    <version>2.1.1</version>
</dependency>

Solution

  • In order to get a broadcaster you have to have a client connected to the server. Are you sure your client is connecting?

    VERSION 2.0

    In order to implement the server in 2.0 I have done: (The client id could be obtained from the request)

    public class AtmosphereHandler extends AbstractReflectorAtmosphereHandler {
    
    private static Logger logger = Logger.getLogger(AtmosphereHandler.class);;
    
    @Override
    public void onRequest(final AtmosphereResource ar) throws IOException {
        logger.info("Connecting to comet with: "
                + ar.getRequest().getRequestURI());
        Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup(
                YOUR_CLIENT_ID, true);
        if (broadcaster.getAtmosphereResources().size() > 0) {
            logger.debug("Broadcaster recovered with name: "
                    + broadcaster.getID());
        } else {
            logger.debug("Broadcaster created with name: "
                    + broadcaster.getID());
        }
        ar.setBroadcaster(broadcaster);
    
        ar.setSerializer(new Serializer() {
            Charset charset = Charset.forName(ar.getResponse()
                    .getCharacterEncoding());
    
            @Override
            public void write(OutputStream os, Object o) throws IOException {
                try {
                    logger.info("Writing object to JSON outputstream with charset: "
                            + charset.displayName());
                    String payload = serializer.serialize(o);
                    os.write(payload.getBytes(charset));
                    os.flush();
                } catch (SerializationException ex) {
                    throw new IOException("Failed to serialize object to JSON",
                            ex);
                }
            }
        });
    
        ar.suspend();
    
    }
    
    private ServerSerializer serializer = new JacksonSerializerProvider()
            .getServerSerializer();
    

    In the client part you should have something similar to that:

         AutoBeanClientSerializer json_serializer = new AutoBeanClientSerializer();
        json_serializer.registerBeanFactory(beanFactory, ActivityMessage.class);
        AtmosphereRequestConfig jsonRequestConfig = AtmosphereRequestConfig.create(json_serializer);
        jsonRequestConfig.setUrl(GWT.getHostPageBaseURL() + HANDLER_URL_PART);
        jsonRequestConfig.setContentType("application/json; charset=UTF-8");
        jsonRequestConfig.setTransport(AtmosphereRequestConfig.Transport.WEBSOCKET);
        jsonRequestConfig.setFallbackTransport(AtmosphereRequestConfig.Transport.STREAMING);
        jsonRequestConfig.setOpenHandler(new AtmosphereOpenHandler() {
            @Override
            public void onOpen(AtmosphereResponse response) {
                GWT.log("JSON Connection opened");
            }
        });
        jsonRequestConfig.setCloseHandler(new AtmosphereCloseHandler() {
            @Override
            public void onClose(AtmosphereResponse response) {
                GWT.log("JSON Connection closed");
            }
        });
        jsonRequestConfig.setMessageHandler(new AtmosphereMessageHandler() {
            @Override
            public void onMessage(AtmosphereResponse response) {
    
            }
        });
    
    
        Atmosphere atmosphere = Atmosphere.create();
        final AtmosphereRequest jsonRequest = atmosphere.subscribe(jsonRequestConfig);
    

    VERSION 1.1.0RC4

    I extend the AtmosphereGwtHandler for implementing the server like this:

    private static Logger logger;
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
        logger = Logger.getLogger(AtmosphereHandler.class);
    }
    
    @Override
    public int doComet(GwtAtmosphereResource resource) throws ServletException, IOException {
        logger.info("Connecting to comet with: " +resource.getRequest().getRequestURI());
        Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup(YOUR_CONNECTION_ID, true);
        if(broadcaster.getAtmosphereResources().size()>0){
            logger.debug("Broadcaster recovered with name: " + broadcaster.getID());
        }
        else{
            logger.debug("Broadcaster created with name: " + broadcaster.getID());
        }
        resource.getAtmosphereResource().setBroadcaster(broadcaster);
        return NO_TIMEOUT;
    }
    
    @Override
    public void cometTerminated(GwtAtmosphereResource cometResponse, boolean serverInitiated) {
        logger.info("Disconnecting from comet. Broadcaster : " + cometResponse.getBroadcaster().getID());
        super.cometTerminated(cometResponse, serverInitiated);
    }
    
    @Override
    public void doPost(HttpServletRequest postRequest, HttpServletResponse postResponse,
            List<?> messages, GwtAtmosphereResource cometResource) {
        broadcast(messages, cometResource);
    }
    

    You have to initialize it with a atmosphere.xml file at META-INF folder in your target directory.

    I hope that helps!