`
yangzb
  • 浏览: 3506892 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Interoperable WSDL faults in gSOAP and Apache Axis webservices

阅读更多

his document describes how to successfuly use WSDL faults in webservices implemented in C using gSOAP or in Java using Apache Axis for reporting unusual return values. It assumes that you know how to use gSOAP and Axis.

Content

What are WSDL faults ?

Exceptions in programming languages

In some programming languages, like Java and C++, a method (function) can throw so called "exception", which is basicaly an object returned instead of the normal return value if something unusual (exceptional) happens. For example when dividing two integers, the return value is normally an integer. But if the second one is zero, no value is returned and an instance of java.lang.ArithmeticException class is "thrown". The type of the object indicates the problem which just occured (ArithmeticException ) so that it can be handled programaticaly, and in Java each exception has a human-understandable text associated with it, which can be used by humans to resolve the problem, in this example the text is "/ by zero ". The exception can be "catched" and processed using special language constructs (try{ ... } catch (Exception ex) { ... } ) or left propagating up from the current method to its calling method. This greatly simplifies processing errors.

Checked and unchecked exceptions

There are two types of exceptions, checked and unchecked ones. Checked exceptions must be declared in method signatures together with parameters and return value, while unchecked exception don't have to be declared. Typicaly checked exceptions are used when a method needs to make its users aware of the known exceptional states which can happen. For example most of methods in the java.io package can throw checked IOException when some Input/Output problem happens. Unchecked exceptions are used for errors which are too common to be declared, like NullPointerException thrown when an object variable is empty and thus a method cannot be called on it.

SOAP Faults

Webservices have similar concept of faults . As with checked and unchecked exceptions, there are two types of them. Some are user-defined and declared in WSDL (like checked exceptions), and some can happen anytime on the SOAP layer during communication, so they are not declared (like unchecked exceptions). The declared ones are called WSDL faults.

WSDL Faults

Interface of a webservice is described independently of any programming language using WSDL language. The WSDL language allows to have three types of messages - input , output and fault . The fault message can have only one part, which can be a XML Schema complex type, thus containing several values. Let's see an example of a service called MyService which has one operation called myOperation with one input parameter myInput , one return value of type string and two possible faults named MyFirstException and MySecondException . The faults carry values in them, the first one has some text and the second one has a number.

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="MyService"
 targetNamespace="urn:myuri:1.0"
 xmlns:tns="urn:myuri:1.0"
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:ns1="urn:myuri:1.0"
 xmlns:SOAP="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:MIME="http://schemas.xmlsoap.org/wsdl/mime/"
 xmlns:DIME="http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/"
 xmlns:WSDL="http://schemas.xmlsoap.org/wsdl/"
 xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
 <schema targetNamespace="urn:myuri:1.0"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:ns1="urn:myuri:1.0"
  xmlns="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="unqualified"
  attributeFormDefault="unqualified">
  <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
  <!-- fault element -->

  <element name="MyFirstException">
   <complexType>
    <sequence>
     <element name="text" type="xsd:string" minOccurs="1" maxOccurs="1" nillable="false"/>
    </sequence>
   </complexType>
  </element>

  <!-- fault element -->

  <element name="MySecondException">
   <complexType>
    <sequence>
     <element name="number" type="xsd:int" minOccurs="1" maxOccurs="1"/>
    </sequence>
   </complexType>
  </element>

  <!-- operation request element -->

  <element name="myOperation">
   <complexType>
    <sequence>
     <element name="myInput" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
    </sequence>
   </complexType>
  </element>
  <!-- operation response element -->

  <element name="myOperationResponse">
   <complexType>
    <sequence>
     <element name="myOutput" type="xsd:string" minOccurs="0" maxOccurs="1" nillable="true"/>
    </sequence>
   </complexType>
  </element>
 </schema>

</types>

<message name="myOperationRequest">
 <part name="parameters" element="ns1:myOperation"/>
</message>

<message name="myOperationResponse">
 <part name="parameters" element="ns1:myOperationResponse"/>
</message>

<message name="MySecondExceptionFault">
 <part name="fault" element="ns1:MySecondException"/>
</message>

<message name="MyFirstExceptionFault">
 <part name="fault" element="ns1:MyFirstException"/>
</message>


<portType name="MyType">
 <operation name="myOperation">
  <documentation>Service definition of function ns1__myOperation</documentation>
  <input message="tns:myOperationRequest"/>
  <output message="tns:myOperationResponse"/>
  <fault name="MySecondException" message="tns:MySecondExceptionFault"/>
  <fault name="MyFirstException" message="tns:MyFirstExceptionFault"/>

 </operation>
</portType>

<binding name="MyService" type="tns:MyType">
 <SOAP:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
 <operation name="myOperation">
  <SOAP:operation soapAction=""/>
  <input>
   <SOAP:body use="literal"/>
  </input>
  <output>
   <SOAP:body use="literal"/>
  </output>
  <fault name="MySecondException">
   <SOAP:fault name="MySecondException" use="literal"/>
  </fault>
  <fault name="MyFirstException">
   <SOAP:fault name="MyFirstException" use="literal"/>
  </fault>
 </operation>
</binding>

<service name="MyService">
 <documentation>gSOAP 2.7.1 generated service definition</documentation>
 <port name="MyService" binding="tns:MyService">
  <SOAP:address location="http://localhost:10000"/>
 </port>
</service>

</definitions>
    

This webservice can be implemented in any language, even in C, and still it will have the option to return a fault instead of the usual string return value. Because the WSDL is independent of any language, it does not provide a place to store a stack trace associated with Java exceptions for example, because a client implemented in C would not know what to do with the stacktrace.

A SOAP message with the first fault looks like this:

HTTP/1.1 500 Internal Server Error
Server: gSOAP/2.7
Content-Type: text/xml; charset=utf-8
Content-Length: 577
Connection: close

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
                   xmlns:ns1="urn:myuri:1.0">
 <SOAP-ENV:Body>
  <SOAP-ENV:Fault>
   <faultcode>SOAP-ENV:Client</faultcode>
   <faultstring>Deliberately thrown exception.</faultstring>
   <detail>
     <ns1:MyFirstException>
      <text>Input values are wrong.</text>
     </ns1:MyFirstException>
   </detail>
  </SOAP-ENV:Fault>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
    

So, in short, WSDL faults are alternative return messages declared in WSDL. They can be used to return structured information when an error occurs.

WSDL faults in gSOAP and Axis

WSDL faults are working among gSOAP and Axis clients and servers only when using latest versions of the tools (in the moment of this writing), gSOAP 2.7.1 and Axis 1.2RC3. And you should use "document/literal wrapped" style for WSDL which is default now in gSOAP and can be used in Axis too. Older versions and other WSDL styles are known to have problems.

Generating WSDL

The WSDL example above was generated using gSOAP. I have found that nowadays gSOAP produces much better WSDL files than Axis, even if several years ago it was the other way round.

The following file was used to generate it. Please note that the names of exception structures begin with underscores. That's a requirement which is not mentioned in the gSOAP user guide as of time of this writing.


//gsoap ns1 service name:       MyService 
//gsoap ns1 service type:       MyType 
//gsoap ns1 service port:       http://localhost:10000 
//gsoap ns1 service namespace:  urn:myuri:1.0


struct _ns1__MyFirstException {
    char* text 1;
};
struct _ns1__MySecondException {
    int number 1;
};

//gsoap ns1 service method-fault: myOperation _ns1__MyFirstException
//gsoap ns1 service method-fault: myOperation _ns1__MySecondException

int ns1__myOperation(
    char * myInput,
    struct ns1__myOperationResponse { char *myOutput; } *
);
    

Writing a client in gSOAP

Now it is the time to write a client in gSOAP. Creat an empty directory and create there a Makefile with following content. It assumes that GSOAPDIR is set to the location of gSOAP:

Makefile

SOAPCPP2=$(GSOAPDIR)/soapcpp2
WSDL2H=$(GSOAPDIR)/wsdl2h

all: client server

soapC.c: faultdemo.h
	"$(SOAPCPP2)" -c faultdemo.h

client: client.c soapC.c
	gcc -g -I. -DDEBUG -o client client.c soapClient.c soapC.c stdsoap2.c

server: server.c soapC.c
	gcc -g -I. -o server server.c soapServer.c soapC.c stdsoap2.c

clean:
	rm -rf *.xml *.nsmap soap* *.xsd *.log client server MyService.wsdl core
    

You also need a file with source code for the client:

client.c

#include "soapH.h"
#include "MyService.nsmap"

void processFault(struct soap *soap);

int main(int argc,char** argv) {
    struct soap *soap = soap_new();
    struct ns1__myOperationResponse out;
    char * url = "http://localhost:10000/";
    //char * url = "http://localhost:8080/axis/services/MyService" ;

    if(argc==2) { url = argv[1]; }

    printf("calling first ...\n");
    if(soap_call_ns1__myOperation(soap,url,"","first",&out) == SOAP_OK) {
        printf("OK\n");
    } else {
        processFault(soap);
    }
    printf("\ncalling second ...\n");
    if(soap_call_ns1__myOperation(soap,url,"","second",&out) == SOAP_OK) {
        printf("OK\n");
    } else {
        processFault(soap);
    }
}

void processFault(struct soap *soap) {
        soap_print_fault(soap, stderr);
        if((soap->fault != NULL) && (soap->fault->detail != NULL)) {
            switch (soap->fault->detail->__type) {
                case SOAP_TYPE__ns1__MyFirstException: {
                    struct _ns1__MyFirstException * ex 
                        = (struct _ns1__MyFirstException *) soap->fault->detail->fault;
                    if(ex!=NULL) { printf("MyFirstException.text=%s\n",ex->text); }
                }; break;
                case SOAP_TYPE__ns1__MySecondException: {
                    struct _ns1__MySecondException * ex 
                        = (struct _ns1__MySecondException *) soap->fault->detail->fault;
                    if(ex!=NULL) { printf("MySecondException.number=%d\n",ex->number); }
                }; break;
            }
        }
}
    

And finaly you need to copy files stdsoap2.c and stdsoap2.h from your gSOAP installation and type "make client". That will generate WSDL, communication stubs and compile the client.

Writing a server in gSOAP

In the same directory create a file with source of gSOAP server.

server.c

#include "soapH.h"
#include "MyService.nsmap"

int ns1__myOperation(struct soap* soap,char * myInput,struct ns1__myOperationResponse *out) {
     soap_sender_fault(soap,"Deliberately thrown exception.",NULL);
     soap->fault->detail = (struct SOAP_ENV__Detail*)soap_malloc(soap, sizeof(struct SOAP_ENV__Detail));
     soap->fault->detail->__any = NULL; 
     if(strncmp(myInput,"first",5)==0) {
        struct _ns1__MyFirstException *ex = (struct _ns1__MyFirstException *) soap_malloc(soap,sizeof(*ex));
        ex->text = "Input values are wrong.";
        soap->fault->detail->__type = SOAP_TYPE__ns1__MyFirstException;
        soap->fault->detail->fault = ex;
     } else {
        struct _ns1__MySecondException *ex = (struct _ns1__MySecondException *) soap_malloc(soap,sizeof(*ex));
        ex->number = 1111;
        soap->fault->detail->__type = SOAP_TYPE__ns1__MySecondException;
        soap->fault->detail->fault = ex;
     }
     return SOAP_FAULT;
}
int port = 10000;

int main() {
   struct soap soap;
   int i, m, s; 
   soap_init(&soap);
   m = soap_bind(&soap, NULL, port, 100);
   if (m < 0)
      soap_print_fault(&soap, stderr);
   else {
      fprintf(stderr, "Running on port %d\n",port);
      for (i = 1; ; i++) {
         s = soap_accept(&soap);
         fprintf(stderr, "%d: accepted connection from IP=%d.%d.%d.%d\n", i,
                 (soap.ip >> 24)&0xFF, (soap.ip >> 16)&0xFF, (soap.ip >> 8)&0xFF, soap.ip&0xFF);
         if (s < 0) {
             soap_print_fault(&soap, stderr);
             break;
         }
         if (soap_serve(&soap) != SOAP_OK) { // process RPC request
                 soap_print_fault(&soap, stderr); // print error
         }
         fprintf(stderr, "request served\n");
         soap_destroy(&soap); // clean up class instances
         soap_end(&soap); // clean up everything and close socket
      }
   }
   soap_done(&soap); // close master socket
}
    

Type "make server". That will compile the server. Now run the gSOAP client against the gSOAP server. The client makes two calls, each ends with different fault.

$ ./server &
$ ./client
calling first ...
SOAP FAULT: SOAP-ENV:Client
"Deliberately thrown exception."
MyFirstException.text=Input values are wrong.

calling second ...
SOAP FAULT: SOAP-ENV:Client
"Deliberately thrown exception."
MySecondException.number=1111
    

Creating a client in Axis

For creating client and server using Axis, you need Axis installation location set in variable AXIS_HOME and TomCat installation in CATALINA_BASE.

First we must generate stub classes from the WSDL and write a client.

CallMyService.java

import faultdemo.*;
import java.rmi.RemoteException;
import java.net.URL;

public class CallMyService {

 public static void main(String [] args) throws Exception {
    String url = "http://localhost:10000/";
    //String url = "http://localhost:8080/axis/services/MyService";
    MyType myType = new MyServiceLocator().getMyService(new URL(url));

    String[] inputs = new String[] { "first", "second" };
    for(int i=0;i<2;i++) {
        try {
            myType.myOperation(inputs[i]);
        } catch (MyFirstException ex) {
            System.out.println("MyFirstException");
            System.out.println("ex.faultstring="+ex.getFaultString());
            System.out.println("ex.text="+ex.getText());
        } catch (MySecondException ex) {
            System.out.println("MySecondException");
            System.out.println("ex.faultstring="+ex.getFaultString());
            System.out.println("ex.number="+ex.getNumber());
        }
    }
 }
}
    
export CLASSPATH=.
for i in "$AXIS_HOME"/lib/*.jar; do CLASSPATH="$i:$CLASSPATH"; done
for i in "$CATALINA_BASE/common/lib"/*.jar; do CLASSPATH="$i:$CLASSPATH"; done
echo $CLASSPATH

java  org.apache.axis.wsdl.WSDL2Java -v \
      --server-side \
      --deployScope Application \
      --NStoPkg urn:myuri:1.0=faultdemo \
      --output . \
      MyService.wsdl

javac -source 1.4 faultdemo/*.java CallMyService.java
    

Now we have an Axis client for that service. Run it against the gSOAP server.

$ java CallMyService

MyFirstException
ex.faultstring=Deliberately thrown exception.
ex.text=Input values are wrong.
MySecondException
ex.faultstring=Deliberately thrown exception.
ex.number=1111
    

You can see that the faults thrown from C were correctly converted to Java Exceptions.

Deploying a server in Axis

The WSDL2Java command used in the last section produced even server-side stubs and a deployment descriptor for them. You just need to edit faultdemo/MyServiceImpl.java and provide implementation for the server side of the service:

faultdemo/MyServiceImpl.java

/**
 * MyServiceImpl.java
 *
 * This file was auto-generated from WSDL
 * by the Apache Axis 1.2RC3 Feb 28, 2005 (10:15:14 EST) WSDL2Java emitter.
 */

package faultdemo;

public class MyServiceImpl implements faultdemo.MyType{
    public java.lang.String myOperation(java.lang.String myInput) 
            throws java.rmi.RemoteException, faultdemo.MyFirstException, faultdemo.MySecondException {

        if("first".equals(myInput)) {
            MyFirstException ex = new MyFirstException();
            ex.setFaultString("Deliberately thrown");
            ex.setText("Problem");
            throw ex;
        } else {
            MySecondException ex = new MySecondException();
            ex.setFaultString("Deliberately thrown");
            ex.setNumber(2222);
            throw ex;
        }
    }

}
    

Now you have to compile it and deploy it into Axis webservice inside TomCat.

javac -source 1.4 faultdemo/MyServiceImpl.java
cp -r faultdemo/ $CATALINA_BASE/webapps/axis/WEB-INF/classes/
    

Now you have to restart TomCat, or at least the Axis webapp, because it needs to be able to find the new classes. Then do:

java org.apache.axis.client.AdminClient faultdemo/deploy.wsdd
    

The service is now deployed, but I found that the WSDL generated by Axis on-the-fly is not correct to namespaces, so you need to provide the original WSDL file to Axis. Copy it to classes dir and edit the deployment configuration:

cp MyService.wsdl $CATALINA_BASE/webapps/axis/WEB-INF/classes/
vi $CATALINA_BASE/webapps/axis/WEB-INF/server-config.wsdd
    

You need to add a line to the service config:

     <service name="MyService" provider="java:RPC" style="wrapped" use="literal">
       <wsdlFile>/MyService.wsdl</wsdlFile>

         <operation name="myOperation" ...
    

Now restart the TomCat again and check that the service is deployed by seeing http://localhost:8080/axis/servlet/AxisServlet .

Change both clients so that they connect to the Axis server and run them:

$ java CallMyService
MyFirstException
ex.faultstring=Deliberately thrown
ex.text=Problem
MySecondException
ex.faultstring=Deliberately thrown
ex.number=2222

$ ./client 
calling first ...
SOAP FAULT: SOAP-ENV:Server.generalException
"Deliberately thrown"
Detail: faultdemo.MyFirstException
MyFirstException.text=Problem

calling second ...
SOAP FAULT: SOAP-ENV:Server.generalException
"Deliberately thrown"
Detail: faultdemo.MySecondException
MySecondException.number=2222
    

It works ! Amazing :-)


Send any comments to Martin Kuba . Last updated: $Date: 2005/05/06 10:11:21 $

分享到:
评论

相关推荐

    Interoperable Python ZSI WSDL SOAP Web Services tutorial

    Interoperable Python ZSI WSDL SOAP Web Services tutorial

    REST in Practice: Hypermedia and Systems Architecture

    Learn how to make Web-based solutions secure and interoperable Extend integration patterns for event-driven computing with the Atom Syndication Format and implement multi-party interactions in AtomPub...

    Research Advances in Cloud Computing-Springer(2017).pdf

    Today, for almost all the sectors in the world, cloud computing is synonym to on-demand provisioning and delivery of IT services in a pay-as-you-go model. The success story of cloud computing as a ...

    Model Driven Architecture.pdf

    - **Web Services**: Creating interoperable web services that can be accessed and used by a wide range of clients. - **Cloud Computing**: Designing scalable and flexible cloud-based applications and ...

    NIST SP800-85A-1.pdf

    the conformance tests in this document provide the assurance that the set of PIV middleware and PIV card applications that have passed these tests are interoperable. This in turn facilitates ...

    NIST SP800-85A-2-final.pdf

    the conformance tests in this document provide the assurance that the set of PIV Middleware and PIV Card Applications that have passed these tests are interoperable. This in turn facilitates ...

    Protected Interoperable File Format (PIFF) 1.1

    虽然文档的详细内容没有完全提供,但可以推断,PIFF标准的文档会包含以下部分:作用范围和正当性(Scope and Justification),参考文献(References),其中可能包括标准参考(Normative References)和信息性参考...

    isag_sms_axis.rar_SendSmsBindingStub_ctcc_comm_isag ax_isag s_is

    Axis是一个开源的Web服务开发工具,它允许开发者创建、部署和管理基于SOAP(Simple Object Access Protocol)的Web服务。在本例中,Axis被用来作为客户端绑定 stub(SendSmsBindingStub),这是一个自动生成的Java类...

    SUSE Linux Enterprise Server服务器版SLES12sp1 Vagrant虚拟机virtualbox亲测有效

    The only enterprise Linux recommended by Microsoft and SAP, SUSE Linux Enterprise Server is optimized to deliver high-performance mission-critical services, as well as edge of network, and web ...

    SUSE Linux Enterprise Server 12 SP2 Vagrant虚拟机virtualbox亲测可用

    The only enterprise Linux recommended by Microsoft and SAP, SUSE Linux Enterprise Server is optimized to deliver high-performance mission-critical services, as well as edge of network, and web ...

    [Python] Python and HDF5 (英文版)

    Through real-world examples and practical exercises, you’ll explore topics such as scientific datasets, hierarchically organized groups, user-defined metadata, and interoperable files. Examples are ...

    pdschconformncetet.zip_3gpp turbo code_MIMO IN LTE LTE-A_Mobile

    the United States and Vodafone in Europe. Here,the throughput of LTE physical layer in downlink transmissions is carried out. The various steps like CRC,turbo coding, code block segmentation,...

    Basic Interoperable Scrambling System with Encrypted keys

    ### 基本可互操作加密系统(BISS-E)技术规范详解 #### 一、概述与背景 《基本可互操作加密系统(BISS-E)》是一份由欧洲广播联盟(European Broadcasting Union, EBU)发布的技术规范文档,旨在为数字贡献线路...

    NIST SP800-170.pdf

    Overview: ...bodies to develop interoperable security standards and guidelines. In addition, CTG worked with industry partners to promote the use of NIST-approved cryptographic methods.

    Modern PHP New Features and Good Practices

    Find out how the new PHP has become a more mature language with community standards, a growing affinity for interoperable components, and a passionate community committed to improving performance.

    NIST SP800-49.pdf

    S/MIME is based upon the widely used MIME standard [MIME] and describes a protocol for adding cryptographic security services through MIME encapsulation of digitally signed and encrypted objects....

    Hands-On Enterprise Java Microservices with Eclipse MicroProfile

    Eclipse MicroProfile has gained momentum in the industry as a multi-vendor, interoperable, community-driven specification. It is a major disruptor that allows organizations with large investments in ...

    Learning.Internet.of.Things

    Learn the capabilities and differences between popular protocols and communication patterns and how they can be used, and should not be used, to create secure and interoperable services and things ...

Global site tag (gtag.js) - Google Analytics