Camel 2.14.0 / CXF 3.0.1 Jetty config: protocol mismatch error
We have a couple of webservices (REST + SOAP) running in Apache Camel 2.13.0 based on CXF version 2.7.10 that use SSL and Basic Authentication in full, which works very well.
Due to the upgrade from Camel version to 2.14.0, which internally uses CXF 3.0.1, our services have now stopped working Protocol mismatch for port x: engine protocol is http, the url protocol is https
- however the configuration was not affected during the version upgrade.
...
Caused by: java.io.IOException: Protocol mismatch for port 8081: engine protocol is http, the url protocol is https
at org.apache.cxf.transport.http_jetty.JettyHTTPServerEngineFactory.createJettyHTTPServerEngine(JettyHTTPServerEngineFactory.java:271)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.retrieveEngine(JettyHTTPDestination.java:121)
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.finalizeConfig(JettyHTTPDestination.java:154)
... 48 more
So I created a new eclipse project that simplifies it to the bare minimum (just a simple SOAP service with two endpoints that use either HTTP or HTTPS).
Jetty server configuration can be seen here
The actual service is configured as a bean to use that bean in the Camel route later:
@Bean(name="endpoint1ServiceSSL")
public CxfSpringEndpoint endpoint1ServiceSSL() throws Exception
{
final CxfSpringEndpoint factoryBean = new CxfSpringEndpoint();
factoryBean.setServiceClass(EnhancedEndpoint1Endpoint.class);
factoryBean.setWsdlURL("classpath:/wsdl/test.wsdl");
factoryBean.setEndpointName(new QName(NAMESPACE, "Endpoint1ServicePort", PREFIX));
factoryBean.setServiceName(new QName(NAMESPACE, "Endpoint1_Service", PREFIX));
factoryBean.setAddress(env.getProperty("services.address.ssl")+"/endpoint1");
factoryBean.setDataFormat(DataFormat.POJO);
final Map<String, Object> properties = new HashMap<>();
properties.put("schema-validation-enabled", "true");
properties.put("allowStreaming", true);
factoryBean.setProperties(properties);
factoryBean.getInInterceptors().add(new LoggingInInterceptor());
factoryBean.getOutInterceptors().add(new LoggingOutInterceptor());
return factoryBean;
}
NAMESPACE
and PREFIX
- these are just some constants, nothing important for this example. bean gets specific values ββlike the base address of the service from a properties file that only contains values ββlike:
services.address = http://0.0.0.0:8080/
services.address.ssl = https://0.0.0.0:8081/
and other ssl keystore related stuff. Note that CXF will use the quay beans configuration during the initialization process and therefore create a secure SSL connection for HTTPS-invoked URLs - at least this happened before the version update.
The route can now access the service using this very simple route:
public class Endpoint1Route extends RouteBuilder
{
@Override
public void configure() throws Exception
{
from("cxf:bean:endpoint1Service")
.to("log:endpoint1Service");
from("cxf:bean:endpoint1ServiceSSL")
.to("log:endpoint1ServiceSSL");
}
}
This worked well with CXF 2.7.10 and Camel 2.13.0 - but as said above, there is a protocol inconsistency after the upgrade for whatever reason (hopefully you can see from the github linked project; after cloning the project, you you must execute generate-sources and then run ServicesApp
as a stand-alone Java application).
I also created a new branch to update the version to make it easier to switch between both versions.
Does anyone know why the Jetty config that was working before the version upgrade now returns a protocol mismatch error? Are there any updated libraries missing that I haven't figured out yet? Or am I setting something wrong in the first place?
@Edit:
After further testing, I'm pretty sure that some API changes inside CXF led to problems as the bean that configures the secure SSL Jetty server is no longer executed on startup, and with version 2.7.10 the bean gets executed.
This changes the actual question to "How to set up a Jetty Server SSL in Apache CXF 3.0.1"
@Edit # 2:
I was able to get a secure SSL Jetty server running in Camel 2.14.0 / CXF 3.0.1, but only via XML config . Since we prefer Java configuration over XML, we are still looking for a method to configure Jetty with SSL in CXF 3.0.1. However, the jettySSLEngineFactory Spring bean pass file seems to me to be another CXF error.
To clarify, in CXF 2.7.x, the jetty server can be configured in Java when creating a Spring bean that returns an instance JettyHTTPServerEngineFactory
as shown in the master branch of the github project linked above. This bean was used by CXF when configuring the server instance and hence configuring the Jetty SSL secured server. However, in CXF 3.0.1, this bean is no longer called - the only JettyDestinationFactory
one I don't know about is how to set up a secure SSL server. Also, the XML example provided in the docs does not provide any clue on how to set up Jetty with SSL using a destination factory.
Since engine-factory
inside the XML example in the docs actually maps to the configuration JettyHTTPServerEngineFactory
and Jetty via XML, it works fine, this seems to indicate a Spring bean error inside CXF 3.0.1 so that I.
source to share
As the protocol mismatch error was caused by CXF skipping the bean initialization of the jetty bean configuration. However, it turns out that there are certain issues with an internal change to the Spring version in CXF extending the Spring configuration class.
When you remove extends SoapSSLConfig
in CxfEndpointConfig
and inject this class, the configuration is done by @Import(SoapSSLConfig.class)
initializing the bean, and so the configuration of the Jetty server still works.
Used code:
@Configuration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
public class CxfEndpointConfig extends SoapSSLConfig
{
...
}
which lead to injection failures. Replacing the above code with the below solution to the problem.
@Configuration
@ImportResource({ "classpath:META-INF/cxf/cxf.xml" })
@Import(SoapSSLConfig.class)
public class CxfEndpointConfig
{
...
}
source to share