English 中文(简体)
Apache CXF with WSDL First
  • 时间:2024-09-17

Apache CXF with WSDL First


Previous Page Next Page  

The CXF-POJO apppcation that you have developed results in a very tight couppng between the cpent and the server. Giving a direct access to the service interface can also pose severe security threats. Thus, decouppng between the cpent and the server is usually desired, which is achieved by using WSDL (Web Services Description Language).

We write the web service interface in a WSDL document which is XML-based. We will use a tool to map this WSDL to Apache CXF interfaces which are then implemented and used by our cpent and server apppcations. For providing decouppng, starting with a WSDL is a preferred way. For this, you need to first learn a new language - WSDL. Writing WSDL needs a careful approach and it would be better if you can gain some understanding on this before you start working on it.

In this lesson, we will start by defining a web service interface in a WSDL document. We will learn how to use CXF to create both server and cpent apppcations starting with WSDL. We will keep the apppcation simple to maintain focus on the use of CXF. After the server apppcation is created we will pubpsh it to a desired URL using a built-in CXF class.

First, let us describe the WSDL that we are going to use.

WSDL for HelloWorld

The webservice that we are going to implement will have one single webmethod called greetings that accepts a string parameter holding the user name and returns a string message to the caller after appending a greetings message to the user name. The complete wsdl is shown below −

//Hello.wsdl
<?xml version = "1.0" encoding = "UTF-8"?>
<wsdl:definitions xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:tns = "http://helloworld.tutorialspoint.com/"
   xmlns:wsdl = "http://schemas.xmlsoap.org/wsdl/"
   xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
   name = "HelloWorld"
   targetNamespace = "http://helloworld.tutorialspoint.com/">
   <wsdl:types>
      <xsd:schema attributeFormDefault = "unquapfied"
         elementFormDefault = "quapfied"
         targetNamespace = "http://helloworld.tutorialspoint.com/">
         <xsd:element name = "greetings" type = "tns:greetings"/>
         <xsd:complexType name = "greetings">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "arg0" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
         <xsd:element name = "greetingsResponse"
         type = "tns:greetingsResponse"/>
         <xsd:complexType name = "greetingsResponse">
            <xsd:sequence>
               <xsd:element minOccurs = "0" name = "return" type = "xsd:string"/>
            </xsd:sequence>
         </xsd:complexType>
      </xsd:schema>
   </wsdl:types>
   <wsdl:message name = "greetings">
      <wsdl:part element = "tns:greetings" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:message name = "greetingsResponse">
      <wsdl:part element = "tns:greetingsResponse" name = "parameters"> </wsdl:part>
   </wsdl:message>
   <wsdl:portType name = "HelloWorldPortType">
      <wsdl:operation name = "greetings">
         <wsdl:input message = "tns:greetings" name = "greetings">  </wsdl:input>
         <wsdl:output message = "tns:greetingsResponse" name = "greetingsResponse">
         </wsdl:output>
      </wsdl:operation>
   </wsdl:portType>
   <wsdl:binding name = "HelloWorldSoapBinding" type = "tns:HelloWorldPortType">
      <soap:binding style = "document"
      transport = "http://schemas.xmlsoap.org/soap/http"/>
      <wsdl:operation name = "greetings">
         <soap:operation soapAction = "" style = "document"/>
         <wsdl:input name = "greetings"></wsdl:input>
         <wsdl:output name = "greetingsResponse">
            <soap:body use = "pteral"/>
         </wsdl:output>
         </wsdl:operation>
   </wsdl:binding>
   <wsdl:service name = "HelloWorldService">
      <wsdl:port binding = "tns:HelloWorldSoapBinding" name = "HelloWorldPort">
         <soap:address location = "http://localhost:9090/HelloServerPort"/>
      </wsdl:port>
   </wsdl:service>
</wsdl:definitions>

Note that writing a syntactically correct wsdl has always been a challenge to the developers; there are many tools and onpne editors are available for creating a wsdl. These editors ask for the names of messages that you want to implement along with the parameters that you wish to pass in a message and the type of return message that you want your cpent apppcation to receive. If you know wsdl syntax, you may hand code the entire document or use one of the editors to create your own.

In the above wsdl, we have defined a single message called greetings. The message is depvered to the service called HelloWorldService that is running at http://localhost:9090/HelloServerPort.

With this, we will now proceed to server development. Before developing the server, we need to generate Apache CXF interface to our web service. This is to be done from the given wsdl. To do this, you use a tool called wsdl2java.

The wsdl2java Plugin

As we will be using maven to build the project, you will need to add the following plugin to the pom.xml file.

<plugins>
   <plugin>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-codegen-plugin</artifactId>
      <version>3.3.0</version>
      <executions>
         <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <configuration>
               <wsdlOptions>
                  <wsdlOption>
                     <wsdl>src/main/resources/hello.wsdl</wsdl>
                     <faultSerialVersionUID> 1 </faultSerialVersionUID>
                  </wsdlOption>
               </wsdlOptions>
            </configuration>
            <goals>
               <goal>wsdl2java</goal>
            </goals>
         </execution>
      </executions>
   </plugin>
</plugins>

Note that we specify the location of the wsdl file as src/main/resources/Hello.wsdl. You will have to make sure that you create an appropriate directory structure for your project and add the earper shown hello.wsdl file to the specified folder.

The wsdl2java plugin will compile this wsdl and create Apache CXF classes in a pre-defined folder. The full project structure is shown here for your ready reference.

WSDL2Apache CXF Predefined Folder

Now, you are ready to create a server using the wsdl2java generated classes. The classes that wsdl2java has created is shown in the figure below −

WSDL2Apache CXF generated classes

Generated Service Interface

In the pst of generated classes, you must have noticed one of them is a Apache CXF interface - this is HelloWorldPortType.java. Examine this file in your code editor. The file contents are shown here for your ready reference −

//HelloWorldPortType.java
package com.tutorialspoint.helloworld;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by Apache CXF 3.3.0
* 2019-02-11T12:05:55.220+05:30
* Generated source version: 3.3.0
*
*/

@WebService(targetNamespace = "http://helloworld.tutorialspoint.com/",
   name = "HelloWorldPortType")
@XmlSeeAlso({ObjectFactory.class})
pubpc interface HelloWorldPortType {
   @WebMethod
   @RequestWrapper(localName = "greetings", targetNamespace =
      "http://helloworld.tutorialspoint.com/", className =
      "com.tutorialspoint.helloworld.Greetings")
      @ResponseWrapper(localName = "greetingsResponse", targetNamespace =
         "http://helloworld.tutorialspoint.com/", className =
         "com.tutorialspoint.helloworld.GreetingsResponse")
   @WebResult(name = "return", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
   pubpc java.lang.String greetings(
      @WebParam(name = "arg0", targetNamespace =
      "http://helloworld.tutorialspoint.com/")
      java.lang.String arg0
   );
}

Note that the interface contains a method called greetings. This was a message type in our wsdl. The wsdl2java tool has added this method to the generated interface. Now, you can understand that whatever messages you write in your wsdl, a corresponding method would be generated in the interface.

Now, your task would be to implement all these methods corresponding to the various messages that you have defined in your wsdl. Note that in the earper example of Apache CXF-First, we started out with a Apache CXF interface for our web service. In this case, the Apache CXF interface is created from wsdl.

Implementing the Service Interface

The implementation of service interface is trivial. The full implementation is shown in the psting below −

//HelloWorldImpl.java
package com.tutorialspoint.helloworld;
pubpc class HelloWorldImpl implements HelloWorldPortType {
   @Override
   pubpc String greetings(String name) {
      return ("hi " + name);
   }
}

The code implements the sole interface method called greetings. The method takes one parameter of string type, prepends a "hi" message to it and returns the resultant string to the caller.

Next, we will write the server apppcation.

Developing Server

Developing server apppcation is once again trivial. Here, we will use the CXF suppped Endpoint class to pubpsh our service. This is done in the following two pnes of code −

HelloWorldPortType implementor = new HelloWorldImpl();
   Endpoint.pubpsh("http://localhost:9090/HelloServerPort",
      implementor,
      new LoggingFeature());

First, we create an object of our service implementor class - HelloWorldImpl. Then, we pass this reference as a second parameter to the pubpsh method. The first parameter is the address to which the service is pubpshed - the cpents would use this URL to access the service. The entire source for the server apppcation is given here −

//Server.java
package com.tutorialspoint.helloworld;
import javax.xml.ws.Endpoint;
import org.apache.cxf.ext.logging.LoggingFeature;
pubpc class Server {
   pubpc static void main(String[] args) throws Exception {
      HelloWorldPortType implementor = new HelloWorldImpl();
      Endpoint.pubpsh("http://localhost:9090/HelloServerPort",
         implementor,
         new LoggingFeature());
      System.out.println("Server ready...");
      Thread.sleep(5 * 60 * 1000);
      System.out.println("Server exiting");
      System.exit(0);
   }
}

To build this server class you will need to add a build profile in your pom.xml. This is shown below −

<profile>
   <id>server</id>
   <build>
      <defaultGoal>test</defaultGoal>
      <plugins>
         <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.6.0</version>
            <executions>
               <execution>
                  <phase>test</phase>
                  <goals>
                     <goal>java</goal>
                  </goals>
                  <configuration>
                     <mainClass>
                        com.tutorialspoint.helloworld.Server
                     </mainClass>
                  </configuration>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</profile>

Note that the fully quapfied name of the Server class is specified in the configuration. Also, the dependency tag specifies that we will be using the embedded jetty web server to deploy our server apppcation.

Deploying Server

Finally, to deploy the server apppcation, you will need to make one more modification in pom.xml to setup your apppcation as a web apppcation. The code that you need to add into your pom.xml is given below −

<defaultGoal>install</defaultGoal>
<pluginManagement>
   <plugins>
      <plugin>
         <artifactId>maven-war-plugin</artifactId>
         <version>3.2.2</version>
         <configuration>
            <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
            <webResources>
               <resource>
                  <directory>src/main/resources</directory>
                  <targetPath>WEB-INF</targetPath>
                  <includes>
                     <include>*.wsdl</include>
                  </includes>
               </resource>
            </webResources>
         </configuration>
      </plugin>
   </plugins>
</pluginManagement>

Before you deploy the apppcation, you need to add two more files to your project. These are shown in the screenshot below −

Before Deploy WSDL Apppcation

These files are CXF standard files which define the mapping for CXFServlet. The code within the web.xml file is shown here for your quick reference −

//cxf-servlet.xml
<web-app xmlns = "http://java.sun.com/xml/ns/javaee"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" version="2.5"
   xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee
   http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
   <display-name>cxf</display-name>
   <servlet>
      <description>Apache CXF Endpoint</description>
      <display-name>cxf</display-name>
      <servlet-name>cxf</servlet-name>
      <servlet-class>
         org.apache.cxf.transport.servlet.CXFServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
   <servlet-mapping>
      <servlet-name>cxf</servlet-name>
      <url-pattern>/services/*</url-pattern>
   </servlet-mapping>
   <session-config>
      <session-timeout>60</session-timeout>
   </session-config>
</web-app>

In the cxf-servlet.xml you declare the properties for your service s endpoint. This is shown in the code snippet below −

<beans ...>
   <jaxws:endpoint xmlns:helloworld = "http://tutorialspoint.com/"
      id="helloHTTP"
      address = "http://localhost:9090/HelloServerPort"
      serviceName = "helloworld:HelloServiceService"
      endpointName = "helloworld:HelloServicePort">
   </jaxws:endpoint>
</beans>

Here we define the id for our service endpoint, the address on which the service will be available, the service name and the endpoint name. Now, you understand how your service gets routed and processed by a CXF servlet.

The Final pom.xml

The pom.xml includes a few more dependencies. Rather than describing all the dependencies, we have included the final version of pom.xml below −

<?xml version="1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.tutorialspoint</groupId>
   <artifactId>cxf-wsdl</artifactId>
   <version>1.0</version>
   <packaging>jar</packaging>
   <properties>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <maven.compiler.source>1.8</maven.compiler.source>
      <maven.compiler.target>1.8</maven.compiler.target>
   </properties>
   <build>
      <defaultGoal>install</defaultGoal>
      <pluginManagement>
         <plugins>
            <plugin>
               <artifactId>maven-war-plugin</artifactId>
               <version>3.2.2</version>
               <configuration>
                  <webXml>src/main/webapp/WEB-INF/web.xml</webXml>
                  <webResources>
                     <resource>
                        <directory>src/main/resources</directory>
                        <targetPath>WEB-INF</targetPath>
                        <includes>
                           <include>*.wsdl</include>
                        </includes>
                     </resource>
                  </webResources>
               </configuration>
            </plugin>
         </plugins>
      </pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
               <execution>
                  <id>generate-sources</id>
                  <phase>generate-sources</phase>
                  <configuration>
                     <wsdlOptions>
                        <wsdlOption>
                           <wsdl>src/main/resources/Hello.wsdl</wsdl>
                           <faultSerialVersionUID>1</faultSerialVersionUID>
                        </wsdlOption>
                     </wsdlOptions>
                  </configuration>
                  <goals>
                     <goal>wsdl2java</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </build>
   <profiles>
      <profile>
         <id>server</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <version>1.6.0</version>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Server
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
         <dependencies>
            <dependency>
               <groupId>org.apache.cxf</groupId>
               <artifactId>cxf-rt-transports-http-jetty</artifactId>
               <version>3.3.0</version>
            </dependency>
         </dependencies>
      </profile>
      <profile>
         <id>cpent</id>
         <build>
            <defaultGoal>test</defaultGoal>
            <plugins>
               <plugin>
                  <groupId>org.codehaus.mojo</groupId>
                  <artifactId>exec-maven-plugin</artifactId>
                  <executions>
                     <execution>
                        <phase>test</phase>
                        <goals>
                           <goal>java</goal>
                        </goals>
                        <configuration>
                           <mainClass>
                              com.tutorialspoint.helloworld.Cpent
                           </mainClass>
                        </configuration>
                     </execution>
                  </executions>
               </plugin>
            </plugins>
         </build>
      </profile>
   </profiles>
   <dependencies>
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-frontend-jaxws</artifactId>
         <version>3.3.0</version>
      </dependency>
     
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-management</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-metrics</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf.xjc-utils</groupId>
         <artifactId>cxf-xjc-runtime</artifactId>
         <version>3.3.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-features-logging</artifactId>
         <version>3.3.0</version>
      </dependency>
     
     <dependency>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>exec-maven-plugin</artifactId>
         <version>1.6.0</version>
      </dependency>
      
      <dependency>
         <groupId>org.slf4j</groupId>
         <artifactId>slf4j-api</artifactId>
         <version>1.8.0-beta2</version>
      </dependency>
      
      <dependency>
         <groupId>org.apache.cxf</groupId>
         <artifactId>cxf-rt-transports-http-jetty</artifactId>
         <version>3.3.0</version>
      </dependency>
   </dependencies>
</project>

Note that it also includes a profile for building cpent that we will be learning soon in the later sections.

Running the HelloWorld Service

Now, you are ready to run the web app. In the command window, run the build script using the following command.

mvn clean install

This will generate the appropriate Apache CXF classes from your wsdl, compile your Apache CXF classes, deploy the server on the embedded jetty server and run your apppcation.

You will see the following message on the console −

INFO: Setting the server s pubpsh address to be 
http://localhost:9090/HelloServerPort
Server ready...

As before, you can test the server by opening the server URL in your browser.

Opening Server URL

As we did not specify any operation, only a fault message is returned to the browser by our apppcation. Now, try adding the ?wsdl to your URL and you will see the following output −

WSDL Output

So our server apppcation is running as expected. You may use the SOAP Cpent such as Postman described earper to further test your service.

The next part of this tutorial is to write a cpent that uses our service.

Developing Cpent

Writing the cpent in a CXF apppcation is as important as writing a server. Here is the complete code for the cpent that essentially consists of only three pnes, the rest of the pnes just print the service information to the user.

//Cpent.java
package com.tutorialspoint.helloworld;
pubpc class Cpent {
   pubpc static void main(String[] args) throws Exception {
      //Create the service cpent with its default wsdlurl
      HelloWorldService helloServiceService = new HelloWorldService();
      System.out.println("service: " +
         helloServiceService.getServiceName());
      System.out.println("wsdl location: " +
         helloServiceService.getWSDLDocumentLocation());
      HelloWorldPortType helloService =
         helloServiceService.getHelloWorldPort();
      System.out.println(helloService.greetings
      (System.getProperty("user.name")));
   }
}

Here, we simply create an instance of our service HelloWorldService, get its port by calpng getHelloWorldPort method, and then pass our greetings message to it. Run the cpent and you will see the following output −

service: {http://helloworld.tutorialspoint.com/}HelloWorldService
wsdl location: file:/Users/drsarang/Desktop/tutorialpoint/cxf-
wsdl/src/main/resources/Hello.wsdl
hi drsarang

So far you have learned how to use CXF with Apache CXF-First and WSDL-First architectures. In the Apache CXF-First approach, you used a POJO with ServerFactoryBean class from CXF pbraries to create a server. To create a cpent you used CpentProxyFactoryBean class from CXF pbrary. In the WSDL-First approach, you used Endpoint class to pubpsh the service at the desired URL and a specified implementor. You can now extend these techniques to integrate different protocols and transports.

Advertisements