karthi chellam
karthi chellam

Reputation: 11

Cometd Client not handshaking with cometD Server

I am new to CometD.I have a written a basic CometD Server in java and simple CometD Client.I am getting Successful response from postman for /meta/handshake,/meta/connect,/meta/subscribe channels. But when i start using my cometD java client(which i reused from the https://protect-us.mimecast.com/s/vLH6CNk58of1Ow1GsmVz4u?domain=github.com), handshake is failing with the below message.

Failing {supportedConnectionTypes=[long-polling], channel=/meta/handshake, id=22, version=1.0}

I am using cometdVersion - '4.0.0',jettyVersion - '9.4.0.v20161208', springbootVersion - '1.5.14.RELEASE' in my code. I have done a dynamic servlet registration to AnnotationCometDServlet and added /notifications as mapping. I have created a channel as below in bayeuxServer configuration class.

bayeuxServerImpl.createChannelIfAbsent("/updates", 
(ServerChannel.Initializer) channel -> channel.addAuthorizer(GrantAuthorizer.GRANT_ALL));

In client code, i have used /notifications as the defaulturl and channel as /updates

@Service("cometListener")
@Slf4j
public class BayeuxListener implements BayeuxServer.SessionListener  {

@Inject
private BayeuxServer bayeuxServer;
@Session
private ServerSession serverSession;


@Configure({"/updates**,/notifications**"})
protected void configureChannel(ConfigurableServerChannel channel) {
    channel.addAuthorizer(GrantAuthorizer.GRANT_ALL);
    channel.addAuthorizer(GrantAuthorizer.GRANT_PUBLISH);
    channel.setPersistent(true);
}

@Listener("/meta/*")
public void monitorMeta(ServerSession session, ServerMessage message) {
    log.info("monitoring meta"+message.toString()+"channel "+message.getChannel()+"session id "+session.getId());
}

@Listener("/meta/subscribe")
public void monitorSubscribe(ServerSession session, ServerMessage message) {      
    log.info("Monitored Subscribe from " + session + " for " + message.get(Message.SUBSCRIPTION_FIELD));
}

@Listener("/meta/unsubscribe")
public void monitorUnsubscribe(ServerSession session, ServerMessage message) {
    log.info("Monitored Unsubscribe from " + session + " for " + message.get(Message.SUBSCRIPTION_FIELD));
}

@Listener("/updates")
public void handlesrgUpdates(ServerSession client, ServerMessage message) {
    ServerSession cilentSession = bayeuxServer.getSession(client.getId());
    client.deliver(cilentSession,"/updates", "Received message back from client");
}
}

Upvotes: 1

Views: 1791

Answers (1)

sbordet
sbordet

Reputation: 18507

You have a strange combination of CometD version, Jetty version and Spring Boot version. I recommend that you stick with the default versioning declared in the CometD POM, i.e. CometD 4.0.2, Jetty 9.4.14 and Spring Boot 2.0.6.

The handshake failure you mention is not complete or it is not a failed handshake reply. This is because handshake replies have the successful field, and what you mention {supportedConnectionTypes=[long-polling], channel=/meta/handshake, id=22, version=1.0} looks like the handshake request. As such it's difficult to say what the problem is, because the failure reason is typically reported in the handshake reply.

If you have dynamically registered the CometD Servlet under the /notifications Servlet mapping, then the client should have a URL that ends with /notifications. Note that the Servlet mapping /notifications and the CometD channel /notifications are two different things and are not related - they just happen to have the same name.

Your code is mostly fine, but contains a few errors.

@Configure({"/updates**,/notifications**"})
protected void configureChannel(ConfigurableServerChannel channel) {
    channel.addAuthorizer(GrantAuthorizer.GRANT_ALL);
    channel.addAuthorizer(GrantAuthorizer.GRANT_PUBLISH);
    channel.setPersistent(true);
}

The code above must instead be:

@Configure({"/updates/**,/notifications/**"})
protected void configureChannel(ConfigurableServerChannel channel) {
    channel.addAuthorizer(GrantAuthorizer.GRANT_ALL);
    channel.setPersistent(true);
}

Note that the channel globbing must be after a /. There is no need to GRANT_PUBLISH after a GRANT_ALL, which include GRANT_PUBLISH. The configuration method should be public, not protected.

@Listener("/updates")
public void handlesrgUpdates(ServerSession client, ServerMessage message) {
    ServerSession cilentSession = bayeuxServer.getSession(client.getId());
    client.deliver(cilentSession,"/updates", "Received message back from client");
}

There is no need to retrieve clientSession from bayeuxServer because it is already been passed as parameter client to the method. The method can be better implemented as:

@Listener("/updates")
public void handlesrgUpdates(ServerSession client, ServerMessage message) {
    client.deliver(serverSession, "/updates", "Received message back from client");
}

Note how the "sender" of the message is the serverSession reference that has been injected as a field of the class.

The code above is still possibly wrong. Because /updates is a broadcast channel, if the client is subscribed to the /updates channel, when the client publishes a message to the /updates channel it will receive it back from the server (because the client is subscribed to the /updates channel) and the code above will also send another message to the client on the /updates channel via deliver(), so the client will receive two different messages on the /updates channel. This may be what you want, but most of the times it's not. Please have a read at the difference between broadcast channels and service channels.

Update the question with the details of your handshake failure, and use consistent versioning for CometD, Jetty and Spring Boot.

Upvotes: 1

Related Questions