Main Page

From scio (inactive) Wiki
Jump to: navigation, search

Contents

Introduction

The SCIO project is a low level API which enables an application to communicate with other applications. The focus is set on event driven message exchange. The API is designed to allow an easy use and to be economical with system resources although it implements standards like SOAP and XMPP. The SCIO API implements the following components:

  • Messaging framework
  • JAXB
  • SOAP
  • XMPP

Messaging framework

?

JAXB

The Java Architecture for XML Binding API helps to map java objects to an XML representation. The mapping of objects to XML is called marshalling and the inverse mapping is called unmarshalling. This enables applications to serialize objects to files or to exchange objects with other applications which are connected in a network. The applications do not need to implement routines which realise the mapping between objects and XML data. The java classes which should be serializable with JAXB can be generated automatically from an XML schema. So it is not needed to synchronize changes of Java classes and XML schema files.


SOAP

SOAP can be used to exchange XML based messages between applications which are connected over a network. Often it is used to perform a remote procedure call (rpc) using HTTP, but it can also be used over a different transport protocoll and with another message exchange pattern.



Implement a SOAP client project

Before you want to implement a SOAP client you need a WSDL-document which describes the service interface. This document (which can consist of more than one file) will be included in the client project. The project then will be configured that the Java code which is application specific will be automatically generated from the WSDL-document. This will be a Java interface which containes the operations of the webservice and the complex datatypes which are used by this interface. This ensures that no time-consuming synchronization between the service definition and implementation is necessary. If you don't want to read the following description about how a client project can be started, you can get a running sample project by checking out

users/hendrik/soapdemo

in the CVS repository

kassandra.tarent.de:/cvs/newcvsroot

Which WSDL-style?

If you want to create a WSDL file to describe a service, you need to know that there is more than one way to define the same interface. One thing that must be considered is, if the Rpc or the Document SOAP binding style should be used. Further it can be chosen between literal or encoded use of the parameters. The use of the encoded version is not recommondable because it is not WS-I compliant and the Rpc/encoded-style is not supported by JAXWS 2.0. So in practice mostly the Rpc/literal and Document/literal are used. The Document/literal-style can not be used directly because the resulting SOAP message does not contain an operation identificator. As follows it is generally not possible to correlate a message to the right operation and the message is not WS-I compliant because the SOAP body can contain more than one child. But if for each operation a parameter wrapping XML element is defined in the XML schema, it can be used and the resulting SOAP message will be mostly the same as in the Rpc/literal style. This style is designated as the Document/literal wrapped style. So together with the Rpc/literal style there are two practicable approaches which have different advantages and disadvantages:

Rpc/literal Document/literal wrapped
WSDL size the WSDL file is as clear as it is possible the WSDL file is more complicated
Operation element part of the SOAP part of the schema
Operation overloading possible not possible


Configuration of the project

Assuming that the build process will be performed by Maven, we start with an empty project. Such a project can be created with the command:

mvn archetype:create -DgroupId=org.evolvis -DartifactId=soapdemo

To define the dependency to the SCIO project, add the following to the pom.xml file:

<dependency>
    <groupId>org.evolvis.scio</groupId>
    <artifactId>scio</artifactId>
    <version>0.1.0-SNAPSHOT</version>
</dependency>

The following repositories must be added to the file pom.xml under the root tag project:

<repositories>
    <repository>
        <id>apache-snapshots</id>
        <name>Apache SNAPSHOT Repository</name>
        <url>http://people.apache.org/repo/m2-snapshot-repository/</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>apache-incubating</id>
        <name>Apache Incubating Repository</name>
        <url>http://people.apache.org/repo/m2-incubating-repository/</url>
    </repository>
    <!-- for jaxb-impl -->
    <repository>
        <id>java.net</id>
        <url>http://download.java.net/maven/1/</url>
        <layout>legacy</layout>
    </repository>
</repositories>
 
<pluginRepositories>
    <pluginRepository>
        <id>apache-plugin-snapshots</id>
        <name>Apache Maven Plugin Snapshots</name>
        <url>http://people.apache.org/repo/m2-snapshot-repository</url>
        <releases>
            <enabled>false</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </pluginRepository>
    <pluginRepository>
        <id>apache-plugin-incubating</id>
        <name>Apache Plugin Incubating Repository</name>
        <url>http://people.apache.org/repo/m2-incubating-repository/</url>
    </pluginRepository>
</pluginRepositories>

The WSDL-document must be added to the project (for example at /src/main/wsdl/myService.wsdl). Now the following plugin configurations must be added to the pom.xml file under the root tag (please adjust the url to the WSDL-file):

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.5</source&gt;
                <target>1.5</target>
                <encoding>UTF-8</encoding>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-codegen-plugin</artifactId>
            <version>2.0.2-incubator</version>
            <executions>
                <execution>
                    <id>generate-sources</id>
                    <phase>generate-sources</phase>
                    <configuration>
                        <sourceRoot>${basedir}/src/main/generated</sourceRoot>
                        <wsdlOptions>
                            <wsdlOption>
                                <wsdl>${basedir}/src/main/wsdl/myService.wsdl</wsdl>
                            </wsdlOption>
                        </wsdlOptions>
                    </configuration>
                    <goals>
                        <goal>wsdl2java</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Now you can test the configuration with the command

mvn install

if everything is configured correctly and the WSDL-file is valid, there will be some generated files in the folder /src/main/generated. The generated files should not be added to the version control system (cvs, subversion). In the same folder you have to create a file which must be named "jaxb.index" and write all names of the classes in the current package which should be (de)serializable by the JAXB-API,

It is also possible to generate a WSDL-file form an annotated Java class by a plugin (for configuration see section Java2WS here). So you can also choose a code-first approach or realize a round-trip.

Implement a SOAP client

Assume we have the following WSDL-file:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="TestServiceImpl"
	targetNamespace="http://evolvis.org/soapdemo"
	xmlns:tns="http://evolvis.org/soapdemo"
	xmlns:types="http://evolvis.org/soapdemo/types"
	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
	xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
	xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
	<wsdl:types>
		<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
			attributeFormDefault="unqualified" elementFormDefault="qualified"
			targetNamespace="http://evolvis.org/soapdemo/types">
		</xsd:schema>
	</wsdl:types>
	<wsdl:message name="stringValue">
		<wsdl:part name="value" type="xsd:string"></wsdl:part>
	</wsdl:message>
	<wsdl:message name="stringReturn">
		<wsdl:part name="return" type="xsd:string"></wsdl:part>
	</wsdl:message>
	<wsdl:message name="byteValue">
		<wsdl:part name="value" type="xsd:byte"></wsdl:part>
	</wsdl:message>
	<wsdl:message name="byteReturn">
		<wsdl:part name="return" type="xsd:byte"></wsdl:part>
	</wsdl:message>
	<wsdl:portType name="TestInterface">
		<wsdl:operation name="identityString">
			<wsdl:input name="stringValue" message="tns:stringValue">
			</wsdl:input>
			<wsdl:output name="stringReturn"
				message="tns:stringReturn">
			</wsdl:output>
		</wsdl:operation>
		<wsdl:operation name="identityByte">
			<wsdl:input name="byteValue" message="tns:byteValue">
			</wsdl:input>
			<wsdl:output name="byteReturn" message="tns:byteReturn">
			</wsdl:output>
		</wsdl:operation>
	</wsdl:portType>
	<wsdl:binding name="TestSoapBinding" type="tns:TestInterface">
		<soap:binding style="rpc"
			transport="http://www.w3.org/2003/05/soap-envelope" />
		<wsdl:operation name="identityString">
			<soap:operation soapAction="" />
			<wsdl:input name="stringValue">
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output name="stringReturn">
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
		<wsdl:operation name="identityByte">
			<soap:operation soapAction="" />
			<wsdl:input name="byteValue">
				<soap:body use="literal" />
			</wsdl:input>
			<wsdl:output name="byteReturn">
				<soap:body use="literal" />
			</wsdl:output>
		</wsdl:operation>
	</wsdl:binding>
	<wsdl:service name="TestService">
		<wsdl:port name="TestPort" binding="tns:TestSoapBinding">
			<soap:address location="http://localhost:9090/TestService" />
		</wsdl:port>
	</wsdl:service>
</wsdl:definitions>

If called

mvn install

there will be generated a Java class for each complex type (in this example there are no complex types) which has the package org.evolvis.soapdemo.types and is located in the source directory src/main/generated. Also the following interface will be created:

package org.evolvis.soapdemo;
 
import javax.jws.*;
import javax.jws.soap.SOAPBinding;
 
/**
 * This class was generated by the CXF 2.0.2-incubator
 * Thu Feb 21 10:12:56 GMT+01:00 2008
 * Generated source version: 2.0.2-incubator
 * 
 */
 
@WebService(targetNamespace = "http://evolvis.org/soapdemo", name = "TestInterface")
@SOAPBinding(style = SOAPBinding.Style.RPC)
 
public interface TestInterface {
 
    @WebResult(targetNamespace = "http://evolvis.org/soapdemo", partName = "return", name = "return")
    @WebMethod
    public java.lang.String identityString(
        @WebParam(partName = "value", name = "value")
        java.lang.String value
    );
 
    @WebResult(targetNamespace = "http://evolvis.org/soapdemo", partName = "return", name = "return")
    @WebMethod
    public byte identityByte(
        @WebParam(partName = "value", name = "value")
        byte value
    );
}

Now we are able to implement a client application:

package org.evolvis.soapdemo;
 
import javax.xml.bind.JAXBException;
 
import org.evolvis.scio.bind.BindContext;
import org.evolvis.scio.bind.BindContextHolder;
import org.evolvis.scio.soap.StubFactory;
 
public class Client {
 
	public static void main(String[] args) throws JAXBException {
		// create and register bind context
		BindContext defaultContext = BindContext.newInstance("org.evolvis.soapdemo.types");
		BindContextHolder.setDefaultContext(defaultContext);
 
		// create client stub
		TestInterface client = (TestInterface) StubFactory.getInstance().createStub(
			"http://localhost:9000/testService",
			TestInterface.class);
 
		// use client stub
		System.out.println(client.identityString("Hello World!"));
		System.out.println("The answer is: "+client.identityByte((byte) 42));
	}
}

First there must be created a BindContext at initialization time of the application. This class must get the package name in which the generated type classes which are used by the service interface are collected. This instance will be set as static default context in the application so that it can be accessed from any class by the class BindContextHolder. Further a client stub which must be initialized with the given url of the service and the class of the generated service interface will be created .

Testing of the SOAP client

If you want to do some unit testing you probably don't want or are not able to do calls to the used webservice. So it can be useful to create a dummy web service and test the client with it. At first we can implement the dummy web service in the test source folder:

package org.evolvis.soapdemo;
 
public class TestInterfaceImpl implements TestInterface {
 
	public byte identityByte(byte value) {
		return value;
	}
 
	public String identityString(String value) {
		return value;
	}
}

Now we can implement a testcase, which starts a (CXF-)SOAP endpoint and runs the Client application:

package org.evolvis.soapdemo;
 
import javax.xml.bind.JAXBException;
import javax.xml.ws.Endpoint;
import javax.xml.ws.soap.SOAPBinding;
 
import junit.framework.TestCase;
 
public class ClientTest extends TestCase {
 
	private Endpoint endpoint;
 
	protected void setUp() throws Exception {
		endpoint = Endpoint.create(SOAPBinding.SOAP12HTTP_BINDING, new TestInterfaceImpl());
		endpoint.publish("http://localhost:9000/testService");
	}
 
	public void testMain() throws JAXBException {
		Client.main(null);
	}
 
	protected void tearDown() throws Exception {
		endpoint.stop();
	}
}

The output on the console should be:

Hello World!
The answer is: 42

It can be helpful to monitor the transfered SOAP messages. This can be done by the Apache TCPMon tool. For example if you change the port 9000 in the above testcase ClientTest to 9001 and start the TCPMon with the command

java -cp tcpmon-1.0.jar org.apache.ws.commons.tcpmon.TCPMon 9000 localhost 9001

you can check if everything is correct at the SOAP message level.

XMPP

XMPP is the protocoll of the Jabber instant messanging technology. It can handle intsant messaging and presence information.