WSDL from server-code and client from WSDL … CXF

Für die BA werde ich mir noch ein wenig die Webservice-Eigenheiten des Message-Routers anschauen. Dafür brauche ich ja irgendwie nen Dummy oder nen Prototypen, mit dem ich arbeiten kann. Und da man das nicht jeden Tag macht, mal unter der Rubrik "für-mich-und-später" 🙂


Zuerst der Server mit dem Code-first-Approach als Überblick:

Zuerst das Interface mit den Anotationen:

package eu.christophburmeister.webservice.interfaces; 
import javax.jws.WebParam; 
import javax.jws.WebService; 
@WebService public interface IMath { 
   int produktMethod( @WebParam(name = "faktor1") 
   int factor1, @WebParam(name = "faktor2") 
   int factor2 ); 
} 

anschließend die Implementierung auf Server-Seite:

package eu.christophburmeister.webservice.server;

import eu.christophburmeister.webservice.interfaces.IMath;

public class MathImpl implements IMath {

	public int produktMethod(int factor1, int factor2) {
		int produkt = factor1 * factor2;
		return produkt;
	}
	
}

Um den Server zu starten noch die WebServiceProvider-Klasse:

	
package eu.christophburmeister.webservice.server;

import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

import eu.christophburmeister.webservice.interfaces.IMath;

public class WebServiceProvider {
	/** the cxf-server of the webservice-provider */
	Server server;

	public WebServiceProvider(String target) {
		MathImpl webServiceImplementation = new MathImpl();
		JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean();
		svrFactory.setServiceBean(webServiceImplementation);
		svrFactory.setServiceClass(IMath.class);
		String targetAdress = target;
		svrFactory.setAddress(targetAdress);
		server = svrFactory.create();
	}

	public void startWebserviceProvider() {
		this.server.start();
	}

	public void stopWebserviceProvider() {
		this.server.stop();
	}
}

dann noch ein Test, um den Server einfach zu starten:

	
package eu.christophburmeister.webservice;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;

import eu.christophburmeister.webservice.server.WebServiceProvider;

public class ServerTest {

	private static final Logger logger = Logger.getLogger(ServerTest.class);
	private WebServiceProvider webServiceProvider;
	private static final String PROVIDER_URL = "http://127.0.0.1:8080";

	@Before
	public void setUp() throws Exception {
		logger.info("creating webservice-provider");
		webServiceProvider = new WebServiceProvider(PROVIDER_URL);
		logger.info("starting webservice-provider");
		webServiceProvider.startWebserviceProvider();
	}

	@Test
	public void executeOperationTest() throws InterruptedException {
		
		while (true){
			//
		}
		
	}
}

und die pom.xml, in der noch die wsdl generiert wird. Dafür musste ich aber eine ältere Version des cxf-codegen-Plugins (2.0.9) nutzen, weil die neueren Versionen das goal für die Generierung der WSDL nicht mehr haben. Da schaue ich nochmal nach einer aktuelleren Version.

<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>eu.christophburmeister</groupid>
	<artifactid>webservice</artifactid>
	<version>0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<build>
		<plugins>
 
			<plugin>
				<groupid>org.apache.maven.plugins</groupid>
				<artifactid>maven-compiler-plugin</artifactid>
				<version>2.3.2</version>
				<configuration>
					<source>1.6
					<target>1.6</target>
				</source></configuration><source><source><source><source><source><source>
			</source></source></source></source></source></source></plugin><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source><source>
			
			<plugin>
				<groupid>org.apache.cxf</groupid>
				<artifactid>cxf-codegen-plugin</artifactid>
				<version>2.0.9</version>
				<dependencies>
					<dependency>
						<groupid>org.apache.cxf</groupid>
						<artifactid>cxf-rt-frontend-jaxws</artifactid>
						<version>2.0.9</version>
					</dependency>
				</dependencies>
				<executions>
					<execution>
						<id>generate-wsdl</id>
						<phase>process-classes</phase>
						<configuration>
							<classname>eu.christophburmeister.webservice.interfaces.IMath</classname>
							<outputfile>target/Math.wsdl</outputfile>
						</configuration>
						<goals>
							<goal>java2wsdl</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-frontend-jaxws</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-transports-http</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-transports-http-jetty</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>junit</groupid>
			<artifactid>junit</artifactid>
			<version>4.0</version>
		</dependency>
		<dependency>
			<groupid>log4j</groupid>
			<artifactid>log4j</artifactid>
			<version>1.2.16</version>
		</dependency>
	</dependencies>
</project>	

Das war’s auch schon auf Server-Seite. Der Server bietet jetzt einen Service an, der zwei Argumente als int nimmt und als Rückgabe-Wert des Produkt der beiden Argumente gibt. Die entstandene WSDL sieht folgendermaßen aus:

>
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="IMathService" targetnamespace="http://interfaces.webservice.christophburmeister.eu/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://interfaces.webservice.christophburmeister.eu/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
<xsd:schema attributeformdefault="unqualified" elementformdefault="unqualified" targetnamespace="http://interfaces.webservice.christophburmeister.eu/" xmlns:tns="http://interfaces.webservice.christophburmeister.eu/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="produktMethod" type="tns:produktMethod">
    <xsd:complextype name="produktMethod">
        <xsd:sequence>
            <xsd:element name="faktor1" type="xsd:int">
            <xsd:element name="faktor2" type="xsd:int">
        </xsd:element></xsd:element></xsd:sequence>
    </xsd:complextype>
    <xsd:element name="produktMethodResponse" type="tns:produktMethodResponse">
    <xsd:complextype name="produktMethodResponse">
        <xsd:sequence>
            <xsd:element name="return" type="xsd:int">
        </xsd:element></xsd:sequence>
    </xsd:complextype>
</xsd:element></xsd:element></xsd:schema>
  </wsdl:types>
  <wsdl:message name="produktMethodResponse">
    <wsdl:part element="tns:produktMethodResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="produktMethod">
    <wsdl:part element="tns:produktMethod" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:porttype name="IMath">
    <wsdl:operation name="produktMethod">
      <wsdl:input message="tns:produktMethod" name="produktMethod">
    </wsdl:input>
      <wsdl:output message="tns:produktMethodResponse" name="produktMethodResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:porttype>
  <wsdl:binding name="IMathServiceSoapBinding" type="tns:IMath">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http">
    <wsdl:operation name="produktMethod">
      <soap:operation soapaction="" style="document">
      <wsdl:input name="produktMethod">
        <soap:body use="literal">
      </soap:body></wsdl:input>
      <wsdl:output name="produktMethodResponse">
        <soap:body use="literal">
      </soap:body></wsdl:output>
    </soap:operation></wsdl:operation>
  </soap:binding></wsdl:binding>
  <wsdl:service name="IMathService">
    <wsdl:port binding="tns:IMathServiceSoapBinding" name="IMathPort">
      <soap:address location="http://localhost:9090/hello">
    </soap:address></wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Die Client-Seite kann ebenfalls über das cxf-codegen-Plugin erstellt werden. Dabei gibt die Option "-client" an, dass eine Stub-Klasse für den Client erstellt wird, der die Nutzung der generierten Sources einfach demonstriert. Feinheiten werden dabei außen vorgelassen 🙂 die Pom für den Client sieht dann so aus:

	
<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>eu.christophburmeister</groupid>
	<artifactid>webclient</artifactid>
	<version>0.1-SNAPSHOT</version>

	<build>
		<plugins>

			<!-- Generate Java classes from WSDL during build -->
			<plugin>
				<groupid>org.apache.cxf</groupid>
				<artifactid>cxf-codegen-plugin</artifactid>
				<version>2.0.9</version>
				<executions>
					<execution>
						<id>generate-sources</id>
						<phase>generate-sources</phase>
						<configuration>
							<sourceroot>${project.build.directory}/generated/src/main/java</sourceroot>
							<wsdloptions>
								<wsdloption>
									<wsdl>${basedir}/src/main/wsdl/Math.wsdl</wsdl>
									<extraargs>
										<extraarg>-impl</extraarg>
										<extraarg>-client</extraarg>
										<extraarg>-verbose</extraarg>
									</extraargs>
								</wsdloption>
							</wsdloptions>
						</configuration>
						<goals>
							<goal>wsdl2java</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

			<!-- Add generated sources - avoids having to copy generated sources to 
				build location -->
			<plugin>
				<groupid>org.codehaus.mojo</groupid>
				<artifactid>build-helper-maven-plugin</artifactid>
				<version>1.7</version>
				<executions>
					<execution>
						<id>add-source</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>add-source</goal>
						</goals>
						<configuration>
							<sources>
								<source>${basedir}/target/generated/src/main/java</source>
							</sources>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-frontend-jaxws</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-transports-http</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>org.apache.cxf</groupid>
			<artifactid>cxf-rt-transports-http-jetty</artifactid>
			<version>2.0.9</version>
		</dependency>
		<dependency>
			<groupid>junit</groupid>
			<artifactid>junit</artifactid>
			<version>4.0</version>
		</dependency>
		<dependency>
			<groupid>log4j</groupid>
			<artifactid>log4j</artifactid>
			<version>1.2.16</version>
		</dependency>
	</dependencies>

AnschlieĂźend muss man nur noch die IMath_IMathPort_Client-Klasse anpassen:


package eu.christophburmeister.webservice.interfaces;

/**
 * Please modify this class to meet your needs
 * This class is not complete
 */

import java.net.URL;

import javax.xml.namespace.QName;

/**
 * This class was generated by Apache CXF 2.0.9
 * Tue Sep 06 22:03:22 CEST 2011
 * Generated source version: 2.0.9
 * 
 */

public final class IMath_IMathPort_Client {

    private static final QName SERVICE_NAME = new QName("http://interfaces.webservice.christophburmeister.eu/", "IMathService");

    private IMath_IMathPort_Client() {
    }

    public static void main(String args[]) throws Exception {
        URL wsdlURL = IMathService.WSDL_LOCATION;
             
        IMathService ss = new IMathService(wsdlURL, SERVICE_NAME);
        IMath port = ss.getIMathPort();  
        
        System.out.println("Invoking produktMethod...");
        int _produktMethod_faktor1 = 2;
        int _produktMethod_faktor2 = 4;
        int _produktMethod__return = port.produktMethod(_produktMethod_faktor1, _produktMethod_faktor2);
        System.out.println("produktMethod.result=" + _produktMethod__return);


        System.exit(0);
    }

}