设为首页 收藏本站
查看: 1399|回复: 0

[经验分享] Interoperable WSDL faults in gSOAP and Apache Axis webservices

[复制链接]

尚未签到

发表于 2017-1-11 10:49:47 | 显示全部楼层 |阅读模式
  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

    • Checked and unchecked exceptions

    • SOAP Faults

    • WSDL Faults



  • WSDL faults in gSOAP and Axis

  • Generating WSDL

  • Writing a client in gSOAP

  • Writing a server in gSOAP

  • Writing a client in Axis

  • Deploying a server in Axis


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);
} 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 $

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-326972-1-1.html 上篇帖子: http://cwiki.apache.org/confluence/display/WW/OVal 下篇帖子: Apache 2.2 + Tomcat 使用UrlRewrite实现泛域名解析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表