Reputation: 11
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
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