您的位置:首页 > 编程语言 > C语言/C++

[8,9]wsdl2h,soapcpp2 工具的使用

2013-06-11 16:20 302 查看

8 The wsdl2h WSDL and Schema Importer

The wsdl2h tool is an advanced application that converts one or more WSDLs to C/C++. It can also be used without WSDLs to convert XML schemas (XSD files) to C/C++ to implement XML data bindings in C and C++. The creation of C and C++ applications from one of more WSDL service descriptions is a two-step process. To convert a WSDL to C++, use:

> wsdl2h file.wsdl
to generate a C++ header file file.h.
This generated header file is a Web service specification that contains
the parameter types and service function definitions in an
understandable format in C++ (or ANSI C as shown below).
Web service operations are represented as function prototypes. Schema
types are
represented by semantically equivalent C/C++ types that are convenient
and
natural to use in a C/C++ application. The generated header file also
contains
various annotations related to the Web service properties defined in the
WSDL.

To generate ANSI C, use option -c:

> wsdl2h -c file.wsdl
Multiple WSDL specifications can be processed at once and saved to one file with the -o option:

> wsdl2h -o file.h file1.wsdl file2.wsdl file3.wsdl
You can retrieve WSDLs from one of more URLs:

> wsdl2h -o file.h http://www.example.com/example.wsdl
To convert XML schemas to C or C++ XML data binding code, use:

> wsdl2h -o file.h file1.xsd file2.xsd file3.xsd
The wsdl2h-generated header file file.h is processed by the
soapcpp2 tool to auto-generate the advanced data binding logic to
convert the C/C++ data to XML and vice versa at runtime for your SOAP/XML
application.

To process a gSOAP header file file.h (generated by wsdl2h) to generate advanced XML data bindings for C++, use:

> soapcpp2 -i -Iimport file.h
When the header file file.h was generated for C++, then this command
generates a couple of C++ source files (more details will follow in
Section 9) that implement XML encoders for the data binding.
Option -i generates a client proxy objects and service objects to invoke
and serve SOAP/XML operations, respectively. Option -Iimport sets the
import directory for imported files from the package's import, such as
stlvector.h for STL vector serialization support.

When the header file file.h was generated for ANSI C, then the above
command generates a couple of C files that implement XML encoders, client stubs
for remote invocation, and service skeletons for service operations.

Consider for example the following commands to implement a c++ client of a service:

> wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
...

> soapcpp2 -i -Iimport calc.h
The first command generates calc.h from the WSDL at the specified URL.
The header file is then processed by the soapcpp2 tool to generate the
proxies (and service objects that we will not use) for the client application.

The C++ client application uses the auto-generated soapcalcProxy.h class and
calc.nsmap XML namespace table to access the Web
service. Both need to be #include-d in your source. Then compile and link
the soapcalcProxy.cpp, soapC.cpp and stdsoap2.cpp sources to complete the build.


8.1 wsdl2h Options

The wsdl2h tool is an advanced XML data binding tool for converting WSDLs
and XML schemas (XSD files) to C or C++. The tool takes WSDL and/or XSD files
or URLs and converts these to a C or C++ specification in one easy-to-read
C/C++ header file. The header file is not intended to be included in your
code directly!
. It should be converted by soapcpp2 to generate the logic
for the data bindings. It can however be safely converted by a documentation
tool such as Doxygen to analyze and represent the service operations and data
in a convenient layout. To this end, the header file is self-explanatory.

The wsdl2h tool generates only one file, the header file that includes
all of the information obtained from all WSDL and schema files provided to the
tool at the command-line prompt. The default output file name of wsdl2h
is the first WSDL/schema input file name but with extension .h instead of
.wsdl (or .xsd). When an input file is absent or a WSDL file from a
Web location is accessed, the header output will be produced on the standard
output unless option -o is used to direct the output to a file.

The wsdl2h command-line options are:

Option Description
-a generate indexed struct names for local elements with anonymous types
-b bi-directional operations to serve one-way response messages (duplex)
-c generate C source code
-d use DOM to populate xs:any and xsd:anyType elements
-e don't qualify enum names
This option is for backward compatibility with gSOAP 2.4.1 and earlier.
The option does not produce code that conforms to WS-I Basic Profile 1.0a.
-f generate flat C++ class hierarchy for schema extensions
-g generate global top-level element declarations
-h print help information
-I path use path to locate source files for #import
-i don't import (advanced option)
-j don't generate SOAP_ENV__Header and SOAP_ENV__Detail definitions
-k don't generate SOAP_ENV__Header mustUnderstand qualifiers
-l include license information in output
-m use xsd.h module to import primitive types
-N name use name for service prefixes to produce a service for each binding
-n name use name as the base namespace prefix name instead of ns
-o file output to file
-P don't create polymorphic types inherited from xsd__anyType
-p create polymorphic types inherited from base xsd__anyType
This is automatically performed when WSDL contains polymorphic definitions
-q name use name for the C++ namespace of all declarations
-r host[:port[:uid:pwd]] connect via proxy host, port, and proxy credentials
-R generate REST operations for REST bindings in the WSDL
-s don't generate STL code (no std::string and no std::vector)
-t file use type map file instead of the default file typemap.dat
-u don't generate unions
-v verbose output
-W suppress warnings
-w always wrap response parameters in a response struct
-x don't generate _XML any/anyAttribute extensibility elements
-y generate typedef synonyms for structs and enums
-z1 compatibility with 2.7.6e: generate pointer-based arrays
-z2 compatibility with 2.7.15: qualify element/attribute referenced members
-z3 compatibility with 2.7.16 to 2.8.7: qualify element/attribute references
-z4 compatibility up to 2.8.11: don't generate union structs in std::vector
-_ don't generate _USCORE (replace with UNICODE _x005f)
Note: see README.txt in the wsdl directory for the latest
information on installation and options to of the wsdl2h WSDL/schema importer.


8.2 Customizing Data Bindings With The typemap.dat File

The typemap.dat file for the wsdl2h tool is intended to customize or optimize
the type bindings by mapping schema types to C/C++ types. It contains custom
XML Schema to C/C++ type bindings and a few bindings are defined for
convenience.

Here is an example typemap file's content:

# This file contains custom definitions of the XML Schema types and

# C/C++ types for your project, and XML namespace prefix definitions.

# The wsdl2h WSDL importer consults this file to determine bindings.

[

// This comment will be included in the generated .h file

// You can include any additional declarations, includes, imports, etc.

// within [ ] sections. The brackets MUST appear at the start of a line

]

# XML namespace prefix definitions can be provided to override the

# default choice of ns1, ns2, ... prefixes. For example:

i = "http://www.soapinterop.org/"

s = "http://www.soapinterop.org/xsd"
Type bindings can be provided to bind XML schema types to C/C++
types for your project.
Type bindings have four parts:

prefix__type = declaration | use | ptr-use
where 'prefix__type' is the C/C++-translation of the schema type,
'declaration' introduces the C/C++ type in the header file, the optional
'use' specifies how the type is used directly, and the optional
'ptr-use' specifies how the type is used as a pointer type.

# Example XML Schema and C/C++ type bindings:

xsd__int = | int

xsd__string = | char* | char*

xsd__boolean = enum xsd__boolean false_, true_ ; | enum xsd__boolean

xsd__base64Binary = class xsd__base64Binary unsigned char *__ptr; int __size; ; | xsd__base64Binary | xsd__base64Binary

# You can extend structs and classes with member data and functions.

# For example, adding a constructor to ns__myClass:
ns__myClass = $ ns__myClass();

# The general form is
# class_name = $ member;

The i and s prefixes are declared such that the header
file output by the WSDL parser will use these to produce C/C++ code.
XML Schema types are associated with an optional C/C++ type declaration,
a use reference, and a pointer-use reference. The pointer-use reference
of the xsd__byte type for example, is int* because char* is reserved for strings.

When a type binding requires only the usage to be changed, the
declaration part can be given by an elipsis ..., as in:

prefix__type = ... | use | ptr-use
This ensures that the wsdl2h-generated type definition is preserved,
while the use and ptr-use are remapped.

This method is useful to serialize dynamic types in C, where elements types int
XML carry the xsi:type attribute.

The following example illustrates an "any" type mapping for the
ns:sometype XSD type in a schema. This type will be replaced with a "any"
type wrapper that supports dynamic serialization with xsi:type:

[

struct __any

{

int __type;

void *__item;

}

]

xsd__anyType = ... | struct __any | struct __any
where __type and __item are used to (de)serialize any data type in the wrapper,
including base and its derived types based on xsi:type attribuation.

To support complexType extensions that are dynamically bound in C code, i.e.
polymorphic types based on inheritance hierarchies, we can redeclare the base
type of a hierarchy as a wrapper type and use the __type to serialize
base or derived types. One addition is needed to support base type
serialization without the use of xsi:type attributes. The absence of this attribute requires the serialization of the base type.

Basically, we need to be able to both handle a base type and its extensions
as per schema extensibility. Say base type ns:base is a
complexType that is extended by several other complexTypes. To implement
dynamic binding in C to serialize the base type and derived types, we
define:

[

struct __ns__base

{

int __type;

void *__item;

struct ns__base *__self;

}

]

ns__base = ... | struct __ns__base | struct __ns__base
The __self field refers to the element tag (basically a struct member name)
to which the ns:base type is associated. So for example, we see in the soapcpp2-generated output:

struct ns__data

{

...

struct __ns__base name;

...

};
where __item represents name when the __ns__base is
serialized with an xsi:type attribute, and __self represents
name when the __ns__base is serialized wwithout an xsi:type
attribute. Therefore, the dynamic binding defaults to struct ns__base
*__self when no dynamic type information in XML is available.

Additional data and function members can be provided to extend a
generated struct or class.
Class and struct extensions are of the form:

prefix__type = $ member-declaration
For example, to add a constructor and destructor to class myns__record:

myns__record = $ myns__record();
myns__record = $ ~myns__record();
Type remappings can be given to map a type to another type:

prefix__type1 == prefix__type2
which replaces prefix__type1 by prefix__type2 in the wsdl2h output.
For example:

SOAP_ENC__boolean == xsd__boolean
where SOAP_ENC__boolean is mapped to xsd__boolean, which in turn may be mapped to a C enum xsd__boolean type or C++ bool type.


9 Using the soapcpp2 Compiler and Code Generator

The soapcpp2 compiler and code generator is invoked from the command line
and optionally takes the name of a header file as an argument or, when the file
name is absent, parses the standard input:

> soapcpp2 [aheaderfile.h]
where aheaderfile.h is a C/C++ header file generated by wsdl2h or
developed manually to specify the SOAP/XML service operations as function
prototypes and the C/C++ data types to be auto-mapped to XML.

The soapcpp2 tool produces C/C++ source files. These files are used to
implement SOAP/XML clients and services, and to implement the advanced XML data
binding logic to convert C/C++ data into XML and vice versa.

The type of files generated by soapcpp2 are:

File Name Description
soapStub.h A modified and annotated header file produced from the input header file
soapH.h Main header file to be included by all client and service sources
soapC.cpp Serializers and deserializers for the specified data structures
soapClient.cpp Client stub routines for remote operations
soapServer.cpp Service skeleton routines
soapClientLib.cpp Client stubs combined with local static (de)serializers
soapServerLib.cpp Service skeletons combined with local static (de)serializers
soapXYZProxy.h A C++ proxy object (link with soapC.cpp soapClient.cpp)
soapXYZProxy.h With option -i: proxy object (link with soapC.cpp and soapXYZProxy.cpp)
soapXYZProxy.cpp With option -i: proxy code
soapXYZObject.h A C++ server object (link with soapC.cpp and soapServer.cpp)
soapXYZService.h With option -i: server object (link with soapC.cpp and soapXYZService.cpp)
soapXYZService.cpp With option -i: server code
.xsd An ns.xsd file is generated with an XML Schema for each namespace prefix ns used by a data structure in the header
file input to the compiler, see Section 7.2.9
.wsdl A ns.wsdl file is generated with an WSDL description for each namespace prefix ns used by a service operation in the
header file input to the compiler, see Section 7.2.9
.xml Several SOAP/XML request and response files are generated. These are example message files are valid provided
that sufficient schema namespace directives are added to the header file or the generated .nsmap namespace table for the
client/service is not modified by hand
.nsmap A ns.nsmap file is generated for each namespace prefix ns used by a service operation in the
header file input to the compiler, see Section 7.2.9. The file contains a namespace mapping table that can be used in the client/service sources
Both client and service applications are developed from a header file that
specifies the service operations. If client and service applications are
developed with the same header file, the applications are guaranteed to be
compatible because the stub and skeleton routines use the same serializers and
deserializers to encode and decode the parameters. Note that when client and
service applications are developed together, an application developer does not
need to know the details of the internal SOAP encoding used by the client and
service.

The soapClientLib.cpp and soapServerLib.cpp can be used to
build (dynamic) client and server libraries. The serialization routines
are local (static) to avoid link symbol conflicts. You must create a
separate library for SOAP Header and Fault handling, as described in
Section 19.36.

The following files are part of the gSOAP package and are required to build client and service applications:

File Name Description
stdsoap2.h Header file of stdsoap2.cpp runtime library
stdsoap2.c Runtime C library with XML parser and run-time support routines
stdsoap2.cpp Runtime C++ library identical to stdsoap2.c


9.1 soapcpp2 Options

The soapcpp2 source-to-source compiler supports the following command-line options:

Option Description
-1 Generate SOAP 1.1 bindings
-2 Generate SOAP 1.2 bindings
-0 Remove SOAP bindings, use plain REST
-C Generate client-side code only
-S Generate server-side code only
-T Generate server auto-test code
-L Do not generate soapClientLib/soapServerLib
-a Use SOAPAction with WS-Addressing to invoke server-side operations
-A Require SOAPAction to invoke server-side operations
-b serialize byte arrays char
as string
-c Generate pure C code
-d < path > Save sources in directory specified by < path >
-e Generate SOAP RPC encoding style bindings
-f N File split of N XML serializer implementations per file
-h Print a brief usage message
-i Generate service proxies and objects inherited from soap struct
-j Generate C++ service proxies and objects that can share a soap struct
-I < path > Use < path > (or paths separated with `:') for #import
-k generate data structure walkers (experimental)
-l Generate linkable modules (experimental)
-m Generate Matlabtm code for MEX compiler
-n When used with -p, enables multi-client and multi-server builds:
Sets compiler option WITH_NONAMESPACES, see Section 9.11
Saves the namespace mapping table with name < name > _namespaces instead of namespaces
Renames soap_serve() into < name > _serve() and soap_destroy() into < name > _destroy()
-p < name > Save sources with file name prefix < name > instead of "soap"
-q < name > Use name for the C++ namespace of all declarations
-s Generates deserialization code with strict XML validation checks
-t Generates code to send typed messages (with the xsi:type attribute)
-u uncomment comments in WSDL/schema output by suppressing XML comments
-v Display version info
-w Do not generate WSDL and schema files
-x Do not generate sample XML message files
-y include C/C++ type access information in sample XML messages
-z1 generate deprecated old-style C++ service proxies and objects
For example

> soapcpp2 -cd '../projects' -pmy file.h
Saves the sources:

../projects/myH.h

../projects/myC.c

../projects/myClient.c

../projects/myServer.c

../projects/myStub.h

MS Windows users can use the usual "/" for options, for example:

soapcpp2 /cd '..\projects' /pmy file.h
Compiler options c, i, n, l, w can be set in the gSOAP header file using the //gsoapopt directive. For example,

// Generate pure C and do not produce WSDL output:

//gsoapopt cw

int ns__myMethod(char*,char**); // takes a string and returns a string


9.2 SOAP 1.1 Versus SOAP 1.2 and Dynamic Switching

gSOAP supports SOAP 1.1 by default. SOAP 1.2 support is automatically
turned on when the appropriate SOAP 1.2 namespace is used, which shows
up in
the namespace mapping table:

struct Namespace namespaces[] =

{

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", ... },

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding, ... "},

...

}
Normally the soapcpp2-generated namespace table allows dynamic switching between SOAP 1.1 to SOAP 1.2 by providing the SOAP 1.2 namespace
as a pattern in the third column of a namespace table:

struct Namespace namespaces[] =

{

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-encoding"},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-envelope"},

...

}
where the "*" in the third column of the namespace URI pattern is a meta wildcard. This is used to match and accept inbound namespaces.

This way, gSOAP Web services can respond to either SOAP 1.1 or SOAP 1.2
requests. gSOAP will automatically return SOAP 1.2 responses for SOAP
1.2 requests.

The gSOAP soapcpp2 tool generates a .nsmap file with SOAP-ENV and SOAP-ENC namespace patterns similar to the above.
Since clients issue a send first, they will always use SOAP 1.1 for requests when the namespace table is similar as shown above.
Clients can accept SOAP 1.2 responses by inspecting the response message.

To use SOAP 1.2 by default and allow SOAP 1.1 messages to be received, use the soapcpp2 -2 option to generate SOAP 1.2 conformant .nsmap and .wsdl files. Alternatively, add the following line to your service definitions header file (generated by wsdl2h) for soapcpp2:

#import "import/soap12.h"
Caution: SOAP 1.2 does not support partially transmitted arrays. So the __offset field of a dynamic array is meaningless.

Caution: SOAP 1.2 requires the use of SOAP_ENV__Code, SOAP_ENV__Reason, and SOAP_ENV__Detail fields
in a SOAP_ENV__Fault fault struct, while SOAP 1.1 uses faultcode, faultstring, and detail fields.
Use soap_receiver_fault_subcode(struct soap *soap, const char *subcode, const char *faultstring, const char *detail) to set a SOAP 1.1/1.2
fault at the server-side with a fault subcode (SOAP 1.2).
Use soap_sender_fault_subcode(struct soap *soap, const char *subcode, const char *faultstring, const char *detail) to set a SOAP 1.1/1.2
unrecoverable Bad Request fault at the server-side with a fault subcode (SOAP 1.2).


9.3 The soapdefs.h Header File

The soapdefs.h header file is included in stdsoap2.h when compiling with option -DWITH_SOAPDEFS_H:

> c++ -DWITH_SOAPDEFS_H -c stdsoap2.cpp
The soapdefs.h file allows users to include definitions and add includes without requiring changes to stdsoap2.h.
For example,

// Contents of soapdefs.h

#include < ostream >

#define SOAP_BUFLEN 65536 // use large send/recv buffer

The following header file can now refer to ostream:

extern class ostream; // ostream can't be (de)serialized, but need to be declared to make it visible to gSOAP

class ns__myClass

{ ...

virtual void print(ostream &s) const; // need ostream here

...

};
See also Section 19.3.


9.4 How to Build Modules and Libraries with the #module Directive

The #module directive is used to build modules. A library can be
build from a module and linked with multiple Web services applications.
The directive should appear at the top of the header file and has the
following formats:

#module "name"

and

#module "name" "fullname"

where name must be a unique short name for the module. The name is case insensitive and MUST not exceed 4 characters in length. The fullname, when present, represents the full name of the module.

The rest of the content of the header file includes type declarations
and optionally the declarations of service operations and SOAP
Headers/Faults. When the gSOAP soapcpp2 compiler processes the
header file module, it will generate the source codes for a library. The
Web services application that uses the library should use a header file
that imports the module with the #import directive.

For example:

/* Contents of module.h */

#module "test"

long;

char*;

struct ns__S

{ ... }
The module.h header file declares a long, char*, and a struct ns__X. The module name is "test", so the gSOAP soapcpp2 compiler produces a testC.cpp file with the (de)serializers for these types. The testC.cpp
library can be separately compiled and linked with an application that
is built from a header file that imports "module.h" using #import "module.h". You should also compile testClient.cpp when you want to build a library that includes the service opertions that you defined in the module header file.

There are some limitations on a sequence of module imports. A module
MUST be imported into another header to use the module content and you
MUST place this import statement before all other statements in the
file, including other imports (except when these are also modules). It
is also advised to put all basic data type definitions in the root
module of a module import hierarchy, e.g. using typedef to declare XSD types (see also Section 11.3).

You cannot use a module alone to build a SOAP or XML application. That
is, the final gSOAP header file in the import chain SHOULD NOT be a
module.

When multiple modules are linked, the types that they declare MUST be
declared in one module only to avoid name clashes and link errors. You
cannot create two modules that share the same type declaration and link
the modules. When necessary, you should consider creating a module
hierarchy such that types are declared only once and by only one module
when these modules must be linked.


9.5 How to use the #import Directive

The #import directive is used to include gSOAP header files into other gSOAP header files for processing with
the gSOAP compiler soapcpp2.
The C #include directive cannot be used to include gSOAP header files.
The #include directive is reserved to control the post-gSOAP compilation process, see 9.6.

The #import directive is used for two purposes: you can use it to
include the contents of a header file into another header file and you
can use it to import a module, see 9.4.

An example of the #import directive:

#import "mydefs.gsoap"

int ns__mymethod(xsd__string in, xsd__int *out);
where "mydefs.gsoap" is a gSOAP header file that defines xsd__string and xsd__int:

typedef char *xsd__string;

typedef int xsd__int;
When importing a module, where the module content is declared with #module,
then note that this module MUST place the import statement before all
other statements in the header file, including other imports (except
when these are also modules).


9.6 How to Use #include and #define Directives

The #include and #define directives are normally ignored by the gSOAP soapcpp2 compiler and just passed on to the generated code.
Thus, the gSOAP compiler will not actually parse the contents of the header files provided by the #include directives in a header file.
Instead, the #include and #define directives will be added to the generated soapH.h header file before
any other header file is included. Therefore, #include and #define directives can be used to control the C/C++
compilation process of the sources of an application. However, they have no effect on soapcpp2.

The following example header file refers to ostream by including < ostream > :

#include < ostream >

#define WITH_COOKIES // use HTTP cookie support (you must compile stdsoap2.cpp with -DWITH_COOKIES)

#define WITH_OPENSSL // enable HTTPS/SSL support (you must compile stdsoap2.cpp with -DWITH_OPENSSL)

#define WITH_GNUTLS // enable HTTPS/SSL support (you must compile stdsoap2.cpp with -DWITH_GNUTLS)

#define SOAP_DEFAULT_float FLT_NAN // use NaN instead of 0.0

extern class ostream; // ostream can't be (de)serialized, but need to be declared to make it visible to gSOAP

class ns__myClass

{ ...

virtual void print(ostream &s) const; // need ostream here

...

};
This example also uses #define directives for various settings in the target source code.

Caution: Note that the use of #define in the header file does not automatically result in compiling
stdsoap2.cpp with these directives. You MUST use the -DWITH_COOKIES and -DWITH_OPENSSL (or -DWITH_GNUTLS options when
compiling stdsoap2.cpp before linking the object file with your codes. As an alternative, you can use #define
WITH_SOAPDEFS_H and put the #define directives in the soapdefs.h file.


9.7 Compiling a SOAP/XML Client Application with soapcpp2

After invoking the gSOAP soapcpp2 tool on a header file description of a service, the client application can be compiled on a Linux machine as follows:

> c++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp
Or on a Unix machine:

> c++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl
(Depending on your system configuration, the libraries libsocket.a,
libxnet.a, libnsl.a or dynamic *.so versions of those libraries are required.)

The myclient.cpp file must include soapH.h and must define a global namespace mapping table. A typical client program layout with namespace mapping table is shown below:

// Contents of file "myclient.cpp"

#include "soapH.h";

...

// A service operation invocation:

soap_call_some_remote_method(...);

...

struct Namespace namespaces[] =

{ // {"ns-prefix", "ns-name"}

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"},

{"xsi", "http://www.w3.org/2001/XMLSchema-instance"},

{"xsd", "http://www.w3.org/2001/XMLSchema"},

{"ns1", "urn:my-remote-method"},

{NULL, NULL}

};

...
A mapping table is generated by the gSOAP soapcpp2 compiler that can be used in the source, see Section 7.2.9.


9.8 Compiling a SOAP/XML Web Service with soapcpp2

After invoking the gSOAP soapcpp2 tool on a header file description of the service, the server application can be compiled on a Linux machine as follows:

> c++ -o myserver myserver.cpp stdsoap2.cpp soapC.cpp soapServer.cpp
Or on a Unix machine:

> c++ -o myserver myserver.cpp stdsoap2.cpp soapC.cpp soapServer.cpp -lsocket -lxnet -lnsl
(Depending on your system configuration, the libraries libsocket.a,
libxnet.a, libnsl.a or dynamic *.so versions of those libraries are required.)

The myserver.cpp file must include soapH.h and must define a global namespace mapping table. A typical service program layout with namespace mapping table is shown below:

// Contents of file "myserver.cpp"

#include "soapH.h";

int main()

{

soap_serve(soap_new());

}

...

// Implementations of the service operations as C++ functions

...

struct Namespace namespaces[] =

{ // {"ns-prefix", "ns-name"}

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"},

{"xsi", "http://www.w3.org/2001/XMLSchema-instance"},

{"xsd", "http://www.w3.org/2001/XMLSchema"},

{"ns1", "urn:my-remote-method"},

{NULL, NULL}

};

...
When the gSOAP service is compiled and installed as a CGI application, the soap_serve
function acts as a service dispatcher. It listens to standard input and
invokes the method via a skeleton routine to serve a SOAP client
request. After the request is served, the response is encoded in
SOAP and send to standard output. The method must be implemented in the
server application and the type signature of the method
must be identical to the service operations specified in the header
file. That is, the function prototype in the header file must be a
valid prototype of the method implemented as a C/C++ function.


9.9 Compiling Web Services and Clients in ANSI C

The gSOAP soapcpp2 compiler can be used to create pure C Web services and clients. The gSOAP stub and skeleton compiler
soapcpp2 generates .cpp files by default. The compiler generates .c files with the -c option.
However, these files only use C syntax and data types if the header
file input to soapcpp2 uses C syntax and data types. For example:

> soapcpp2 -c quote.h

> cc -o quote quote.c stdsoap2.c soapC.c soapClient.c
Warnings will be issued by the compiler when C++ class declarations occur in the header file.


9.10 Limitations of gSOAP

gSOAP is SOAP 1.1 and SOAP 1.2 compliant and supports SOAP RPC and document/literal operations.

From the perspective of the C/C++ language, a few C++ language features
are not supported by gSOAP and these features cannot be used in the
specification of SOAP service operations.

There are certain limitations for the following C++ language constructs:

STL and STL templates The gSOAP soapcpp2 compiler supports C++ strings std::string and std::wstring (see Section 11.3.6) and the STL containers std::deque, std::list, std::vector, and std::set, (see Section 11.11.8).Templates The gSOAP soapcpp2 compiler is a preprocessor that cannot
determine the template instantiations used by the main program, nor can
it generate templated code. You can however implement containers similar
to the STL containers.Multiple inheritance Single class inheritance is supported. Multiple inheritance cannot be supported due to limitations of the SOAP protocol.Abstract methods A class must be instantiatable to allow decoding of instances of the class.Directives Directives and pragmas such as #include and #define are interpreted by the gSOAP soapcpp2 compiler.
However, the interpretation is different compared to the usual handling of directives, see Section 9.6. If necessary, a traditional C++
preprocessor can be used for the interpretation of directives. For example, Unix and Linux users can use "cpp -B"
to expand the header file, e.g. cpp -B myfile.h - soapcpp2.
Use the gSOAP #import directive to import gSOAP header files, see 9.5.C and C++ programming statements All class methods of a class should be declared within the class
declaration in the header file, but the methods should not be
implemented in code. All class method implementations must be defined
within another C++ source file and linked to the application.

The following data types require some attention to ensure they are serialized:

[b]union types[/b] A union data type can not be serialized unless run-time information is associated with a union in a struct/class as discussed in Section 11.7. An alternative is to use a struct with a pointer type for each field. Because NULL pointers are not encoded, the resulting encoding will appear as a union type if only one pointer field is valid (i.e. non-NULL) at the time that the data type is encoded.[b]void and void* types[/b] The void data type cannot be serialized unless run-time type information is associated with the pointer using a int __type field in the struct/class that contains the void*. The void*
data type is typically used to point to some object or to some array of
some type of objects at run-time. The compiler cannot determine the
type of data pointed to and the size of the array pointed to. A struct
or class with a void* field can be augmented to support the (de)serialization of the void* using a int __type field as described in Section 11.9.Pointers to sequences of elements in memory Any pointer, except for C strings which are pointers to a sequence of
characters, are treated by the compiler as if the pointer points to only one element in memory at run-time. Consequently,
the encoding and decoding routines will ignore any subsequent elements that follow the first in memory. For the same reason,
arrays of undetermined length, e.g. float a[] cannot be used. gSOAP supports dynamic arrays using a special type convention,
see Section 11.11.Uninitialized pointers Obviously, all pointers that are part of a data structure must be valid or NULL to enable
serialization of the data structure at run time.

There are a number of programming solutions that can be adopted to circumvent these limitations. Instead of using void*,
a program
can in some cases be modified to use a pointer to a known type. If the
pointer is intended to point to different types of objects, a generic
base class can be declared and the pointer is declared to point to the
base class. All the other types are declared to be derived
classes of this base class. For pointers that point to a sequence of
elements in memory dynamic arrays should be used instead,
see 11.11.


9.11 Library Build Flags

The following macros (#defines) can be used to enable certain optional features when building the libgsoap library or when compiling and linking stdsoap2.c and stdsoap2.cpp:

Macro Description
WITH_SOAPDEFS_H includes the soapdefs.h file for custom settings, see Section 9.3
WITH_COOKIES enables HTTP cookies, see Sections 19.28 19.29
WITH_OPENSSL enables OpenSSL, see Sections 19.22 19.21
WITH_GNUTLS enables GNUTLS, see Sections 19.22 19.21
WITH_IPV6 enables IPv6 support (compile ALL sources with this macro set)
WITH_IPV6_V6ONLYIPv6-only server option (compile ALL sources with this macro set)
WITH_NO_IPV6_V6ONLYresets IPv6-only server option (compile ALL sources with this macro set)
WITH_TCPFIN use TCP FIN after sends when socket is ready to close
WITH_FASTCGI enables FastCGI, see Sections 19.31
WITH_GZIP enables gzip and deflate compression, see Section 19.27
WITH_ZLIB enables deflate compression only, see Section 19.27
WITH_FAST (obsolete)
WITH_NOIO eliminates need for file IO and BSD socket library, see Section 19.33
WITH_NOIDREF eliminates href/ref and id attributes to (de)serialize multi-ref data,
or alternatively use the SOAP_XML_TREE runtime flag
WITH_NOHTTP eliminates HTTP stack to reduce code size
WITH_NOZONE silently ignores the timezone in time conversions
WITH_LEAN creates a small-footprint executable, see Section 19.32
WITH_LEANER creates an even smaller footprint executable, see Section 19.32
WITH_COMPAT removes dependency on C++ stream libraries, eliminating C++ exceptions
WITH_NONAMESPACESremoves dependence on global namespaces table, MUST set it
explicitly with soap_set_.namespaces()
see also Section 10.4
WITH_PURE_VIRTUAL for C++ abstract service classes with pure virtual methods
WITH_NOEMPTYSTRUCT inserts a dummy member in empty structs to allow compilation
WITH_NOGLOBAL omit SOAP Header and Fault serialization code
WITH_NOCDATA do not retain the parsed CDATA sections in literal XML strings (no conversion)
WITH_CDATA retain the parsed CDATA sections in literal XML strings (no conversion, by default)
WITH_C_LOCALE use locale functions when available to ensure locale-independent
number conversions (force the use of C locale)
WITH_CASEINSENSITIVETAGS enable case insensitive XML parsing
Other compile-time flags:

Macro Description
SOCKET_CLOSE_ON_EXIT prevents a server port from staying in listening mode after exit
by internally setting fcntl(sock, F_SETFD, FD_CLOEXEC)
Compile-time flags to change the default engine settings:

Macro Description
SOAP_BUFLEN the length of the internal message buffer (affects socket comms)
SOAP_TAGLEN maximum length of XML tags and URL domain names (buffering)
SOAP_SSL_RSA_BITS the length of the RSA key (2048 by default)
SOAP_UNKNOWN_CHAR an 8 bit code that represents a character that could not be converted
to an ASCII char (e.g. from Unicode, applicable when SOAP_C_UTFSTRING is off)
Caution: it is important that all of these macros MUST be consistently defined to
compile all sources, such as stdsoap2.cpp, soapC.cpp,
soapClient.cpp, soapServer.cpp, and all application sources that
include stdsoap2.h or soapH.h. If the macros are not consistently
used, the application will crash due to a mismatches in the declaration and
access of the gSOAP context.


9.12 Run Time Flags

gSOAP provides flags to control the input and output mode settings at runtime.
These flags are divided into four categories: transport (IO), content encoding
(ENC), XML marshalling (XML), and C/C++ data mapping (C).

Although gSOAP is fully SOAP 1.1 compliant, some SOAP implementations may have
trouble accepting multi-reference data and/or require explicit nil data so
these flags can be used to put gSOAP in "safe mode". In addition, the
embedding (or inlining) of multi-reference data is adopted in the SOAP 1.2
specification, which gSOAP automatically supports when handling with SOAP 1.2
messages.

To set and clear flags for inbound message processing use:

soap_set_imode(soap, inflag);

soap_clr_imode(soap, inflag);

To set and clear the flags for outbound message processing use:

soap_set_omode(soap, outflag);

soap_clr_imode(soap, outflag);
To allocate and initialize a gSOAP context with inbound and outbound flags use:

soap_new2(soap, inflag, outflag);
To initialize an unitialized gSOAP context with inbound and outbound flags use:

soap_init2(soap, inflag, outflag);
The input-mode and output-mode flags for inbound and outbound message processing are:

Flag Description
SOAP_IO_FLUSH in: disable buffering and flush output (default for all file-based output)
SOAP_IO_BUFFER in: enable buffering (default for all socket-oriented connections)
SOAP_IO_STORE in: store entire message to calculate HTTP content length
SOAP_IO_CHUNK out: use HTTP chunking
SOAP_IO_LENGTH out: (internal flag) require apriori calculation of content length
SOAP_IO_KEEPALIVE in&out: attempt to keep socket connections alive (open)
SOAP_IO_UDP in&out: use UDP (datagram) transport, maximum message length is SOAP_BUFLEN
SOAP_ENC_XML out: use plain XML encoding without HTTP headers (useful with SOAP_ENC_ZLIB)
SOAP_ENC_DIME out: use DIME encoding (automatic when DIME attachments are used)
SOAP_ENC_MIME out: use MIME encoding (activate using soap_set_mime)
SOAP_ENC_MTOM out: use MTOM XOP attachments (instead of DIME)
SOAP_ENC_ZLIB out: compress encoding with Zlib (deflate or gzip format)
SOAP_ENC_SSL in&out: encrypt with SSL (automatic with "https:" endpoints)
SOAP_XML_INDENT out: produces indented XML output
SOAP_XML_CANONICAL out: produces canonical XML output
SOAP_XML_DEFAULTNS out: produces xmlns="..." default binding namespaced output
SOAP_XML_IGNORENS in: ignores the use of XML namespaces in input
SOAP_XML_STRICT in: XML strict validation
SOAP_XML_TREE out: serialize data as XML trees (no multi-ref, duplicate data when necessary)
in: ignore id attributes (do not resolve id-ref)
SOAP_XML_GRAPH out: serialize data as an XML graph with inline multi-ref (SOAP 1.2 default)
SOAP_XML_NIL out: serialize NULL data as xsi:nil attributed elements
SOAP_XML_NOTYPE out: disable xsi:type attributes
SOAP_C_NOIOB in: do not fault with SOAP_IOB
SOAP_C_UTFSTRING in&out: (de)serialize 8-bit strings "as is" (strings MUST have UTF-8 encoded content)
SOAP_C_MBSTRING in&out: enable multibyte character support (depends on locale)
SOAP_C_NILSTRING out: serialize empty strings as nil (ommited element)
The flags can be selectively turned on/off at any time, for example when
multiple Web services are accessed by a client that require special treatment.

All flags are orthogonal, except
SOAP_IO_FLUSH,
SOAP_IO_BUFFER,
SOAP_IO_STORE, and
SOAP_IO_CHUNK
which are enumerations and only one of these I/O flags can be used. Also the
XML serialization flags
SOAP_XML_TREE and
SOAP_XML_GRAPH should not be mixed.

The flags control the inbound and outbound message transport, encoding, and
(de)serialization. The following functions are used to set and reset the flags
for input and output modes:

Function Description
soap_init2(struct soap *soap, int imode, int omode) Initialize the runtime and set flags
soap_imode(struct soap *soap, int imode) Set all input mode flags
soap_omode(struct soap *soap, int omode) Set all output mode flags
soap_set_imode(struct soap *soap, int imode) Enable input mode flags
soap_set_omode(struct soap *soap, int omode) Enable output mode flags
soap_clr_imode(struct soap *soap, int omode) Disable input mode flags
soap_clr_omode(struct soap *soap, int omode) Disable output mode flags
The default setting is SOAP_IO_DEFAULT for both input and output modes.

For example

struct soap soap;

soap_init2(&soap, SOAP_IO_KEEPALIVE,

SOAP_IO_KEEPALIVE | SOAP_ENC_ZLIB | SOAP_XML_TREE | SOAP_XML_CANONICAL);

if (soap_call_ns__myMethod(&soap, ...))

...
sends a compressed client request with keep-alive enabled and all data serialized as canonical XML trees.

In many cases, setting the input mode will have no effect, especially with HTTP
transport because gSOAP will determine the optimal input buffering and the
encoding used for an inbound message. The flags that have an effect on
handling inbound messages are SOAP_IO_KEEPALIVE, SOAP_ENC_SSL
(but automatic when "https:" endpoints are used or soap_ssl_accept),
SOAP_C_NOIOB, SOAP_C_UTFSTRING, and SOAP_C_MBSTRING.

Caution: The SOAP_XML_TREE serialization flag can be used to
improve interoperability with SOAP implementations that are not fully SOAP 1.1
compliant. However, a tree serialization will duplicate data when necessary
and will crash the serializer for cyclic data structures.


9.13 Memory Management

Understanding gSOAP's run-time memory management is important to optimize
client and service applications by eliminating memory leaks and/or dangling
references.

There are two forms of dynamic (heap) allocations made by gSOAP's runtime for
serialization and deserialization of data. Temporary data is created by the
runtime such as hash tables to keep pointer reference information for
serialization and hash tables to keep XML id/href information for
multi-reference object deserialization. Deserialized data is created upon
receiving SOAP messages. This data is stored on the heap and requires several
calls to the malloc library function to allocate space for the data and
new to create class instances. All such allocations are tracked by
gSOAP's runtime by linked lists for later deallocation. The linked list for
malloc allocations uses some extra space in each malloced block to
form a chain of pointers through the malloced blocks. A separate
malloced linked list is used to keep track of class instance allocations.

If you want to preserve the deserialized data before deleting a soap
context, you can assign management of the data and delegate
responsibility of deletion to another soap context using soap_delegate_deletion(struct soap *soap_from, struct soap *soap_to). This moves all deserialized and temporary data to the other soap context soap_to, which will delete its data and all the delegated data it is responsible for when you call soap_destroy and soap_end.
This can be particularly useful for making client calls inside a server
operation, i.e. a mixed server/client. The client call inside the
server operation requires a new soap context, e.g. copied from the
server's with soap_copy. Before destroying the client context with soap_free, the data can be delegated to the server's context with soap_delegate_deletion. See samples/mashup/machupserver.c code for an example.

Note that gSOAP does not per se enforce a deallocation policy and the user can
adopt a deallocation policy that works best for a particular application. As a
consequence, deserialized data is never deallocated by the gSOAP runtime unless
the user explicitly forces deallocation by calling functions to deallocate data
collectively or individually.

The deallocation functions are:

Function Call Description
soap_destroy(struct soap *soap) Remove all dynamically allocated C++ objects.
must be called before soap_end()
soap_end(struct soap *soap) Remove temporary data and deserialized data except
class instances
soap_free_temp(struct soap *soap) Instead of soap_destroy and soap_end:
remove temporary data only
soap_dealloc(struct soap *soap, void *p) Remove malloced data at p. When p==NULL: remove all
dynamically allocated (deserialized) data except class instances
soap_delete(struct soap *soap, void *p) Remove class instance at p. When p==NULL: remove all
dynamically allocated (deserialized) class instances
(this is identical to calling soap_destroy(struct soap *soap))
soap_unlink(struct soap *soap, void *p) Unlink data/object at p from gSOAP's deallocation chain
so gSOAP won't deallocate it
soap_done(struct soap *soap) Detach context (reset runtime context)
soap_free(struct soap *soap) Detach and free context (allocated with soap_new)
Temporary data (i.e. the hash tables) are automatically removed with calls to
the soap_free_temp function which is also made by soap_end and
soap_done or when the next call to a stub or skeleton routine is made to
send a message or receive a message. Deallocation of non-class based data is
straightforward: soap_end removes all dynamically allocated deserialized
data (data allocated with soap_malloc. That is, when the client/service
application does not use any class instances that are (de)marshalled, but uses
structs, arrays, etc., then calling the soap_end function is safe to
remove all deserialized data. The function can be called after processing the
deserialized data of a service operation call or after a number of service operation
calls have been made. The function is also typically called after
soap_serve, when the service finished sending the response to a client
and the deserialized client request data can be removed.

Individual data objects can be unlinked from the deallocation chain if
necessary, to prevent deallocation by the collective soap_end or
soap_destroy functions.


9.13.1 Memory Allocation and Management Policies

There are three situations to consider for memory deallocation policies for class instances:

the program code deletes the class
instances and the class destructors in turn SHOULD delete and free any dynamically allocated data (deep deallocation) without
calling the soap_end and soap_destroy functions,

or the class
destructors SHOULD NOT deallocate any data and the soap_end and soap_destroy functions can be called to remove
the data.

or the class
destructors SHOULD mark their own deallocation and mark the deallocation of any other data deallocated by it's destructors
by calling the soap_unlink function. This allows
soap_destroy and soap_end to remove the remaining instances and data without causing duplicate deallocations.

It is advised to use pointers to class instances that are used within
other structs and classes to avoid the creation of temporary
class instances during deserialization. The problem with temporary class
instances is that the destructor of the temporary may affect data used
by
other instances through the sharing of data parts accessed with
pointers. Temporaries and even whole copies of class instances
can be created when deserializing SOAP multi-referenced objects.
A dynamic array of class instances is similar: temporaries may be
created to fill the array upon deserialization. To avoid
problems, use dynamic arrays of pointers to class instances. This also
enables the exchange of polymorphic arrays when the
elements are instances of classes in an inheritance hierarchy.
In addition, allocate data and class instances with soap_malloc and soap_new_X functions (more details below).

To summarize, it is advised to pass class data types by pointer to a service operation. For example:

class X { ... };

ns__remoteMethod(X *in, ...);
Response elements that are class data types can be passed by reference, as in:

class X { ... };

class ns__remoteMethodResponse { ... };

ns__remoteMethod(X *in, ns__remoteMethodResponse &out);
But dynamic arrays declared as class data types should use a pointer to a valid object that will be overwritten when the
function is called, as in:

typedef int xsd__int;

class X { ... };

class ArrayOfint { xsd__int *__ptr; int __size; };

ns__remoteMethod(X *in, ArrayOfint *out);
Or a reference to a valid or NULL pointer, as in:

typedef int xsd__int;

class X { ... };

class ArrayOfint { xsd__int *__ptr; int __size; };

ns__remoteMethod(X *in, ArrayOfint *&out);
The gSOAP memory allocation functions can be used in client and/or service code to allocate temporary data that will be
automatically deallocated.
These functions are:

Function Call Description
void *soap_malloc(struct soap *soap, size_t n) return pointer to n bytes
Class *soap_new_Class(struct soap *soap) instantiate Class
Class *soap_new_Class(struct soap *soap, int n) instantiate array of n objects
Class *soap_new_set_Class(struct soap *soap, m1, ..., mn) instantiate and set members mi
Class *soap_new_req_Class(struct soap *soap, m1, ..., mn) instantiate and set required-only mi
The soap_new_X functions are generated by the gSOAP soapcpp2 compiler for every class X in the header file.

Space allocated with soap_malloc will be released with the soap_end and soap_dealloc functions.
All objects instantiated with soap_new_X(struct soap*) are removed altogether with soap_destroy(struct soap*).
To remove just a single object, use soap_delete_X(struct soap*, X*).

For example, the following service uses temporary data in the service operation implementation:

int main()

{ ...

struct soap soap;

soap_init(&soap);

soap_serve(&soap);

soap_end(&soap);

...

}
An example service operation that allocates a temporary string is:

int ns__itoa(struct soap *soap, int i, char **a)

{

*a = (char*)soap_malloc(soap, 11);

sprintf(*a, "%d", i);

return SOAP_OK;

}
This temporary allocation can also be used to allocate strings for the SOAP Fault data structure. For example:

int ns__mymethod(...)

{ ...

if (exception)

{

char *msg = (char*)soap_malloc(soap, 1024); // allocate temporary space for detailed message

sprintf(msg, "...", ...); // produce the detailed message

return soap_receiver_fault(soap, "An exception occurred", msg); // return the server-side fault

}

...

}
Use soap_receiver_fault(struct soap *soap, const char *faultstring, const char *detail) to set a SOAP 1.1/1.2 fault at the server-side.
Use soap_sender_fault(struct soap *soap, const char *faultstring,
const char *detail) to set a SOAP 1.1/1.2 unrecoverable Bad Request fault
at the server-side. Sending clients are not supposed to retry messages after a
Bad Request, while errors at the receiver-side indicate temporary problems.

The above functions do not include a SOAP 1.2 Subcode element. To include Subcode element, use soap_receiver_fault_subcode(struct soap *soap, const char *subcode, const char *faultstring, const char *detail) to set a SOAP 1.1/1.2 fault with Subcode at the server-side.
Use soap_sender_fault_subcode(struct soap *soap, const char *subcode, const char *faultstring, const char *detail) to set a SOAP 1.1/1.2 unrecoverable Bad Request fault with Subcode at the server-side.

gSOAP provides a function to duplicate a string into gSOAP's memory space:

char *soap_strdup(struct soap *soap, const char *s)
The function allocates space for s with soap_malloc, copies the
string, and returns a pointer to the duplicated string. When s is NULL,
the function does not allocate and copy the string and returns NULL.


9.13.2 Intra-Class Memory Management

When a class declaration has a struct soap * field, this field will be set to point to the current gSOAP runtime context by
gSOAP's deserializers and by the soap_new_Class functions.
This simplifies memory management for class instances.
The struct soap* pointer is implicitly set by the gSOAP deserializer for
the class or explicitly by calling the soap_new_X function for class X.
For example:

class Sample

{ public:

struct soap *soap; // reference to gSOAP's run-time

...

Sample();

~Sample();

};
The constructor and destructor for class Sample are:

Sample::Sample()

{ this->soap = NULL;

}

Sample::~Sample()

{ soap_unlink(this->soap, this);

}
The soap_unlink() call removes the object from gSOAP's deallocation chain.
In that way, soap_destroy can be safely called to remove all class instances.
The following code illustrates the explicit creation of a Sample object and cleanup:

struct soap *soap = soap_new(); // new gSOAP runtime

Sample *obj = soap_new_Sample(soap); // new Sample object with obj->soap set to runtime

...

delete obj; // also calls soap_unlink to remove obj from the deallocation chain

soap_destroy(soap); // deallocate all (other) class instances

soap_end(soap); // clean up
Here is another example:

class ns__myClass

{ ...

struct soap *soap; // set by soap_new_ns__myClass()

char *name;

void setName(const char *s);

...

};
Calls to soap_new_ns__myClass(soap) will set the soap field in the class instance to the current gSOAP
context. Because the deserializers invoke the soap_new functions, the soap field of the ns__myClass
instances are set as well.
This mechanism is convenient when Web Service methods need to return objects that are instantiated in the methods.
For example

int ns__myMethod(struct soap *soap, ...)

{

ns__myClass *p = soap_new_ns__myClass(soap);

p->setName("SOAP");

return SOAP_OK;

}

void ns__myClass::ns__setName(const char *s)

{

if (soap)

name = (char*)soap_malloc(soap, strlen(s)+1);

else

name = (char*)malloc(strlen(s)+1);

strcpy(name, s);

}

ns__myClass::ns__myClass()

{

soap = NULL;

name = NULL;

}

ns__myClass::~ns__myClass()

{

if (!soap && name) free(name);

soap_unlink(soap, this);

}
Calling soap_destroy right after soap_serve in the Web Service will destroy all dynamically allocated
class instances.


9.14 Debugging

To activate message logging for debugging, un-comment the #define DEBUG directive in stdsoap2.h. Compile the client and/or
server applications as described above (or simply use c++ -DDEBUG ... to compile with debugging activated). When the client and server applications run, they will log their activity in three
separate files:

File Description
SENT.log The SOAP content transmitted by the application
RECV.log The SOAP content received by the application
TEST.log A log containing various activities performed by the application
Caution: The client and server applications may run slow due to the logging activity.

Caution: When installing a CGI application on the Web with debugging activated, the log files may sometimes not be created due to file
access permission restrictions imposed on CGI applications. To get around this, create empty log files with universal write
permissions. Be careful about the security implication of this.

You can test a service CGI application without deploying it on the Web.
To do this, create a client application for the service and activate message logging by this client.
Remove any old SENT.log file and run the client (which connects to the Web service or to another dummy, but valid address)
and copy the SENT.log file to another file, e.g. SENT.tst.
Then redirect the SENT.tst file to the service CGI application. For example,

> ./myservice.cgi < SENT.tst
This should display the service response on the terminal.

The file names of the log files and the logging activity can be controlled at the application level. This allows the creation of
separate log files by separate services, clients, and threads.
For example, the following service logs all SOAP messages (but no debug messages) in separate directories:

struct soap soap;

soap_init(&soap);

...

soap_set_recv_logfile(&soap, "logs/recv/service12.log"); // append all messages received in /logs/recv/service12.log

soap_set_sent_logfile(&soap, "logs/sent/service12.log"); // append all messages sent in /logs/sent/service12.log

soap_set_test_logfile(&soap, NULL); // no file name: do not save debug messages

...

soap_serve(&soap);

...
Likewise, messages can be logged for individual client-side service operation calls.


9.15 Generating an Auto Test Server for Client Testing

The soapcpp2 -T option generates an auto-test server application in soapTester.cpp, which is to be compiled and linked with the code generated for a server implementation, i.e. soapServer.cpp (or with the generated server object class) and soapC.cpp. The feature also supports C, so use the soapcpp2 -c option to generate C.

The auto-test server can be used to test a client application. Suppose the
generated code is compiled into the executable named tester (compile soapServer.cpp, soapC.cpp, and stdsoap2.cpp or link libgsoap++). We can use the IO
redirect to "send" it a message saved in a file, for example one of the
sample request messages generated by soapcpp2:

> ./tester < example.req.xml
which then returns the response with default XML values displayed on the terminal.

To run the auto test service on a port to test a client against, use two
command-line arguments. The first argument is the OR-ed values of the
gSOAP runtime context flags such as SOAP_IO_KEEPALIVE (0x10 = 16) and the second argument is the port number:

> ./tester 16 8080
This starts an iterative stand-alone server on port 8080. This way, messages
can be sent to http://localhost:8080 to test the client. The data in the
response messages are copied from the request messages
when possible, or XML default values, or empty otherwise.


9.16 Required Libraries

The socket library is essential and requires the inclusion of the appropriate libraries with the compile command for Sun
Solaris systems:

> c++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl
These library loading options are not required with Linux.

The gSOAP runtime uses the math library for the NaN, INF, and -INF floating point representations. The library
is not strictly necessary and the < math.h > header file import can be commented out from the stdsoap2.h header file.
The application can be linked without the -lm math library e.g. under Sun Solaris:

> c++ -o myclient myclient.cpp stdsoap2.cpp soapC.cpp soapClient.cpp -lsocket -lxnet -lnsl


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: