2. Spring Bayeux Integration for Comet on Jetty

Web Configuration

The SpringContinuationCometdServlet is configured to handle all Comet requests. It only needs the asyncDeliver value set on it and the other values you would normally set on ContinuationCometdServlet are all set on SpringContinuationBayeux in the Spring configuration.

                    
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
    <display-name>Spring Cometd Test WebApp</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/web-application-context.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <servlet>
        <servlet-name>cometd</servlet-name>
        <servlet-class>org.springbyexample.cometd.continuation.SpringContinuationCometdServlet</servlet-class>
        <init-param>
            <param-name>asyncDeliver</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>cometd</servlet-name>
        <url-pattern>/cometd/*</url-pattern>
    </servlet-mapping>  
</web-app>
                    
                

Spring Configuration

                    
[
    { 
        "channels": "/**",
        "filter"  : "org.mortbay.cometd.filter.NoMarkupFilter",
        "init"    : {}
    },

    { 
        "channels": "/chat/*",
        "filter"   : "org.mortbay.cometd.filter.RegexFilter",
        "init"    : [ 
                        [ "[Ss]pring [Bb]y [Ee]xample","Spring by Example" ],
                        [ "[Ss][Bb][Ee]","Spring by Example" ]
                    ]
    },
  
    { 
        "channels": "/chat/**",
        "filter"   : "org.mortbay.cometd.filter.RegexFilter",
        "init"    : [ 
                          [ "teh ","the "],
                          [ "sring ","spring "] 
                    ]
    }
  
]
            ]]>
        </value>
    </property>
</bean>
                    
                

Code Example

The only difference in this compared to a standard BayeuxService is that this Bayeux implementation is instantiated by Spring and the Bayuex instance is injected into it's constructor.

                    
@Component
public class ChatService extends BayeuxService {
    
    final Logger logger = LoggerFactory.getLogger(ChatService.class);
    
    final ConcurrentMap<String, Set<String>> _members = new ConcurrentHashMap<String, Set<String>>();

    /**
     * Constructor
     */
    @Autowired
    public ChatService(Bayeux bayeux) {
        super(bayeux, "chat");
        subscribe("/chat/**", "trackMembers");
    }

    /**
     * Tracks chat clients.
     */
    public void trackMembers(Client joiner, String channel,
                             Map<String, Object> data, String id) {
        if (Boolean.TRUE.equals(data.get("join"))) {
            Set<String> m = _members.get(channel);

            if (m == null) {
                Set<String> new_list = new CopyOnWriteArraySet<String>();
                m = _members.putIfAbsent(channel, new_list);
                if (m == null) {
                    m = new_list;
                }
            }

            final Set<String> members = m;
            final String username = (String) data.get("user");

            members.add(username);

            joiner.addListener(new RemoveListener() {
                public void removed(String clientId, boolean timeout) {
                    members.remove(username);

                    logger.info("members: " + members);
                }
            });
            
            logger.info("Members: " + members);
            
            send(joiner, channel, members, id);
        }
    }
    
}