Playing with Atmosphere and Comet/WebSocket

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Playing with Atmosphere and Comet/WebSocket

ncolomer
Salut JeanFrancois,

You and your team have done an amazing work on Atmosphere ! I'm playing with it since few days and it just rocks, thanks :)

Nevertheless, I encountered some issues while experimenting your jquery-pubsub sample. Just want to share some feedbacks and questions with you and the community.

I deployed jquery-pubsub sample on a GlassFish 3.1.2 fresh instance and enabled Comet and WebSocket. I use Chrome as web browser.

When using the WebSocket protocol, it seems that the WebSocket handshake is correctly done (101 Web Socket Protocol Handshake) and the request correctly pended, but I was unable to write any message using the form : nothing append on the web page (no other request or written data), and on server side neither (no logs wirtten).

When switching to the Streaming protocol, all works fine (on GF3.1 and Tomcat6/7).

Finally, I switched to the long-polling protocol and i remarked a strange behavior. When two clients are connected using the long-polling protocol, it seems messages are distributed erratically among them : when messages are sent from a client, it is delivered to other non long-polling client (ie streaming), but never delivered back to the sender. Is it normal ?

Here is my web.xml :
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
	<display-name>Test</display-name>
	<servlet>
		<description>AtmosphereServlet</description>
		<servlet-name>AtmosphereServlet</servlet-name>
		<servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
		<init-param>
			<param-name>com.sun.jersey.config.property.packages</param-name>
			<param-value>org.test.resources</param-value>
		</init-param>

		<init-param>
			<param-name>org.atmosphere.useWebSocket</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>org.atmosphere.useNative</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>org.atmosphere.cpr.WebSocketProcessor</param-name>
			<param-value>org.atmosphere.cpr.HttpServletRequestWebSocketProcessor</param-value>
		</init-param>

		<load-on-startup>0</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>AtmosphereServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>

And here is my resource :
@Path("/{topic}")
@Produces("text/html;charset=UTF-8")
public class LiveResource {

	private @PathParam("topic") Broadcaster topic;

	@GET
	public SuspendResponse<String> subscribe() {
		return new SuspendResponse.SuspendResponseBuilder<String>()
			.broadcaster(topic)
			.outputComments(true)
			.addListener(new LiveLogger())
			.build();
	}

	@POST
	@Broadcast({JavascriptClientFilter.class})
	public Broadcastable publish(@FormParam("message") String message) {
		return new Broadcastable(message, "", topic);
	}

}

Another questions,

Is the <async-supported>true</async-supported> always necessary ? I saw it in your livre blanc, but not in your recent samples. But if I ommit this declaration in my web.xml, GF throw me a java.lang.IllegalStateException: Request is within the scope of a filter or servlet that does not support asynchronous operations

I also tried to understand the consequences of specifying the following params ?
- org.atmosphere.useWebSocket
- org.atmosphere.useNative
- org.atmosphere.cpr.WebSocketProcessor
What does it induce for the container ? When I remove them, all seems to work fine with streaming (Maybe that means the framework choose the default servlet 3.0 implem ?)

Encore bravo et merci !
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Playing with Atmosphere and Comet/WebSocket

ncolomer
I tried the atmosphere-jquery-pubsub-0.8 sample on (fresh instances of) Tomcat7, GlassFish3.1 and Jetty8. Here is more feedbacks :

** Tomcat7, GlassFish3.1 + chrome
The behavior of long-polling was the same: it seems the jQuery API get a response back (when a message was broadcasted) but its responseBody is always empty :
Invoking 1 callbacks
response.state: messageReceived
response.transport: long-polling
response.responseBody:

Switching WebSocket (only with GlassFish, comet & websocket enabled), the behavior is the same as mentionned in my precedent message:
The handshake is initiated and then marked as pending. See the http request below
Origin: http://127.0.0.1:8080
Sec-WebSocket-Key1: 5) 1S7 P& 9D  734 &72
Connection: Upgrade
Host: 127.0.0.1:8080
Sec-WebSocket-Key2: @   388 4428040
Upgrade: WebSocket

Here is the printed log in the browser :
Invoking executeWebSocket
Invoking 1 callbacks
response.state: openning
response.transport: websocket
response.responseBody:

When sending messages, nothing append.
And after a while, the following http response is sent and the connection is closed
Sec-WebSocket-Location: ws://127.0.0.1:8080/atmosphere-jquery-pubsub-0.8-20110808.170750-32/pubsub/sdf
Sec-WebSocket-Origin: http://127.0.0.1:8080
Connection: Upgrade
Upgrade: WebSocket

** For Jetty8 + chrome,
I have the following browser log error when using WebSocket :
Invoking executeWebSocket
Error during WebSocket handshake: origin mismatch: http://127.0.0.1:8080 != 127.0.0.1:8080
Websocket failed. Downgrading to Comet and resending

When switching to long-polling, the Jetty server throws the following
21:44:11.269 [qtp1927739346-16] DEBUG o.a.cpr.AsynchronousProcessor - (suspend) invoked:
 HttpServletRequest: [POST /atmosphere-jquery-pubsub-0.8-20110808.170750-32/pubsub/sdf]@555989664 org.eclipse.jetty.server.Request@2123baa0
 HttpServletResponse: HTTP/1.1 200 


21:44:11.279 [Atmosphere-AsyncWrite-1] INFO  o.a.samples.pubsub.EventsLogger - onBroadcast(): <script id="atmosphere_0">parent.callback('test sent trying to use long-polling');</script>
21:44:11.279 [Atmosphere-AsyncWrite-2] INFO  o.a.samples.pubsub.EventsLogger - onResume(): 127.0.0.1:58921
21:44:11.301 [Atmosphere-AsyncWrite-0] DEBUG o.a.j.util.JerseyBroadcasterUtil - onException()
java.io.IOException: Connection closed
	at org.atmosphere.websocket.container.Jetty8WebSocketSupport.write(Jetty8WebSocketSupport.java:53) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.websocket.WebSocketHttpServletResponse$2.write(WebSocketHttpServletResponse.java:404) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at com.sun.jersey.spi.container.servlet.WebComponent$Writer.write(WebComponent.java:305) ~[jersey-server-1.6.jar:1.6]
	at com.sun.jersey.spi.container.ContainerResponse$CommittingOutputStream.write(ContainerResponse.java:134) ~[jersey-server-1.6.jar:1.6]
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202) ~[na:1.6.0_26]
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272) ~[na:1.6.0_26]
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276) ~[na:1.6.0_26]
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122) ~[na:1.6.0_26]
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212) ~[na:1.6.0_26]
	at java.io.BufferedWriter.flush(BufferedWriter.java:236) ~[na:1.6.0_26]
	at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) ~[jersey-server-1.6.jar:1.6]
	at org.atmosphere.jersey.util.JerseyBroadcasterUtil.broadcast(JerseyBroadcasterUtil.java:59) ~[atmosphere-jersey-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.jersey.JerseyBroadcaster.broadcast(JerseyBroadcaster.java:66) [atmosphere-jersey-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultBroadcaster.executeAsyncWrite(DefaultBroadcaster.java:504) [atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultBroadcaster$3.run(DefaultBroadcaster.java:523) [atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) [na:1.6.0_26]
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_26]
	at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_26]
	at java.lang.Thread.run(Thread.java:680) [na:1.6.0_26]
21:44:11.302 [Atmosphere-AsyncWrite-0] INFO  o.a.samples.pubsub.EventsLogger - onDisconnect(): 127.0.0.1:58926
21:44:12.493 [qtp1927739346-17] DEBUG o.a.cpr.AsynchronousProcessor - (suspend) invoked:
 HttpServletRequest: [POST /atmosphere-jquery-pubsub-0.8-20110808.170750-32/pubsub/sdf]@555989664 org.eclipse.jetty.server.Request@2123baa0
 HttpServletResponse: HTTP/1.1 200 


21:44:12.500 [Atmosphere-AsyncWrite-3] DEBUG o.a.j.util.JerseyBroadcasterUtil - onException()
org.eclipse.jetty.io.EofException: null
	at org.eclipse.jetty.http.HttpGenerator.flushBuffer(HttpGenerator.java:916) ~[na:na]
	at org.eclipse.jetty.http.AbstractGenerator.flush(AbstractGenerator.java:433) ~[na:na]
	at org.eclipse.jetty.server.HttpOutput.flush(HttpOutput.java:90) ~[na:na]
	at org.eclipse.jetty.server.HttpConnection$Output.flush(HttpConnection.java:998) ~[na:na]
	at com.sun.jersey.spi.container.servlet.WebComponent$Writer.flush(WebComponent.java:313) ~[jersey-server-1.6.jar:1.6]
	at com.sun.jersey.spi.container.ContainerResponse$CommittingOutputStream.flush(ContainerResponse.java:145) ~[jersey-server-1.6.jar:1.6]
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:278) ~[na:1.6.0_26]
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122) ~[na:1.6.0_26]
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212) ~[na:1.6.0_26]
	at java.io.BufferedWriter.flush(BufferedWriter.java:236) ~[na:1.6.0_26]
	at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58) ~[jersey-core-1.6.jar:1.6]
	at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306) ~[jersey-server-1.6.jar:1.6]
	at org.atmosphere.jersey.util.JerseyBroadcasterUtil.broadcast(JerseyBroadcasterUtil.java:59) ~[atmosphere-jersey-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.jersey.JerseyBroadcaster.broadcast(JerseyBroadcaster.java:66) [atmosphere-jersey-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultBroadcaster.executeAsyncWrite(DefaultBroadcaster.java:504) [atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultBroadcaster$3.run(DefaultBroadcaster.java:523) [atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441) [na:1.6.0_26]
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) [na:1.6.0_26]
	at java.util.concurrent.FutureTask.run(FutureTask.java:138) [na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_26]
	at java.lang.Thread.run(Thread.java:680) [na:1.6.0_26]
Caused by: java.io.IOException: Broken pipe
	at sun.nio.ch.FileDispatcher.write0(Native Method) ~[na:1.6.0_26]
	at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:29) ~[na:1.6.0_26]
	at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:72) ~[na:1.6.0_26]
	at sun.nio.ch.IOUtil.write(IOUtil.java:28) ~[na:1.6.0_26]
	at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:334) ~[na:1.6.0_26]
	at org.eclipse.jetty.io.nio.ChannelEndPoint.flush(ChannelEndPoint.java:227) ~[na:na]
	at org.eclipse.jetty.io.nio.SelectChannelEndPoint.flush(SelectChannelEndPoint.java:292) ~[na:na]
	at org.eclipse.jetty.http.HttpGenerator.flushBuffer(HttpGenerator.java:855) ~[na:na]
	... 24 common frames omitted
21:44:12.507 [Atmosphere-AsyncWrite-3] INFO  o.a.samples.pubsub.EventsLogger - onDisconnect(): 127.0.0.1:58920
21:44:18.580 [qtp1927739346-17] DEBUG o.a.cpr.AsynchronousProcessor - (suspend) invoked:
 HttpServletRequest: [POST /atmosphere-jquery-pubsub-0.8-20110808.170750-32/pubsub/sdf]@555989664 org.eclipse.jetty.server.Request@2123baa0
 HttpServletResponse: HTTP/1.1 200 

** About Tomcat7, despite my efforts, I don't understand how activate NIO support. I tried to set the appropriate connector in server.xml, removing one or both META-INF/context.xml and WEB-INF/lib/atmosphere-compat-tomcat.jar.
I always get the following WARN logs when launching and sending first broadcast via the client :
21:59:16.704 [http-bio-8080-exec-3] WARN  org.atmosphere.cpr.AtmosphereServlet - Tomcat failed to detect this is a Comet application because context.xml is missing or the Http11NioProtocol Connector is not enabled.
If that's not the case, you can also remove META-INF/context.xml and WEB-INF/lib/atmosphere-compat-tomcat.jar
java.lang.IllegalStateException: Tomcat failed to detect this is a Comet application because context.xml is missing or the Http11NioProtocol Connector is not enabled.
If that's not the case, you can also remove META-INF/context.xml and WEB-INF/lib/atmosphere-compat-tomcat.jar
	at org.atmosphere.container.Tomcat7CometSupport.<clinit>(Tomcat7CometSupport.java:45) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.6.0_26]
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) ~[na:1.6.0_26]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) ~[na:1.6.0_26]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513) ~[na:1.6.0_26]
	at org.atmosphere.cpr.DefaultCometSupportResolver.newCometSupport(DefaultCometSupportResolver.java:187) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultCometSupportResolver.resolveWebSocket(DefaultCometSupportResolver.java:245) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.DefaultCometSupportResolver.resolve(DefaultCometSupportResolver.java:233) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.AtmosphereServlet.autoDetectContainer(AtmosphereServlet.java:987) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.atmosphere.cpr.AtmosphereServlet.init(AtmosphereServlet.java:572) ~[atmosphere-runtime-0.8-SNAPSHOT.jar:0.8-SNAPSHOT]
	at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1228) ~[catalina.jar:7.0.20]
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1147) ~[catalina.jar:7.0.20]
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1043) ~[catalina.jar:7.0.20]
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4957) ~[catalina.jar:7.0.20]
	at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5284) ~[catalina.jar:7.0.20]
	at org.apache.catalina.core.StandardContext$3.call(StandardContext.java:5279) ~[catalina.jar:7.0.20]
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) ~[na:1.6.0_26]
	at java.util.concurrent.FutureTask.run(FutureTask.java:138) ~[na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [na:1.6.0_26]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [na:1.6.0_26]
	at java.lang.Thread.run(Thread.java:680) [na:1.6.0_26]
21:59:16.704 [http-bio-8080-exec-3] WARN  org.atmosphere.cpr.AtmosphereServlet - failed using comet support: org.atmosphere.container.Tomcat7CometSupport, error: Tomcat failed to detect this is a Comet application because context.xml is missing or the Http11NioProtocol Connector is not enabled.
If that's not the case, you can also remove META-INF/context.xml and WEB-INF/lib/atmosphere-compat-tomcat.jar
21:59:16.704 [http-bio-8080-exec-3] WARN  org.atmosphere.cpr.AtmosphereServlet - Using BlockingIOCometSupport.

Maybe I missed something (or lot of things :-). These deployment problems bother me especially as I think I get the concepts (thanks to blogs and this ml) but I'm not able to run these beatiful things :D

Thanks!
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Playing with Atmosphere and Comet/WebSocket

jfarcand
Administrator
Salut,

OK I will take a closer look at your scenario and make sure everything works. It may be a regression in 0.8 (I was out for awhile).

Thanks again for the detailed explanation and test scenario.

-- Jeanfrancois
Loading...