{"id":4714,"date":"2017-03-23T22:28:15","date_gmt":"2017-03-23T22:28:15","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=4714"},"modified":"2017-03-23T22:28:15","modified_gmt":"2017-03-23T22:28:15","slug":"hosting-a-cxf-soap-webservice-in-an-existing-jetty-instance","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/hosting-a-cxf-soap-webservice-in-an-existing-jetty-instance\/","title":{"rendered":"Hosting a CXF SOAP webservice in an existing Jetty instance"},"content":{"rendered":"<p>In the previous post we looked at creating a web service, exposing SOAP and running in a CXF created instance of Jetty, but what if you already have an application with an existing instance of Jetty running. All you want to do is drop a SOAP capable service into this instance.<\/p>\n<p>Like most of the things I&#8217;ve discovered working with CXF (and Spring), it&#8217;s not that difficult, once you know how. It&#8217;s the finding out &#8220;how&#8221; that seems more difficult :)<\/p>\n<p>First off, much credit goes to this post <a href=\"https:\/\/dzone.com\/articles\/embedded-jetty-and-apache-cxf\" target=\"_blank\">Embedded Jetty and Apache CXF: Secure REST Services With Spring Security<\/a> or more specifically the source code for this post, <a href=\"https:\/\/github.com\/reta\/jax-rs-2.0-spring-security\" target=\"_blank\">here<\/a>.<\/p>\n<p>I&#8217;m not interested (at this time) in security, so we&#8217;ll ignore that and just concern ourselves with injecting a service into an instance of Jetty created by the application itself (not by CXF).<\/p>\n<p>First up, let&#8217;s create our pom.xml<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;project xmlns=&quot;http:\/\/maven.apache.org\/POM\/4.0.0&quot; xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;\r\n  xsi:schemaLocation=&quot;http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd&quot;&gt;\r\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\r\n  &lt;groupId&gt;com.putridparrot.core&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;cxfws&lt;\/artifactId&gt;\r\n  &lt;packaging&gt;jar&lt;\/packaging&gt;\r\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\r\n  &lt;name&gt;cxfws&lt;\/name&gt;\r\n  &lt;url&gt;http:\/\/maven.apache.org&lt;\/url&gt;\r\n\r\n  &lt;properties&gt;\r\n    &lt;cxf.version&gt;3.0.1&lt;\/cxf.version&gt;\r\n    &lt;spring.version&gt;4.1.0.RELEASE&lt;\/spring.version&gt;\r\n    &lt;jetty.version&gt;9.4.2.v20170220&lt;\/jetty.version&gt;\r\n  &lt;\/properties&gt;\r\n\r\n  &lt;dependencies&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.apache.cxf&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;cxf-rt-frontend-jaxws&lt;\/artifactId&gt;\r\n      &lt;version&gt;${cxf.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-core&lt;\/artifactId&gt;\r\n      &lt;version&gt;${spring.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-context&lt;\/artifactId&gt;\r\n      &lt;version&gt;${spring.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-web&lt;\/artifactId&gt;\r\n      &lt;version&gt;${spring.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.eclipse.jetty&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;jetty-server&lt;\/artifactId&gt;\r\n      &lt;version&gt;${jetty.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.eclipse.jetty&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;jetty-servlet&lt;\/artifactId&gt;\r\n      &lt;version&gt;${jetty.version}&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n  &lt;\/dependencies&gt;\r\n&lt;\/project&gt;\r\n<\/pre>\n<p>As usual, run <em>mavn install<\/em> to grab the dependencies.<\/p>\n<p>Now create the usual folder structure for our source, \/src\/main\/java and within this your package folders, i.e. com\/putridparrot\/core.<\/p>\n<p>We&#8217;re going to create four files, two of which we&#8217;ve used in previous posts, HelloWorld and HelloWorldImpl, I&#8217;ll include those here first just for completeness<\/p>\n<p>HelloWorld.java<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage com.putridparrot.core;\r\n\r\nimport javax.jws.WebParam;\r\nimport javax.jws.WebService;\r\n\r\n@WebService\r\npublic interface HelloWorld {\r\n    String reply(@WebParam(name=&quot;text&quot;) String text);\r\n}\r\n<\/pre>\n<p>HelloWorldImpl.java<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage com.putridparrot.core;\r\n\r\nimport javax.jws.WebParam;\r\nimport javax.jws.WebService;\r\n\r\n@WebService(endpointInterface = &quot;com.putridparrot.core.HelloWorld&quot;, serviceName=&quot;HelloWorld&quot;)\r\npublic class HelloWorldImpl implements HelloWorld {\r\n    public String reply(@WebParam(name = &quot;text&quot;) String text) {\r\n        return &quot;Hello &quot; + text;\r\n    }\r\n}\r\n<\/pre>\n<p>As per the example from the referenced post <a href=\"https:\/\/dzone.com\/articles\/embedded-jetty-and-apache-cxf\" target=\"_blank\">Embedded Jetty and Apache CXF: Secure REST Services With Spring Security<\/a> we&#8217;re going to create the configuration in code, so create AppConfig.java and place the following in this file<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage com.putridparrot.core;\r\n\r\nimport org.apache.cxf.bus.spring.SpringBus;\r\nimport org.apache.cxf.endpoint.Server;\r\nimport org.apache.cxf.jaxws.JaxWsServerFactoryBean;\r\nimport org.springframework.context.annotation.Bean;\r\nimport org.springframework.context.annotation.Configuration;\r\nimport org.springframework.context.annotation.DependsOn;\r\n\r\n@Configuration\r\npublic class AppConfig {\r\n    @Bean( destroyMethod = &quot;shutdown&quot; )\r\n    public SpringBus cxf() {\r\n        return new SpringBus();\r\n    }\r\n\r\n    @Bean @DependsOn( &quot;cxf&quot; )\r\n    public Server getServer() {\r\n        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();\r\n        factory.setServiceBean(getService());\r\n        return factory.create();\r\n    }\r\n\r\n    @Bean\r\n    public HelloWorldImpl getService() {\r\n        return new HelloWorldImpl();\r\n    }\r\n}\r\n<\/pre>\n<p>Finally create App.java and place the following inside it<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\npackage com.putridparrot.core;\r\n\r\nimport org.apache.cxf.transport.servlet.CXFServlet;\r\nimport org.eclipse.jetty.server.Server;\r\nimport org.eclipse.jetty.servlet.ServletContextHandler;\r\nimport org.eclipse.jetty.servlet.ServletHolder;\r\nimport org.springframework.web.context.ContextLoaderListener;\r\nimport org.springframework.web.context.support.AnnotationConfigWebApplicationContext;\r\n\r\npublic class App {\r\n    public static void main( String&#x5B;] args ) throws Exception {\r\n\r\n        Server server = new Server( 9000 );\r\n\r\n        ServletHolder servletHolder = new ServletHolder( new CXFServlet() );\r\n        ServletContextHandler context = new ServletContextHandler();\r\n        context.setContextPath( &quot;\/&quot; );\r\n        context.addServlet( servletHolder, &quot;\/*&quot; );\r\n        context.addEventListener( new ContextLoaderListener() );\r\n\r\n        context.setInitParameter( &quot;contextClass&quot;, AnnotationConfigWebApplicationContext.class.getName() );\r\n        context.setInitParameter( &quot;contextConfigLocation&quot;, AppConfig.class.getName() );\r\n\r\n        server.setHandler( context );\r\n        server.start();\r\n        server.join();\r\n\r\n        System.in.read();\r\n\r\n        System.exit(0);\r\n    }\r\n}\r\n<\/pre>\n<p>Once this is built, run App.main and you should be able to use your web browser to navigate to http:\/\/localhost:9000\/HelloWorld?wsdl and see the wsdl definitions for this service.<\/p>\n<p><strong>Great, but what&#8217;s it all doing?<\/strong><\/p>\n<p>Let&#8217;s start with the App.main method. The <em>server<\/em> variable is our Jetty instance. So really the only thing we&#8217;re interested here is which port have we assigned the instance to and the <em>server.setHandler<\/em> method call. This is where we embed our servlet context into the Jetty engine. From what I can understand, this basically allows us a way to intercept calls and pass to our specific servlet, in this case (ultimately) our CXFServlet.<\/p>\n<p>The ServletHolder, as the name suggests, holds the servlet object that we want to use and will be added to the ServletContextHandler. As you can see this is where the bulk of the code is. The <em>setContextPath<\/em> call sets up the root level path of our context, i.e. changing to <em>context.setContextPath( &#8220;\/ws&#8221; )<\/em> means our webservice will now be located off of the ws path, thus http:\/\/localhost:9000\/ws\/HelloWorld?wsdl.<\/p>\n<p>When we call <em>addServlet<\/em> we can, in essence, extend the root path further, so for example <em>context.addServlet( servletHolder, &#8220;\/services\/*&#8221; )<\/em> will simply moved the servlet to your root path\/services.<\/p>\n<p>We add the spring <a href=\"http:\/\/docs.spring.io\/spring\/docs\/current\/javadoc-api\/org\/springframework\/web\/context\/ContextLoaderListener.html\" target=\"_blank\">ContextLoaderListener<\/a> to the ServletContext and this is where we can setup the parameters required for spring to bring in our webservices etc.<\/p>\n<p>The ContextLoaderListener <em>&#8220;Create a new ContextLoaderListener that will create a web application context based on the &#8220;contextClass&#8221; and &#8220;contextConfigLocation&#8221; servlet context-params.&#8221;<\/em> we&#8217;ll need to supplied the contextClass and contextConfigLocation parameters and that&#8217;s exactly what we do in the two <em>setInitParameter<\/em> lines of code.<\/p>\n<p>The contextClass is going to use the web annotations (hence our webservices are annotated) and the contextConfigLocation will use our AppConfig class (instead of a config. file).<\/p>\n<p><strong>Configuration class<\/strong><\/p>\n<p>The AppConfig class supplies the configuration for the <em>ContextLoaderListener<\/em> and is first annotated with the <em><a href=\"http:\/\/docs.spring.io\/autorepo\/docs\/spring-framework\/4.1.4.RELEASE\/javadoc-api\/org\/springframework\/context\/annotation\/Configuration.html\" target=\"_blank\">Configuration<\/a><\/em>, although removing this seemed to have no effect. What does have a big effect is the requirement for a bean named cxf &#8211; if this is missing you&#8217;ll get the following exception<\/p>\n<p><em><br \/>\nException in thread &#8220;main&#8221; org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named &#8216;cxf&#8217; is defined<br \/>\n<\/em><\/p>\n<p>In our case we return a <a href=\"https:\/\/cxf.apache.org\/javadoc\/latest\/org\/apache\/cxf\/bus\/spring\/SpringBus.html\" target=\"_blank\">SpringBus<\/a><\/p>\n<p>Next up we supply a <em>getServer<\/em> bean which depends on the cxf bean &#8211; this simply means the cxf bean should be created before the getServer bean. This code creates the web service implementation (we could have created a REST implementation using JAXRSServerFactoryBean). Within this code we set the factory bean to use the web service supplied via our getService method (which above is marked as a bean but needn&#8217;t be). The we simply return the result of the create method and we&#8217;re done.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post we looked at creating a web service, exposing SOAP and running in a CXF created instance of Jetty, but what if you already have an application with an existing instance of Jetty running. All you want to do is drop a SOAP capable service into this instance. Like most of the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[163,161],"tags":[],"class_list":["post-4714","post","type-post","status-publish","format-standard","hentry","category-cxf","category-java"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4714","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=4714"}],"version-history":[{"count":4,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4714\/revisions"}],"predecessor-version":[{"id":4725,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/4714\/revisions\/4725"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=4714"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=4714"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=4714"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}