Giter VIP home page Giter VIP logo

atmosphere's Introduction

Welcome to Atmosphere: The Event Driven Framework supporting WebSocket and HTTP

The Atmosphere Framework contains client and server side components for building Asynchronous Web Applications. Atmosphere transparently supports WebSockets, Server Sent Events (SSE), Long-Polling, HTTP Streaming and JSONP.

The Atmosphere Framework works on all Servlet based servers, Spring Boot and frameworks like Netty, Play! Framework and Vert.x. We support a variety of extensions like Apache Kafka, Hazelcast, RabbitMQ, Redis and many more.

Atmosphere's Java/Scala/Android Client is called wAsync.

Main development branch is atmosphere-2.7.x. Jakarta support is supported on branch main

Atmosphere 2.7.x on JDK 8 up to 21

Atmopshere 2.7.x

Atmosphere 3.0.x on JDK 18 and 21

Atmopshere 3.0.x

Commercial support

Commercial Support is available via Async-IO.org

To use Atmosphere, add the following dependency:

     <dependency>
         <groupId>org.atmosphere</groupId>
         <artifactId>atmosphere-{atmosphere-module}</artifactId>
         <version>2.7.14</version> 
      </dependency>

Support for Jakarta EE (jakarta.*) is available with Atmosphere 3.0.0

     <dependency>
         <groupId>org.atmosphere</groupId>
         <artifactId>atmosphere-runtime</artifactId>
         <version>3.0.8</version> 
      </dependency>

atmosphere-module can be: runtime (main module), jersey, spring, kafka, guice, redis, hazelcast, jms, rabbitmq, jgroups etc. Our official releases are available from Maven Central download.

Getting started

Here's how to get your first Atmosphere project off the ground.

Prerequisites

Ensure you have Java 8 (or later) installed on your system. For managing your Java Project and its dependencies, you'll need a build automation tool. We recommend Maven, which is widely used in the Java ecosystem.

Project Setup

Create a new project using Maven. Add Atmosphere as a dependency in your pom.xml to access all the necessary libraries.

Server Configuration

In your project, you'll define a server endpoint that listens to incoming connections. Atmosphere's annotations and resource handlers make this process straightforward.

Running Your Server

With the server set up, use your IDE or the Maven CLI to compile and run your application.

Create a Client

Your web client will need to establish a connection to your server. You can create a simple HTML page with JavaScript to connect and communicate with your server endpoint.

Keep Going!

Once you've got the basics down, explore the full range of Atmosphere's capabilities to create more sophisticated real-time applications.

For detailed instructions, examples, and advanced configurations, refer to the official Atmosphere tutorial.

Official Documentation

Complete repository of samples sample.

Our Wiki contains several tutorials for getting started as well as FAQ. You can also browse the framework's Javadoc for Server Components, and atmosphere.js for Client Components. Z

Supported Atmosphere Versions

Atmosphere 2.7.x requires JDK 8 or 11. Atmosphere 3.0.x requires JDK 11.

@Copyright 2008-2024 Async-IO.org

atmosphere's People

Contributors

aleksandarn avatar artur- avatar casualjim avatar dmitry-treskunov avatar dreamershl avatar elakito avatar flowersinthesand avatar gdrouet avatar jfarcand avatar klieber avatar marens-ox avatar markathomas avatar mattnathan avatar mjeanroy avatar mvsmasiero avatar neotyk avatar nfranke avatar nite23 avatar pmiklos avatar reda-alaoui avatar rlubke avatar sbalmos avatar sdnetwork avatar slovdahl avatar smaldini avatar sroebuck avatar superpat45 avatar survivant avatar wimplash avatar zrvan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

atmosphere's Issues

Wrong TOMCAT_7 class name in DefaultCometSupportResolver ?

in DefaultCometSupportResolver, instead of

String TOMCAT_7 = "org.apache.catalina.core.StuckThreadDetectionValve";

shouldn't it be

String TOMCAT_7 = "org.apache.catalina.valves.StuckThreadDetectionValve";

?

I grepped the tomcat source and found StuckThreadDetectionValve under valves, not core.

Wicket-Ajax-Rendering in Websocket Thread. (Jetty8)

I try to do a full wicket ajax rendering from AtmosphereResourceEventListener.onBroadcast().
Unfortunaly accessing some attributes from the Original Jetty-Request result in NPE. I guess its Thread-local related, since the WebSocket-Thread is not the same as the original Request.

/**

  • Starting with 7.5.x and 8.0.2, the internal Jetty's Request object gets recycled once the handshake occurs,
  • hence we need to cache the original value. Since a WebSocketProtocol handler can wrap the request, we must first
  • do it here to avoid all kind of issue with Jetty.
    */

JettyWebSocketHandler.JettyRequestFix should also save the serverName and serverPort and override also the following methods.

@OverRide
public HttpSession getSession(boolean create) {
return httpSession;
}

jquery.atmosphere.js cosmetic change websocket.onopen

Please change:

   websocket.onopen = function(message) {
            jQuery.atmosphere.debug("Websocket successfully opened");
            webSocketSupported = true;
            jQuery.atmosphere.response.state = 'opening';
            jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);

            if (jQuery.atmosphere.request.method == 'POST') {
                data = jQuery.atmosphere.request.data;
                jQuery.atmosphere.response.state = 'messageReceived';
                websocket.send(jQuery.atmosphere.request.data);
            }
        };

to

        websocket.onopen = function() {
            jQuery.atmosphere.debug("Websocket successfully opened");
            webSocketSupported = true;
            jQuery.atmosphere.response.state = 'opening';
            jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);

            if (jQuery.atmosphere.request.method == 'POST') {
                jQuery.atmosphere.response.state = 'messageReceived';
                websocket.send(jQuery.atmosphere.request.data);
            }
        };

Cannot define one callback per request

If you subscribe to multiple topics, you cannot define one callback per subscriptions : all callbacks are always called.
Since "jQuery.atmosphere.request" has a "callback" property, I thought it was possible but no, because "invokeCallback" function don't look at it.
I looked at jQuery plugin and I think you can fix it by adding to "invokeCallback" function :

if (typeof(jQuery.atmosphere.request.callback) == 'function') {
  jQuery.atmosphere.request.callback(response);
}

I tested, it seems to work, but maybe it's not the best way to do it.

Inconsistent transport implementation

It appears as though there is no consistent method for implementing the various transports in an application's handler. I expected websockets to create "fake" onRequest() calls generating "fake" GET requests for incoming messages but this is not the case. However it is done, we need to have a consistent model providing us the incoming messages from the browser for any transport: Comet, Websocket, Long-Polling or Polling.

Warning when using atmosphere-jgroups

I get the following warning when using atmosphere-jgroups:

WARN [Atmosphere-BroadcasterConfig-0] - failed to join /224.0.75.75:7500 on net4: java.net.SocketException: Unrecognized Windows Sockets error: 0: no Inet4Address associated with interface - [org.jgroups.protocols.UDP]

This seems to be a known jgroups bug:
https://issues.jboss.org/browse/JGRP-978?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel

replacing jgroups jar with version 2.8 fixes the warning.

Tested on atmosphere 0.8-RC3

atmospherehandler timeout needs documentation

The sample in samples/jquery-atmospherehandler-pubsub has a default timeout
of 5 minutes. After this timeout the sample application will silently fail to Publish Message.

The location of this timeout (and how to change it) is not obvious and requires documentation.

For extra credit it may make sense for the action tied to Publish Message to
detect that the connection is not alive and refresh it (automatically) or warn
the user that it has timed out (e.g. so that the re-authenticate again).

EMPTY_DESTROY -broadcasterLifeCyclePolicy causes error in grizzly

hi jeanfrancois,

to make sure the problem in #43, is not from jetty i tried to use grizzly. The problem is with the bc-lifecycle-policy set to BroadcasterLifeCyclePolicy.ATMOSPHERE_RESOURCE_POLICY.EMPTY_DESTROY
none of my @Supend-requests work. heres my stracktrace, somehow the resume fails which causes the connection to close. (the second part is my client-stacktrace from com.ning AsyncHttpClient)

i tested this with 0.8.0-RC2 and 0.8.0-RC3

08.11.2011 01:32:37 com.sun.grizzly.http.ProcessorTask terminateProcess
WARNUNG: GRIZZLY0024: Terminate process interrupted.
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(AbstractQueuedSynchronizer.java:1302)
at java.util.concurrent.Semaphore.tryAcquire(Semaphore.java:383)
at com.sun.grizzly.http.ProcessorTask.terminateProcess(ProcessorTask.java:978)
at com.sun.grizzly.arp.DefaultAsyncExecutor.finishResponse(DefaultAsyncExecutor.java:186)
at com.sun.grizzly.arp.DefaultAsyncExecutor.finishExecute(DefaultAsyncExecutor.java:210)
at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:119)
at com.sun.grizzly.comet.CometEngine.flushPostExecute(CometEngine.java:411)
at com.sun.grizzly.comet.CometEngine.interrupt0(CometEngine.java:393)
at com.sun.grizzly.comet.CometEngine.interrupt(CometEngine.java:371)
at com.sun.grizzly.comet.CometContext.resumeCometHandler(CometContext.java:435)
at org.atmosphere.container.GrizzlyCometSupport.resume(GrizzlyCometSupport.java:160)
at org.atmosphere.container.GrizzlyCometSupport.action(GrizzlyCometSupport.java:172)
at org.atmosphere.container.GrizzlyCometSupport.action(GrizzlyCometSupport.java:65)
at org.atmosphere.cpr.AtmosphereResourceImpl.resume(AtmosphereResourceImpl.java:209)
at org.atmosphere.jersey.util.JerseyBroadcasterUtil.broadcast(JerseyBroadcasterUtil.java:93)
at org.atmosphere.jersey.JerseyBroadcaster.broadcast(JerseyBroadcaster.java:58)
at org.atmosphere.cpr.DefaultBroadcaster.executeAsyncWrite(DefaultBroadcaster.java:601)
at org.atmosphere.cpr.DefaultBroadcaster$3.run(DefaultBroadcaster.java:626)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)

01:32:37.428 [New I/O client worker #2-6] ERROR o.m.web.AtmosphereWebSender - error with async-request
java.io.IOException: Remotely Closed [id: 0x003c40f0, /127.0.0.1:57952 :> localhost/127.0.0.1:9881]
at com.ning.http.client.providers.netty.NettyAsyncHttpProvider.channelClosed(NettyAsyncHttpProvider.java:1514) [async-http-client-1.6.5.jar:na]
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:98) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.handler.stream.ChunkedWriteHandler.handleUpstream(ChunkedWriteHandler.java:149) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline$DefaultChannelHandlerContext.sendUpstream(DefaultChannelPipeline.java:783) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.cleanup(ReplayingDecoder.java:554) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.channelClosed(ReplayingDecoder.java:455) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:98) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.handler.codec.http.HttpClientCodec.handleUpstream(HttpClientCodec.java:77) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.Channels.fireChannelClosed(Channels.java:404) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.close(NioWorker.java:600) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:356) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:280) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:200) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) [netty-3.2.5.Final.jar:na]
at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44) [netty-3.2.5.Final.jar:na]
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_23-ea]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_23-ea]
at java.lang.Thread.run(Thread.java:619) [na:1.6.0_23-ea]

i basically setup the grizzly server the same way as in your test-class: https://github.com/jfarcand/atmosphere/blob/master/modules/jersey/src/test/java/org/atmosphere/jersey/tests/BaseGrizzyTest.java

kind regards,
Christian

RPGGameDemo does not work..

..on Tomcat 7! I tested the demo with Netbeans 7.0.1 and I get following:
Error: You are not connected to a server.
INFO: Connection error 500: Internal Server Error

[atmosphere.js] Add support for TrackMessageSize

If the server send a response larger than the Browser buffer or in chunks, the response.responseBody may be partially completed. Atmosphere must make sure, when the trackMessageEnabled is enabled, that the full message has been received before invoking callback/function.

jquery-pubsub: Websocket transport fails

Environment:
Atmosphere 0.8-SNAPSHOT
atmosphere-jquery-pubsub
Tomcat 7.0.14
Firefox 6.0.2 / Chrome 14.0.835.126 (Linux)

I have checked that AsynchronousProcessor#action(...) is invoked for websocket request.

Firebug console:

Chrome console:

  • Invoking executeWebSocket
  • Unexpected response code: 501
  • Websocket failed. Downgrading to Comet and resending

jetty websocket request getSession() : java.lang.IllegalStateException: No SessionManager

if I use a block like that

if (supportSession()) {
// Create the session needed to support the Resume
// operation from disparate requests.
HttpSession session = req.getSession(true); // HERE
// Do not allow times out.
if (session.getMaxInactiveInterval() == DEFAULT_SESSION_TIMEOUT) {
session.setMaxInactiveInterval(-1);
}
}

or.. in the Handler

event.getRequest().getSession().getId() // will crash here.

java.lang.IllegalStateException: No SessionManager
at org.eclipse.jetty.server.Request.getSession(Request.java:1151) ~[na:na]
at org.eclipse.jetty.server.Request.getSession(Request.java:1130) ~[na:na]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:267) ~[servlet-api-3.0.jar:na]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:267) ~[servlet-api-3.0.jar:na]
at org.atmosphere.container.Servlet30CometSupport.action(Servlet30CometSupport.java:160) ~[atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]

Glassfish 3.1.1 invalid connection header

Hi.

I use the atmosphere-0.8.0-R1 implementation with glassfish 3.1.1 (build 12). When connecting from FF 7 using websockets I get the following exception:

[#|2011-10-12T14:10:53.399+0200|SEVERE|glassfish3.1.1|websocket|_ThreadID=18;_ThreadName=Thread-3;|Invalid Connection header returned: 'keep-alive, Upgrade'
com.sun.grizzly.websockets.HandshakeException: Invalid Connection header returned: 'keep-alive, Upgrade'
at com.sun.grizzly.websockets.ServerHandShake.checkForHeader(ServerHandShake.java:84)
at com.sun.grizzly.websockets.ServerHandShake.(ServerHandShake.java:64)
at com.sun.grizzly.websockets.ServerNetworkHandler.handshake(ServerNetworkHandler.java:95)
at com.sun.grizzly.websockets.WebSocketEngine.upgrade(WebSocketEngine.java:136)
at com.sun.grizzly.websockets.WebSocketAsyncFilter.doFilter(WebSocketAsyncFilter.java:52)
at com.sun.grizzly.arp.DefaultAsyncExecutor.invokeFilters(DefaultAsyncExecutor.java:171)
at com.sun.grizzly.arp.DefaultAsyncExecutor.interrupt(DefaultAsyncExecutor.java:143)
at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:94)
at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:204)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
|#]

With 0.7.2 atmosphere doesn't even see the incoming connection.
Did I miss something?

Best regards,

Alexander.

Better X-Cache support

The following was contributed by the community and needs to be integrated/evaluated

/**

  • Licensed under the Apache License, Version 2.0 (the "License");

  • you may not use this file except in compliance with the License.

  • You may obtain a copy of the License at
    *

  • http://www.apache.org/licenses/LICENSE-2.0
    *

  • Unless required by applicable law or agreed to in writing, software

  • distributed under the License is distributed on an "AS IS" BASIS,

  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

  • See the License for the specific language governing permissions and

  • limitations under the License.
    */
    jQuery.atmosphere = function() {

    var activeRequest;
    var lastTimestamp = 0;

    jQuery(window).unload(function() {
    if (activeRequest) {
    activeRequest.abort();
    }

    if (!(typeof(transferDoc) == 'undefined')) {
        if (transferDoc != null && transferDoc != undefined) {
            transferDoc = null;
            CollectGarbage();
        }
    }
    

    });

    return {
    version : 0.7,
    response : {
    status: 200,
    responseBody : '',
    headers : [],
    state : "messageReceived",
    transport : "long-polling",
    push : [],
    error: null,
    id : 0
    },

    request : {},
    abortingConnection: false,
    logLevel : 'info',
    callbacks: [],
    activeTransport : null,
    websocket : null,
    killHiddenIFrame : null,
    
    subscribe: function(url, callback, request, timestamp) {
    
        jQuery.atmosphere.request = jQuery.extend({
                    timeout: 300000,
                    method: 'GET',
                    headers: {},
                    contentType : '',
                    cache: true,
                    async: true,
                    ifModified: false,
                    callback: null,
                    dataType: '',
                    url : url,
                    data : '',
                    suspend : true,
                    maxRequest : 60,
                    lastIndex : 0,
                    logLevel : 'info',
                    requestCount : 0,
                    fallbackTransport : 'streaming',
                    transport : 'long-polling',
                    webSocketImpl: null
    
                }, request);
    
        // Set the lastTimestamp
        if (timestamp != null && timestamp != undefined){
            lastTimestamp = timestamp;
        }
    
        logLevel = jQuery.atmosphere.request.logLevel || 'info';
    
        if (callback != null) {
            jQuery.atmosphere.addCallback(callback);
            jQuery.atmosphere.request.callback = callback;
        }
    
        if (jQuery.atmosphere.request.transport != jQuery.atmosphere.activeTransport) {
            jQuery.atmosphere.closeSuspendedConnection();
        }
    
        jQuery.atmosphere.activeTransport = jQuery.atmosphere.request.transport;
    
        if (jQuery.atmosphere.request.transport != 'websocket') {
            jQuery.atmosphere.executeRequest(lastTimestamp);
        } 
        else if (jQuery.atmosphere.request.transport == 'websocket') {
    
            if (jQuery.atmosphere.request.webSocketImpl == null && !window.WebSocket) {
    
                jQuery.atmosphere.log(logLevel, ["Websocket is not supported, using request.fallbackTransport"]);
                jQuery.atmosphere.request.transport = jQuery.atmosphere.request.fallbackTransport;
                jQuery.atmosphere.response.transport = jQuery.atmosphere.request.fallbackTransport;
                jQuery.atmosphere.executeRequest();
            }
            else {
                jQuery.atmosphere.executeWebSocket();
            }
        }            
    },
    
    /**
     * Always make sure one transport is used, not two at the same time except for Websocket.
     */
    closeSuspendedConnection : function () {
    
        jQuery.atmosphere.abortingConnection = true;
    
        if (activeRequest != null) {
            activeRequest.abort();
        }
    
        if (jQuery.atmosphere.websocket != null) {
            jQuery.atmosphere.websocket.close();
            jQuery.atmosphere.websocket = null;
        }
    
        jQuery.atmosphere.abortingConnection = false;
    
        if (!(typeof(transferDoc) == 'undefined')) {
            if (transferDoc != null && transferDoc != undefined) {
                transferDoc = null;
                CollectGarbage();
            }
        }
    },
    
    executeRequest: function(timestamp) {
    
        if (jQuery.atmosphere.request.transport == 'streaming') {
    
            if (jQuery.browser.msie) {
                jQuery.atmosphere.ieStreaming();
                return;
            } 
            else if (jQuery.browser.opera) {
                jQuery.atmosphere.operaStreaming();
                return;
            }
        }
    
        if (jQuery.atmosphere.request.requestCount++ > jQuery.atmosphere.request.maxRequest) {
            jQuery.atmosphere.log(logLevel, ["Max re-connection reached."]);
            return;
        }
    
        jQuery.atmosphere.response.push = function (url) {
            jQuery.atmosphere.request.callback = null;
            jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
        };
    
        var request = jQuery.atmosphere.request;
        var response = jQuery.atmosphere.response;
    
        if (request.transport != 'long-polling') {
            response.transport = request.transport;
        }
    
        var ajaxRequest;
        var error = false;
    
        if (jQuery.browser.msie) {
    
            var activexmodes = ["Msxml2.XMLHTTP", "Microsoft.XMLHTTP"];
    
            for (var i = 0; i < activexmodes.length; i++) {
                try {
                    ajaxRequest = new ActiveXObject(activexmodes[i]);
                }
                catch(e) {
                }
            }
        } 
        else if (window.XMLHttpRequest) {
            ajaxRequest = new XMLHttpRequest();
        }
    
        if (request.suspend) {
            activeRequest = ajaxRequest;
        }
    
        ajaxRequest.open(request.method, request.url, true);
        ajaxRequest.setRequestHeader("X-Atmosphere-Framework", jQuery.atmosphere.version);
        ajaxRequest.setRequestHeader("X-Atmosphere-Transport", request.transport);
    
        if (timestamp != undefined && timestamp != null){
            lastTimestamp = timestamp;
            ajaxRequest.setRequestHeader("X-Cache-Date", lastTimestamp);
        }
        else {
            ajaxRequest.setRequestHeader("X-Cache-Date", lastTimestamp);
        }
    
        if (jQuery.atmosphere.request.contentType != '') {
            ajaxRequest.setRequestHeader("Content-Type", jQuery.atmosphere.request.contentType);
        }
    
        for (var x in request.headers) {
            ajaxRequest.setRequestHeader(x, request.headers[x]);
        }
    
        if (!jQuery.browser.msie) {
    
            ajaxRequest.onerror = function() {
    
                error = true;
    
                try {
                    response.status = XMLHttpRequest.status;
                }
                catch(e) {
                    response.status = 404;
                }
    
                response.state = "error";
                jQuery.atmosphere.invokeCallback(response);
                ajaxRequest.abort();
                activeRequest = null;
            };
        }
    
        /**
         * Handler for the Ajax request lifcycle.
         */
        ajaxRequest.onreadystatechange = function() {
    
            if (jQuery.atmosphere.abortingConnection) return;
    
            var junkForWebkit = false;
            var update = false;
    
            if (ajaxRequest.readyState == 4 && ajaxRequest.status == 200) {
    
                jQuery.atmosphere.request = request;
    
                if (request.suspend) {
    
                    jQuery.atmosphere.handleResponse(request, response, ajaxRequest);
    
                    tempDate = ajaxRequest.getResponseHeader('X-Cache-Date');
    
                    if (tempDate != null || tempDate != undefined) {
                        lastTimestamp = tempDate.split(" ").pop();  // Double header vaules.
                    }
    
                    clearTimeout(request.id);
    
                    jQuery.atmosphere.executeRequest(lastTimestamp);
                }
            } 
        };
    
        // Make the call
        ajaxRequest.send(request.data);
    
        if (request.suspend) {
    
            request.id = setTimeout(function() {
                ajaxRequest.abort();
                jQuery.atmosphere.subscribe(request.url, null, request);
    
            }, request.timeout);
        }
    },
    
    handleResponse : function(request, response, ajaxRequest) {
    
        if (ajaxRequest.responseText == "" || ajaxRequest.responseText == undefined){
            return;
        }
        if (request.transport == 'streaming') {
    
            response.responseBody = ajaxRequest.responseText.substring(request.lastIndex, ajaxRequest.responseText.length);
    
            if (request.lastIndex == 0 && response.responseBody.indexOf("<!-- Welcome to the Atmosphere Framework.") != -1) {
    
                var endOfJunk = "<!-- EOD -->";
                var endOfJunkLenght = "<!-- EOD -->".length;
                var junkEnd = response.responseBody.indexOf(endOfJunk) + endOfJunkLenght;
    
                if (junkEnd != ajaxRequest.responseText.length) {
                    response.responseBody = response.responseBody.substring(junkEnd);
                } 
                else {
                    junkForWebkit = true;
                }
            }
    
            request.lastIndex = ajaxRequest.responseText.length;
    
            if (junkForWebkit) return;
        } 
        else {
            response.responseBody = ajaxRequest.responseText;
        }
    
        try {
            response.status = ajaxRequest.status;
            response.headers = ajaxRequest.getAllResponseHeaders();
        }
        catch(e) {
            response.status = 404;
        }
    
        if (request.suspend) {
            response.state = "messageReceived";
        } else {
            response.state = "messagePublished";
        }
    
        if (response.responseBody.indexOf("parent.callback") != -1) {
    
            var index = 0;
            var responseBody = response.responseBody;
    
            while (responseBody.indexOf("('", index) != -1) {
    
                var start = responseBody.indexOf("('", index) + 2;
                var end = responseBody.indexOf("')", index);
    
                if (start == -1 || end == -1){
                    break;
                }
    
                response.responseBody = responseBody.substring(start, end);
                index = end + 2;
    
                jQuery.atmosphere.invokeCallback(response);
            }
        } 
        else {
            jQuery.atmosphere.invokeCallback(response);
        }
    },
    
    operaStreaming: function() {
    
        jQuery.atmosphere.closeSuspendedConnection();
    
        var url = jQuery.atmosphere.request.url;
        var callback = jQuery.atmosphere.request.callback;
    
        jQuery.atmosphere.response.push = function (url) {
            jQuery.atmosphere.request.transport = 'long-polling';
            jQuery.atmosphere.request.callback = null;
            jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
        };
    
        function init() {
    
            var iframe = document.createElement("iframe");
    
            iframe.style.width = "0px";
            iframe.style.height = "0px";
            iframe.style.border = "0px";
            iframe.id = "__atmosphere";
            document.body.appendChild(iframe);
    
            var d;
    
            if (iframe.contentWindow) {
                d = iframe.contentWindow.document;
            } else if (iframe.document) {
                d = iframe.document;
            } else if (iframe.contentDocument) {
                d = iframe.contentDocument;
            }
    
            if (/\?/i.test(url)) url += "&";
            else url += "?";
    
            url += "callback=jquery.atmosphere.streamingCallback";
    
            iframe.src = url;
        }
    
        init();
    
    },
    
    ieStreaming : function() {
    
        if (!(typeof(transferDoc) == 'undefined')) {
            if (transferDoc != null && transferDoc != undefined) {
                transferDoc = null;
                CollectGarbage();
            }
        }
    
        var url = jQuery.atmosphere.request.url;
    
        jQuery.atmosphere.response.push = function (url) {
            jQuery.atmosphere.request.transport = 'long-polling';
            jQuery.atmosphere.request.callback = null;
            jQuery.atmosphere.publish(url, null, jQuery.atmosphere.request);
        };
    
        //Must not use var here to avoid IE from disconnecting
        transferDoc = new ActiveXObject("htmlfile");
        transferDoc.open();
        transferDoc.close();
    
        var ifrDiv = transferDoc.createElement("div");
    
        transferDoc.body.appendChild(ifrDiv);
        ifrDiv.innerHTML = "<iframe src='" + url + "'></iframe>";
        transferDoc.parentWindow.callback = jQuery.atmosphere.streamingCallback;
    }
    ,
    
    streamingCallback : function(args) {
        var response = jQuery.atmosphere.response;
        response.transport = "streaming";
        response.status = 200;
        response.responseBody = args;
        response.state = "messageReceived";
    
        jQuery.atmosphere.invokeCallback(response);
    }
    ,
    
    executeWebSocket : function() {
    
        var request = jQuery.atmosphere.request;
        var success = false;
    
        jQuery.atmosphere.log(logLevel, ["Invoking executeWebSocket"]);
    
        jQuery.atmosphere.response.transport = "websocket";
    
        var url = jQuery.atmosphere.request.url;
        var callback = jQuery.atmosphere.request.callback;
    
        if (url.indexOf("http") == -1 && url.indexOf("ws") == -1) {
            url = jQuery.atmosphere.parseUri(document.location, url);
        }
    
        var location = url.replace('http:', 'ws:').replace('https:', 'wss:');
    
        var websocket = null;
    
        if (jQuery.atmosphere.request.webSocketImpl != null) {
            websocket = jQuery.atmosphere.request.webSocketImpl;
        } else {
            websocket = new WebSocket(location);
        }
    
        jQuery.atmosphere.websocket = websocket;
    
        jQuery.atmosphere.response.push = function (url) {
    
            var data;
            var ws = jQuery.atmosphere.websocket;
    
            try {
                data = jQuery.atmosphere.request.data;
                ws.send(jQuery.atmosphere.request.data);
            } catch (e) {
                jQuery.atmosphere.log(logLevel, ["Websocket failed. Downgrading to Comet and resending " + data]);
                // Websocket is not supported, reconnect using the fallback transport.
                request.transport = request.fallbackTransport;
                jQuery.atmosphere.response.transport = request.fallbackTransport;
                jQuery.atmosphere.request = request;
                jQuery.atmosphere.executeRequest();
    
                ws.onclose = function(message) {
                };
                ws.close();
            }
        };
    
        websocket.onopen = function(message) {
            success = true;
            jQuery.atmosphere.response.state = 'openning';
            jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
        };
    
        websocket.onmessage = function(message) {
    
            var data = message.data;
    
            if (data.indexOf("parent.callback") != -1) {
                var start = data.indexOf("('") + 2;
                var end = data.indexOf("')");
                jQuery.atmosphere.response.responseBody = data.substring(start, end);
            }
            else {
                jQuery.atmosphere.response.responseBody = data;
            }
    
            jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
        };
    
        websocket.onerror = function(message) {
            jQuery.atmosphere.response.state = 'error';
            jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
        };
    
        websocket.onclose = function(message) {
            if (!success) {
                var data = jQuery.atmosphere.request.data;
                jQuery.atmosphere.log(logLevel, ["Websocket failed. Downgrading to Comet and resending " + data]);
                // Websocket is not supported, reconnect using the fallback transport.
                request.transport = request.fallbackTransport;
                jQuery.atmosphere.response.transport = request.fallbackTransport;
    
                jQuery.atmosphere.request = request;
                jQuery.atmosphere.executeRequest();
            } else {
                jQuery.atmosphere.response.state = 'closed';
                jQuery.atmosphere.invokeCallback(jQuery.atmosphere.response);
            }
        };
    }
    ,
    
    addCallback: function(func) {
        if (jQuery.inArray(func, jQuery.atmosphere.callbacks) == -1) {
            jQuery.atmosphere.callbacks.push(func);
        }
    }
    ,
    
    removeCallback: function(func) {
        var index = jQuery.inArray(func, jQuery.atmosphere.callbacks);
        if (index != -1) { jQuery.atmosphere.callbacks.splice(index); }
    }
    ,
    
    invokeCallback: function(response) {
        var call = function (index, func) {
            func(response);
        };
    
        jQuery.atmosphere.log(logLevel, ["Invoking " + jQuery.atmosphere.callbacks.length + " callbacks"]);
        if (jQuery.atmosphere.callbacks.length > 0) {
            jQuery.each(jQuery.atmosphere.callbacks, call);
        }
    }
    ,
    
    publish: function(url, callback, request) {
        jQuery.atmosphere.request = jQuery.extend({
                    connected: false,
                    timeout: 60000,
                    method: 'POST',
                    contentType : '',
                    headers: {},
                    cache: true,
                    async: true,
                    ifModified: false,
                    callback: null,
                    dataType: '',
                    url : url,
                    data : '',
                    suspend : false,
                    maxRequest : 60,
                    logLevel : 'info',
                    requestCount : 0,
                    transport: 'long-polling'
                }, request);
    
        if (callback != null) {
            jQuery.atmosphere.addCallback(callback);
        }
    
        jQuery.atmosphere.request.transport = 'long-polling';
    
        if (jQuery.atmosphere.request.transport != 'websocket') {
            jQuery.atmosphere.executeRequest();
        } else if (jQuery.atmosphere.request.transport == 'websocket') {
            if (!window.WebSocket) {
                alert("WebSocket not supported by this browser");
            }
            else {
                jQuery.atmosphere.executeWebSocket();
            }
        }
    }
    ,
    
    unload: function (arg) {
        if (window.addEventListener) {
            document.addEventListener('unload', arg, false);
            window.addEventListener('unload', arg, false);
        } else { // IE
            document.attachEvent('onunload', arg);
            window.attachEvent('onunload', arg);
        }
    }
    ,
    
    kill_load_bar : function() {
        if (jQuery.atmosphere.killHiddenIFrame == null) {
            jQuery.atmosphere.killHiddenIFrame = document.createElement('iframe');
            var ifr = jQuery.atmosphere.killHiddenIFrame;
            ifr.style.display = 'block';
            ifr.style.width = '0';
            ifr.style.height = '0';
            ifr.style.border = '0';
            ifr.style.margin = '0';
            ifr.style.padding = '0';
            ifr.style.overflow = 'hidden';
            ifr.style.visibility = 'hidden';
        }
        document.body.appendChild(ifr);
        ifr.src = 'about:blank';
        document.body.removeChild(ifr);
    }
    ,
    
    log: function (level, args) {
        if (window.console) {
            var logger = window.console[level];
            if (typeof logger == 'function') {
                logger.apply(window.console, args);
            }
        }
    }
    ,
    
    warn: function() {
        log('warn', arguments);
    }
    ,
    
    
    info :function() {
        if (logLevel != 'warn') {
            log('info', arguments);
        }
    }
    ,
    
    debug: function() {
        if (logLevel == 'debug') {
            log('debug', arguments);
        }
    }
    ,
    
    close : function() {
        jQuery.atmosphere.closeSuspendedConnection();
    },
    
    
    parseUri : function(baseUrl, uri) {
        var protocol = window.location.protocol;
        var host = window.location.host;
        var path = window.location.pathname;
        var parameters = {};
        var anchor = '';
        var pos;
    
        if ((pos = uri.search(/\:/)) >= 0) {
            protocol = uri.substring(0, pos + 1);
            uri = uri.substring(pos + 1);
        }
    
        if ((pos = uri.search(/\#/)) >= 0) {
            anchor = uri.substring(pos + 1);
            uri = uri.substring(0, pos);
        }
    
        if ((pos = uri.search(/\?/)) >= 0) {
            var paramsStr = uri.substring(pos + 1) + '&;';
            uri = uri.substring(0, pos);
            while ((pos = paramsStr.search(/\&/)) >= 0) {
                var paramStr = paramsStr.substring(0, pos);
                paramsStr = paramsStr.substring(pos + 1);
    
                if (paramStr.length) {
                    var equPos = paramStr.search(/\=/);
                    if (equPos < 0) {
                        parameters[paramStr] = '';
                    }
                    else {
                        parameters[paramStr.substring(0, equPos)] =
                                decodeURIComponent(paramStr.substring(equPos + 1));
                    }
                }
            }
        }
    
        if (uri.search(/\/\//) == 0) {
            uri = uri.substring(2);
            if ((pos = uri.search(/\//)) >= 0) {
                host = uri.substring(0, pos);
                path = uri.substring(pos);
            }
            else {
                host = uri;
                path = '/';
            }
        } else if (uri.search(/\//) == 0) {
            path = uri;
        }
    
        else // relative to directory
        {
            var p = path.lastIndexOf('/');
            if (p < 0) {
                path = '/';
            } else if (p < path.length - 1) {
                path = path.substring(0, p + 1);
            }
    
            while (uri.search(/\.\.\//) == 0) {
                var p = path.lastIndexOf('/', path.lastIndexOf('/') - 1);
                if (p >= 0) {
                    path = path.substring(0, p + 1);
                }
                uri = uri.substring(3);
            }
            path = path + uri;
        }
    
        var uri = protocol + '//' + host + path;
        var div = '?';
        for (var key in parameters) {
            uri += div + key + '=' + encodeURIComponent(parameters[key]);
            div = '&';
        }
        return uri;
    }
    

    };
    }();

NPE if header-param not set

when i let the atmosphere-framework inject my resource-method with a broadcaster like this

public Broadcastable someMethod(@HeaderParam(ResourceConstants.X_REQUEST_ID) final Broadcaster bc) {

the framework runs into a null-pointer-exception

java.lang.RuntimeException: java.lang.NullPointerException
at org.atmosphere.handler.ReflectorServletProcessor.onRequest(ReflectorServletProcessor.java:155) ~[atmosphere-runtime-0.7.2.jar:0.7.2]
at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:191) ~[atmosphere-runtime-0.7.2.jar:0.7.2]
at org.atmosphere.cpr.AsynchronousProcessor.suspended(AsynchronousProcessor.java:142) ~[atmosphere-runtime-0.7.2.jar:0.7.2]
at org.atmosphere.container.Jetty7CometSupport.service(Jetty7CometSupport.java:81) ~[atmosphere-runtime-0.7.2.jar:0.7.2]
at org.atmosphere.cpr.AtmosphereServlet.doCometSupport(AtmosphereServlet.java:1156) ~[atmosphere-runtime-0.7.2.jar:0.7.2]
at org.atmosphere.cpr.AtmosphereServlet.doPost(AtmosphereServlet.java:1138) ~[atmosphere-runtime-0.7.2.jar:0.7.2]

instead a HTTP 400 Bad-Request or something should be responded.

jqeury plugin gives problem at ie9

justa simple chat example. it works with chrome and firefox but when I try it with ie9 it gives this

SCRIPT16389: Unspecified error

jquery.atmosphere.js, line 234 character 28

when I call this

$.atmosphere.subscribe('chat/chatroom', function(response) {
log('Transport used: ' + response.transport);
if (response.transport != 'polling' && response.state != 'connected' && response.state != 'closed') {
if (response.status == 200) {
addChats($.parseJSON(response.responseBody));
}
}
}, $.atmosphere.request);

any ideas ?

is it possible to hide this exception on Jetty shutdown.

The atmosphere application throw a exception on resume when Jetty shutdown using websocket.

09:25:53.405 [Thread-1] DEBUG o.a.cpr.AsynchronousProcessor - failed on resume: AtmosphereResourceImpl{, action=org.atmosphere.cpr.AtmosphereServlet$Action@17e5307, broadcaster=org.atmosphere.cpr.DefaultBroadcaster, cometSupport=org.atmosphere.container.Servlet30CometSupportWithWebSocket@7cf883, serializer=null, isInScope=true, useWriter=true, listeners=[]}
java.lang.IllegalStateException: No SessionManager
at org.eclipse.jetty.server.Request.getSession(Request.java:1151) ~[na:na]
at org.eclipse.jetty.server.Request.getSession(Request.java:1130) ~[na:na]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:267) ~[servlet-api-3.0.jar:na]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:267) ~[servlet-api-3.0.jar:na]
at org.atmosphere.container.Servlet30CometSupport.action(Servlet30CometSupport.java:160) ~[atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]
at org.atmosphere.container.Servlet30CometSupport.action(Servlet30CometSupport.java:63) ~[atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]
at org.atmosphere.cpr.AtmosphereResourceImpl.resume(AtmosphereResourceImpl.java:184) ~[atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]
at org.atmosphere.cpr.AsynchronousProcessor.shutdown(AsynchronousProcessor.java:471) ~[atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]
at org.atmosphere.cpr.AtmosphereServlet.destroy(AtmosphereServlet.java:834) [atmosphere-runtime-0.8.0-RC2-SNAPSHOT.jar:0.8.0-RC2-SNAPSHOT]

AtmosphereGwtHandler.doComet/HttpSession timeouts

When overriding AtmosphereGwtHandler.doComet the following difference can be observed between Servlet 3.0 Async and Grizzley comet, using Glassfish 3.1.1, Oracle JDK 7, GWT 2.4, Atmosphere 0.8.0-RC3.

Let TIMEOUT be the value returned by the override of AtmosphereGwtHandler.doComet. On Grizzley, a connected GWT client calls doComet approximately every TIMEOUT milliseconds. On Servlet 3.0 async, AtmosphereGwtHandler.doComet is called only once. The result is that despite setting org.atmosphere.cpr.sessionSupport to true in web.xml, HttpSessions timeout using servlet 3.0 async if no other requests touch a user's session. My ugly workaround for Servlet 3.0 async is to put an otherwise bogus rpc call in AtmosphereListener.onHeartbeat() as given below. I expected that setting org.atmosphere.cpr.sessionSupport to true would keep my user's sessions alive, as documented on the successor project.

@Override
public void onHeartbeat() {
    Client.sessionService.touchSession(new AsyncCallback<Void>() {
            @Override
            public void onFailure(Throwable caught) {
                log.warning("HttpSession touch failed, the danger of timeout exists");
            }

            @Override
            public void onSuccess(Void result) {
                log.fine("HttpSession touched to prevent a timeout");
            }
        });
}

WebSocket.Event broadcasted as String.

On a close.

webSocketProcessor.notifyListener(new WebSocketEventListener.WebSocketEvent("", CLOSE, webSocketProcessor.webSocket()));

a WebSocketEventListener.WebSocketEvent is created.. but it's converted as a String when this event is broadcasted to the AtmopshereHandler.onStateChange.

AtmosphereResourceEventImpl{isCancelled=false,
isResumedOnTimeout=false,
throwable=null,
message=[B@13a0067,
resource=AtmosphereResourceImpl{, hasCode-1129813192,
action=org.atmosphere.cpr.AtmosphereServlet$Action@1282707,
broadcaster=org.atmosphere.util.ExcludeSessionBroadcaster,
cometSupport=org.atmosphere.protocol.socketio.SocketIOCometSupport@11a6631,
serializer=null,
isInScope=true,
useWriter=true,
listeners=[org.atmosphere.protocol.socketio.SocketIOWebSocketEventListener@2b2cf8]}}

Jquery Pub/Sub with multiple channel hangs

I have been trying to subscribe to multiple channels using the Jquery pub/sub example which actually hangs when i try to subscribe and publish.

Code Snippet -
for(var i = 0; i < 10; i++) {
subscribe(i);
}
function subscribe(channel_id) {
// jquery.atmosphere.response
function callback(response) {
// Websocket events.
$.atmosphere.log('info', ["response.state: " + response.state]);


    <a href="javascript:send_message(0)" title="For Bidding" >on click hangs the request

Environment -
atmosphere 0.7.2
Tomcat 7.0.12 with Nio connector

Any help would be great!!

Thanks,
-Viv

Call to unsubscribe schould remove callback

When you call to $.atmosphere.unsubscribe(), it schould remove callback saved when called to $.atmosphere.subscribe.
Currently, if you subscribe with a callback function, then you unsubscribe, then you subscribe again, callback function is called twice.
Workaroud : call manually $.atmosphere.removeCallback

close event : NULL vs EMPTY

je ne suis pas sur.. mais je pense que les events envoyés sur

public void onStateChange(AtmosphereResourceEvent<HttpServletRequest, HttpServletResponse> event) throws IOException {

pour une connection Comet et WebSocket ne sont pas les mêmes.

dans mon code actuel.. j'ai ceci :

if(event.getMessage()!=null){
logger.error("onStateChange Event isResumedOnTimeout =" + event.isResumedOnTimeout() + " Event isResuming =" + event.isResuming() + " Event isSuspended =" + event.isSuspended() + " Message = " + event.getMessage().toString());
} else {
logger.error("onStateChange Message = null");

        if(event.isResumedOnTimeout()){

            if(outbound!=null){
                try {
                    outbound.sendMessage("2::");
                } catch (Exception e) {
                    outbound.disconnect();
                }
            }

        } 

        return;
    }

ca marche bien pour les connections long-polling.

mais pour les websocket..

le event.getMessage n'est pas NULL.. il est VIDE.

new WebSocketEventListener.WebSocketEvent("", CLOSE, webSocketProcessor.webSocket())

mais pire.. dans mon public void onStateChange(AtmosphereResourceEvent<HttpServletRequest, HttpServletResponse> event) throws IOException {

il arrive à ce bout de code..

if(outbound!=null && event.getMessage().toString().length()>0){
try {

            List<SocketIOEvent> messages = SocketIOEvent.parse(event.getMessage().toString());

...

qui est valide.. car event.getMessage() n'est pas vide... mais comme c'est un OBJECT.. je faisais un .toString() pour obtenir le contenu du message.. mais dans le code du close du webSocket.. c'est pas une String..

donc il essaye de parser la String : [B@127f4f9

en gros... je suis en train de tester le close des Websocket du Chat :)

je fais un F5. J'obtiens une connection Websocket... et si je fais un F5 encore... ca close le websocket et en ouvre un nouveau... (Chrome).. et c'est ca que je teste. Je cherche à détecter correctment l'event dans mon AtmosphereHandler.

voici les stacktraces

Thread [qtp8550760-15](Suspended %28breakpoint at line 236 in WebSocketProcessor%29)
WebSocketProcessor.notifyListener(WebSocketEventListener$WebSocketEvent) line: 236
JettyWebSocketHandler.onClose(int, String) line: 197
WebSocketConnectionD08.closeOut(int, String) line: 356
WebSocketConnectionD08.idleExpired() line: 271
SelectChannelEndPoint.idleExpired() line: 282
SelectChannelEndPoint.checkIdleTimestamp(long) line: 276
SelectorManager$SelectSet$2.run() line: 713
QueuedThreadPool.runJob(Runnable) line: 598
QueuedThreadPool$3.run() line: 533
Thread.run() line: not available

et celle la dans le handler

Daemon Thread [Atmosphere-AsyncWrite-0](Suspended %28breakpoint at line 114 in ChatAtmosphereHandler%29)
ChatAtmosphereHandler.onStateChange(AtmosphereResourceEvent<HttpServletRequest,HttpServletResponse>) line: 114
ExcludeSessionBroadcaster(DefaultBroadcaster).broadcast(AtmosphereResource, AtmosphereResourceEvent) line: 677
ExcludeSessionBroadcaster(DefaultBroadcaster).executeAsyncWrite(AtmosphereResource, Object, BroadcasterFuture) line: 611
DefaultBroadcaster$3.run() line: 636
Executors$RunnableAdapter.call() line: not available
FutureTask$Sync.innerRun() line: not available
FutureTask.run() line: not available
ThreadPoolExecutor$Worker.runTask(Runnable) line: not available
ThreadPoolExecutor$Worker.run() line: not available
Thread.run() line: not available

Configuration file settings are different for websocket vs. comet use

I have my project setup to use websockets currently. I wanted to seamlessly downgrade to comet and so I set my client to use Comet instead of websockets and the server came back with an error....

09:53:02.640 [qtp9613729-21] WARN o.a.cpr.AsynchronousProcessor - No AtmosphereHandler maps request for /Connect//
09:53:02.640 [qtp9613729-21] WARN o.a.cpr.AsynchronousProcessor - AtmosphereHandler registered: /Spacewar/Connect
2011-05-30 09:53:02.640:WARN::/Spacewar/Connect
javax.servlet.ServletException: No AtmosphereHandler maps request for /Connect//
at org.atmosphere.cpr.AsynchronousProcessor.map(AsynchronousProcessor.java:260)
at org.atmosphere.cpr.AsynchronousProcessor.action(AsynchronousProcessor.java:183)

I understand the error, I can fix it but it requires a change in my server side configuration files. Websockets work just fine (asside from the bugs I reported earlier).

My server side configurations are as follows:

atmosphere.xml:



web.xml:


spacewar.SWServer


AtmosphereServlet
AtmosphereServlet
org.atmosphere.cpr.AtmosphereServlet


org.atmosphere.useWebSocket
true

0


AtmosphereServlet
/Connect

[gwt] AtmosphereCometHandler.cometTerminated never called

If a GWT comet connection terminates on GF 3.1.1/Atmosphere 0.8.0-RC3/GWT 2.4/ both Grizzley and Servlet 3.0 Async, my override of AtmosphereCometHandler.cometTerminated on the server-side is never called despite a call to AtmosphereClient.stop() on a connected client.

memory leak when running 2 atmosphere instances in one VM

hi jeanfrancois.

i use atmosphere 0.7.2 (i tried 0.8.0-RC2 but with this version something goes wrong, but i couldn't quite make out what exactly "The current Broadcaster has been destroyed and cannot be re-used. Recreating a new one with the same name. You can turn off that mechanism by adding, in web.xml, org.atmosphere.cpr.recoverFromDestroyedBroadcaster set to false" => turned it off, doesn't work either), jersey 1.9.1 and jetty 7.5.1.v20110908 (Jetty7CometSupport).

heres my scenario. i'm performing benchmark tests with 2 programmatically configured and bootstrapped jetty instances with jersey and atmosphere. (every instance-specific objects i bind in the servletContext) one instance sequentially calls the other using AsyncHTTPClient invoking a atmosphere annotaded method like this.

    @Path("/read")
    @POST
    @Suspend(scope = SCOPE.REQUEST, resumeOnBroadcast = true, outputComments = true, listeners = Listener.class)
    public Broadcastable readEntries(
            ReadEntriesRequest<Serializable> areq, 
            @HeaderParam(ResourceConstants.X_REQUEST_ID) final Broadcaster bc) {
            //first i put my the broadcaster together with a latch in a map so my worker and AtmosphereResourceListener can
            //synchronize with it. 
            lachtes.put(bc, countDownLatch);
            //.. here a thread is started that waits on the latch until the listeners onSuspend-Method is called
            // and then calls bc.broadcast(data);
            return new Broadcastable(null, bc);
    }

    //Listener-Class

    @Override
    public void onSuspend(
            AtmosphereResourceEvent<HttpServletRequest, HttpServletResponse> event) {
        //log.info("on suspend: " + event);
        Broadcaster bc = event.getResource().getBroadcaster();
        CountDownLatch l = latches.get(bc);
        l.countDown();
        latches.remove(bc);
    }

now my tests make ~200.000 requests like this sequentially. after some time theres no progess anymore. The GC is running all the time but cannot free any memory (i guess it's not throwing a OOM because my client stops requesting too at that time). so i made a heapdump and i saw that there are many JerseyBroadcasters still in Memory (20.091). (when i set Xmx to a high enough level my test completes but still the memory consumption raises the whole time when someone would expect it to be pretty constant since it's the same request over and over again)

i learned the hard way that atmosphere doesn't destroy those by default but i configured the "org.atmosphere.cpr.broadcasterLifeCyclePolicy" to be EMPTY_DESTROY (before that i ran out of memory much ealier). the heapdump now tells me (i analyzed it with the eclipse MemoryAnalyzerTool. i don't do that often so i may misinterpret this) that those Broadcasters are still in the DefaultBroadcasterFactory's ConcurrentHashMap (store).

i stored the heapdump. zipped it's 30 MB. if you could take a look at it i would really appreciate it. how can i make it available to you? should i create a git-repo for it or do you know an easier way?

greets christian

Unterminated broadcaster threads

It appears that after a message has been sent from the server, the thread created to do the sending stays suspended for a time. I believe this is due to the fact that the thread is expected to be "reused". If you wait, the threads will eventually die. This is a problem however because I think there is no finite limit to the number of threads that can be created per client. I've tested sending thousands of tiny messages to a client and it will attempt to create a new thread for each message waiting to be sent.

There was someone else on IRC who noticed the same issue. He apparently noticed the issue in pubsub as well so that could be used for testing. My analysis of the situation has not been confirmed and is only a user-level theory so feel free to take it for a grain of salt.

could this be a race condition?

hi, i'm not completely sure if i use the framework correctly, but i didn't find an example that was quite like my use-case

i have the following resource.

@Path("/write")
@POST
@Suspend(scope = SCOPE.REQUEST, resumeOnBroadcast = true, outputComments = false)
public Broadcastable writeEntries(
        WriteEntriesRequest awer, ,
        @HeaderParam(ResourceConstants.X_REQUEST_ID) final Broadcaster bc) {
    //the Broadcaster has SCOPE = APPLICATION at this point, but it is set to REQUEST later by the container (debugged it)

    WriteEntriesRequest wer = new WriteEntriesRequest(awer.getEntries(), containerReference, awer.getTimeout(), 
            transactionReference, awer.getIsolation(), awer.getContext());
    core.send(wer, null, new ReadOrTakeEntriesRequestCallbackHandler(bc));
    return new Broadcastable(bc);
}

now this line

core.send(wer, null, new ReadOrTakeEntriesRequestCallbackHandler(bc));

is calling bc.broadcast(...) quite fast, the Broadcastable may not be returned by the method by that time.

this Code is called by your AsyncHttpClient.

I worked around this problem by just letting the thread that invokes broadcast sleep for 50 ms before that invocation.

resolving AtmosphereHandlers needs to support deep-path wildcards

I would like to be able to assign an AtmosphereHandler to /chat/rooms/* (for a URL that would be chat/rooms/1/messages). A longer match (/chat/rooms/private, for instance) should also be supported, with resolver going to the best match. (So I'd need /chat/rooms/private/* as a separate handler)

Add feature to intercept broadcasted message to AtmosphereHandler ?

I would propose to add this feature in the next release.

Because Atmophere will support custom protocol, it would be nice to be able to intercept message before they are send to AtmopshereHandler.onStateChange (example)

The goal could be to remove the need to implements onStateChange and replace it by another Interface. If that Interface is implemented in out AtmosphereHandler, it will be used. Heu.. ok.. explaination.

Suppose that my protocol support events like : onClose, onDisconnect, onConnect, onTimeout, onResume.....

I want these events to be transparent to the user. Instead of implementing onStateChange... for resume and close and dispatch the event into the Handler...

I think it could be useful to intercept theses event.. and dispatch to the appropriate method : onTimeout...

I don't want to force the user the extends a CustomAtmopshereHandler just to do that, if it could be done by the protocol implementation and hide from the user.

Lifecycle policy scheduler needs to be modified based on activity

The code in DefaultBroadcaster.setBroadcasterLifeCyclePolicy schedules a Runnable to execute every units, where is the policy timeout. The IDLE_RESUME code path will execute if there are active resources for the broadcaster (!resources.isEmpty()) in which case the broadcaster is destroyed.

How does the Runnable determine how long the broadcaster has been idle? Is it cancelled if any activity on the broadcaster has been detected, and re-scheduled? If not, wouldn't the IDLE_RESUME code path be executed any time there is an active connection?

Need a generic way to configure plugin

Currently configuring plug-in require recompiling the class itself. Atmosphere should use reflection and some design pattern to configure Plugin on the fly based on a atmosphere.xml or web.xml property.

As an example, JGroup and Redis have their own way, something should be abstracted.

jquery.atmosphere.js add callback when websocket is really open

When you do:

$.atmosphere.subscribe(url, callback, $.atmosphere.request);

and RIGHT after that:

$.atmosphere.response.push(url);

The websocket may fail because it isn't open yet. (you have to check the state in the subscribe callback)

It would be nice to have an 'global' onopen callback where you can do your initial call for example

Minimum packet size for google chrome

This is not necessarily a bug in Atmosphere but we may be able to find a way to deal with it. Chrome appears to have a minimum receive buffer size for comet implementations. It seems to be that a message sent from the server to Chrome will be ignored until at least 8 bytes of data are received. Padding the message with extra bytes works well.

A possible Atmosphere workaround could be that atmosphere detects a chrome browser and pads the message for us and perhaps adds some information in the header about the padding so the client implementation can strip it off. This would only work if it is possible to send header information mid-stream which I don't think is possible. Even if adding to the header isn't possible, automatically padding the message with spaces would probably be the least painful solution since most applications would trim off extra space anyway.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.