Skip to content

Commit

Permalink
Fix for #635 Add support for simple AtmosphereHandler called OnMessag…
Browse files Browse the repository at this point in the history
…e. Simplify the chat sample
  • Loading branch information
jfarcand committed Sep 18, 2012
1 parent bac4699 commit 4d3cfbd
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 96 deletions.
56 changes: 56 additions & 0 deletions modules/cpr/src/main/java/org/atmosphere/handler/OnMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2012 Jean-Francois Arcand
*
* 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.
*/
package org.atmosphere.handler;

import org.atmosphere.cpr.AtmosphereHandler;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.cpr.AtmosphereResponse;

import java.io.IOException;

/**
* Simple {@link AtmosphereHandler} that can be used with the {@link org.atmosphere.interceptor.AtmosphereResourceLifecycleInterceptor}
* and {@link org.atmosphere.interceptor.BroadcastOnPostAtmosphereInterceptor} to reduce the handling of the suspend/resume/disconnect and
* broadcast operation.
*
* @author Jeanfrancois Arcand
*/
public abstract class OnMessage<T> implements AtmosphereHandler {
@Override
public final void onRequest(AtmosphereResource resource) throws IOException {
}

@Override
public final void onStateChange(AtmosphereResourceEvent event) throws IOException {
if (event.isSuspended()) {
onMessage(event.getResource().getResponse(), (T) event.getMessage());
}
}

@Override
public final void destroy() {
}

/**
* Implement this method to get invoked every time a new {@link org.atmosphere.cpr.Broadcaster#broadcast(Object)}
* occurs.
*
* @param message a message of type T
*/
abstract public void onMessage(AtmosphereResponse response, T message) throws IOException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,10 @@ public void postInspect(AtmosphereResource r) {
r.getBroadcaster().broadcast(stringBuilder.toString());
}
}

@Override
public String toString() {
return "Broadcast POST Body Interceptor";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
package org.atmosphere.samples.chat;

import org.atmosphere.config.service.AtmosphereHandlerService;
import org.atmosphere.cpr.AtmosphereHandler;
import org.atmosphere.cpr.AtmosphereRequest;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.cpr.AtmosphereResponse;
import org.atmosphere.handler.OnMessage;
import org.atmosphere.interceptor.AtmosphereResourceLifecycleInterceptor;
import org.atmosphere.interceptor.BroadcastOnPostAtmosphereInterceptor;

import java.io.IOException;
import java.util.Date;
Expand All @@ -30,59 +29,17 @@
*
* @author Jeanfrancois Arcand
*/
@AtmosphereHandlerService(path="/chat")
public class ChatAtmosphereHandler implements AtmosphereHandler {
@AtmosphereHandlerService(path="/chat", interceptors = {AtmosphereResourceLifecycleInterceptor.class, BroadcastOnPostAtmosphereInterceptor.class})
public class ChatAtmosphereHandler extends OnMessage<String> {

@Override
public void onRequest(AtmosphereResource r) throws IOException {
public void onMessage(AtmosphereResponse response, String message) throws IOException {
// Simple JSON -- Use Jackson for more complex structure
// Message looks like { "author" : "foo", "message" : "bar" }
String author = message.substring(message.indexOf(":") + 2, message.indexOf(",") - 1);
String chat = message.substring(message.lastIndexOf(":") + 2, message.length() - 2);

AtmosphereRequest req = r.getRequest();

// First, tell Atmosphere to allow bi-directional communication by suspending.
if (req.getMethod().equalsIgnoreCase("GET")) {
// The negotiation header is just needed by the sample to list all the supported transport.
if (req.getHeader("negotiating") == null) {
r.suspend();
} else {
r.getResponse().getWriter().write("OK");
}
// Second, broadcast message to all connected users.
} else if (req.getMethod().equalsIgnoreCase("POST")) {
r.getBroadcaster().broadcast(req.getReader().readLine().trim());
}
}

@Override
public void onStateChange(AtmosphereResourceEvent event) throws IOException {
AtmosphereResource r = event.getResource();
AtmosphereResponse res = r.getResponse();

if (event.isSuspended()) {
String body = event.getMessage().toString();

// Simple JSON -- Use Jackson for more complex structure
// Message looks like { "author" : "foo", "message" : "bar" }
String author = body.substring(body.indexOf(":") + 2, body.indexOf(",") - 1);
String message = body.substring(body.lastIndexOf(":") + 2, body.length() - 2);

res.getWriter().write(new Data(author, message).toString());
switch (r.transport()) {
case JSONP:
case AJAX:
case LONG_POLLING:
event.getResource().resume();
break;
default:
res.getWriter().flush();
break;
}
} else if (!event.isResuming()){
event.broadcaster().broadcast(new Data("Someone", "say bye bye!").toString());
}
}

@Override
public void destroy() {
response.getWriter().write(new Data(author, chat).toString());
}

private final static class Data {
Expand Down
9 changes: 0 additions & 9 deletions samples/chat/src/main/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@
margin-right: auto;
}

#detect {
padding: 5px;
background: #ffc0cb;
border-radius: 5px;
border: 1px solid #CCC;
margin-top: 10px;
}

#content {
padding: 5px;
background: #ddd;
Expand Down Expand Up @@ -71,7 +63,6 @@
</head>
<body>
<div id="header"><h3>Atmosphere Chat. Default transport is WebSocket, fallback is long-polling</h3></div>
<div id="detect"><h3>Detecting what the browser and server are supporting</h3></div>
<div id="content"></div>
<div>
<span id="status">Connecting...</span>
Expand Down
33 changes: 0 additions & 33 deletions samples/chat/src/main/webapp/jquery/application.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
$(function () {
"use strict";

var detect = $('#detect');
var header = $('#header');
var content = $('#content');
var input = $('#input');
Expand All @@ -13,38 +12,6 @@ $(function () {
var subSocket;
var transport = 'websocket';

<!-- The following code is just here for demonstration purpose and not required -->
<!-- Used to demonstrate the request.onTransportFailure callback. Not mandatory -->
var sseSupported = false;

var transports = new Array();
transports[0] = "websocket";
transports[1] = "sse";
transports[2] = "jsonp";
transports[3] = "long-polling";
transports[4] = "streaming";
transports[5] = "ajax";

$.each(transports, function (index, transport) {
var req = new $.atmosphere.AtmosphereRequest();

req.url = document.location.toString() + 'chat';
req.contentType = "application/json";
req.transport = transport;
req.headers = { "negotiating" : "true" };

req.onOpen = function(response) {
detect.append('<p><span style="color:blue">' + transport + ' supported: ' + '</span>' + (response.transport == transport));
}

req.onReconnect = function(request) {
request.close();
}

socket.subscribe(req)
});
<!-- Below is code that can be re-used -->

// We are now ready to cut the request
var request = { url: document.location.toString() + 'chat',
contentType : "application/json",
Expand Down

0 comments on commit 4d3cfbd

Please sign in to comment.