Reverse Ajax, Part 4: Atmosphere and CometD

Introduction

This  series of  articles shows you how to develop event-driven Web programs using reverse Ajax techniques. Part 1  covered Reverse Ajax, polling, streaming, Comet, and long polling. Part 2  explained how to implement Reverse Ajax using WebSocket, and discussed the limitations of Web servers using Comet and WebSocket. Part 3  explores some of the difficulties you encounter when implementing your own Comet or WebSocket communication system when you need to support multiple servers or provide a standalone Web application that users can deploy on their own servers. Even if the JavaScript code on the client is simple, you still need some exception handling, reconnection, and confirmation. On the server side, the lack of a global API as well as some web server APIs necessitates the use of frameworks with abstractions. Part 3 also discusses Socket.IO.

In this article, you'll learn about Atmosphere and CometD, the most well-known open source reverse Ajax libraries for Java servers.

You can download the  source code used in this article .

prerequisites

Ideally, you should know JavaScript and Java if you want to get the most out of this article. To run the examples in this article, you need the latest version of Maven and JDK (see  Resources ).

 

Atmosphere framework

Atmosphere is a Java technology framework that provides a common API for using the Comet and WebSocket features of many Web servers, including Tomcat, Jetty, GlassFish, Weblogic, Grizzly, JBossWeb, JBoss, and Resin. It supports any Web server that supports the Servlet 3.0 Specification. Of all the frameworks presented in this series, Atmosphere supports the most servers.

Atmosphere can detect the native server API against Comet, Atmosphere and switch back to the Servlet 3.0 runtime environment. Or fall back to "managed" asynchronous mode (but without the scalability of Jetty Continuations), which also applies to Comet. Atmosphere has been on the market for over two years and is still in active development. It is used in large web applications such as JIRA, one of the most well-known issue trackers. Figure 1 shows the Atmosphere framework.

Figure 1. Architectural view of Atmosphere

Architectural view of the Atmosphere framework

The Atmosphere framework consists of the Atmosphere runtime, which provides a common API for a variety of different Web server solutions and standards. At runtime, clients can access the API and reverse Ajax features by setting up a servlet and using the Google Web Toolkit (GWT). Alternatively, you can also use Jersey, a framework for implementing JSR-311 (the JAX-RS specification). Therefore, Atmosphere can be used in many other REST scenarios using annotations. After configuring the modules of your choice, you can access the Atmosphere runtime by implementing classes (discussed later in this article). You are also free to use the provided plugins to add support for clustering, messaging, dependency injection. If you're using a web framework (Wicket, Struts, or Spring MVC), you can explicitly add support for reverse Ajax by using Atmosphere's MeteorServlet. The servlet exposes Meteor objects that can be retrieved in controllers and services to suspend or restart requests.

The strength of Atmosphere is still on the server side: it provides a standardized API that contains all the different solutions and methods for communicating with WebSockets or Comet. Atmosphere does not use protocols for communication between client and server, such as Socket.IO and CometD. Both libraries provide client-side JavaScript and server-side servlets that communicate using specific protocols (protocols for handshake, messaging, acknowledgments, and heartbeats). The goal of Atmosphere is to provide a common communication channel on the server side. If you need to use a specific protocol, such as Bayeux (the one used by CometD), you must develop your own "handler" in Atmosphere. The CometD plug-in does what you need: it leverages Atmosphere's API to suspend and resume requests, and manages CometD communication by using the Bayeux protocol to delegate to the CometD class.

Atmosphere provides a jQuery client library that makes connection setup easier by automatically detecting the best transport protocol available (WebSockets or CometD). The usage of Atmosphere's jQuery plugin is similar to the HTML5 WebSockets API. First connect to the server, register a callback to receive messages, and then put some data in.

The source code provided with this article   includes an Atmosphere sample that uses the handler directly with the Atmosphere servlet. The client code remains the same; the same  code used in the Part 1, Part 2, and Part 3 articles of this series (all in the chat sample code using Comet long polling). You can also use the jQuery plugin for Atmosphere, but this is not required because Atmosphere does not enforce any communication protocol. It is highly recommended that you look at other examples in the Atmosphere project, especially those using JSR-311 annotations (Jersey). They really simplify writing handlers.

Listing 1 shows the interface for the Atmosphere handler.

Listing 1.  AtmosphereHandler Interface
public interface AtmosphereHandler<F, G> {
    void onRequest(AtmosphereResource<F, G> resource)
        throws IOException;
    void onStateChange(AtmosphereResourceEvent<F, G> event)
        throws IOException;
    void destroy();
}

onRequest The method receives all requests from the client and decides whether to suspend or restart the request (or do nothing). Every time a request is suspended or restarted, a broadcast is sent, or a timeout occurs,  onStateChange an event is sent and received through the method.

onRequest Listing 2 shows the implementation of the methods for the Comet chat application  .

Listing 2.  AtmosphereHandler Interface - onRequest
Broadcaster broadcaster =
        BroadcasterFactory.getDefault().lookup(
        DefaultBroadcaster.class, ChatHandler.class.getName(), true);
broadcaster.setScope(Broadcaster.SCOPE.APPLICATION);
resource.setBroadcaster(broadcaster);
HttpServletRequest req = resource.getRequest();
String user = (String) req.getSession().getAttribute("user");
if (user != null) {
    if ("GET".equals(req.getMethod())) {
        resource.suspend(-1, false);
    } else if ("POST".equals(req.getMethod())) {
        String cmd = req.getParameter("cmd");
        String message = req.getParameter("message");
        if ("disconnect".equals(cmd)) {
            close(resource);
        } else if (message != null && message.trim().length() > 0) {
            broadcaster.broadcast("[" + user + "] " + message);
        }
    }
}

A typical convention is to suspend a GET request, and use a POST request to send the message. After receiving the message, it will broadcast to all resources registered in the broadcasting device. Note that the example does not HttpServlet write anything to the output stream aspect. Broadcast or suspend operations only send events received by other implementation methods, as shown in Listing 3:

Listing 3.  AtmosphereHandler Interface - onStateChange
Broadcaster broadcaster =
    BroadcasterFactory.getDefault().lookup(
        DefaultBroadcaster.class, ChatHandler.class.getName(), true);
// Client closed the connection.
if (event.isCancelled()) {
    close(event.getResource());
    return;
}
try {
    String message = (String) event.getMessage();
    if (message != null) {
        PrintWriter writer =
            event.getResource().getResponse().getWriter();
        writer.write(message);
        writer.flush();
    }
} finally {
    if (!event.isResumedOnTimeout()) {
        event.getResource().resume();
    }
}

Now you need a working Comet chat application. In a nutshell, the important Atmosphere concepts are: a resource object that represents a connection, and a broadcaster responsible for triggering resource events and deciding to suspend or resume requested events. Note that this is just a Comet example. To be able to use WebSocket and Comet, you need to use a client library, and a more complex handler.

Table 1 The following table outlines the pros and cons of using the Atmosphere framework.

Table 1. Pros and cons of Atmosphere
pros and cons

If you have to deploy a web application on multiple web servers out of your control. Also, because Atmosphere supports the use of multiple Web servers, it is a better choice for getting the reverse Ajax feature of the application to work properly.

When you need to use a generic API over raw reverse Ajax communication, if there isn't any well-defined protocol, then you may want to develop or extend the protocol.

There is a lack of documentation on Atmosphere's architecture, projects, concepts, and API, which can be helpful if you need to study the source code or analyze the provided examples. Compared to the simpler APIs of other frameworks (such as Socket.IO and ometD), this API is more technical, albeit a little confusing at times. Even with Atmosphere annotations, some names and properties are still very technical.

While there are great abstractions on the server side, there are no good client libraries and no protocols, so everything else is left to the developers. If you need to use advanced timeout detection, acknowledgment, fallback, and cross-origin features, especially on mobile devices, the current library is too simple for the needs of large, scalable web applications. In this case, CometD is more reliable; it uses a communication protocol that can be used to activate some control flow and error detection, all of which are available in CometD. If you need extra features, using the CometD JavaScript client and the Atmosphere CometD plugin is a good alternative.

 

CometD framework

CometD 框架是基于 HTTP 的事件驱动通信解决方案,已面市多年。CometD 框架的第 2 版本中添加了对注释配置和 WebSocket 的支持。CometD 框架提供了一个 Java 服务器部件和一个 Java 客户端部件,还有一个基于 jQuery 和 Dojo 的 JavaScript 客户端库。CometD 使用了一个叫 Bayeux 的标准化通信协议,充许您针对于消息确认、流控制、同步、集群等方面进行扩展。

CometD 的事件驱动方法非常适合事件驱动 Web 开发的新概念。正如传统的桌面用户界面那样,所有的组件均通过总线进行通信,以便发送通知和接收事件。因此所有的通信都是异步的。

CometD 框架:

  • 有大量的相关资料。
  • 提供了一些示例和 Maven 原型,以促进项目的启动。
  • 拥有精心设计的 API,支持扩展开发。
  • 提供了一个称为 Oort 的集群模块,该模块使您能够运行多个CometD Web 服务器,将它们看作是负载均衡器背后的集群中的节点,从而扩展许多 HTTP 连接。
  • 支持安全策略,允许更具体地配置由谁通过哪条通道发送消息。
  • 更好地与 Spring 和 Google Guice(依赖注入框架)集成。

Bayeux 协议

Bayeux 通信协议主要是基于 HTTP。它提供了客户端与服务器之间的响应性双向异步通信。Bayeux 协议基于通道进行通信,通过该通道从客户端到服务器、从服务器到客户端或从客户端到客户端(但是是通过服务器)路由和发送消息。Bayeux 是一种 “发布- 订阅” 协议。CometD 实现了 Bayeux 协议,除了 Comet 和 WebSocket 传输协议之外,它还提供了一个抽象层,以便通过 Bayeux 发送请求。

服务器和内部构件

CometD 与三个传输协议绑定在一起:JSON、JSONP 和 WebSocket。他们都依赖于 Jetty Continuations 和 Jetty WebSocket API。在默认情况下,可以在 Jetty 6、Jetty 7、和 Jetty 8 中以及其他所有支持 Servlet 3.0 Specification 的服务中使用 CometD。可以使用与扩展相同的方式添加和开发传输协议。您应该能够编写支持 Grizzly WebSocket API 和其他 API 的传输协议,然后再在配置 CometD 服务器的步骤中添加这些协议。图 2 显示了主要 CometD 数据块的概述。

图 2. CometD 的构架视图

Architectural view of the CometD framework, consisting of client and server libraries that communicate over the Bayeux protocol.  CometD supports extensions and different transport layers (WebSockets, Ajax long polling, etc.) and also supports multiple APIs on the server.

图 2图中没有显示访问消息通道的安全层。

本文提供的 源代码 包括一个使用 CometD 的 Web 应用程序。该 Web 应用程序的描述符包括 清单 4 中的定义,以便使用该聊天示例。

清单 4. web.xml
<servlet> 
    <servlet-name>cometd</servlet-name> 
    <servlet-class>
        org.cometd.java.annotation.AnnotationCometdServlet
    </servlet-class> 
    <async-supported>true</async-supported> 
    [...]
    <init-param> 
        <param-name>services</param-name> 
        <param-value>ChatService</param-value> 
    </init-param> 
    <init-param> 
        <param-name>transports</param-name> 
        <param-value>
            com.ovea.cometd.websocket.jetty8.Jetty8WebSocketTransport
        </param-value> 
    </init-param> 
</servlet>

CometD servlet 支持一些控制全局设置的选项,比如能够设置传输协议和服务的选项。在本示例中,假设您想要为 Jetty 8 添加 WebSocket 支持。服务器端的 CometD 服务类 ChatService 会控制每个人说话的聊天室,如 清单 5 中所示:

清单 5. CometD ChatService
@Service 
public final class ChatService { 

    @Inject 
    BayeuxServer server; 

    @PostConstruct 
    void init() { 
        server.addListener(new BayeuxServer.SessionListener() { 
            @Override 
            public void sessionAdded(ServerSession session) { 
                [...]
            } 

            @Override 
            public void sessionRemoved(ServerSession session, boolean timedout) {
                [...]
            } 
        }); 
    } 

    @Configure("/**") 
    void any(ConfigurableServerChannel channel) { 
        channel.addAuthorizer(GrantAuthorizer.GRANT_NONE); 
    } 

    @Configure("/chatroom") 
    void configure(ConfigurableServerChannel channel) { 
        channel.addAuthorizer(new Authorizer() { 
            @Override 
            public Result authorize(
                [..] // check that the user is in session
            } 
        }); 
    } 

    @Listener("/chatroom") 
    void appendUser(ServerSession remote, 
                    ServerMessage.Mutable message) { 
        [...]
    } 

}

清单 5 演示了 CometD 的一些重要特性,其中包括 :

  • 依赖注入
  • 生命周期管理
  • 全局信道配置
  • 安全管理
  • 消息转换(在所有消息前添加用户名)
  • 会话管理

在客户端,该示例没有进行任何扩展,只是使用原始的 CometD 代码,如 清单 6 中所示:

清单 6. CometD 客户端代码
// First create t cometd object and configure it

var cometd = new $.Cometd('CometD chat client'); 
cometd.configure({ 
    url: document.location + 'cometd', 
    logLevel: 'debug' 
}); 
cometd.websocketEnabled = 'WebSocket' in window;

// Then we register some listeners. Meta channels (those with 
// the form /meta/<name> are specific reserved channels)

cometd.addListener('/meta/disconnect', function(message) { 
    [...]
}); 

cometd.addListener('/meta/connect', function(message) { 
    [...]
});

// Then, starting a connexion can be done using:

cometd.handshake();

// And subscriptions with:

cometd.subscribe('/chatroom', function(event) { 
    [...] //  event.data holds the message
});

// We finally send data to the chatroom like this:

cometd.publish('/chatroom', msg);

CometD 的客户端 API 功能强大、可以扩展并且易于理解和使用。本文只介绍了 Web 应用程序的主要部件,所以请参见 示例应用程序,以便更好地了解 CometD 的强大。

表 2 概括了使用 CometD 框架的利与弊。

Table 2. Pros and Cons of CometD
pros and cons

CometD provides a complete solution from client to server and from standalone Java client to server. The framework has extensive documentation, an excellent API, and is easy to use. Best of all, it has an event-driven approach. CometD and Bayeux are part of many event-driven Web applications. Other reverse Ajax frameworks do not provide any event-driven mechanism, forcing end users to develop their own custom solutions.

CometD supports many necessary features such as reconnection, reliable timeout detection, fallback, batching, message acknowledgement and many more features you won't find in other reverse Ajax frameworks. CometD allows for the most reliable communication with the lowest latency.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326643441&siteId=291194637