7
--------------------------------------------------------------------------------
8
gSOAP XML Web services tools
9
Copyright (C) 2001-2004, Robert van Engelen, Genivia, Inc. All Rights Reserved.
10
This software is released under one of the following two licenses:
11
GPL or Genivia's license for commercial use.
12
--------------------------------------------------------------------------------
15
This program is free software; you can redistribute it and/or modify it under
16
the terms of the GNU General Public License as published by the Free Software
17
Foundation; either version 2 of the License, or (at your option) any later
20
This program is distributed in the hope that it will be useful, but WITHOUT ANY
21
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
22
PARTICULAR PURPOSE. See the GNU General Public License for more details.
24
You should have received a copy of the GNU General Public License along with
25
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
26
Place, Suite 330, Boston, MA 02111-1307 USA
28
Author contact information:
29
engelen@genivia.com / engelen@acm.org
30
--------------------------------------------------------------------------------
31
A commercial use license is available from Genivia, Inc., contact@genivia.com
32
--------------------------------------------------------------------------------
34
TODO: add support for HTTP operations (non-SOAP access)
35
add headerfault output definitions
42
static void comment(const char *start, const char *middle, const char *end, const char *text);
44
////////////////////////////////////////////////////////////////////////////////
46
// Definitions methods
48
////////////////////////////////////////////////////////////////////////////////
50
Definitions::Definitions()
53
void Definitions::collect(const wsdl__definitions &definitions)
54
{ // Collect information: analyze WSDL definitions and imported definitions
55
if (definitions.service.empty())
56
fprintf(stderr, "Warning: no wsdl:definitions/service in definitions %s targetNamespace %s\n", definitions.name?definitions.name:"", definitions.targetNamespace);
58
for (vector<wsdl__import>::const_iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
59
if ((*import).definitionsPtr())
60
analyze(*(*import).definitionsPtr());
63
void Definitions::analyze(const wsdl__definitions &definitions)
64
{ // Analyze WSDL and build Service information
65
for (vector<wsdl__binding>::const_iterator binding = definitions.binding.begin(); binding != definitions.binding.end(); ++binding)
66
{ // /definitions/binding/documentation
67
const char *binding_documentation = (*binding).documentation;
68
// /definitions/binding/soap:binding
69
soap__binding *soap__binding_ = (*binding).soap__binding_;
70
// /definitions/binding/soap:binding/@transport
71
const char *soap__binding_transport = NULL;
73
soap__binding_transport = soap__binding_->transport;
74
// /definitions/binding/soap:binding/@style
75
soap__styleChoice soap__binding_style = rpc;
76
if (soap__binding_ && soap__binding_->style)
77
soap__binding_style = *soap__binding_->style;
78
// /definitions/binding/http:binding
79
http__binding *http__binding_ = (*binding).http__binding_;
80
const char *http__binding_verb = NULL;
82
http__binding_verb = http__binding_->verb;
83
// /definitions/binding/operation*
84
for (vector<wsdl__binding_operation>::const_iterator operation = (*binding).operation.begin(); operation != (*binding).operation.end(); ++operation)
85
{ // /definitions/portType/operation/ associated with /definitions/binding/operation
86
wsdl__operation *wsdl__operation_ = (*operation).operationPtr();
87
// /definitions/binding/operation/soap:operation
88
soap__operation *soap__operation_ = (*operation).soap__operation_;
89
// /definitions/binding/operation/soap:operation/@style
90
soap__styleChoice soap__operation_style = soap__binding_style;
91
if (soap__operation_ && soap__operation_->style)
92
soap__operation_style = *soap__operation_->style;
93
// /definitions/binding/operation/http:operation
94
http__operation *http__operation_ = (*operation).http__operation_;
95
// /definitions/binding/operation/http:operation/@location
96
const char *http__operation_location = NULL;
98
http__operation_location = http__operation_->location;
99
// /definitions/binding/operation/input
100
wsdl__ext_input *ext_input = (*operation).input;
101
// /definitions/binding/operation/output
102
wsdl__ext_output *ext_output = (*operation).output;
103
// /definitions/portType/operation
104
if (wsdl__operation_)
105
{ wsdl__input *input = wsdl__operation_->input;
106
wsdl__output *output = wsdl__operation_->output;
107
if (http__operation_)
108
{ // TODO: HTTP operation
110
else if (input && ext_input)
111
{ soap__body *input_body = ext_input->soap__body_;
112
if (ext_input->mime__multipartRelated_)
113
{ for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part)
114
if ((*part).soap__body_)
115
{ input_body = (*part).soap__body_;
119
// MUST have an input, otherwise can't generate a service operation
122
if (soap__operation_style == rpc)
123
URI = input_body->namespace_;
125
URI = definitions.targetNamespace;
127
{ const char *prefix = types.nsprefix(NULL, URI);
128
const char *name = types.aname(NULL, NULL, (*binding).name); // name of service is binding name
129
Service *s = services[prefix];
131
{ s = services[prefix] = new Service();
135
if ((*binding).portTypePtr())
136
s->type = types.aname(NULL, NULL, (*binding).portTypePtr()->name);
140
for (vector<wsdl__service>::const_iterator service = definitions.service.begin(); service != definitions.service.end(); ++service)
141
{ for (vector<wsdl__port>::const_iterator port = (*service).port.begin(); port != (*service).port.end(); ++port)
142
{ if ((*port).bindingPtr() == &(*binding))
143
{ if ((*port).soap__address_)
144
s->location.insert((*port).soap__address_->location);
145
// TODO: HTTP address for HTTP operations
146
// if ((*port).http__address_)
147
// http__address_location = http__address_->location;
148
if ((*service).documentation)
149
s->service_documentation[(*service).name] = (*service).documentation;
150
if ((*port).documentation && (*port).name)
151
s->port_documentation[(*port).name] = (*port).documentation;
152
if (binding_documentation)
153
s->binding_documentation[(*binding).name] = binding_documentation;
157
Operation *o = new Operation();
158
o->name = types.aname(NULL, NULL, wsdl__operation_->name);
161
o->style = soap__operation_style;
162
o->documentation = wsdl__operation_->documentation;
163
o->operation_documentation = (*operation).documentation;
164
o->parameterOrder = wsdl__operation_->parameterOrder;
165
if ((*operation).soap__operation_)
166
o->soapAction = (*operation).soap__operation_->soapAction;
168
{ o->soapAction = "";
169
// determine if we use SOAP 1.2 in which case soapAction is absent, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives
170
for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++)
171
{ if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/"))
172
{ o->soapAction = NULL;
177
o->input = new Message();
178
o->input->name = (*operation).name; // RPC uses operation/@name
179
if (soap__operation_style == rpc && !input_body->namespace_)
180
{ o->input->URI = "";
181
fprintf(stderr, "Error: no soap:body namespace attribute\n");
184
o->input->URI = input_body->namespace_;
185
o->input->use = input_body->use;
186
o->input->encodingStyle = input_body->encodingStyle;
187
o->input->message = input->messagePtr();
188
o->input->body_parts = input_body->parts;
189
o->input->part = NULL;
190
o->input->header = ext_input->soap__header_;
191
o->input->multipartRelated = ext_input->mime__multipartRelated_;
192
if (ext_input->dime__message_)
193
o->input->layout = ext_input->dime__message_->layout;
195
o->input->layout = NULL;
196
o->input->documentation = input->documentation;
197
o->input->ext_documentation = ext_input->documentation;
198
if (soap__operation_style == document)
199
o->input_name = types.oname("__", o->URI, o->input->name);
201
o->input_name = types.oname(NULL, o->input->URI, o->input->name);
202
if (output && ext_output)
203
{ soap__body *output_body = ext_output->soap__body_;
204
if (ext_output->mime__multipartRelated_)
205
{ for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part)
206
if ((*part).soap__body_)
207
{ output_body = (*part).soap__body_;
211
o->output = new Message();
212
o->output->name = (*operation).name; // RPC uses operation/@name with suffix 'Response' as set below
213
o->output->use = output_body->use;
214
// the code below is a hack around the RPC encoded response message element tag mismatch with Axis:
215
if (!output_body->namespace_ || o->output->use == encoded)
216
o->output->URI = o->input->URI; // encoded seems (?) to require the request's namespace
218
o->output->URI = output_body->namespace_;
219
o->output->encodingStyle = output_body->encodingStyle;
220
o->output->message = output->messagePtr();
221
o->output->body_parts = output_body->parts;
222
o->output->part = NULL;
223
o->output->header = ext_output->soap__header_;
224
o->output->multipartRelated = ext_output->mime__multipartRelated_;
225
if (ext_output->dime__message_)
226
o->output->layout = ext_output->dime__message_->layout;
228
o->output->layout = NULL;
229
o->output->documentation = output->documentation;
230
o->output->ext_documentation = ext_output->documentation;
231
char *s = (char*)soap_malloc(definitions.soap, strlen(o->output->name) + 9);
232
strcpy(s, o->output->name);
233
strcat(s, "Response");
234
if (soap__operation_style == document)
235
o->output_name = types.oname("__", o->URI, s);
237
o->output_name = types.oname(NULL, o->output->URI, s);
240
{ o->output_name = NULL;
243
// collect input headers and headerfaults
245
{ for (vector<soap__header>::const_iterator header = ext_input->soap__header_.begin(); header != ext_input->soap__header_.end(); ++header)
246
{ Message *h = new Message();
247
h->message = (*header).messagePtr();
248
h->body_parts = NULL;
249
h->part = (*header).partPtr();
250
h->URI = (*header).namespace_;
251
if (h->part && h->part->element)
252
h->name = types.aname(NULL, NULL, h->part->element);
253
else if (h->URI && h->part && h->part->name && h->part->type)
254
h->name = types.aname(NULL, h->URI, h->part->name);
256
{ fprintf(stderr, "Error in SOAP Header part definition\n");
259
h->encodingStyle = (*header).encodingStyle;
260
h->use = (*header).use;
261
h->multipartRelated = NULL;
263
h->ext_documentation = NULL; // TODO: add document content
264
h->documentation = NULL; // TODO: add document content
265
s->header[h->name] = h;
266
for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault)
267
{ // TODO: complete headerfault processing
271
// collect output headers and headerfaults
273
{ for (vector<soap__header>::const_iterator header = ext_output->soap__header_.begin(); header != ext_output->soap__header_.end(); ++header)
274
{ Message *h = new Message();
275
h->message = (*header).messagePtr();
276
h->body_parts = NULL;
277
h->part = (*header).partPtr();
278
h->URI = (*header).namespace_;
279
if (h->part && h->part->element)
280
h->name = types.aname(NULL, NULL, h->part->element);
281
else if (h->URI && h->part && h->part->name && h->part->type)
282
h->name = types.aname(NULL, h->URI, h->part->name);
284
{ fprintf(stderr, "Error in SOAP Header part definition\n");
287
h->encodingStyle = (*header).encodingStyle;
288
h->use = (*header).use;
289
h->multipartRelated = NULL;
291
h->ext_documentation = NULL; // TODO: add document content
292
h->documentation = NULL; // TODO: add document content
293
s->header[h->name] = h;
294
for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault)
295
{ // TODO: complete headerfault processing
300
for (vector<wsdl__ext_fault>::const_iterator ext_fault = (*operation).fault.begin(); ext_fault != (*operation).fault.end(); ++ext_fault)
301
{ if ((*ext_fault).soap__fault_ && (*ext_fault).messagePtr())
302
{ Message *f = new Message();
303
f->message = (*ext_fault).messagePtr();
304
f->body_parts = NULL;
306
f->encodingStyle = (*ext_fault).soap__fault_->encodingStyle;
307
f->URI = (*ext_fault).soap__fault_->namespace_;
308
f->use = (*ext_fault).soap__fault_->use;
309
f->multipartRelated = NULL;
311
f->ext_documentation = (*ext_fault).documentation;
312
f->name = types.aname("_", f->URI, f->message->name);
313
f->documentation = f->message->documentation;
314
o->fault.push_back(f);
315
s->fault[f->name] = f;
318
fprintf(stderr, "Error: no wsdl:definitions/binding/operation/fault/soap:fault\n");
320
s->operation.push_back(o);
323
fprintf(stderr, "Warning: no SOAP RPC operation namespace, operations will be ignored\n");
326
fprintf(stderr, "Error: no wsdl:definitions/binding/operation/input/soap:body\n");
329
fprintf(stderr, "Error: no wsdl:definitions/portType/operation/input\n");
332
fprintf(stderr, "Error: no wsdl:definitions/portType/operation\n");
337
void Definitions::compile(const wsdl__definitions& definitions)
338
{ // compile the definitions and generate gSOAP header file
339
collect(definitions);
340
fprintf(stream, "/** @mainpage %s Definitions\n\n", definitions.name?definitions.name:outfile?outfile:"Web Service");
341
// copy documentation from WSDL definitions
342
if (definitions.documentation)
343
fprintf(stream, "@section Service Documentation\n\n%s\n\n", definitions.documentation);
344
for (MapOfStringToService::const_iterator service = services.begin(); service != services.end(); ++service)
345
{ Service *sv = (*service).second;
346
if (sv && (*sv).name)
347
{ fprintf(stream, "@section %s Service Binding \"%s\"\n\n", (*sv).name, (*sv).name);
348
for (MapOfStringToString::const_iterator service_doc = (*sv).service_documentation.begin(); service_doc != (*sv).service_documentation.end(); ++service_doc)
349
fprintf(stream, "@subsection %s \"%s\" Documentation\n\n%s\n\n", (*service_doc).first, (*service_doc).first, (*service_doc).second);
350
for (MapOfStringToString::const_iterator port_doc = (*sv).port_documentation.begin(); port_doc != (*sv).port_documentation.end(); ++port_doc)
351
fprintf(stream, "@subsection %s Port \"%s\" Documentation\n\n%s\n\n", (*port_doc).first, (*port_doc).first, (*port_doc).second);
352
for (MapOfStringToString::const_iterator binding_doc = (*sv).binding_documentation.begin(); binding_doc != (*sv).binding_documentation.end(); ++binding_doc)
353
fprintf(stream, "@subsection %s Binding \"%s\" Documentation\n\n%s\n\n", (*binding_doc).first, (*binding_doc).first, (*binding_doc).second);
354
fprintf(stream, "@subsection %s_operations Operations\n\n", (*sv).name);
355
for (vector<Operation*>::const_iterator op = (*sv).operation.begin(); op != (*sv).operation.end(); ++op)
356
{ if (*op && (*op)->input_name)
357
fprintf(stream, " - @ref %s\n", (*op)->input_name);
359
fprintf(stream, "\n@subsection %s_ports Endpoint Ports\n\n", (*sv).name);
360
for (SetOfString::const_iterator port = (*sv).location.begin(); port != (*sv).location.end(); ++port)
361
fprintf(stream, " - %s\n", *port);
364
fprintf(stream, "\n*/\n\n// Note: modify this file to customize the generated data type declarations\n\n");
366
fprintf(stream, "/*\n%s*/\n\n", licensenotice);
367
// gsoap compiler options: 'w' disables WSDL/schema output to avoid file collisions
369
fprintf(stream, "//gsoapopt cw\n");
371
fprintf(stream, "//gsoapopt w\n");
372
// determine if we must use SOAP 1.2, this is a bit of a hack due to the lack of WSDL1.1/SOAP1.2 support and better alternatives
373
for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++)
374
{ // p->out is set to the actual namespace name that matches the p->in pattern
375
if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/"))
376
{ fprintf(stream, "// This service uses SOAP 1.2 namespaces:\n");
377
fprintf(stream, schemaformat, "SOAP-ENV", "namespace", "http://www.w3.org/2003/05/soap-envelope");
378
fprintf(stream, schemaformat, "SOAP-ENC", "namespace", "http://www.w3.org/2003/05/soap-encoding");
382
if (!cflag && !sflag)
383
fprintf(stream, "#import \"stl.h\"\n");
385
fprintf(stream, "#import \"base.h\"\n");
386
// generate the prototypes first: these should allow use before def, e.g. class names then generate the defs
387
// check if xsd:anyType is used
388
if (!cflag && !pflag)
389
{ for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i)
390
{ if (!cflag && !strcmp(*i, "xs:anyType"))
396
// define xsd:anyType first, if used
399
t = types.cname(NULL, NULL, "xs:anyType");
400
s = types.deftypemap[t];
404
fprintf(stream, "%s\n", s);
406
s = types.usetypemap[t];
409
fprintf(stream, "// base.h must define type: %s\n", s);
410
types.knames.insert(s);
414
{ fprintf(stderr, "Error: no xsd__anyType defined in type map\n");
418
// produce built-in primitive types, limited to the ones that are used only
419
for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i)
421
if (!cflag && pflag && !strcmp(*i, "xs:anyType"))
423
t = types.cname(NULL, NULL, *i);
424
s = types.deftypemap[t];
429
fprintf(stream, "/// Imported type %s\n", *i);
431
fprintf(stream, "/// Built-in type \"%s\"\n", *i);
432
fprintf(stream, "%s\n", s);
435
s = types.usetypemap[t];
437
{ if (mflag && **i != '"')
438
fprintf(stream, "// base.h must define type: %s\n", s);
439
if (types.knames.find(s) == types.knames.end())
440
types.knames.insert(s);
446
fprintf(stream, "// Imported type %s defined by %s\n", *i, t);
448
{ fprintf(stream, "/// Primitive built-in type \"%s\"\n", *i);
449
fprintf(stream, "typedef char *%s;\n", t);
453
fprintf(stream, "// Imported type %s defined by %s\n", *i, t);
455
fprintf(stream, "// base.h must define type: %s\n", t);
456
types.ptrtypemap[t] = types.deftname(TYPEDEF, NULL, NULL, NULL, *i); // already pointer
458
if (pflag && !strncmp(*i, "xs:", 3)) // only xsi types are polymorph
459
{ s = types.aname(NULL, NULL, *i);
461
{ fprintf(stream, "/// Class wrapper for built-in type \"%s\" derived from xsd__anyType\n", *i);
462
fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s);
463
fprintf(stream, elementformat, types.tname(NULL, NULL, *i), "__item;");
464
fprintf(stream, "\n};\n");
466
types.knames.insert(s);
469
// produce built-in primitive elements, limited to the ones that are used only
470
for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j)
471
{ const char *s, *t = types.cname("_", NULL, *j);
472
s = types.deftypemap[t];
476
fprintf(stream, "/// Imported element %s\n", *j);
478
fprintf(stream, "/// Built-in element \"%s\"\n", *j);
481
fprintf(stream, "// base.h must define element: ");
482
fprintf(stream, "%s\n", s);
483
s = types.usetypemap[t];
484
if (s && *s && types.knames.find(s) == types.knames.end())
485
types.knames.insert(s);
490
fprintf(stream, "// Imported element %s defined by %s\n", *j, t);
492
{ fprintf(stream, "/// Built-in element \"%s\"\n", *j);
493
fprintf(stream, "typedef _XML %s;\n", t);
497
fprintf(stream, "// Imported element %s defined by %s\n", *j, t);
499
fprintf(stream, "// base.h must define element: %s\n", t);
500
types.ptrtypemap[t] = types.deftname(TYPEDEF, NULL, NULL, NULL, *j); // already pointer
501
types.knames.insert(t);
504
// produce built-in primitive attributes, limited to the ones that are used only
505
for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k)
506
{ const char *s, *t = types.cname(NULL, NULL, *k);
507
s = types.deftypemap[t];
511
fprintf(stream, "/// Imported attribute %s\n", *k);
513
fprintf(stream, "/// Built-in attribute \"%s\"\n", *k);
516
fprintf(stream, "// base.h must define attribute: ");
517
fprintf(stream, "%s\n", s);
518
s = types.usetypemap[t];
519
if (s && *s && types.knames.find(s) == types.knames.end())
520
types.knames.insert(s);
525
fprintf(stream, "// Imported attribute %s defined by %s\n", *k, t);
527
{ fprintf(stream, "/// Built-in attribute \"%s\"\n", *k);
528
fprintf(stream, "typedef char *%s;\n", t);
532
fprintf(stream, "// Imported attribute %s defined by %s\n", *k, t);
534
fprintf(stream, "// base.h must define attribute: %s\n", t);
535
types.ptrtypemap[t] = types.deftname(TYPEDEF, NULL, NULL, NULL, *k); // already pointer
536
types.knames.insert(t);
540
if (definitions.types)
541
{ fprintf(stream, "\n/*\nTo customize the names of the namespace prefixes generated by wsdl2h, modify\nthe prefix names below and add the modified lines to typemap.dat to run wsdl2h:\n\n");
542
for (vector<xs__schema*>::const_iterator schema1 = definitions.types->xs__schema_.begin(); schema1 != definitions.types->xs__schema_.end(); ++schema1)
543
fprintf(stream, "%s = %s\n", types.nsprefix(NULL, (*schema1)->targetNamespace), (*schema1)->targetNamespace);
544
fprintf(stream, "*/\n\n");
545
comment("Definitions", definitions.name?definitions.name:"", "types", definitions.types->documentation);
546
for (vector<xs__schema*>::const_iterator schema2 = definitions.types->xs__schema_.begin(); schema2 != definitions.types->xs__schema_.end(); ++schema2)
547
fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "namespace", (*schema2)->targetNamespace);
548
for (vector<xs__schema*>::const_iterator schema3 = definitions.types->xs__schema_.begin(); schema3 != definitions.types->xs__schema_.end(); ++schema3)
549
{ if ((*schema3)->elementFormDefault == (*schema3)->attributeFormDefault)
550
fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "form", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified");
552
{ fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "elementForm", (*schema3)->elementFormDefault == qualified ? "qualified" : "unqualified");
553
fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema3)->targetNamespace), "attributeForm", (*schema3)->attributeFormDefault == qualified ? "qualified" : "unqualified");
556
// define class/struct types first
557
fprintf(stream, "\n// Forward declarations\n");
558
for (vector<xs__schema*>::const_iterator schema4 = definitions.types->xs__schema_.begin(); schema4 != definitions.types->xs__schema_.end(); ++schema4)
559
{ for (vector<xs__complexType>::const_iterator complexType = (*schema4)->complexType.begin(); complexType != (*schema4)->complexType.end(); ++complexType)
560
types.define((*schema4)->targetNamespace, NULL, *complexType);
561
for (vector<xs__element>::const_iterator element = (*schema4)->element.begin(); element != (*schema4)->element.end(); ++element)
562
if (!(*element).type && (*element).complexTypePtr())
563
types.define((*schema4)->targetNamespace, (*element).name, *(*element).complexTypePtr());
565
fprintf(stream, "\n// End of forward declarations\n\n");
566
// visit types with lowest base level first
570
{ found = (baseLevel == 1);
571
for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
572
{ for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType)
573
{ if ((*simpleType).baseLevel() == baseLevel)
575
types.gen((*schema)->targetNamespace, NULL, *simpleType);
578
for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
579
{ if (!(*element).type && (*element).simpleTypePtr() && (*element).simpleTypePtr()->baseLevel() == baseLevel)
581
types.gen((*schema)->targetNamespace, (*element).name, *(*element).simpleTypePtr());
583
if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel)
586
for (vector<xs__attribute>::const_iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute)
587
{ if (!(*attribute).type && (*attribute).simpleTypePtr() && (*attribute).simpleTypePtr()->baseLevel() == baseLevel)
589
types.gen((*schema)->targetNamespace, (*attribute).name, *(*attribute).simpleTypePtr()); // URI = NULL won't generate type in schema (type without namespace qualifier)
592
for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType)
593
{ if ((*complexType).baseLevel() == baseLevel)
599
// generate complex type defs. Problem: what if a simpleType restriction/extension depends on a complexType simpleContent restriction/extension?
600
int maxLevel = baseLevel;
601
for (baseLevel = 1; baseLevel < maxLevel; ++baseLevel)
602
{ for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
603
{ for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType)
604
{ if ((*complexType).baseLevel() == baseLevel)
605
types.gen((*schema)->targetNamespace, NULL, *complexType);
607
for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
608
{ if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel)
609
types.gen((*schema)->targetNamespace, (*element).name, *(*element).complexTypePtr());
613
// option to consider: generate local complexTypes iteratively
615
for (MapOfStringToType::const_iterator local = types.locals.begin(); local != types.locals.end(); ++local)
616
{ types.gen(NULL, (*local).first, *(*local).second);
621
fprintf(stream, "\n/* End of %s Definitions */\n", definitions.name?definitions.name:outfile?outfile:"Web Service");
624
void Definitions::generate()
625
{ MapOfStringToMessage headers;
626
MapOfStringToMessage faults;
627
for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1)
628
{ if ((*service1).second)
629
{ for (MapOfStringToMessage::const_iterator header = (*service1).second->header.begin(); header != (*service1).second->header.end(); ++header)
630
headers[(*header).first] = (*header).second;
631
for (MapOfStringToMessage::const_iterator fault = (*service1).second->fault.begin(); fault != (*service1).second->fault.end(); ++fault)
632
faults[(*fault).first] = (*fault).second;
635
// Generate SOAP Header definition
636
if (!headers.empty())
637
{ fprintf(stream, "// SOAP Header\n");
638
//if (cflag) always use structs to avoid compilation warnings
639
fprintf(stream, "struct SOAP_ENV__Header\n{\n");
641
//fprintf(stream, "class SOAP_ENV__Header\n{ public:\n");
642
for (MapOfStringToMessage::const_iterator header = headers.begin(); header != headers.end(); ++header)
643
{ if ((*header).second->URI && !types.uris[(*header).second->URI])
644
fprintf(stream, schemaformat, types.nsprefix(NULL, (*header).second->URI), "namespace", (*header).second->URI);
645
comment("Header", (*header).first, "WSDL", (*header).second->ext_documentation);
646
comment("Header", (*header).first, "SOAP", (*header).second->documentation);
647
if ((*header).second->part && (*header).second->part->elementPtr())
648
{ fprintf(stream, "/// \"%s\" SOAP Header part element\n", (*header).second->part->name);
649
types.gen((*header).second->part->elementPtr()->schemaPtr()->targetNamespace, *(*header).second->part->elementPtr());
651
else if ((*header).second->part && (*header).second->part->name && (*header).second->part->type)
652
{ fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->type), (*header).first);
653
fprintf(stream, ";\n");
656
fprintf(stderr, "Error in SOAP Header part\n");
658
fprintf(stream, "\n};\n");
660
// Generate Fault detail element definitions
661
for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault)
662
{ fprintf(stream, "/// SOAP Fault Detail element\n\n");
663
fprintf(stream, "/// The SOAP Fault Detail element contains one of the following types serialized\n// in the __type and fault fields of the SOAP_ENV__Detail struct (see docs)\n");
664
if ((*fault).second->URI && !types.uris[(*fault).second->URI])
665
fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI);
666
comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation);
667
comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation);
669
fprintf(stream, "struct %s\n{\n", (*fault).first);
671
fprintf(stream, "class %s\n{ public:", (*fault).first);
672
(*fault).second->generate(types, ";", false, true);
674
{ fprintf(stream, "\n");
675
fprintf(stream, pointerformat, "struct soap", "soap");
676
fprintf(stream, ";");
678
fprintf(stream, "\n};\n");
680
/* The SOAP Fault struct below is autogenerated by soapcpp2 (kept here for future mods)
681
if (!mflag && !faults.empty())
682
{ fprintf(stream, "struct SOAP_ENV__Code\n{\n");
683
fprintf(stream, elementformat, "_QName", "SOAP_ENV__Value");
684
fprintf(stream, ";\n");
685
fprintf(stream, pointerformat, "char", "SOAP_ENV__Node");
686
fprintf(stream, ";\n");
687
fprintf(stream, pointerformat, "char", "SOAP_ENV__Role");
688
fprintf(stream, ";\n};\n");
689
fprintf(stream, "struct SOAP_ENV__Detail\n{\n");
690
fprintf(stream, elementformat, "int", "__type");
691
fprintf(stream, ";\n");
692
fprintf(stream, pointerformat, "void", "fault");
693
fprintf(stream, ";\n");
694
fprintf(stream, elementformat, "_XML", "__any");
695
fprintf(stream, ";\n};\n");
696
fprintf(stream, "struct SOAP_ENV__Fault\n{\n");
697
fprintf(stream, elementformat, "_QName", "faultcode");
698
fprintf(stream, ";\n");
699
fprintf(stream, pointerformat, "char", "faultstring");
700
fprintf(stream, ";\n");
701
fprintf(stream, pointerformat, "char", "faultactor");
702
fprintf(stream, ";\n");
703
fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "detail");
704
fprintf(stream, ";\n");
705
fprintf(stream, pointerformat, "struct SOAP_ENV__Code", "SOAP_ENV__Code");
706
fprintf(stream, ";\n");
707
fprintf(stream, pointerformat, "char", "SOAP_ENV__Reason");
708
fprintf(stream, ";\n");
709
fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "SOAP_ENV__Detail");
710
fprintf(stream, ";\n};\n");
713
for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2)
714
if ((*service2).second)
715
(*service2).second->generate(types);
718
////////////////////////////////////////////////////////////////////////////////
722
////////////////////////////////////////////////////////////////////////////////
730
void Service::generate(Types& types)
731
{ fprintf(stream, "\n");
732
fprintf(stream, serviceformat, prefix, "name", name, "");
733
fprintf(stream, serviceformat, prefix, "type", type, "");
734
for (SetOfString::const_iterator port = location.begin(); port != location.end(); ++port)
735
fprintf(stream, serviceformat, prefix, "port", (*port), "");
736
fprintf(stream, serviceformat, prefix, "namespace", URI, "");
737
for (vector<Operation*>::const_iterator op2 = operation.begin(); op2 != operation.end(); ++op2)
738
{ if (*op2 && (*op2)->input)
739
{ bool flag = false, anonymous = (*op2)->parameterOrder != NULL;
740
if ((*op2)->output && (*op2)->output_name)
741
{ flag = ((*op2)->style == document && (*op2)->output->message && (*op2)->output->message->part.size() == 1);
742
if (flag && (*op2)->input->message && (*(*op2)->output->message->part.begin()).element)
743
for (vector<wsdl__part>::const_iterator part = (*op2)->input->message->part.begin(); part != (*op2)->input->message->part.end(); ++part)
744
if ((*part).element && !strcmp((*part).element, (*(*op2)->output->message->part.begin()).element))
747
{ fprintf(stream, "\n/// Operation response struct \"%s\" of service binding \"%s\" operation \"%s\"\n", (*op2)->output_name, name, (*op2)->input_name);
748
fprintf(stream, "struct %s\n{", (*op2)->output_name);
749
(*op2)->output->generate(types, ";", anonymous, true);
750
fprintf(stream, "\n};\n");
753
fprintf(stream, "\n/// Operation \"%s\" of service binding \"%s\"\n\n/**\n\nOperation details:\n\n", (*op2)->input_name, name);
754
if ((*op2)->documentation)
755
fprintf(stream, "%s\n\n", (*op2)->documentation);
756
if ((*op2)->operation_documentation)
757
fprintf(stream, "%s\n\n", (*op2)->operation_documentation);
758
if ((*op2)->input->documentation)
759
fprintf(stream, "Input:\n%s\n\n", (*op2)->input->documentation);
760
if ((*op2)->input->ext_documentation)
761
fprintf(stream, "Input:\n%s\n\n", (*op2)->input->ext_documentation);
763
{ if ((*op2)->output->documentation)
764
fprintf(stream, "Output:\n%s\n\n", (*op2)->output->documentation);
765
if ((*op2)->output->ext_documentation)
766
fprintf(stream, "Output:\n%s\n\n", (*op2)->output->ext_documentation);
768
if ((*op2)->style == document)
769
fprintf(stream, " - SOAP document/literal style\n");
771
{ if ((*op2)->input->use == literal)
772
fprintf(stream, " - SOAP RPC literal style\n");
773
else if ((*op2)->input->encodingStyle)
774
fprintf(stream, " - SOAP RPC encodingStyle=\"%s\"\n", (*op2)->input->encodingStyle);
776
fprintf(stream, " - SOAP RPC encoded\n");
779
{ if ((*op2)->input->use != (*op2)->output->use)
780
{ if ((*op2)->output->use == literal)
781
fprintf(stream, " - SOAP RPC literal response\n");
782
else if ((*op2)->output->encodingStyle)
783
fprintf(stream, " - SOAP RPC response encodingStyle=\"%s\"\n", (*op2)->output->encodingStyle);
785
fprintf(stream, " - SOAP RPC encoded response\n");
788
if ((*op2)->soapAction)
789
if (*(*op2)->soapAction)
790
fprintf(stream, " - SOAP action=\"%s\"\n", (*op2)->soapAction);
791
for (vector<Message*>::const_iterator message = (*op2)->fault.begin(); message != (*op2)->fault.end(); ++message)
792
if ((*message)->message && (*message)->message->name)
793
fprintf(stream, " - SOAP Fault: %s\n", (*message)->name);
794
for (vector<soap__header>::const_iterator inputheader = (*op2)->input->header.begin(); inputheader != (*op2)->input->header.end(); ++inputheader)
795
if ((*inputheader).part)
796
fprintf(stream, " - Request message has mandatory header part: %s\n", types.aname(NULL, (*inputheader).namespace_, (*inputheader).part));
797
if ((*op2)->input->multipartRelated)
798
fprintf(stream, " - Request message has MIME multipart/related attachments\n");
799
if ((*op2)->input->layout)
800
fprintf(stream, " - Request message has DIME attachments in compliance with %s\n", (*op2)->input->layout);
802
for (vector<soap__header>::const_iterator outputheader = (*op2)->output->header.begin(); outputheader != (*op2)->output->header.end(); ++outputheader)
803
if ((*outputheader).part)
804
fprintf(stream, " - Response message has mandatory header part: %s\n", types.aname(NULL, (*outputheader).namespace_, (*outputheader).part));
805
if ((*op2)->output && (*op2)->output_name && (*op2)->output->multipartRelated)
806
fprintf(stream, " - Response message has MIME multipart/related attachments\n");
807
if ((*op2)->output && (*op2)->output_name && (*op2)->output->layout)
808
fprintf(stream, " - Response message has DIME attachments in compliance with %s\n", (*op2)->output->layout);
809
fprintf(stream, "\nC stub function (defined in soapClient.c[pp]):\n@code\n int soap_call_%s(struct soap *soap,\n NULL, // char *endpoint = NULL selects default endpoint for this operation\n NULL, // char *action = NULL selects default action for this operation", (*op2)->input_name);
810
(*op2)->input->generate(types, ",", false, false);
811
if ((*op2)->output && (*op2)->output_name)
813
{ // Shortcut: do not generate wrapper struct
814
(*op2)->output->generate(types, "", false, false);
817
fprintf(stream, "\n struct %s%s", (*op2)->output_name, cflag ? "*" : "&");
819
fprintf(stream, "\n );\n@endcode\n\n");
821
{ fprintf(stream, "C++ proxy class (defined in soap%sProxy.h):\n", name);
822
fprintf(stream, " class %s;\n\n", name);
824
fprintf(stream, "*/\n\n");
825
(*op2)->generate(types);
830
////////////////////////////////////////////////////////////////////////////////
834
////////////////////////////////////////////////////////////////////////////////
836
void Operation::generate(Types &types)
837
{ bool flag = false, anonymous = parameterOrder != NULL;
838
const char *method_name = strstr(input_name + 1, "__") + 2;
840
method_name = input_name;
841
if (style == document)
842
fprintf(stream, serviceformat, prefix, "method-style", method_name, "document");
844
fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc");
845
if (input->use == literal)
846
fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal");
847
else if (input->encodingStyle)
848
fprintf(stream, serviceformat, prefix, "method-encoding", method_name, input->encodingStyle);
850
fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded");
852
{ if (input->use != output->use)
853
{ if (output->use == literal)
854
fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "literal");
855
else if (output->encodingStyle)
856
fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, output->encodingStyle);
858
fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "encoded");
860
if (style == rpc && input->URI && output->URI && strcmp(input->URI, output->URI))
861
fprintf(stream, schemaformat, types.nsprefix(NULL, output->URI), "namespace", output->URI);
865
fprintf(stream, serviceformat, prefix, "method-action", method_name, soapAction);
867
fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\"");
868
for (vector<Message*>::const_iterator message = fault.begin(); message != fault.end(); ++message)
869
if ((*message)->message && (*message)->message->name)
870
fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name);
871
// TODO: add headerfault directives
872
for (vector<soap__header>::const_iterator inputheader = input->header.begin(); inputheader != input->header.end(); ++inputheader)
873
if ((*inputheader).part)
874
fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part));
876
for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader)
877
if ((*outputheader).part)
878
fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part));
880
{ flag = (style == document && output->message && output->message->part.size() == 1);
881
if (flag && input->message && (*output->message->part.begin()).element)
882
for (vector<wsdl__part>::const_iterator part = input->message->part.begin(); part != input->message->part.end(); ++part)
883
if ((*part).element && !strcmp((*part).element, (*output->message->part.begin()).element))
886
fprintf(stream, "int %s(", input_name);
887
input->generate(types, ",", anonymous, true);
890
{ // Shortcut: do not generate wrapper struct
891
output->generate(types, "", anonymous, true);
892
fprintf(stream, " );\n");
895
{ fprintf(stream, "\n struct %s%s );\n", output_name, cflag ? "*" : "&");
899
fprintf(stream, " void );\n");
902
////////////////////////////////////////////////////////////////////////////////
906
////////////////////////////////////////////////////////////////////////////////
908
void Message::generate(Types &types, const char *sep, bool anonymous, bool remark)
910
{ for (vector<wsdl__part>::const_iterator part = message->part.begin(); part != message->part.end(); ++part)
912
{ if (remark && (*part).documentation)
913
comment("", (*part).name, "parameter", (*part).documentation);
915
fprintf(stream, "\n");
916
if ((*part).elementPtr())
917
{ const char *name, *type, *URI;
918
name = (*part).elementPtr()->name;
919
/* comment out to use a type that refers to an element defined with typedef */
920
if ((*part).elementPtr()->type)
921
type = (*part).elementPtr()->type;
925
if ((*part).elementPtr()->schemaPtr())
926
URI = (*part).elementPtr()->schemaPtr()->targetNamespace;
929
fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, URI, type), types.aname(NULL, URI, name), sep);
931
else if ((*part).type)
932
{ if (use == literal)
933
fprintf(stderr, "Warning: part '%s' uses literal style and must refer to an element rather than a type\n", (*part).name);
934
fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*part).type), types.aname(NULL, NULL, (*part).name), sep);
937
fprintf(stderr, "Error: no wsdl:definitions/message/part/@type in part '%s'\n", (*part).name);
940
fprintf(stderr, "Error: no part name in message '%s'\n", message->name?message->name:"");
944
fprintf(stderr, "Error: no wsdl:definitions/message\n");
947
////////////////////////////////////////////////////////////////////////////////
951
////////////////////////////////////////////////////////////////////////////////
953
static void comment(const char *start, const char *middle, const char *end, const char *text)
955
{ if (strchr(text, '\r') || strchr(text, '\n'))
956
fprintf(stream, "\n/** %s %s %s documentation:\n%s\n*/\n\n", start, middle, end, text);
958
fprintf(stream, "\n/// %s %s %s: %s\n", start, middle, end, text);