I'm trying to use CometD with websocket transport in my webapp, but the handshake with such transport fails with error "Unknown Bayeux Transport", and CometD always fallback to long-polling.
I'm using
Here is the web.xml
<servlet>
<servlet-name>cometd</servlet-name>
<servlet-class>org.cometd.server.CometDServlet</servlet-class>
<init-param>
<param-name>jsonContext</param-name>
<param-value>com.myapp.MyAppJettyJSONContextServer</param-value>
</init-param>
<init-param>
<param-name>allowedTransports</param-name>
<param-value>websocket,long-polling</param-value>
</init-param>
<init-param>
<param-name>transports</param-name>
<param-value>org.cometd.websocket.server.JettyWebSocketTransport,org.cometd.server.transport.AsyncJSONTransport</param-value>
</init-param>
<init-param>
<param-name>ws.cometdURLMapping</param-name>
<param-value>/cometd/*</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>cometd</servlet-name>
<url-pattern>/cometd/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>configuration</servlet-name>
<servlet-class>com.myapp.MyAppConfigurationServlet</servlet-class>
<init-param>
<param-name>SERVER_URL</param-name>
<param-value>http://localhost:8380/myapp/cometd</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<filter>
<filter-name>cross-origin</filter-name>
<filter-class>org.eclipse.jetty.servlets.CrossOriginFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>cross-origin</filter-name>
<url-pattern>/cometd/*</url-pattern>
</filter-mapping>
Here is the code of MyAppConfigurationServlet.java
public class MyAppConfigurationServlet extends GenericServlet
{
private static final long serialVersionUID = 6918716199131599352L;
private static final Logger log = LoggerFactory.getLogger(MyAppConfigurationServlet.class);
public static final String PUSH_SERVICE = "pushService";
public static final String CONFIG_SERVER_URL = "SERVER_URL";
@Override
public void init() throws ServletException
{
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
BayeuxServer bayeux = (BayeuxServer) getServletContext().getAttribute(BayeuxServer.ATTRIBUTE);
String serverUrl = getInitParameter(CONFIG_SERVER_URL);
log.debug("Creating PushService at url {}", serverUrl);
PushService pushService = new PushService(bayeux, serverUrl);
sharePushService(ctx, pushService);
}
private void sharePushService(WebApplicationContext ctx, PushService pushService)
{
try
{
PushServiceHolder container = (PushServiceHolder) ctx.getBean(PUSH_SERVICE);
container.setPushService(pushService);
}
catch (BeansException e)
{
log.warn("Cannot find the bean {});
log.trace("Error!", e);
}
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
{
throw new ServletException();
}
}
where PushServiceHolder
is a simple spring bean that makes available the PushService
to the other beans.
Here is the client implementation
Map<String, Object> options = new HashMap<>();
JettyJSONContextClient jsonContext = new MyAppJettyJSONContextClient();
options.put(ClientTransport.JSON_CONTEXT_OPTION, jsonContext);
HttpClient httpClient = new HttpClient();
httpClient.setMaxConnectionsPerDestination(2);
httpClient.setConnectTimeout(60000);
httpClient.start();
WebSocketClient webSocketClient = new WebSocketClient(httpClient);
webSocketClient.start();
ClientTransport wsTransport = new JettyWebSocketTransport(options, null, webSocketClient);
BayeuxClient client = new BayeuxClient(url, wsTransport, longPollingTransport);
client.handshake();
client.waitFor(5000, BayeuxClient.State.CONNECTED);
The handshake is never successful for websocket transport, with a 404 http error code, so CometD fallbacks on long-polling.
Debugging into org.cometd.server.CometDServlet
I found this part
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if ("OPTIONS".equals(request.getMethod())) {
serviceOptions(request, response);
return;
}
AbstractHttpTransport transport = _bayeux.findHttpTransport(request);
if (transport == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown Bayeux Transport");
} else {
transport.handle(request, response);
}
}
The org.cometd.websocket.server.JettyWebSocketTransport
is not an AbstractHttpTransport
, so it will never be taken into account by this code, even if it has been configured correctly as allowed transport.
Thus the handshake request for the websocket transport always ends with the error "Unknown Bayeux Transport".
I've used the CometD documentation here and here to create the web.xml
.
I would like to take a look to the CometD maven primer, as advised many times by the CometD team, but the command
$ mvn org.apache.maven.plugins:maven-archetype-plugin:2.4:generate -DarchetypeCatalog=http://cometd.org
returns this error
[WARNING] Error reading archetype catalog http://cometd.org
org.apache.maven.wagon.TransferFailedException: URI does not specify a valid host name: http:/cometd.org
at org.apache.maven.wagon.providers.http.wagon.shared.AbstractHttpClientWagon.fillInputData (AbstractHttpClientWagon.java:1069)
at org.apache.maven.wagon.providers.http.wagon.shared.AbstractHttpClientWagon.fillInputData (AbstractHttpClientWagon.java:963)
at org.apache.maven.wagon.StreamWagon.getInputStream (StreamWagon.java:126)
at org.apache.maven.wagon.StreamWagon.getIfNewer (StreamWagon.java:88)
at org.apache.maven.wagon.StreamWagon.get (StreamWagon.java:61)
at org.apache.maven.archetype.source.RemoteCatalogArchetypeDataSource.downloadCatalog (RemoteCatalogArchetypeDataSource.java:119)
at org.apache.maven.archetype.source.RemoteCatalogArchetypeDataSource.getArchetypeCatalog (RemoteCatalogArchetypeDataSource.java:87)
at org.apache.maven.archetype.DefaultArchetypeManager.getRemoteCatalog (DefaultArchetypeManager.java:216)
at org.apache.maven.archetype.ui.generation.DefaultArchetypeSelector.getArchetypesByCatalog (DefaultArchetypeSelector.java:218)
at org.apache.maven.archetype.ui.generation.DefaultArchetypeSelector.selectArchetype (DefaultArchetypeSelector.java:71)
at org.apache.maven.archetype.mojos.CreateProjectFromArchetypeMojo.execute (CreateProjectFromArchetypeMojo.java:181)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:954)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:498)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
Caused by: org.apache.maven.wagon.providers.http.httpclient.client.ClientProtocolException: URI does not specify a valid host name: http:/cometd.org
at org.apache.maven.wagon.providers.http.httpclient.impl.client.CloseableHttpClient.determineTarget (CloseableHttpClient.java:95)
at org.apache.maven.wagon.providers.http.httpclient.impl.client.CloseableHttpClient.execute (CloseableHttpClient.java:83)
at org.apache.maven.wagon.providers.http.wagon.shared.AbstractHttpClientWagon.execute (AbstractHttpClientWagon.java:825)
at org.apache.maven.wagon.providers.http.wagon.shared.AbstractHttpClientWagon.fillInputData (AbstractHttpClientWagon.java:986)
at org.apache.maven.wagon.providers.http.wagon.shared.AbstractHttpClientWagon.fillInputData (AbstractHttpClientWagon.java:963)
at org.apache.maven.wagon.StreamWagon.getInputStream (StreamWagon.java:126)
at org.apache.maven.wagon.StreamWagon.getIfNewer (StreamWagon.java:88)
at org.apache.maven.wagon.StreamWagon.get (StreamWagon.java:61)
at org.apache.maven.archetype.source.RemoteCatalogArchetypeDataSource.downloadCatalog (RemoteCatalogArchetypeDataSource.java:119)
at org.apache.maven.archetype.source.RemoteCatalogArchetypeDataSource.getArchetypeCatalog (RemoteCatalogArchetypeDataSource.java:87)
at org.apache.maven.archetype.DefaultArchetypeManager.getRemoteCatalog (DefaultArchetypeManager.java:216)
at org.apache.maven.archetype.ui.generation.DefaultArchetypeSelector.getArchetypesByCatalog (DefaultArchetypeSelector.java:218)
at org.apache.maven.archetype.ui.generation.DefaultArchetypeSelector.selectArchetype (DefaultArchetypeSelector.java:71)
at org.apache.maven.archetype.mojos.CreateProjectFromArchetypeMojo.execute (CreateProjectFromArchetypeMojo.java:181)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:208)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:154)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:146)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
at org.apache.maven.cli.MavenCli.execute (MavenCli.java:954)
at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:288)
at org.apache.maven.cli.MavenCli.main (MavenCli.java:192)
at sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:498)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:356)
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
What am I missing in my configuration? What is the correct address of the CometD archetype catalog?
Thanks a lot
In general, CometD recommends to deploy in Jetty and to use the latest release (at this time 4.0.4).
Your web.xml
has incorrect values for the transports
init-param
.
JettyWebSocketTransport
is a CometD transport that uses Jetty-specific API in its implementation; as such, it only works when your application is deployed in Jetty.
I recommend that you remove the transports
init-param
and let CometD pick the proper defaults, which will work in both Jetty and Tomcat.
For the record, the default WebSocket transport is org.cometd.websocket.server.WebSocketTransport
which is based on the standard JSR 356 APIs that are implemented by both Jetty and Tomcat.
Your client is correct, although there also you may want to use the standard WebSocket transport, org.cometd.websocket.client.WebSocketTransport
.
I tried the command to generate a project from the archetypes and works fine for me.
Perhaps you have a hint in the error: URI does not specify a valid host name: http:/cometd.org
- see how there is only 1 slash, not the required 2 slashes.
In summary:
transports
configuration and use the defaults.https://cometd.org
.