Mercurial > repos > ktnyt > gembassy
view GEMBASSY-1.0.3/gsoap/wsdl/service.cpp @ 0:8300eb051bea draft
Initial upload
author | ktnyt |
---|---|
date | Fri, 26 Jun 2015 05:19:29 -0400 |
parents | |
children |
line wrap: on
line source
/* service.cpp Generate gSOAP service structures from WSDL. -------------------------------------------------------------------------------- gSOAP XML Web services tools Copyright (C) 2000-2013, Robert van Engelen, Genivia Inc. All Rights Reserved. This part of the software is released under one of the following licenses: GPL or Genivia's license for commercial use. -------------------------------------------------------------------------------- GPL license. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: engelen@genivia.com / engelen@acm.org -------------------------------------------------------------------------------- A commercial use license is available from Genivia, Inc., contact@genivia.com -------------------------------------------------------------------------------- TODO: consider adding support for non-SOAP HTTP operations add headerfault output definitions */ #include "types.h" #include "service.h" #include <algorithm> #define URI_CHAR(c) (((c) > 32 && (c) != '"' && (c) != '<' && (c) != '>' && (c) != '\\' && (c) != '^' && (c) != '`' && (c) <= 'z') || (c) == '~') static const char *urienc(struct soap*, const char*); static bool imported(const char *tag); static void comment(const char *start, const char *middle, const char *end, const char *text); static void page(const char *page, const char *title, const char *text); static void section(const char *section, const char *title, const char *text); static void banner(const char*); static void banner(const char*, const char*); static void ident(); static void gen_policy(Service&, const vector<const wsp__Policy*>&, const char*, Types&); static void gen_policy_enablers(const Service&); //////////////////////////////////////////////////////////////////////////////// // // Definitions methods // //////////////////////////////////////////////////////////////////////////////// Definitions::Definitions() { } void Definitions::collect(const wsdl__definitions &definitions) { // Collect information: analyze WSDL definitions and imported definitions analyze(definitions); for (vector<wsdl__import>::const_iterator import = definitions.import.begin(); import != definitions.import.end(); ++import) if ((*import).definitionsPtr()) analyze(*(*import).definitionsPtr()); } void Definitions::analyze(const wsdl__definitions &definitions) { // Analyze WSDL and build Service information int binding_count = 0; // Determine number of relevant SOAP service bindings (service prefix option only) for (vector<wsdl__binding>::const_iterator i = definitions.binding.begin(); i != definitions.binding.end(); ++i) { for (vector<wsdl__ext_operation>::const_iterator j = (*i).operation.begin(); j != (*i).operation.end(); ++j) { if ((*j).operationPtr()) { binding_count++; break; } } } if (binding_count == 0 && definitions.name && (!definitions.portType.empty() || !definitions.interface_.empty())) fprintf(stderr, "\nWarning: WSDL \"%s\" has no bindings to implement operations\n", definitions.name); else if (binding_count > 1 && !service_prefix) { // This puts all operations under a single binding fprintf(stderr, "\nWarning: %d service bindings found, but collected as one service (use option -Nname to produce a separate service for each binding)\n", binding_count); } // Analyze and collect service data for (vector<wsdl__binding>::const_iterator binding = definitions.binding.begin(); binding != definitions.binding.end(); ++binding) { // /definitions/binding/documentation const char *binding_documentation = (*binding).documentation; // /definitions/binding/soap:binding soap__binding *soap__binding_ = (*binding).soap__binding_; // /definitions/binding/soap:binding/@transport const char *soap__binding_transport = NULL; int version = 0; if (soap__binding_) soap__binding_transport = soap__binding_->transport; else if ((*binding).wsoap__version && strlen((*binding).wsoap__version) > 2) version = (*binding).wsoap__version[2]-'0'; // WSDL 2.0 else if (!(*binding).http__binding_) version = 2; // assume WSDL 2.0 if (version == 2) soap12 = true; // /definitions/binding/@soap:protocol if ((*binding).wsoap__protocol) soap__binding_transport = (*binding).wsoap__protocol; // /definitions/binding/@name const char *binding_name = ""; if ((*binding).name) binding_name = (*binding).name; else if ((*binding).portTypePtr() && (*binding).portTypePtr()->name) { char *s = (char*)soap_malloc(definitions.soap, strlen((*binding).portTypePtr()->name) + 8); strcpy(s, (*binding).portTypePtr()->name); strcat(s, "Binding"); binding_name = s; } // /definitions/binding/@type const char *binding_type = NULL; if ((*binding).type_) binding_type = (*binding).type_; // TODO: need to find the Policy of portType, though never used... // const wsp__Policy *portType_policy = NULL; // /definitions/binding/wsp:Policy and wsp:PolicyReference /* const wsp__Policy *binding_policy = NULL; if ((*binding).wsp__Policy_) binding_policy = (*binding).wsp__Policy_; if ((*binding).wsp__PolicyReference_) binding_policy = (*binding).wsp__PolicyReference_->policyPtr(); */ // /definitions/binding/http:binding http__binding *http__binding_ = (*binding).http__binding_; const char *http__binding_verb = NULL; if (http__binding_) http__binding_verb = http__binding_->verb; // HTTP POST and GET else if ((*binding).whttp__methodDefault) http__binding_verb = (*binding).whttp__methodDefault; // HTTP POST and GET // /definitions/binding/soap:binding/@style soap__styleChoice soap__binding_style = document; if (soap__binding_ && soap__binding_->style) soap__binding_style = *soap__binding_->style; // /definitions/binding/operation* for (vector<wsdl__ext_operation>::const_iterator operation = (*binding).operation.begin(); operation != (*binding).operation.end(); ++operation) { // /definitions/portType/operation/ associated with /definitions/binding/operation wsdl__operation *wsdl__operation_ = (*operation).operationPtr(); // /definitions/binding/operation/soap:operation soap__operation *soap__operation_ = (*operation).soap__operation_; // /definitions/binding/operation/soap:operation/@style soap__styleChoice soap__operation_style = soap__binding_style; if (soap__operation_ && soap__operation_->style) soap__operation_style = *soap__operation_->style; // /definitions/binding/@wsoap:mepDefault const char *soap__operation_mep = (*binding).wsoap__mepDefault; // /definitions/binding/operation/@wsoap:mep if ((*operation).wsoap__mep) soap__operation_mep = (*operation).wsoap__mep; // /definitions/binding/operation/@whttp:method const char *http_method = http__binding_verb; if ((*operation).whttp__method) http_method = (*operation).whttp__method; // /definitions/binding/operation/@wsoap:action const char *soap__operation_action = NULL; if ((*operation).wsoap__action) soap__operation_action = (*operation).wsoap__action; // /definitions/binding/operation/http:operation http__operation *http__operation_ = (*operation).http__operation_; // /definitions/binding/wsp:Policy and wsp:PolicyReference const wsp__Policy *ext_operation_policy = NULL; if ((*operation).wsp__Policy_) ext_operation_policy = (*operation).wsp__Policy_; if ((*operation).wsp__PolicyReference_) ext_operation_policy = (*operation).wsp__PolicyReference_->policyPtr(); // /definitions/binding/operation/http:operation/@location const char *http__operation_location = NULL; if (http__operation_) http__operation_location = http__operation_->location; else if ((*operation).whttp__location) http__operation_location = (*operation).whttp__location; // /definitions/binding/operation/input and output wsdl__ext_ioput *ext_input, *ext_output; // /definitions/portType/operation if (wsdl__operation_ && wsdl__operation_->name) { bool reversed = false; wsdl__ioput *input = NULL; wsdl__ioput *output = NULL; // normalize input/output order for solicit-response operations if (wsdl__operation_->__union1 == SOAP_UNION_wsdl__union_ioput_input) input = wsdl__operation_->__ioput1.input; else if (wsdl__operation_->__union1 == SOAP_UNION_wsdl__union_ioput_output) { reversed = true; input = wsdl__operation_->__ioput1.output; } if (wsdl__operation_->__union2 == SOAP_UNION_wsdl__union_ioput_input) { reversed = true; output = wsdl__operation_->__ioput2.input; } else if (wsdl__operation_->__union2 == SOAP_UNION_wsdl__union_ioput_output) output = wsdl__operation_->__ioput2.output; else // one input only or one output only (or none) { reversed = false; input = NULL; output = NULL; if (wsdl__operation_->__union1 == SOAP_UNION_wsdl__union_ioput_input) input = wsdl__operation_->__ioput1.input; else if (wsdl__operation_->__union1 == SOAP_UNION_wsdl__union_ioput_output) output = wsdl__operation_->__ioput1.output; } if (!reversed) { ext_input = (*operation).input; ext_output = (*operation).output; } else { ext_input = (*operation).output; ext_output = (*operation).input; } if ((http_method && !strcmp(http_method, "GET")) || (wsdl__operation_->pattern && !strstr(wsdl__operation_->pattern, "in"))) input = NULL; if (wsdl__operation_->pattern && !strstr(wsdl__operation_->pattern, "out")) output = NULL; if (wsdl__operation_->pattern) // WSDL 2.0 { soap__operation_style = document; if (wsdl__operation_->style && !strcmp(wsdl__operation_->style, "http://www.w3.org/ns/wsdl/rpc")) soap__operation_style = rpc; else if ((*binding).portTypePtr() && (*binding).portTypePtr()->styleDefault && !strcmp( (*binding).portTypePtr()->styleDefault, "http://www.w3.org/ns/wsdl/rpc")) soap__operation_style = rpc; } // /definitions/binding/wsp:Policy and wsp:PolicyReference const wsp__Policy *operation_policy = NULL; if (wsdl__operation_->wsp__Policy_) operation_policy = wsdl__operation_->wsp__Policy_; if (wsdl__operation_->wsp__PolicyReference_) operation_policy = wsdl__operation_->wsp__PolicyReference_->policyPtr(); if (!Rflag && (http__operation_ || http__operation_location)) { // skip WSDL REST HTTP operations if (!Wflag) fprintf(stderr, "\nWarning: ignoring REST operation '%s' in binding '%s' (use option -R to enable REST)\n", wsdl__operation_->name, binding_name); } else if (input) { soap__body *input_body = NULL; mime__mimeXml *input_mime = NULL; mime__content *input_mime_content = NULL; if (!reversed && ext_input) { input_body = ext_input->soap__body_; input_mime = ext_input->mime__mimeXml_; input_mime_content = ext_input->mime__content_; if (ext_input->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part) if ((*part).soap__body_) { input_body = (*part).soap__body_; break; } } } else if (ext_output) { input_body = ext_output->soap__body_; input_mime = ext_output->mime__mimeXml_; input_mime_content = ext_output->mime__content_; if (ext_output->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) if ((*part).soap__body_) { input_body = (*part).soap__body_; break; } } } if (wsdl__operation_->style && !strcmp(wsdl__operation_->style, "http://www.w3.org/ns/wsdl/style/iri")) { input_mime_content = soap_new_mime__content(definitions.soap); input_mime_content->soap_default(definitions.soap); input_mime_content->type = (char*)"application/x-www-form-urlencoded"; } // MUST have an input binding, otherwise can't generate a service operation if (input_body || input_mime || input_mime_content || input->element) { char *URI; if (input_body && soap__operation_style == rpc) URI = input_body->namespace_; else if (binding_count == 1 || !service_prefix) URI = definitions.targetNamespace; else { // multiple service bidings are used, each needs a unique new URI URI = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen(binding_name) + 2); strcpy(URI, definitions.targetNamespace); if (*URI && URI[strlen(URI)-1] != '/') strcat(URI, "/"); strcat(URI, binding_name); } if (URI) { const char *prefix = types.nsprefix(service_prefix, URI); const char *name = types.aname(NULL, NULL, binding_name); // name of service is binding name Service *service = services[prefix]; if (!service) { service = services[prefix] = new Service(); service->prefix = prefix; service->URI = urienc(definitions.soap, URI); service->name = name; service->transport = soap__binding_transport; if ((*binding).portTypePtr() && (*binding).portTypePtr()->name) service->type = types.aname(NULL, NULL, (*binding).portTypePtr()->name); else service->type = NULL; // collect faults (TODO: this is not used anywhere) for (vector<wsdl__ext_fault>::const_iterator fault = (*binding).fault.begin(); fault != (*binding).fault.end(); ++fault) { Message *f = analyze_fault(definitions, service, *fault); if (f) service->fault[f->name] = f; } // collect policies for the bindings for (vector<wsp__Policy>::const_iterator p = (*binding).wsp__Policy_.begin(); p != (*binding).wsp__Policy_.end(); ++p) service->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = (*binding).wsp__PolicyReference_.begin(); r != (*binding).wsp__PolicyReference_.end(); ++r) service->policy.push_back((*r).policyPtr()); // collect policies for the service endpoints for (vector<wsdl__service>::const_iterator s = definitions.service.begin(); s != definitions.service.end(); ++s) { for (vector<wsp__Policy>::const_iterator p = (*s).wsp__Policy_.begin(); p != (*s).wsp__Policy_.end(); ++p) service->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = (*s).wsp__PolicyReference_.begin(); r != (*s).wsp__PolicyReference_.end(); ++r) service->policy.push_back((*r).policyPtr()); } } for (vector<wsdl__service>::const_iterator s = definitions.service.begin(); s != definitions.service.end(); ++s) { for (vector<wsdl__port>::const_iterator port = (*s).port.begin(); port != (*s).port.end(); ++port) { if ((*port).bindingPtr() == &(*binding)) { if ((*port).soap__address_ && (*port).soap__address_->location) service->location.insert(urienc(definitions.soap, (*port).soap__address_->location)); if ((*port).wsa__EndpointReference && (*port).wsa__EndpointReference->Address) service->location.insert(urienc(definitions.soap, (*port).wsa__EndpointReference->Address)); if ((*port).http__address_ && (*port).http__address_->location) service->location.insert(urienc(definitions.soap, (*port).http__address_->location)); // collect service documentation if ((*s).documentation) service->service_documentation[(*service).name] = (*s).documentation; if ((*port).documentation && (*port).name) service->port_documentation[(*port).name] = (*port).documentation; if (binding_documentation) service->binding_documentation[binding_name] = binding_documentation; // collect policies for the service and endpoints if ((*port).wsp__Policy_) service->policy.push_back((*port).wsp__Policy_); if ((*port).wsp__PolicyReference_ && (*port).wsp__PolicyReference_->policyPtr()) service->policy.push_back((*port).wsp__PolicyReference_->policyPtr()); } } for (vector<wsdl__port>::const_iterator endpoint = (*s).endpoint.begin(); endpoint != (*s).endpoint.end(); ++endpoint) { if ((*endpoint).bindingPtr() == &(*binding)) { if ((*endpoint).address) service->location.insert(urienc(definitions.soap, (*endpoint).address)); if ((*endpoint).wsa__EndpointReference && (*endpoint).wsa__EndpointReference->Address) service->location.insert(urienc(definitions.soap, (*endpoint).wsa__EndpointReference->Address)); if ((*endpoint).http__address_ && (*endpoint).http__address_->location) service->location.insert(urienc(definitions.soap, (*endpoint).http__address_->location)); // TODO: locations need auth // service->auth_scheme = (*endpoint).whttp__authenticationScheme; // service->auth_realm = (*endpoint).whttp__authenticationRealm; // collect service documentation if ((*s).documentation) service->service_documentation[(*service).name] = (*s).documentation; if ((*endpoint).documentation && (*endpoint).name) service->port_documentation[(*endpoint).name] = (*endpoint).documentation; if (binding_documentation) service->binding_documentation[binding_name] = binding_documentation; // collect policies for the service and endpoints if ((*endpoint).wsp__Policy_) service->policy.push_back((*endpoint).wsp__Policy_); if ((*endpoint).wsp__PolicyReference_ && (*endpoint).wsp__PolicyReference_->policyPtr()) service->policy.push_back((*endpoint).wsp__PolicyReference_->policyPtr()); } } } Operation *op = new Operation(); op->name = types.aname(NULL, NULL, wsdl__operation_->name); op->prefix = prefix; op->URI = urienc(definitions.soap, URI); op->style = soap__operation_style; op->mep = soap__operation_mep; if (soap__binding_transport && (!strcmp(soap__binding_transport+strlen(soap__binding_transport)-4, "http") || !strcmp(soap__binding_transport+strlen(soap__binding_transport)-5, "HTTP/"))) { if ((op->mep && strstr(op->mep, "soap-response")) || (http_method && !strcmp(http_method, "GET"))) op->protocol = "SOAP-GET"; else if (version == 1) op->protocol = "SOAP1.1"; else if (version == 2) op->protocol = "SOAP1.2"; else op->protocol = "SOAP"; } else { if (http_method) op->protocol = http_method; else op->protocol = "HTTP"; } op->documentation = wsdl__operation_->documentation; op->operation_documentation = (*operation).documentation; op->parameterOrder = wsdl__operation_->parameterOrder; if (http__operation_location) op->action = http__operation_location; // TODO: for now, store HTTP location in action else { op->action = soap__operation_action; if ((*operation).soap__operation_) { if ((*operation).soap__operation_->soapActionRequired) op->action = (*operation).soap__operation_->soapAction; } else if (version != 2) op->action = ""; } if (operation_policy) op->policy.push_back(operation_policy); if (ext_operation_policy) op->policy.push_back(ext_operation_policy); op->input = new Message(); op->input->name = wsdl__operation_->name; if (input_body && soap__operation_style == rpc && !input_body->namespace_) { op->input->URI = ""; fprintf(stderr, "\nError: no soap:body namespace attribute\n"); } else if (input_body) op->input->URI = urienc(definitions.soap, input_body->namespace_); else op->input->URI = service->URI; op->input->style = soap__operation_style; if (input_body) { op->input->use = input_body->use; op->input->encodingStyle = input_body->encodingStyle; } if (input->wsa__Action) op->input->action = input->wsa__Action; else if (input->wsam__Action) op->input->action = input->wsam__Action; else if (op->action) op->input->action = op->action; else if (definitions.targetNamespace && (*binding).portTypePtr() && (*binding).portTypePtr()->name) { const char *name = input->name ? input->name : op->name; char *tmp = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen((*binding).portTypePtr()->name) + strlen(name) + 3); sprintf(tmp, "%s/%s/%s", definitions.targetNamespace, (*binding).portTypePtr()->name, name); op->input->action = tmp; } op->input->message = input->messagePtr(); op->input->element = input->elementPtr(); op->input->part = NULL; op->input->mustUnderstand = false; op->input->multipartRelated = NULL; op->input->content = input_mime_content; op->input->body_parts = NULL; op->input->layout = NULL; op->input->ext_documentation = NULL; if (ext_input) { op->input->multipartRelated = ext_input->mime__multipartRelated_; if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty()) op->input->header = ext_input->mime__multipartRelated_->part.front().soap__header_; else if (!ext_input->soap__header_.empty()) op->input->header = ext_input->soap__header_; else if (!ext_input->wsoap__header_.empty()) op->input->wheader = ext_input->wsoap__header_; if (ext_input->mime__multipartRelated_ && !ext_input->mime__multipartRelated_->part.empty() && ext_input->mime__multipartRelated_->part.front().soap__body_) op->input->body_parts = ext_input->mime__multipartRelated_->part.front().soap__body_->parts; else if (input_body) op->input->body_parts = input_body->parts; if (ext_input->dime__message_) op->input->layout = ext_input->dime__message_->layout; else op->input->layout = NULL; op->input->ext_documentation = ext_input->documentation; } op->input->documentation = input->documentation; // collect input message policies if (op->input->message) { for (vector<wsp__Policy>::const_iterator p = op->input->message->wsp__Policy_.begin(); p != op->input->message->wsp__Policy_.end(); ++p) op->input->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = op->input->message->wsp__PolicyReference_.begin(); r != op->input->message->wsp__PolicyReference_.end(); ++r) op->input->policy.push_back((*r).policyPtr()); } if (input->wsp__Policy_) op->input->policy.push_back(input->wsp__Policy_); if (input->wsp__PolicyReference_ && input->wsp__PolicyReference_->policyPtr()) op->input->policy.push_back(input->wsp__PolicyReference_->policyPtr()); if (ext_input) { if (ext_input->wsp__Policy_) op->input->policy.push_back(ext_input->wsp__Policy_); if (ext_input->wsp__PolicyReference_ && ext_input->wsp__PolicyReference_->policyPtr()) op->input->policy.push_back(ext_input->wsp__PolicyReference_->policyPtr()); } if (soap__operation_style == document) op->input_name = types.oname("__", op->URI, op->input->name); else op->input_name = types.oname(NULL, op->input->URI, op->input->name); if (output) { soap__body *output_body = NULL; mime__mimeXml *output_mime = NULL; mime__content *output_mime_content = NULL; if (ext_output) { output_body = ext_output->soap__body_; output_mime = ext_output->mime__mimeXml_; output_mime_content = ext_output->mime__content_; if (ext_output->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) if ((*part).soap__body_) { output_body = (*part).soap__body_; break; } } } if (ext_output && ext_output->mime__content_) { op->output = new Message(); op->output->name = NULL; op->output->URI = NULL; op->output->style = soap__operation_style; op->output->use = literal; op->output->encodingStyle = NULL; op->output->action = NULL; op->output->body_parts = NULL; op->output->part = NULL; op->output->mustUnderstand = false; op->output->multipartRelated = NULL; op->output->content = output_mime_content; op->output->message = output->messagePtr(); op->output->element = output->elementPtr(); op->output->layout = NULL; } else if (output_body || output_mime || output_mime_content || output->element) { op->output = new Message(); op->output->name = wsdl__operation_->name; // RPC uses operation/@name with suffix 'Response' as set below op->output->style = soap__operation_style; if (output_body) { op->output->use = output_body->use; // the code below is a hack around the RPC encoded response message element tag mismatch with Axis: if (!output_body->namespace_ || output_body->use == encoded) op->output->URI = op->input->URI; // encoded seems (?) to require the request's namespace else op->output->URI = urienc(definitions.soap, output_body->namespace_); op->output->encodingStyle = output_body->encodingStyle; } else op->output->URI = service->URI; if (output->wsa__Action) op->output->action = output->wsa__Action; else if (output->wsam__Action) op->output->action = output->wsam__Action; else if (http__operation_location) op->output->action = NULL; else if (op->action) { const char *name = op->action; char *tmp = (char*)soap_malloc(definitions.soap, strlen(name) + 9); strcpy(tmp, name); strcat(tmp, "Response"); op->output->action = tmp; } else if (definitions.targetNamespace && (*binding).portTypePtr() && (*binding).portTypePtr()->name) { const char *name = output->name ? output->name : op->name; char *tmp = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen((*binding).portTypePtr()->name) + strlen(name) + 11); sprintf(tmp, "%s/%s/%s%s", definitions.targetNamespace, (*binding).portTypePtr()->name, name, output->name ? "" : "Response"); op->output->action = tmp; } op->output->message = output->messagePtr(); op->output->element = output->elementPtr(); op->output->part = NULL; op->output->content = output_mime_content; op->output->body_parts = NULL; op->output->layout = NULL; op->output->ext_documentation = NULL; op->output->mustUnderstand = false; } if (ext_output) { op->output->multipartRelated = ext_output->mime__multipartRelated_; if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty()) op->output->header = ext_output->mime__multipartRelated_->part.front().soap__header_; else if (!ext_output->soap__header_.empty()) op->output->header = ext_output->soap__header_; else if (!ext_output->wsoap__header_.empty()) op->output->wheader = ext_output->wsoap__header_; if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty() && ext_output->mime__multipartRelated_->part.front().soap__body_) op->output->body_parts = ext_output->mime__multipartRelated_->part.front().soap__body_->parts; else if (output_body) op->output->body_parts = output_body->parts; if (ext_output->dime__message_) op->output->layout = ext_output->dime__message_->layout; else op->output->layout = NULL; op->output->ext_documentation = ext_output->documentation; } if (op->output->name) { char *s = (char*)soap_malloc(definitions.soap, strlen(op->output->name) + 9); strcpy(s, op->output->name); strcat(s, "Response"); if (soap__operation_style == document) op->output_name = types.oname("__", op->URI, s); else op->output_name = types.oname(NULL, op->output->URI, s); } op->output->documentation = output->documentation; // collect output message policies if (op->output->message) { for (vector<wsp__Policy>::const_iterator p = op->output->message->wsp__Policy_.begin(); p != op->output->message->wsp__Policy_.end(); ++p) op->output->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = op->output->message->wsp__PolicyReference_.begin(); r != op->output->message->wsp__PolicyReference_.end(); ++r) op->output->policy.push_back((*r).policyPtr()); } if (output->wsp__Policy_) op->output->policy.push_back(output->wsp__Policy_); if (output->wsp__PolicyReference_ && output->wsp__PolicyReference_->policyPtr()) op->output->policy.push_back(output->wsp__PolicyReference_->policyPtr()); if (ext_output) { if (ext_output->wsp__Policy_) op->output->policy.push_back(ext_output->wsp__Policy_); if (ext_output->wsp__PolicyReference_ && ext_output->wsp__PolicyReference_->policyPtr()) op->output->policy.push_back(ext_output->wsp__PolicyReference_->policyPtr()); } } else { op->output_name = NULL; op->output = NULL; } analyze_headers(definitions, service, ext_input, ext_output); analyze_faults(definitions, service, op, operation); service->operation.push_back(op); } else { if (!Wflag) fprintf(stderr, "\nWarning: no SOAP RPC operation namespace, operations will be ignored\n"); } } else fprintf(stderr, "\nError: no wsdl:definitions/binding/operation/input\n"); } else if (output) { // This part is similar to the previous clause, limited to one-way output operations soap__body *output_body = NULL; mime__mimeXml *output_mime = NULL; mime__content *output_mime_content = NULL; if (!reversed && ext_output) { output_body = ext_output->soap__body_; output_mime = ext_output->mime__mimeXml_; output_mime_content = ext_output->mime__content_; if (ext_output->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) if ((*part).soap__body_) { output_body = (*part).soap__body_; break; } } } else if (ext_input) { output_body = ext_input->soap__body_; output_mime = ext_input->mime__mimeXml_; output_mime_content = ext_input->mime__content_; if (ext_input->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part) if ((*part).soap__body_) { output_body = (*part).soap__body_; break; } } } if (wsdl__operation_->style && !strcmp(wsdl__operation_->style, "http://www.w3.org/ns/wsdl/style/iri")) { output_mime_content = soap_new_mime__content(definitions.soap); output_mime_content->soap_default(definitions.soap); output_mime_content->type = (char*)"application/x-www-form-urlencoded"; } if (output_body || output_mime || output_mime_content || output->element) { char *URI; if (output_body && soap__operation_style == rpc) URI = output_body->namespace_; else if (binding_count == 1 || !service_prefix) URI = definitions.targetNamespace; else { // multiple service bidings are used, each needs a unique new URI URI = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen(binding_name) + 2); strcpy(URI, definitions.targetNamespace); if (*URI && URI[strlen(URI)-1] != '/') strcat(URI, "/"); strcat(URI, binding_name); } if (URI) { const char *prefix = types.nsprefix(service_prefix, URI); const char *name = types.aname(NULL, NULL, binding_name); // name of service is binding name Service *service = services[prefix]; if (!service) { service = services[prefix] = new Service(); service->prefix = prefix; service->URI = urienc(definitions.soap, URI); service->name = name; service->transport = soap__binding_transport; if ((*binding).portTypePtr() && (*binding).portTypePtr()->name) service->type = types.aname(NULL, NULL, (*binding).portTypePtr()->name); else service->type = NULL; // collect faults (TODO: this is not used anywhere) for (vector<wsdl__ext_fault>::const_iterator fault = (*binding).fault.begin(); fault != (*binding).fault.end(); ++fault) { Message *f = analyze_fault(definitions, service, *fault); if (f) service->fault[f->name] = f; } // collect policies for the bindings for (vector<wsp__Policy>::const_iterator p = (*binding).wsp__Policy_.begin(); p != (*binding).wsp__Policy_.end(); ++p) service->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = (*binding).wsp__PolicyReference_.begin(); r != (*binding).wsp__PolicyReference_.end(); ++r) service->policy.push_back((*r).policyPtr()); // collect policies for the service endpoints for (vector<wsdl__service>::const_iterator s = definitions.service.begin(); s != definitions.service.end(); ++s) { for (vector<wsp__Policy>::const_iterator p = (*s).wsp__Policy_.begin(); p != (*s).wsp__Policy_.end(); ++p) service->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = (*s).wsp__PolicyReference_.begin(); r != (*s).wsp__PolicyReference_.end(); ++r) service->policy.push_back((*r).policyPtr()); } } for (vector<wsdl__service>::const_iterator s = definitions.service.begin(); s != definitions.service.end(); ++s) { for (vector<wsdl__port>::const_iterator port = (*s).port.begin(); port != (*s).port.end(); ++port) { if ((*port).bindingPtr() == &(*binding)) { if ((*port).soap__address_ && (*port).soap__address_->location) service->location.insert(urienc(definitions.soap, (*port).soap__address_->location)); else if ((*port).wsa__EndpointReference && (*port).wsa__EndpointReference->Address) service->location.insert(urienc(definitions.soap, (*port).wsa__EndpointReference->Address)); // TODO: HTTP address for HTTP operations // if ((*port).http__address_) // http__address_location = http__address_->location; // collect service documentation if ((*s).documentation) service->service_documentation[(*service).name] = (*s).documentation; if ((*port).documentation && (*port).name) service->port_documentation[(*port).name] = (*port).documentation; if (binding_documentation) service->binding_documentation[binding_name] = binding_documentation; // collect policies for the service and endpoints if ((*port).wsp__Policy_) service->policy.push_back((*port).wsp__Policy_); if ((*port).wsp__PolicyReference_ && (*port).wsp__PolicyReference_->policyPtr()) service->policy.push_back((*port).wsp__PolicyReference_->policyPtr()); } } } Operation *op = new Operation(); op->input_name = NULL; op->input = NULL; op->name = types.aname(NULL, NULL, wsdl__operation_->name); op->prefix = prefix; op->URI = urienc(definitions.soap, URI); op->style = soap__operation_style; op->mep = soap__operation_mep; if (soap__binding_transport && (!strcmp(soap__binding_transport+strlen(soap__binding_transport)-4, "http") || !strcmp(soap__binding_transport+strlen(soap__binding_transport)-5, "HTTP/"))) { if (op->mep && strstr(op->mep, "soap-response") || (http_method && !strcmp(http_method, "GET"))) op->protocol = "SOAP-GET"; else if (version == 1) op->protocol = "SOAP1.1"; else if (version == 2) op->protocol = "SOAP1.2"; else op->protocol = "SOAP"; } else { if (http_method) op->protocol = http_method; else op->protocol = "HTTP"; } op->documentation = wsdl__operation_->documentation; op->operation_documentation = (*operation).documentation; op->parameterOrder = wsdl__operation_->parameterOrder; if (http__operation_location) op->action = http__operation_location; // TODO: for now, store HTTP location in action else { op->action = soap__operation_action; if ((*operation).soap__operation_) { if ((*operation).soap__operation_->soapActionRequired) op->action = (*operation).soap__operation_->soapAction; } else if (version != 2) op->action = ""; } if (operation_policy) op->policy.push_back(operation_policy); if (ext_operation_policy) op->policy.push_back(ext_operation_policy); op->output = new Message(); // one-way output operation op->output->name = wsdl__operation_->name; // RPC uses operation/@name if (output_body && soap__operation_style == rpc && !output_body->namespace_) { op->output->URI = ""; fprintf(stderr, "\nError: no soap:body namespace attribute\n"); } else if (output_body) op->output->URI = urienc(definitions.soap, output_body->namespace_); else op->output->URI = service->URI; op->output->style = soap__operation_style; if (output_body) { op->output->use = output_body->use; op->output->encodingStyle = output_body->encodingStyle; } if (output->wsa__Action) op->output->action = output->wsa__Action; else if (output->wsam__Action) op->output->action = output->wsam__Action; else if (op->action) op->output->action = op->action; else if (definitions.targetNamespace && (*binding).portTypePtr() && (*binding).portTypePtr()->name) { const char *name = output->name ? output->name : op->name; char *tmp = (char*)soap_malloc(definitions.soap, strlen(definitions.targetNamespace) + strlen((*binding).portTypePtr()->name) + strlen(name) + 3); sprintf(tmp, "%s/%s/%s", definitions.targetNamespace, (*binding).portTypePtr()->name, name); op->output->action = tmp; } op->output->message = output->messagePtr(); op->output->element = output->elementPtr(); op->output->part = NULL; op->output->mustUnderstand = false; op->output->multipartRelated = NULL; op->output->content = output_mime_content; op->output->body_parts = NULL; op->output->layout = NULL; op->output->ext_documentation = NULL; if (ext_output) { op->output->multipartRelated = ext_output->mime__multipartRelated_; if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty()) op->output->header = ext_output->mime__multipartRelated_->part.front().soap__header_; else if (!ext_output->soap__header_.empty()) op->output->header = ext_output->soap__header_; else if (!ext_output->wsoap__header_.empty()) op->output->wheader = ext_output->wsoap__header_; if (ext_output->mime__multipartRelated_ && !ext_output->mime__multipartRelated_->part.empty() && ext_output->mime__multipartRelated_->part.front().soap__body_) op->output->body_parts = ext_output->mime__multipartRelated_->part.front().soap__body_->parts; else if (output_body) op->output->body_parts = output_body->parts; if (ext_output->dime__message_) op->output->layout = ext_output->dime__message_->layout; else op->output->layout = NULL; op->output->ext_documentation = ext_output->documentation; } op->output->documentation = output->documentation; // collect output message policies if (op->output->message) { for (vector<wsp__Policy>::const_iterator p = op->output->message->wsp__Policy_.begin(); p != op->output->message->wsp__Policy_.end(); ++p) op->output->policy.push_back(&(*p)); for (vector<wsp__PolicyReference>::const_iterator r = op->output->message->wsp__PolicyReference_.begin(); r != op->output->message->wsp__PolicyReference_.end(); ++r) op->output->policy.push_back((*r).policyPtr()); } if (output->wsp__Policy_) op->output->policy.push_back(output->wsp__Policy_); if (output->wsp__PolicyReference_ && output->wsp__PolicyReference_->policyPtr()) op->output->policy.push_back(output->wsp__PolicyReference_->policyPtr()); if (ext_output) { if (ext_output->wsp__Policy_) op->output->policy.push_back(ext_output->wsp__Policy_); if (ext_output->wsp__PolicyReference_ && ext_output->wsp__PolicyReference_->policyPtr()) op->output->policy.push_back(ext_output->wsp__PolicyReference_->policyPtr()); } if (soap__operation_style == document) op->input_name = types.oname("__", op->URI, op->output->name); else op->input_name = types.oname(NULL, op->output->URI, op->output->name); char *s = (char*)soap_malloc(definitions.soap, strlen(op->output->name) + 9); strcpy(s, op->output->name); strcat(s, "Response"); if (soap__operation_style == document) op->output_name = types.oname("__", op->URI, s); else op->output_name = types.oname(NULL, op->output->URI, s); analyze_headers(definitions, service, ext_input, ext_output); analyze_faults(definitions, service, op, operation); service->operation.push_back(op); } else { if (!Wflag) fprintf(stderr, "\nWarning: no SOAP RPC operation namespace, operations will be ignored\n"); } } else fprintf(stderr, "\nError: no wsdl:definitions/binding/operation/output\n"); } else fprintf(stderr, "\nError: no wsdl:definitions/portType/operation/input and output\n"); } else fprintf(stderr, "\nError: no wsdl:definitions/portType/operation\n"); } } } void Definitions::analyze_headers(const wsdl__definitions &definitions, Service *service, wsdl__ext_ioput *ext_input, wsdl__ext_ioput *ext_output) { // collect input headers and headerfaults if (ext_input) { const vector<soap__header> *soap__header_ = NULL; // check if soap header is in mime:multipartRelated if (ext_input->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_input->mime__multipartRelated_->part.begin(); part != ext_input->mime__multipartRelated_->part.end(); ++part) if (!(*part).soap__header_.empty()) { soap__header_ = &(*part).soap__header_; break; } } if (!soap__header_) soap__header_ = &ext_input->soap__header_; for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header) { Message *h = new Message(); h->message = (*header).messagePtr(); h->element = NULL; h->body_parts = NULL; h->part = (*header).partPtr(); h->URI = urienc(definitions.soap, (*header).namespace_); if (h->part && h->part->element) h->name = types.aname(NULL, NULL, h->part->element); else if (h->URI && h->part && h->part->name && h->part->type) h->name = types.aname(NULL, h->URI, h->part->name); else { fprintf(stderr, "\nError in SOAP Header part definition: input part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?"); h->name = ""; } h->encodingStyle = (*header).encodingStyle; h->style = document; // irrelevant h->use = (*header).use; h->mustUnderstand = true; h->multipartRelated = NULL; h->content = NULL; h->layout = NULL; h->ext_documentation = NULL; // TODO: add document content h->documentation = NULL; // TODO: add document content service->header[h->name] = h; for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault) { // TODO: headerfault processing. This is practically never used... } } for (vector<wsoap__header>::const_iterator wheader = ext_input->wsoap__header_.begin(); wheader != ext_input->wsoap__header_.end(); ++wheader) { Message *h = new Message(); h->message = NULL; h->element = (*wheader).elementPtr(); h->body_parts = NULL; h->part = NULL; h->URI = NULL; h->mustUnderstand = (*wheader).mustUnderstand_; h->name = types.aname(NULL, NULL, (*wheader).element); h->encodingStyle = NULL; h->style = document; // irrelevant h->use = literal; h->multipartRelated = NULL; h->content = NULL; h->layout = NULL; h->ext_documentation = NULL; // TODO: add document content h->documentation = NULL; // TODO: add document content service->header[h->name] = h; } } // collect output headers and headerfaults if (ext_output) { const vector<soap__header> *soap__header_ = NULL; // check if soap header is in mime:multipartRelated if (ext_output->mime__multipartRelated_) { for (vector<mime__part>::const_iterator part = ext_output->mime__multipartRelated_->part.begin(); part != ext_output->mime__multipartRelated_->part.end(); ++part) if (!(*part).soap__header_.empty()) { soap__header_ = &(*part).soap__header_; break; } } if (!soap__header_) soap__header_ = &ext_output->soap__header_; for (vector<soap__header>::const_iterator header = soap__header_->begin(); header != soap__header_->end(); ++header) { Message *h = new Message(); h->message = (*header).messagePtr(); h->element = NULL; h->body_parts = NULL; h->part = (*header).partPtr(); h->URI = urienc(definitions.soap, (*header).namespace_); if (h->part && h->part->element) h->name = types.aname(NULL, NULL, h->part->element); else if (h->URI && h->part && h->part->name && h->part->type) h->name = types.aname(NULL, h->URI, h->part->name); else { fprintf(stderr, "\nError in SOAP Header part definition: output part '%s' missing?\n", h->part && h->part->name ? h->part->name : "?"); h->name = ""; } h->encodingStyle = (*header).encodingStyle; h->style = document; // irrelevant h->use = (*header).use; h->mustUnderstand = false; h->multipartRelated = NULL; h->content = NULL; h->layout = NULL; h->ext_documentation = NULL; // TODO: add document content? h->documentation = NULL; // TODO: add document content? service->header[h->name] = h; for (vector<soap__headerfault>::const_iterator headerfault = (*header).headerfault.begin(); headerfault != (*header).headerfault.end(); ++headerfault) { // TODO: headerfault processing. This is practically never used... } } for (vector<wsoap__header>::const_iterator wheader = ext_output->wsoap__header_.begin(); wheader != ext_output->wsoap__header_.end(); ++wheader) { Message *h = new Message(); h->message = NULL; h->element = (*wheader).elementPtr(); h->body_parts = NULL; h->part = NULL; h->URI = NULL; h->mustUnderstand = (*wheader).mustUnderstand_; h->name = types.aname(NULL, NULL, (*wheader).element); h->encodingStyle = NULL; h->style = document; // irrelevant h->use = literal; h->multipartRelated = NULL; h->content = NULL; h->layout = NULL; h->ext_documentation = NULL; // TODO: add document content h->documentation = NULL; // TODO: add document content service->header[h->name] = h; } } } void Definitions::analyze_faults(const wsdl__definitions &definitions, Service *service, Operation *op, vector<wsdl__ext_operation>::const_iterator& operation) { for (vector<wsdl__ext_fault>::const_iterator fault = (*operation).fault.begin(); fault != (*operation).fault.end(); ++fault) { Message *f = analyze_fault(definitions, service, *fault); if (f) { op->outfault.push_back(f); service->fault[f->name] = f; } } for (vector<wsdl__ext_fault>::const_iterator infault = (*operation).infault.begin(); infault != (*operation).infault.end(); ++infault) { Message *f = analyze_fault(definitions, service, *infault); if (f) { op->infault.push_back(f); service->fault[f->name] = f; } } for (vector<wsdl__ext_fault>::const_iterator outfault = (*operation).outfault.begin(); outfault != (*operation).outfault.end(); ++outfault) { Message *f = analyze_fault(definitions, service, *outfault); if (f) { op->outfault.push_back(f); service->fault[f->name] = f; } } } Message *Definitions::analyze_fault(const wsdl__definitions &definitions, Service *service, const wsdl__ext_fault &ext_fault) { Message *f = NULL; const wsdl__fault *fault = ext_fault.faultPtr(); if (fault && (fault->messagePtr() || fault->elementPtr())) { f = new Message(); f->message = fault->messagePtr(); f->element = fault->elementPtr(); f->body_parts = NULL; f->part = NULL; f->encodingStyle = NULL; if (ext_fault.soap__fault_) f->encodingStyle = ext_fault.soap__fault_->encodingStyle; f->action = NULL; if (fault->wsa__Action) f->action = fault->wsa__Action; else f->action = fault->wsam__Action; if (ext_fault.soap__fault_) f->URI = ext_fault.soap__fault_->namespace_; else if (f->element && f->element->schemaPtr()) f->URI = f->element->schemaPtr()->targetNamespace; else f->URI = service->URI; // must have a unique URI f->style = document; // irrelevant f->use = literal; if (ext_fault.soap__fault_) f->use = ext_fault.soap__fault_->use; if (ext_fault.wsoap__code) { char *s = (char*)soap_malloc(definitions.soap, 80 + strlen(ext_fault.wsoap__code) + (ext_fault.wsoap__subcodes ? strlen(ext_fault.wsoap__subcodes) : 0)); sprintf(s, "\"%s\" with subcodes \"%s\"", ext_fault.wsoap__code, ext_fault.wsoap__subcodes ? ext_fault.wsoap__subcodes : ""); f->body_parts = s; } else f->ext_documentation = ext_fault.documentation; f->mustUnderstand = false; f->multipartRelated = NULL; f->content = NULL; f->layout = NULL; if (f->message) { f->name = types.aname("_", f->URI, f->message->name); f->documentation = f->message->documentation; } else { f->name = types.aname(NULL, f->URI, fault->element); f->documentation = fault->documentation; } // collect fault message policies if (fault->wsp__Policy_) f->policy.push_back(fault->wsp__Policy_); if (fault->wsp__PolicyReference_ && fault->wsp__PolicyReference_->policyPtr()) f->policy.push_back(fault->wsp__PolicyReference_->policyPtr()); if (ext_fault.wsp__Policy_) f->policy.push_back(ext_fault.wsp__Policy_); if (ext_fault.wsp__PolicyReference_ && ext_fault.wsp__PolicyReference_->policyPtr()) f->policy.push_back(ext_fault.wsp__PolicyReference_->policyPtr()); } else if (ext_fault.soap__fault_ && ext_fault.soap__fault_->name) fprintf(stderr, "\nError: no wsdl:definitions/binding/operation/fault/soap:fault '%s'\n", ext_fault.soap__fault_->name); else fprintf(stderr, "\nError: no wsdl:definitions/binding/operation/fault/soap:fault\n"); return f; } void Definitions::compile(const wsdl__definitions& definitions) { // compile the definitions and generate gSOAP header file const char *defs; if (definitions.name) defs = types.aname(NULL, NULL, definitions.name); else defs = "Service"; ident(); fprintf(stream, "/** @page page_notes Usage Notes\n\nNOTE:\n\n - Run soapcpp2 on %s to generate the SOAP/XML processing logic.\n Use soapcpp2 -I to specify paths for #import\n To build with STL, 'stlvector.h' is imported from 'import' dir in package.\n Use soapcpp2 -j to generate improved proxy and server classes.\n - Use wsdl2h -c and -s to generate pure C code or C++ code without STL.\n - Use 'typemap.dat' to control namespace bindings and type mappings.\n It is strongly recommended to customize the names of the namespace prefixes\n generated by wsdl2h. To do so, modify the prefix bindings in the Namespaces\n section below and add the modified lines to 'typemap.dat' to rerun wsdl2h.\n - Use Doxygen (www.doxygen.org) on this file to generate documentation.\n - Use wsdl2h -R to generate REST operations.\n - Use wsdl2h -nname to use name as the base namespace prefix instead of 'ns'.\n - Use wsdl2h -Nname for service prefix and produce multiple service bindings\n - Use wsdl2h -d to enable DOM support for xsd:anyType.\n - Use wsdl2h -g to auto-generate readers and writers for root elements.\n - Use wsdl2h -b to auto-generate bi-directional operations (duplex ops).\n - Struct/class members serialized as XML attributes are annotated with a '@'.\n - Struct/class members that have a special role are annotated with a '$'.\n\nWARNING:\n\n DO NOT INCLUDE THIS ANNOTATED FILE DIRECTLY IN YOUR PROJECT SOURCE CODE.\n USE THE FILES GENERATED BY soapcpp2 FOR YOUR PROJECT'S SOURCE CODE:\n THE soapStub.h FILE CONTAINS THIS CONTENT WITHOUT ANNOTATIONS.\n\n", outfile?outfile:"this file"); fprintf(stream, "LICENSE:\n\n@verbatim\n%s@endverbatim\n\n*/\n\n", licensenotice); // gsoap compiler options: 'w' disables WSDL/schema output to avoid file collisions if (cflag) fprintf(stream, "\n//gsoapopt cw\n"); else fprintf(stream, "\n//gsoapopt w\n"); banner("Definitions", definitions.targetNamespace?definitions.targetNamespace:"targetNamespace"); // copy documentation from WSDL definitions if (definitions.documentation) { fprintf(stream, "/* WSDL Documentation:\n\n"); text(definitions.documentation); fprintf(stream, "*/\n\n"); } if (definitions.version) { banner("Version", definitions.version); fprintf(stream, "#define SOAP_WSDL_VERSION \"%s\"\n", definitions.version); } banner("Import"); if (dflag) { fprintf(stream, "\n// dom.h declares the DOM xsd__anyType object (compiler and link with dom.cpp)\n"); fprintf(stream, "#import \"dom.h\"\n"); } if (!cflag && !sflag) { fprintf(stream, "\n// STL vector containers (use option -s to remove STL dependency)\n"); fprintf(stream, "#import \"stlvector.h\"\n"); } if (mflag) { fprintf(stream, "#import \""); fprintf(stream, "xsd.h\"\t// import primitive XSD types.\n"); } for (SetOfString::const_iterator u = exturis.begin(); u != exturis.end(); ++u) { bool found = false; size_t n = strlen(*u); for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) { if (**i == '"' && !strncmp(*u, *i + 1, n) && (*i)[n+1] == '"') { found = true; break; } } if (!found) { for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j) { if (**j == '"' && !strncmp(*u, *j + 1, n) && (*j)[n+1] == '"') { found = true; break; } } } if (!found) { for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k) { if (**k == '"' && !strncmp(*u, *k + 1, n) && (*k)[n+1] == '"') { found = true; break; } } } if (found) { if (vflag) fprintf(stderr, "import %s\n", *u); fprintf(stream, "#import \"%s.h\"\t// %s = <%s>\n", types.nsprefix(NULL, *u), types.nsprefix(NULL, *u), *u); } } banner("Schema Namespaces"); // Determine if bindings use SOAP 1.2 soap12 = false; for (Namespace *p = definitions.soap->local_namespaces; p && p->id; p++) { if (p->out && !strcmp(p->id, "soap") && !strcmp(p->out, "http://schemas.xmlsoap.org/wsdl/soap12/")) { soap12 = true; break; } } if (definitions.types) { fprintf(stream, "\n/* NOTE:\n\nIt is strongly recommended to customize the names of the namespace prefixes\ngenerated by wsdl2h. To do so, modify the prefix bindings below and add the\nmodified lines to typemap.dat to rerun wsdl2h:\n\n"); if (definitions.targetNamespace && *definitions.targetNamespace) fprintf(stream, "%s = \"%s\"\n", types.nsprefix(service_prefix, definitions.targetNamespace), definitions.targetNamespace); for (vector<xs__schema*>::const_iterator schema1 = definitions.types->xs__schema_.begin(); schema1 != definitions.types->xs__schema_.end(); ++schema1) if (!definitions.targetNamespace || strcmp((*schema1)->targetNamespace, definitions.targetNamespace)) fprintf(stream, "%s = \"%s\"\n", types.nsprefix(NULL, (*schema1)->targetNamespace), (*schema1)->targetNamespace); fprintf(stream, "\n*/\n"); for (vector<xs__schema*>::const_iterator schema2 = definitions.types->xs__schema_.begin(); schema2 != definitions.types->xs__schema_.end(); ++schema2) { const char *t = types.nsprefix(NULL, (*schema2)->targetNamespace); fprintf(stream, "\n"); types.document((*schema2)->annotation); fprintf(stream, "#define SOAP_NAMESPACE_OF_%s\t\"%s\"\n", types.aname(NULL, NULL, t), urienc(definitions.soap, (*schema2)->targetNamespace)); fprintf(stream, schemaformat, t, "namespace", urienc(definitions.soap, (*schema2)->targetNamespace)); if ((*schema2)->elementFormDefault == (*schema2)->attributeFormDefault) fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "form", (*schema2)->elementFormDefault == qualified ? "qualified" : "unqualified"); else { fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "elementForm", (*schema2)->elementFormDefault == qualified ? "qualified" : "unqualified"); fprintf(stream, schemaformat, types.nsprefix(NULL, (*schema2)->targetNamespace), "attributeForm", (*schema2)->attributeFormDefault == qualified ? "qualified" : "unqualified"); } } } // generate the prototypes first: these should allow use before def, e.g. class names then generate the defs // check if xsd:anyType is used if (!cflag && !pflag) { for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) { if (!cflag && !strcmp(*i, "xs:anyType")) { pflag = 1; break; } } } if (dflag && pflag && !Pflag) { if (!Wflag) fprintf(stderr, "\nWarning -d option: -p option disabled and xsd__anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\n"); fprintf(stream, "\n/*\nWarning -d option used: -p option disabled and xsd:anyType base class removed.\nUse run-time SOAP_DOM_NODE flag to deserialize class instances into DOM nodes.\nA DOM node is represented by the xsd__anyType object implemented in dom.cpp.\n*/\n\n"); pflag = 0; } // define xsd:anyType first, if used if (!cflag && pflag) { const char *s, *t; t = types.cname(NULL, NULL, "xs:anyType"); s = types.deftypemap[t]; if (s) { if (*s) { if (!mflag) fprintf(stream, "%s\n", s); } s = types.usetypemap[t]; if (s) { if (mflag) fprintf(stream, "// xsd.h: should define type %s\n", s); types.knames.insert(s); } } else { fprintf(stderr, "\nError: no xsd__anyType defined in type map\n"); pflag = 0; } } if (Pflag) pflag = 0; // produce built-in primitive types, limited to the ones that are used only banner("Built-in Schema Types and Top-Level Elements and Attributes"); if (vflag) fprintf(stderr, "\nGenerating built-in types\n"); for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) { const char *s, *t; if (!cflag && !strcmp(*i, "xs:anyType")) continue; t = types.cname(NULL, NULL, *i); s = types.deftypemap[t]; if (s) { if (*s) { if (**i == '"') fprintf(stream, "\n/// Imported type %s from typemap %s.\n", *i, mapfile?mapfile:""); else fprintf(stream, "\n/// Built-in type \"%s\".\n", *i); if (mflag) fprintf(stream, "// (declaration of %s removed by option -m)\n", t); else if (!iflag && !imported(*i)) types.format(s); } s = types.usetypemap[t]; if (s && *s) { if (mflag && **i != '"') fprintf(stream, "\n// xsd.h: typemap override of type %s with %s\n", t, s); if (types.knames.find(s) == types.knames.end()) types.knames.insert(s); } } } for (SetOfString::const_iterator i = definitions.builtinTypes().begin(); i != definitions.builtinTypes().end(); ++i) { const char *s, *t; if (!cflag && !strcmp(*i, "xs:anyType")) continue; t = types.cname(NULL, NULL, *i); s = types.deftypemap[t]; if (!s) { if (!mflag) { if (**i == '"') fprintf(stream, "\n// Imported type %s defined by %s\n", *i, t); else if (!iflag) { s = types.tname(NULL, NULL, "xsd:string"); fprintf(stream, "\n/// Primitive built-in type \"%s\"\n", *i); fprintf(stream, "typedef %s %s;\n", s, t); types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, NULL, NULL, *i); const char *u = types.uri(*i); if (u && !types.uris[u]) fprintf(stream, schemaformat, types.nsprefix(types.prefix(*i), u), "namespace", u); } } else if (**i == '"') fprintf(stream, "\n// Imported type %s defined by %s\n", *i, t); else fprintf(stream, "\n// xsd.h: should define type %s\n", t); types.deftname(TYPEDEF, NULL, false, NULL, NULL, *i); } if (pflag && !strncmp(*i, "xs:", 3)) // only xsi types are polymorph { s = types.aname(NULL, NULL, *i); if (!mflag) { fprintf(stream, "\n/// Class wrapper for built-in type \"%s\" derived from xsd__anyType\n/// Use virtual method soap_type() == SOAP_TYPE_%s to check runtime type (see soapStub.h)\n", *i, s); fprintf(stream, "class %s : public xsd__anyType\n{ public:\n", s); fprintf(stream, elementformat, types.tname(NULL, NULL, *i), "__item;"); fprintf(stream, "\n};\n"); } types.knames.insert(s); } } // produce built-in primitive elements, limited to the ones that are used only if (vflag) fprintf(stderr, "\nGenerating built-in elements\n"); for (SetOfString::const_iterator j = definitions.builtinElements().begin(); j != definitions.builtinElements().end(); ++j) { const char *s, *t; t = types.cname("_", NULL, *j); s = types.deftypemap[t]; if (s) { if (*s) { if (**j == '"') fprintf(stream, "\n/// Imported element %s from typemap %s.\n", *j, mapfile?mapfile:""); else fprintf(stream, "\n/// Built-in element \"%s\".\n", *j); if (mflag) fprintf(stream, "// (declaration of %s removed by option -m)\n", t); else if (!iflag && !imported(*j)) types.format(s); } s = types.usetypemap[t]; if (s && *s) { if (mflag && **j != '"') fprintf(stream, "\n// xsd.h: typemap override of element %s with %s\n", t, s); if (types.knames.find(s) == types.knames.end()) types.knames.insert(s); } } else { if (!mflag) { if (**j == '"') fprintf(stream, "\n// Imported element %s declared as %s\n", *j, t); else if (!iflag && !imported(*j)) { s = types.tname(NULL, NULL, "xsd:any"); fprintf(stream, "\n/// Built-in element \"%s\".\n", *j); fprintf(stream, "typedef %s %s;\n", s, t); types.deftname(TYPEDEF, NULL, true, "_", NULL, *j); // already pointer const char *u = types.uri(*j); if (u && !types.uris[u]) fprintf(stream, schemaformat, types.nsprefix(types.prefix(*j), u), "namespace", u); } } else if (**j == '"') fprintf(stream, "\n// Imported element %s declared as %s\n", *j, t); else fprintf(stream, "\n// xsd.h: should define element %s\n", t); types.deftname(TYPEDEF, NULL, false, "_", NULL, *j); } } // produce built-in primitive attributes, limited to the ones that are used only if (vflag) fprintf(stderr, "\nGenerating built-in attributes\n"); for (SetOfString::const_iterator k = definitions.builtinAttributes().begin(); k != definitions.builtinAttributes().end(); ++k) { const char *s, *t; t = types.cname("_", NULL, *k); s = types.deftypemap[t]; if (s) { if (*s) { if (**k == '"') fprintf(stream, "\n/// Imported attribute %s from typemap %s.\n", *k, mapfile?mapfile:""); else fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k); if (mflag) fprintf(stream, "// (declaration of %s removed by option -m)\n", t); else if (!iflag && !imported(*k)) types.format(s); } s = types.usetypemap[t]; if (s && *s) { if (mflag && **k != '"') fprintf(stream, "\n// xsd.h: typemap override of attribute %s with %s\n", t, s); if (types.knames.find(s) == types.knames.end()) types.knames.insert(s); } } else { s = types.tname(NULL, NULL, "xsd:string"); if (!mflag) { if (**k == '"') fprintf(stream, "\n// Imported attribute %s declared as %s\n", *k, t); else if (!iflag && !imported(*k)) { fprintf(stream, "\n/// Built-in attribute \"%s\".\n", *k); fprintf(stream, "typedef %s %s;\n", s, t); const char *u = types.uri(*k); if (u && !types.uris[u]) fprintf(stream, schemaformat, types.nsprefix(types.prefix(*k), u), "namespace", u); } } else if (**k == '"') fprintf(stream, "// Imported attribute %s declared as %s\n", *k, t); else fprintf(stream, "// xsd.h: should define attribute %s\n", t); types.deftname(TYPEDEF, NULL, strchr(s, '*') != NULL, "_", NULL, *k); } } // produce types // define class/struct types first if (!cflag) banner("Forward Declarations"); if (definitions.types) { comment("Definitions", defs, "types", definitions.types->documentation); fprintf(stream, "\n"); for (vector<xs__schema*>::const_iterator schema4 = definitions.types->xs__schema_.begin(); schema4 != definitions.types->xs__schema_.end(); ++schema4) { if (vflag) fprintf(stderr, "\nDefining types in %s\n", (*schema4)->targetNamespace); for (vector<xs__complexType>::const_iterator complexType = (*schema4)->complexType.begin(); complexType != (*schema4)->complexType.end(); ++complexType) types.define((*schema4)->targetNamespace, NULL, *complexType); if (vflag) fprintf(stderr, "\nDefining elements in %s\n", (*schema4)->targetNamespace); for (vector<xs__element>::const_iterator element = (*schema4)->element.begin(); element != (*schema4)->element.end(); ++element) { if (!(*element).type && !(*element).abstract) { if ((*element).complexTypePtr()) types.define((*schema4)->targetNamespace, (*element).name, *(*element).complexTypePtr()); else if (!(*element).simpleTypePtr()) { fprintf(stream, "\n/// Top-level root element \"%s\":%s.\n", (*schema4)->targetNamespace, (*element).name); if (gflag) { const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema4)->targetNamespace, (*element).name); if (t) fprintf(stream, "typedef _XML %s;\n", t); else fprintf(stream, "// Element definition intentionally left blank.\n"); } else { const char *s = types.cname("_", (*schema4)->targetNamespace, (*element).name); types.ptrtypemap[s] = types.usetypemap[s] = "_XML"; fprintf(stream, "/// Note: use wsdl2h option -g to auto-generate a top-level root element declaration and processing code.\n"); } } } } } // visit types with lowest base level first int baseLevel = 1; bool found; do { found = (baseLevel == 1); for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) { if (found) banner("Schema Types and Top-Level Elements and Attributes", (*schema)->targetNamespace); for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType) { if ((*simpleType).baseLevel() == baseLevel) { found = true; types.gen((*schema)->targetNamespace, NULL, *simpleType, false); } } for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) { if (!(*element).type && (*element).simpleTypePtr() && (*element).simpleTypePtr()->baseLevel() == baseLevel) { found = true; if ((*element).type) fprintf(stream, "/// Top-level root element \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type); types.document((*element).annotation); types.gen((*schema)->targetNamespace, (*element).name, *(*element).simpleTypePtr(), false); } if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel) found = true; } for (vector<xs__attribute>::const_iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute) { if (!(*attribute).type && (*attribute).simpleTypePtr() && (*attribute).simpleTypePtr()->baseLevel() == baseLevel) { found = true; if ((*attribute).type) fprintf(stream, "/// Top-level attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type); types.document((*attribute).annotation); types.gen((*schema)->targetNamespace, (*attribute).name, *(*attribute).simpleTypePtr(), false); // URI = NULL won't generate type in schema (type without namespace qualifier) } } for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType) { if ((*complexType).baseLevel() == baseLevel) found = true; } } ++baseLevel; } while (found); // generate complex type defs. Problem: what if a simpleType restriction/extension depends on a complexType simpleContent restriction/extension? int maxLevel = baseLevel; for (baseLevel = 1; baseLevel < maxLevel; ++baseLevel) { for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) { if (baseLevel == 1) banner("Schema Complex Types and Top-Level Elements", (*schema)->targetNamespace); for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType) { if ((*complexType).baseLevel() == baseLevel) types.gen((*schema)->targetNamespace, NULL, *complexType, false); } for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) { if (!(*element).type && (*element).complexTypePtr() && (*element).complexTypePtr()->baseLevel() == baseLevel) { fprintf(stream, "\n\n/// Top-level root element \"%s\":%s\n", (*schema)->targetNamespace, (*element).name); types.document((*element).annotation); types.gen((*schema)->targetNamespace, (*element).name, *(*element).complexTypePtr(), false); } } } } for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) { for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType) { if ((*simpleType).baseLevel() <= 0) { fprintf(stream, "\n\n/// Warning: '%s' is a simpleType with cyclic restriction/extension inheritance\n", (*simpleType).name?(*simpleType).name:""); fprintf(stream, "typedef _XML %s;\n", types.deftname(TYPEDEF, NULL, false, NULL, (*schema)->targetNamespace, (*simpleType).name)); } } for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType) { if ((*complexType).baseLevel() <= 0) { fprintf(stream, "\n\n/// Warning: '%s' is a complexType with cyclic restriction/extension inheritance\n", (*complexType).name?(*complexType).name:""); if (cflag) fprintf(stream, "typedef _XML %s;\n", types.cname(NULL, (*schema)->targetNamespace, (*complexType).name)); else fprintf(stream, "class %s { };\n", types.cname(NULL, (*schema)->targetNamespace, (*complexType).name)); } } } // option to consider: generate local complexTypes iteratively /* for (MapOfStringToType::const_iterator local = types.locals.begin(); local != types.locals.end(); ++local) { types.gen(NULL, (*local).first, *(*local).second); } */ for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema) { if (vflag) fprintf(stderr, "\nGenerating elements in %s\n", (*schema)->targetNamespace); banner("Additional Top-Level Elements", (*schema)->targetNamespace); for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element) { if ((*element).name && (*element).type && !(*element).abstract) { fprintf(stream, "\n/// Top-level root element \"%s\":%s of type %s.\n", (*schema)->targetNamespace, (*element).name, (*element).type); types.document((*element).annotation); if (!types.is_defined("_", (*schema)->targetNamespace, (*element).name)) { if (gflag) { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*element).type); const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*element).name); if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char* { size_t n = strlen(s); char *r = (char*)malloc(n); strncpy(r, s, n - 1); r[n - 1] = '\0'; fprintf(stream, "typedef %s %s;\n", r, t); free(r); } else fprintf(stream, "typedef %s %s;\n", s, t); } else fprintf(stream, "/// Note: use wsdl2h option -g to auto-generate a top-level root element declaration and processing code.\n"); } else { const char *s = types.cname("_", (*schema)->targetNamespace, (*element).name); const char *t = types.deftypemap[s]; if (t && *t) { fprintf(stream, "/// Imported element %s from typemap %s.\n", s, mapfile?mapfile:""); types.format(t); } else fprintf(stream, "// '%s' element definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*element).name)); } } } if (vflag) fprintf(stderr, "\nGenerating attributes in %s\n", (*schema)->targetNamespace); banner("Additional Top-Level Attributes", (*schema)->targetNamespace); for (vector<xs__attribute>::iterator attribute = (*schema)->attribute.begin(); attribute != (*schema)->attribute.end(); ++attribute) { if ((*attribute).name && (*attribute).type) { fprintf(stream, "\n/// Top-level attribute \"%s\":%s of simpleType %s.\n", (*schema)->targetNamespace, (*attribute).name, (*attribute).type); types.document((*attribute).annotation); if (!types.is_defined("_", (*schema)->targetNamespace, (*attribute).name)) { if (gflag) { const char *s = types.tname(NULL, (*schema)->targetNamespace, (*attribute).type); const char *t = types.deftname(TYPEDEF, NULL, false, "_", (*schema)->targetNamespace, (*attribute).name); if (strncmp(s, "char", 4) && strchr(s, '*')) // don't want pointer typedef, unless char* { size_t n = strlen(s); char *r = (char*)malloc(n); strncpy(r, s, n - 1); r[n - 1] = '\0'; fprintf(stream, "typedef %s %s;\n", r, t); free(r); } else fprintf(stream, "typedef %s %s;\n", s, t); } else fprintf(stream, "/// Note: use wsdl2h option -g to auto-generate a top-level attribute declaration and processing code.\n"); } else { const char *s = types.cname("_", (*schema)->targetNamespace, (*attribute).name); const char *t = types.deftypemap[s]; if (t && *t) { fprintf(stream, "/// Imported attribute %s from typemap %s.\n", s, mapfile?mapfile:""); types.format(t); } else fprintf(stream, "// '%s' attribute definition intentionally left blank.\n", types.cname("_", (*schema)->targetNamespace, (*attribute).name)); } } } } } if (vflag) fprintf(stderr, "\nCollecting service bindings\n"); collect(definitions); if (!services.empty()) { banner("Services"); if (soap12) fprintf(stream, "// This service supports SOAP 1.2 namespaces:\n#import \"soap12.h\"\n"); for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1) { Service *sv = (*service1).second; if (sv && sv->prefix) { fprintf(stream, "\n"); if (sv->name) fprintf(stream, serviceformat, sv->prefix, "name", sv->name, ""); if (sv->type) fprintf(stream, serviceformat, sv->prefix, "type", sv->type, ""); for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port) fprintf(stream, serviceformat, sv->prefix, "port", (*port), ""); if (sv->URI) fprintf(stream, serviceformat, sv->prefix, "namespace", sv->URI, ""); if (sv->transport) fprintf(stream, serviceformat, sv->prefix, "transport", sv->transport, ""); } } fprintf(stream, "\n/** @mainpage %s Definitions\n", definitions.name?definitions.name:"Service"); if (definitions.version) { section(defs, "_version Definitions Version", NULL); text(definitions.version); } if (definitions.documentation) { section(defs, "_documentation Documentation", NULL); text(definitions.documentation); } if (definitions.types && definitions.types->documentation) { section(defs, "_types Schema Type Information", NULL); text(definitions.types->documentation); } section(defs, "_bindings Service Bindings", NULL); for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2) { Service *sv = (*service2).second; if (sv && sv->name) fprintf(stream, "\n - @ref %s\n", sv->name); } section(defs, "_more More Information", NULL); fprintf(stream, "\n - @ref page_notes \"Usage Notes\"\n"); fprintf(stream, "\n - @ref page_XMLDataBinding \"XML Data Binding\"\n"); if (!jflag) fprintf(stream, "\n - @ref SOAP_ENV__Header \"SOAP Header Content\" (when applicable)\n"); if (!jflag) fprintf(stream, "\n - @ref SOAP_ENV__Detail \"SOAP Fault Detail Content\" (when applicable)\n"); fprintf(stream, "\n\n*/\n"); for (MapOfStringToService::const_iterator service3 = services.begin(); service3 != services.end(); ++service3) { Service *sv = (*service3).second; if (sv && sv->name) { fprintf(stream, "\n/**\n"); page(sv->name, " Binding", sv->name); for (MapOfStringToString::const_iterator service_doc = sv->service_documentation.begin(); service_doc != sv->service_documentation.end(); ++service_doc) { const char *name = types.aname(NULL, NULL, (*service_doc).first); section(name, "_service Service Documentation", (*service_doc).first); text((*service_doc).second); } for (MapOfStringToString::const_iterator port_doc = sv->port_documentation.begin(); port_doc != sv->port_documentation.end(); ++port_doc) { const char *name = types.aname(NULL, NULL, (*port_doc).first); section(name, "_port Port Documentation", (*port_doc).first); text((*port_doc).second); } for (MapOfStringToString::const_iterator binding_doc = sv->binding_documentation.begin(); binding_doc != sv->binding_documentation.end(); ++binding_doc) { const char *name = types.aname(NULL, NULL, (*binding_doc).first); section(name, "_binding Binding Documentation", (*binding_doc).first); text((*binding_doc).second); } section(sv->name, "_operations Operations of Binding ", sv->name); for (vector<Operation*>::const_iterator op = sv->operation.begin(); op != sv->operation.end(); ++op) { if (*op && (*op)->input && (*op)->input_name) fprintf(stream, "\n - @ref %s\n", (*op)->input_name); else if (*op && (*op)->output_name) fprintf(stream, "\n - @ref %s\n", (*op)->output_name); } section(sv->name, "_ports Endpoints of Binding ", sv->name); for (SetOfString::const_iterator port = sv->location.begin(); port != sv->location.end(); ++port) fprintf(stream, "\n - %s\n", *port); if (!sv->policy.empty()) { section(sv->name, "_policy Policy of Binding ", sv->name); fprintf(stream, "\nSee Section @ref %s_policy_enablers\n", sv->name); gen_policy(*sv, sv->policy, "service endpoint ports", types); } if (!service_prefix) fprintf(stream, "\nNote: use wsdl2h option -Nname to change the service binding prefix name\n"); fprintf(stream, "\n\n*/\n"); } } } generate(); if (definitions.types) { banner("XML Data Binding"); fprintf(stream, "\n/**\n"); page("page_XMLDataBinding", " XML Data Binding", NULL); fprintf(stream, "\nSOAP/XML services use data bindings contractually bound by WSDL and auto-\ngenerated by wsdl2h and soapcpp2 (see Service Bindings). Plain data bindings\nare adopted from XML schemas as part of the WSDL types section or when running\nwsdl2h on a set of schemas to produce non-SOAP-based XML data bindings.\n\nThe following readers and writers are C/C++ data type (de)serializers auto-\ngenerated by wsdl2h and soapcpp2. Run soapcpp2 on this file to generate the\n(de)serialization code, which is stored in soapC.c[pp]. Include \"soapH.h\" in\nyour code to import these data type and function declarations. Only use the\nsoapcpp2-generated files in your project build. Do not include the wsdl2h-\ngenerated .h file in your code.\n\nData can be read in XML and deserialized from:\n - a file descriptor, using soap->recvfd = fd\n - a socket, using soap->socket = ...\n - a C++ stream, using soap->is = ...\n - a buffer, using the soap->frecv() callback\n\nData can be serialized in XML and written to:\n - a file descriptor, using soap->sendfd = fd\n - a socket, using soap->socket = ...\n - a C++ stream, using soap->os = ...\n - a buffer, using the soap->fsend() callback\n\nThe following options are available for (de)serialization control:\n - soap->encodingStyle = NULL; to remove SOAP 1.1/1.2 encodingStyle\n - soap_mode(soap, SOAP_XML_TREE); XML without id-ref (no cycles!)\n - soap_mode(soap, SOAP_XML_GRAPH); XML with id-ref (including cycles)\n - soap_set_namespaces(soap, struct Namespace *nsmap); to set xmlns bindings\n\n"); for (vector<xs__schema*>::const_iterator schema5 = definitions.types->xs__schema_.begin(); schema5 != definitions.types->xs__schema_.end(); ++schema5) { const char *prefix = types.nsprefix(NULL, (*schema5)->targetNamespace); fprintf(stream, "\n@section %s Top-level root elements of schema \"%s\"\n", prefix, (*schema5)->targetNamespace); for (vector<xs__element>::const_iterator element = (*schema5)->element.begin(); element != (*schema5)->element.end(); ++element) { fprintf(stream, "\n - <%s:%s> ", prefix, (*element).name); if (types.is_defined("_", (*schema5)->targetNamespace, (*element).name)) { const char *cname = types.cname("_", (*schema5)->targetNamespace, (*element).name); const char *pname = types.pname(true, "_", (*schema5)->targetNamespace, (*element).name); fprintf(stream, "@ref %s\n", cname); fprintf(stream, " @code\n // Reader (returns SOAP_OK on success):\n soap_read_%s(struct soap*, %s);\n // Writer (returns SOAP_OK on success):\n soap_write_%s(struct soap*, %s);\n @endcode\n", cname, pname, cname, pname); } else fprintf(stream, "(use wsdl2h option -g to auto-generate)\n"); } } fprintf(stream, "\n*/\n"); } if (cppnamespace) fprintf(stream, "\n} // namespace %s\n", cppnamespace); fprintf(stream, "\n/* End of %s */\n", outfile?outfile:"file"); } void Definitions::generate() { MapOfStringToMessage headers; MapOfStringToMessage faults; const char *t; for (MapOfStringToService::const_iterator service1 = services.begin(); service1 != services.end(); ++service1) { if ((*service1).second) { for (MapOfStringToMessage::const_iterator header = (*service1).second->header.begin(); header != (*service1).second->header.end(); ++header) headers[(*header).first] = (*header).second; for (MapOfStringToMessage::const_iterator fault = (*service1).second->fault.begin(); fault != (*service1).second->fault.end(); ++fault) faults[(*fault).first] = (*fault).second; } } // Generate SOAP Header definition t = types.deftypemap["SOAP_ENV__Header"]; if (t && *t) { banner("Custom SOAP Header"); types.format(t); } else if (!jflag && !headers.empty()) { banner("SOAP Header"); fprintf(stream, "/**\n\nThe SOAP Header is part of the gSOAP context and its content is accessed\nthrough the soap.header variable. You may have to set the soap.actor variable\nto serialize SOAP Headers with SOAP-ENV:actor or SOAP-ENV:role attributes.\nUse option -j to remove entire SOAP Header definition.\nUse option -k to remove the mustUnderstand qualifiers.\n\n*/\n"); fprintf(stream, "struct SOAP_ENV__Header\n{\n"); for (MapOfStringToMessage::const_iterator header = headers.begin(); header != headers.end(); ++header) { if ((*header).second->URI && !types.uris[(*header).second->URI]) fprintf(stream, schemaformat, types.nsprefix(NULL, (*header).second->URI), "namespace", (*header).second->URI); comment("Header", (*header).first, "WSDL", (*header).second->ext_documentation); comment("Header", (*header).first, "SOAP", (*header).second->documentation); if ((*header).second->mustUnderstand && !kflag) { fprintf(stream, elementformat, "mustUnderstand", "// must be understood by receiver"); fprintf(stream, "\n"); } if ((*header).second->part && (*header).second->part->elementPtr()) { fprintf(stream, "/// \"%s\" SOAP Header part element\n", (*header).second->part->name); if ((*header).second->part->elementPtr()->type && (*header).second->part->element) fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->elementPtr()->type), types.aname(NULL, NULL, (*header).second->part->element)); else if ((*header).second->part->element) fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->element), types.aname(NULL, NULL, (*header).second->part->element)); else fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->elementPtr()->name), (*header).first); fprintf(stream, ";\n"); } else if ((*header).second->part && (*header).second->part->type) { fprintf(stream, "/// \"%s\" SOAP Header part type\n", (*header).second->part->type); fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*header).second->part->type), types.aname(NULL, (*header).second->URI, (*header).second->part->name)); fprintf(stream, ";\n"); } else if ((*header).second->element) { fprintf(stream, "/// \"%s\" SOAP Header element", (*header).second->name); (*header).second->generate(types, ";", false, true, false, true); fprintf(stream, "\n"); } else { if ((*header).second->part && (*header).second->part->element) fprintf(stream, elementformat, types.pname(true, "_", NULL, (*header).second->part->element), (*header).first); else fprintf(stream, pointerformat, (*header).first, (*header).first); fprintf(stream, ";\t///< TODO: Please check element name and type (imported type)\n"); } } types.modify("SOAP_ENV__Header"); fprintf(stream, "\n};\n"); } // Generate Fault detail element definitions for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault) { if ((*fault).second->use == encoded) { banner("SOAP Fault Detail Message"); fprintf(stream, "/// SOAP Fault detail message \"%s:%s\"\n", (*fault).second->URI, (*fault).second->message->name); comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation); comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation); if (cflag) fprintf(stream, "struct %s\n{", (*fault).first); else fprintf(stream, "class %s\n{ public:", (*fault).first); (*fault).second->generate(types, ";", false, true, false, true); if (!cflag) { fprintf(stream, "\n"); fprintf(stream, pointerformat, "struct soap", "soap"); fprintf(stream, ";"); } fprintf(stream, "\n};\n"); if (cflag) fprintf(stream, "typedef struct %s %s;\n", (*fault).first, (*fault).first); if ((*fault).second->URI && !types.uris[(*fault).second->URI]) fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI); } } t = types.deftypemap["SOAP_ENV__Detail"]; if (t && *t) { banner("Custom SOAP Fault Detail"); types.format(t); } else if (!jflag && !faults.empty()) { SetOfString fault_elements; banner("SOAP Fault Detail"); fprintf(stream, "/**\n\nThe SOAP Fault is part of the gSOAP context and its content is accessed\nthrough the soap.fault->detail variable (SOAP 1.1) or the\nsoap.fault->SOAP_ENV__Detail variable (SOAP 1.2).\nUse wsdl2h option -j to omit these declarations.\n\n*/\n"); fprintf(stream, "struct SOAP_ENV__Detail\n{\n"); if (dflag) { const char *t = types.tname(NULL, NULL, "xsd:anyAttribute"); fprintf(stream, attributeformat, t, "__anyAttribute"); fprintf(stream, ";\t///< Catch any attribute content in DOM.\n"); } else fprintf(stream, "// xsd:anyAttribute omitted: to parse attribute content of the Detail element into DOM anyAttribute, use wsdl2h option -d.\n"); types.modify("SOAP_ENV__Detail"); /* See below */ fprintf(stream, elementformat, "_XML", "__any"); fprintf(stream, ";\t///< Catch any element content in XML string.\n"); /* The DOM representation is not desired since faultdetail is NULL. However, future options may reenable this feature (see keep code here). const char *t = types.tname(NULL, NULL, "xsd:any"); fprintf(stream, elementformat, t, "__any"); if (dflag) fprintf(stream, ";\t///< Catch any element content in DOM.\n"); else fprintf(stream, ";\t///< Catch any element content in XML string.\n"); */ for (MapOfStringToMessage::const_iterator fault = faults.begin(); fault != faults.end(); ++fault) { if ((*fault).second->URI && !types.uris[(*fault).second->URI]) fprintf(stream, schemaformat, types.nsprefix(NULL, (*fault).second->URI), "namespace", (*fault).second->URI); comment("Fault", (*fault).first, "WSDL", (*fault).second->ext_documentation); comment("Fault", (*fault).first, "SOAP", (*fault).second->documentation); if ((*fault).second->message) { if ((*fault).second->use == literal) { for (vector<wsdl__part>::const_iterator part = (*fault).second->message->part.begin(); part != (*fault).second->message->part.end(); ++part) { if ((*part).elementPtr()) { if (fault_elements.find((*part).element) == fault_elements.end()) { if ((*part).elementPtr()->type) fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).elementPtr()->type), types.aname(NULL, (*fault).second->URI, (*part).element)); else fprintf(stream, elementformat, types.pname(true, "_", NULL, (*part).element), types.aname(NULL, (*fault).second->URI, (*part).element)); fprintf(stream, ";\n"); fault_elements.insert((*part).element); } fprintf(stream, "///< SOAP Fault element \"%s\" part \"%s\"\n", (*part).element?(*part).element:"", (*part).name?(*part).name:""); } else if ((*part).name && (*part).type) { if (fault_elements.find((*part).name) == fault_elements.end()) { fprintf(stream, elementformat, types.pname(true, NULL, NULL, (*part).type), types.aname("_", (*fault).second->URI, (*part).name)); fprintf(stream, ";\n"); fault_elements.insert((*part).name); } fprintf(stream, "///< SOAP Fault type \"%s\" part \"%s\"\n", (*part).type, (*part).name); } else fprintf(stream, "// Unknown SOAP Fault element \"%s\" part \"%s\"\n", (*fault).second->message->name, (*part).name?(*part).name:""); } } else { fprintf(stream, elementformat, (*fault).first, types.aname(NULL, (*fault).second->URI, (*fault).second->message->name)); fprintf(stream, ";\t///< SOAP Fault detail message \"%s\":%s\n", (*fault).second->URI, (*fault).second->message->name); } } else if ((*fault).second->element) { if (fault_elements.find((*fault).second->name) == fault_elements.end()) { fprintf(stream, pointerformat, types.pname(true, "_", (*fault).second->URI, (*fault).second->element->name), (*fault).second->name); fprintf(stream, ";\t///< SOAP Fault detail message \"%s\":%s\n", (*fault).second->URI, (*fault).second->element->name); fault_elements.insert((*fault).second->name); } } } fprintf(stream, elementformat, "int", "__type"); fprintf(stream, ";\t///< set to SOAP_TYPE_X for a serializable type X\n"); fprintf(stream, pointerformat, "void", "fault"); fprintf(stream, ";\t///< points to serializable object X or NULL\n"); fprintf(stream, "};\n"); } /* The SOAP Fault struct below is autogenerated by soapcpp2 (kept here for future mods) if (!mflag && !faults.empty()) { fprintf(stream, "struct SOAP_ENV__Code\n{\n"); fprintf(stream, elementformat, "_QName", "SOAP_ENV__Value"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "char", "SOAP_ENV__Node"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "char", "SOAP_ENV__Role"); fprintf(stream, ";\n};\n"); fprintf(stream, "struct SOAP_ENV__Detail\n{\n"); fprintf(stream, elementformat, "int", "__type"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "void", "fault"); fprintf(stream, ";\n"); fprintf(stream, elementformat, "_XML", "__any"); fprintf(stream, ";\n};\n"); fprintf(stream, "struct SOAP_ENV__Fault\n{\n"); fprintf(stream, elementformat, "_QName", "faultcode"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "char", "faultstring"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "char", "faultactor"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "detail"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "struct SOAP_ENV__Code", "SOAP_ENV__Code"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "char", "SOAP_ENV__Reason"); fprintf(stream, ";\n"); fprintf(stream, pointerformat, "struct SOAP_ENV__Detail", "SOAP_ENV__Detail"); fprintf(stream, ";\n};\n"); } */ for (MapOfStringToService::const_iterator service2 = services.begin(); service2 != services.end(); ++service2) if ((*service2).second) (*service2).second->generate(types); } //////////////////////////////////////////////////////////////////////////////// // // Service methods // //////////////////////////////////////////////////////////////////////////////// Service::Service() { prefix = NULL; URI = NULL; name = NULL; type = NULL; transport = NULL; } void Service::generate(Types& types) { const char *method_name; banner("Service Binding", name); for (vector<Operation*>::const_iterator op2 = operation.begin(); op2 != operation.end(); ++op2) { if (*op2 && ((*op2)->input || bflag)) { bool flag = false, anonymous = ((*op2)->style != document && (*op2)->parameterOrder != NULL); if (!(*op2)->input) method_name = (*op2)->output_name; else method_name = (*op2)->input_name; banner("Service Operation", method_name); if ((*op2)->output && (*op2)->output_name) { if ((*op2)->style == document) flag = ((*op2)->output->element || ((*op2)->output->message && (*op2)->output->message->part.size() == 1)); else if (!wflag) flag = ((*op2)->output->element || ((*op2)->output->message && (*op2)->output->use == encoded && (*op2)->output->message->part.size() == 1 && !(*(*op2)->output->message->part.begin()).simpleTypePtr() && !(*(*op2)->output->message->part.begin()).complexTypePtr())); if (flag && (*op2)->input && (*op2)->output && (*op2)->input->message && (*(*op2)->output->message->part.begin()).element) for (vector<wsdl__part>::const_iterator part = (*op2)->input->message->part.begin(); part != (*op2)->input->message->part.end(); ++part) if ((*part).element && !strcmp((*part).element, (*(*op2)->output->message->part.begin()).element)) flag = false; if (!flag) { if (bflag) fprintf(stream, "/* soapcpp2 generates the following struct automatically for your use:\n"); fprintf(stream, "/// Operation response struct \"%s\" of operation \"%s\"\n", (*op2)->output_name, method_name); fprintf(stream, "struct %s\n{", (*op2)->output_name); (*op2)->output->generate(types, ";", anonymous, false, false, false); fprintf(stream, "\n};\n"); if (bflag) fprintf(stream, "*/\n"); } } fprintf(stream, "\n/// Operation \"%s\" of service binding \"%s\"\n\n/**\n\nOperation details:\n", method_name, name); if ((*op2)->documentation) text((*op2)->documentation); if ((*op2)->operation_documentation) text((*op2)->operation_documentation); if ((*op2)->input && (*op2)->input->documentation) { fprintf(stream, "Input request:\n"); text((*op2)->input->documentation); } if ((*op2)->input && (*op2)->input->ext_documentation) { fprintf(stream, "Input request:\n"); text((*op2)->input->ext_documentation); } if ((*op2)->output) { if ((*op2)->output->documentation) { fprintf(stream, "Output response:\n"); text((*op2)->output->documentation); } if ((*op2)->output->ext_documentation) { fprintf(stream, "Output response:\n"); text((*op2)->output->ext_documentation); } } gen_policy(*this, (*op2)->policy, "operation", types); if ((*op2)->input) { gen_policy(*this, (*op2)->input->policy, "request message", types); if ((*op2)->input->content) { fprintf(stream, "\n - Request message MIME content"); if ((*op2)->input->content->type) { fprintf(stream, " type=\""); text((*op2)->input->content->type); fprintf(stream, "\""); } if ((*op2)->input->content->type && !strcmp((*op2)->input->content->type, "application/x-www-form-urlencoded")) fprintf(stream, "\n Use the httpform.c plugin to retrieve key-value pairs from the REST request\n message form data at the server side (client side is automated).\n"); else fprintf(stream, "\n TODO: this form of MIME content is not automatically handled.\n"); } } if ((*op2)->output) { gen_policy(*this, (*op2)->output->policy, "response message", types); if ((*op2)->output->content) { fprintf(stream, "\n - Response message MIME content"); if ((*op2)->output->content->type) { fprintf(stream, " type=\""); text((*op2)->output->content->type); fprintf(stream, "\""); } fprintf(stream, "\n TODO: this form of MIME content response is not automatically handled.\n Use one-way request and implement code to parse response.\n"); } } else fprintf(stream, "\n - One-way service request message\n"); if ((*op2)->mep) fprintf(stream, "\n - SOAP MEP: \"%s\"\n", ((*op2)->mep)); if ((*op2)->style == document) fprintf(stream, "\n - %s %s messaging\n", (*op2)->protocol, (*op2)->input && (*op2)->input->content && (*op2)->input->content->type ? (*op2)->input->content->type : "document/literal style"); else if ((*op2)->input) { if ((*op2)->input->use == literal) fprintf(stream, "\n - %s literal messaging\n", (*op2)->protocol); else if ((*op2)->input->encodingStyle) fprintf(stream, "\n - %s RPC encodingStyle=\"%s\"\n", (*op2)->input->encodingStyle, (*op2)->protocol); else fprintf(stream, "\n - %s RPC encoded messaging\n", (*op2)->protocol); } if ((*op2)->output) { if (!(*op2)->input || (*op2)->input->use != (*op2)->output->use) { if ((*op2)->output->use == literal) fprintf(stream, "\n - %s literal response messages\n", (*op2)->protocol); else if ((*op2)->output->encodingStyle) fprintf(stream, "\n - %s RPC response encodingStyle=\"%s\"\n", (*op2)->protocol, (*op2)->output->encodingStyle); else fprintf(stream, "\n - %s RPC encoded response messages\n", (*op2)->protocol); } } if ((*op2)->action) { if (*(*op2)->action) fprintf(stream, "\n - Action: \"%s\"\n", (*op2)->action); } if ((*op2)->input) { if ((*op2)->input->action) fprintf(stream, "\n - Addressing input action: \"%s\"\n", (*op2)->input->action); } if ((*op2)->output) { if ((*op2)->output->action) fprintf(stream, "\n - Addressing output action: \"%s\"\n", (*op2)->output->action); } for (vector<Message*>::const_iterator infault = (*op2)->infault.begin(); infault != (*op2)->infault.end(); ++infault) { if ((*infault)->message) { if ((*infault)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*infault)->message->part.begin(); part != (*infault)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, "\n - SOAP Input Fault: %s (literal)\n", (*part).element); else if ((*part).name && (*part).type) fprintf(stream, "\n - SOAP Input Fault: %s (literal)\n", (*part).name); } } else if ((*infault)->message->name) fprintf(stream, "\n - SOAP Input Fault: %s\n", (*infault)->name); if ((*infault)->message->name && (*infault)->action) fprintf(stream, " - SOAP Input Fault addressing action: \"%s\"\n", (*infault)->action); } else if ((*infault)->name) fprintf(stream, "\n - SOAP Input Fault: %s (literal)\n", (*infault)->name); if ((*infault)->body_parts) fprintf(stream, " SOAP Input Fault code: %s\n", (*infault)->body_parts); text((*infault)->documentation); text((*infault)->ext_documentation); gen_policy(*this, (*infault)->policy, "fault message", types); } for (vector<Message*>::const_iterator outfault = (*op2)->outfault.begin(); outfault != (*op2)->outfault.end(); ++outfault) { if ((*outfault)->message) { if ((*outfault)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*outfault)->message->part.begin(); part != (*outfault)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*part).element); else if ((*part).name && (*part).type) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*part).name); } } else if ((*outfault)->message->name) fprintf(stream, "\n - SOAP Output Fault: %s\n", (*outfault)->name); if ((*outfault)->message->name && (*outfault)->action) fprintf(stream, " - SOAP Output Fault addressing action: \"%s\"\n", (*outfault)->action); } else if ((*outfault)->name) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*outfault)->name); if ((*outfault)->body_parts) fprintf(stream, " SOAP Output Fault code: %s\n", (*outfault)->body_parts); text((*outfault)->documentation); text((*outfault)->ext_documentation); gen_policy(*this, (*outfault)->policy, "fault message", types); } if ((*op2)->input) { if (!(*op2)->input->header.empty()) fprintf(stream, "\n - Request message has mandatory header part(s) (see @ref SOAP_ENV__Header):\n"); for (vector<soap__header>::const_iterator inputheader = (*op2)->input->header.begin(); inputheader != (*op2)->input->header.end(); ++inputheader) { if ((*inputheader).part) { if ((*inputheader).use == encoded && (*inputheader).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*inputheader).partPtr()->element)); } } } if ((*op2)->input && (*op2)->input->multipartRelated) { int k = 2; fprintf(stream, "\n - Request message MIME multipart/related attachments:\n"); for (vector<mime__part>::const_iterator part = (*op2)->input->multipartRelated->part.begin(); part != (*op2)->input->multipartRelated->part.end(); ++part) { if ((*part).soap__body_) { fprintf(stream, " -# MIME attachment with SOAP Body and mandatory header part(s):\n"); for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header) { if ((*header).part) { if ((*header).use == encoded && (*header).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*header).namespace_, (*header).part)); else if ((*header).partPtr() && (*header).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element)); } } } else { fprintf(stream, " -# MIME attachment %d:\n", k++); for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content) { fprintf(stream, " -"); if ((*content).part) { fprintf(stream, " part=\""); text((*content).part); fprintf(stream, "\""); } if ((*content).type) { fprintf(stream, " type=\""); text((*content).type); fprintf(stream, "\""); } fprintf(stream, "\n"); } } } } if ((*op2)->input && (*op2)->input->layout) fprintf(stream, "\n - Request message has DIME attachments in compliance with %s\n", (*op2)->input->layout); if ((*op2)->output) { if (!(*op2)->output->header.empty()) fprintf(stream, "\n - Response message has mandatory header part(s): (see @ref SOAP_ENV__Header)\n"); for (vector<soap__header>::const_iterator outputheader = (*op2)->output->header.begin(); outputheader != (*op2)->output->header.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } } if ((*op2)->output && (*op2)->output_name && (*op2)->output->multipartRelated) { int k = 2; fprintf(stream, "\n - Response message MIME multipart/related attachments\n"); for (vector<mime__part>::const_iterator part = (*op2)->output->multipartRelated->part.begin(); part != (*op2)->output->multipartRelated->part.end(); ++part) { if ((*part).soap__body_) { fprintf(stream, " -# MIME attachment with SOAP Body and mandatory header part(s):\n"); for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header) { if ((*header).part) { if ((*header).use == encoded && (*header).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*header).namespace_, (*header).part)); else if ((*header).partPtr() && (*header).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element)); } } } else { fprintf(stream, " -# MIME attachment %d:\n", k++); for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content) { fprintf(stream, " -"); if ((*content).part) { fprintf(stream, " part=\""); text((*content).part); fprintf(stream, "\""); } if ((*content).type) { fprintf(stream, " type=\""); text((*content).type); fprintf(stream, "\""); } fprintf(stream, "\n"); } } } } if ((*op2)->output && (*op2)->output_name && (*op2)->output->layout) fprintf(stream, "\n - Response message has DIME attachments in compliance with %s\n", (*op2)->output->layout); fprintf(stream, "\nC stub function (defined in soapClient.c[pp] generated by soapcpp2):\n@code\n int soap_%s_%s(\n 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\n // input parameters:", (*op2)->output?"call":"send", method_name); if ((*op2)->input) (*op2)->input->generate(types, ",", false, false, false, false); if ((*op2)->output && (*op2)->output_name) { fprintf(stream, "\n // output parameters:"); if (flag) { if ((*op2)->style == rpc && (*op2)->output->message && (*(*op2)->output->message->part.begin()).name) { fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), ""); } else (*op2)->output->generate(types, "", anonymous, false, true, false); } else fprintf(stream, "\n struct %s%s", (*op2)->output_name, cflag ? "*" : "&"); } fprintf(stream, "\n );\n@endcode\n\nC server function (called from the service dispatcher defined in soapServer.c[pp]):\n@code\n int %s(\n struct soap *soap,\n // input parameters:", method_name); if ((*op2)->input) (*op2)->input->generate(types, ",", false, false, false, false); fprintf(stream, "\n // output parameters:"); if ((*op2)->output && (*op2)->output_name) { if (flag) { if ((*op2)->style == rpc && (*op2)->output->message && (*(*op2)->output->message->part.begin()).name) { fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*(*op2)->output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*(*op2)->output->message->part.begin()).name), ""); } else (*op2)->output->generate(types, "", anonymous, false, true, false); } else fprintf(stream, "\n struct %s%s", (*op2)->output_name, cflag ? "*" : "&"); } fprintf(stream, "\n );\n@endcode\n\n"); if (!cflag) { fprintf(stream, "C++ proxy class (defined in soap%sProxy.h):\n", name); fprintf(stream, "@code\n class %sProxy;\n@endcode\n", name); fprintf(stream, "Important: use soapcpp2 option '-j' (or '-i') to generate greatly improved and easy-to-use proxy classes;\n\n"); fprintf(stream, "C++ service class (defined in soap%sService.h):\n", name); fprintf(stream, "@code\n class %sService;\n@endcode\n", name); fprintf(stream, "Important: use soapcpp2 option '-j' (or '-i') to generate greatly improved and easy-to-use service classes;\n\n"); } fprintf(stream, "*/\n\n"); (*op2)->generate(types, *this); } else if (*op2 && (*op2)->output) { if (!(*op2)->input) method_name = (*op2)->output_name; else method_name = (*op2)->input_name; banner("Service Operation", method_name); fprintf(stream, "\n/// Operation \"%s\" of service binding \"%s\"\n\n/**\n\nOperation details:\n", method_name, name); if ((*op2)->documentation) text((*op2)->documentation); if ((*op2)->operation_documentation) text((*op2)->operation_documentation); if ((*op2)->output->documentation) { fprintf(stream, "Output response:\n"); text((*op2)->output->documentation); } if ((*op2)->output->ext_documentation) { fprintf(stream, "Output response:\n"); text((*op2)->output->ext_documentation); } gen_policy(*this, (*op2)->policy, "operation", types); gen_policy(*this, (*op2)->output->policy, "response message", types); fprintf(stream, "\n - One-way service response message\n"); if ((*op2)->mep) fprintf(stream, "\n - SOAP MEP: \"%s\"\n", ((*op2)->mep)); if ((*op2)->style == document) fprintf(stream, "\n - %s document/literal style messaging\n", (*op2)->protocol); else { if ((*op2)->output->use == literal) fprintf(stream, "\n - %s RPC literal messaging\n", (*op2)->protocol); else if ((*op2)->output->encodingStyle) fprintf(stream, "\n - %s RPC encodingStyle=\"%s\"\n", (*op2)->output->encodingStyle, (*op2)->protocol); else fprintf(stream, "\n - %s RPC encoded messaging\n", (*op2)->protocol); } if ((*op2)->action) { if (*(*op2)->action) fprintf(stream, "\n - Action: \"%s\"\n", (*op2)->action); } if ((*op2)->output) { if ((*op2)->output->action) fprintf(stream, "\n - Addressing output action: \"%s\"\n", (*op2)->output->action); } for (vector<Message*>::const_iterator outfault = (*op2)->outfault.begin(); outfault != (*op2)->outfault.end(); ++outfault) { if ((*outfault)->message) { if ((*outfault)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*outfault)->message->part.begin(); part != (*outfault)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*part).element); else if ((*part).name && (*part).type) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*part).name); } } else if ((*outfault)->message->name) fprintf(stream, "\n - SOAP Output Fault: %s\n", (*outfault)->name); if ((*outfault)->message->name && (*outfault)->action) fprintf(stream, " - SOAP Output Fault addressing action: \"%s\"\n", (*outfault)->action); } else if ((*outfault)->name) fprintf(stream, "\n - SOAP Output Fault: %s (literal)\n", (*outfault)->name); gen_policy(*this, (*outfault)->policy, "fault message", types); } if (!(*op2)->output->header.empty()) fprintf(stream, "\n - Response message has mandatory header part(s) (see @ref SOAP_ENV__Header):\n"); for (vector<soap__header>::const_iterator outputheader = (*op2)->output->header.begin(); outputheader != (*op2)->output->header.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } if ((*op2)->output->multipartRelated) { int k = 2; fprintf(stream, "\n - Response message MIME multipart/related attachments:\n"); for (vector<mime__part>::const_iterator part = (*op2)->output->multipartRelated->part.begin(); part != (*op2)->output->multipartRelated->part.end(); ++part) { if ((*part).soap__body_) { fprintf(stream, " -# MIME attachment with SOAP Body and mandatory header part(s):\n"); for (vector<soap__header>::const_iterator header = (*part).soap__header_.begin(); header != (*part).soap__header_.end(); ++header) { if ((*header).part) { if ((*header).use == encoded && (*header).namespace_) fprintf(stream, " - %s\n", types.aname(NULL, (*header).namespace_, (*header).part)); else if ((*header).partPtr() && (*header).partPtr()->element) fprintf(stream, " - %s\n", types.aname(NULL, NULL, (*header).partPtr()->element)); } } } else { fprintf(stream, " -# MIME attachment %d:\n", k++); for (vector<mime__content>::const_iterator content = (*part).content.begin(); content != (*part).content.end(); ++content) { fprintf(stream, " -"); if ((*content).part) { fprintf(stream, " part=\""); text((*content).part); fprintf(stream, "\""); } if ((*content).type) { fprintf(stream, " type=\""); text((*content).type); fprintf(stream, "\""); } fprintf(stream, "\n"); } } } } if ((*op2)->output->layout) fprintf(stream, "\n - Response message has DIME attachments in compliance with %s\n", (*op2)->output->layout); fprintf(stream, "\nC stub function (defined in soapClient.c[pp] generated by soapcpp2):\n@code\n int soap_call_%s(\n 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\n // parameters:", method_name); (*op2)->output->generate(types, ",", false, false, false, false); fprintf(stream, "\n );\n@endcode\n\nC server function (called from the service dispatcher defined in soapServer.c[pp]):\n@code\n int %s(\n struct soap *soap,\n // parameters:", method_name); (*op2)->output->generate(types, ",", false, false, false, false); fprintf(stream, "\n );\n@endcode\n\n"); if (!cflag) { fprintf(stream, "C++ proxy class (defined in soap%sProxy.h):\n", name); fprintf(stream, "@code\n class %sProxy;\n@endcode\n", name); fprintf(stream, "Important: use soapcpp2 option '-j' (or '-i') to generate greatly improved and easy-to-use proxy classes;\n\n"); fprintf(stream, "C++ service class (defined in soap%sService.h):\n", name); fprintf(stream, "@code\n class %sService;\n@endcode\n", name); fprintf(stream, "Important: use soapcpp2 option '-j' (or '-i') to generate greatly improved and easy-to-use service classes;\n\n"); } fprintf(stream, "*/\n\n"); (*op2)->generate(types, *this); } } gen_policy_enablers(*this); } void Service::add_import(const char *s) { if (find_if(imports.begin(), imports.end(), eqstr(s)) == imports.end()) imports.push_back(s); } void Service::del_import(const char *s) { VectorOfString::iterator i = find_if(imports.begin(), imports.end(), eqstr(s)); if (i != imports.end()) imports.erase(i); } //////////////////////////////////////////////////////////////////////////////// // // Operation methods // //////////////////////////////////////////////////////////////////////////////// void Operation::generate(Types &types, Service &service) { bool flag = false, anonymous = ((style != document) && parameterOrder != NULL); const char *method_name = NULL; if (output) { if (style == document) flag = (output->element || (output->message && output->message->part.size() == 1)); else if (!wflag) flag = (output->element || (output->message && output->use == encoded && output->message->part.size() == 1 && !(*output->message->part.begin()).simpleTypePtr() && !(*output->message->part.begin()).complexTypePtr())); if (flag && input && input->message && (*output->message->part.begin()).element) for (vector<wsdl__part>::const_iterator part = input->message->part.begin(); part != input->message->part.end(); ++part) if ((*part).element && !strcmp((*part).element, (*output->message->part.begin()).element)) flag = false; } if (output && output_name && bflag) // (output && (!input || bflag)) { if (input) { method_name = strstr(output_name + 1, "__"); if (method_name) method_name += 2; else method_name = output_name; } else { method_name = strstr(input_name + 1, "__"); if (method_name) method_name += 2; else method_name = input_name; } if (protocol) fprintf(stream, serviceformat, prefix, "method-protocol", method_name, protocol); if (output->content && output->content->type) fprintf(stream, serviceformat, prefix, "method-mime-type", method_name, output->content->type); else if (style == document) fprintf(stream, serviceformat, prefix, "method-style", method_name, "document"); else fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc"); if (output->use == literal) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal"); else if (output->encodingStyle) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, output->encodingStyle); else fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded"); if (output && output->action && *output->action) fprintf(stream, serviceformat, prefix, "method-action", method_name, output->action); else if (action) { if (*action) fprintf(stream, serviceformat, prefix, "method-action", method_name, action); else fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\""); } for (vector<Message*>::const_iterator message = outfault.begin(); message != outfault.end(); ++message) { if ((*message)->message) { if ((*message)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, NULL, (*part).element)); else if ((*part).type) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, (*message)->URI, (*part).name)); } } else { if ((*message)->message->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if ((*message)->action) fprintf(stream, serviceformat, prefix, "method-fault-action", method_name, (*message)->action); } else if ((*message)->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if (output->multipartRelated) { for (vector<mime__part>::const_iterator outputmime = output->multipartRelated->part.begin(); outputmime != output->multipartRelated->part.end(); ++outputmime) { for (vector<soap__header>::const_iterator outputheader = (*outputmime).soap__header_.begin(); outputheader != (*outputmime).soap__header_.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<mime__content>::const_iterator content = (*outputmime).content.begin(); content != (*outputmime).content.end(); ++content) if ((*content).type) fprintf(stream, serviceformat, prefix, "method-mime-type", method_name, (*content).type); } } // TODO: add headerfault directives for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<wsoap__header>::const_iterator outputwheader = output->wheader.begin(); outputwheader != output->wheader.end(); ++outputwheader) { if ((*outputwheader).element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputwheader).element)); } if (input) { fprintf(stream, "/// Operation response \"%s\" of operation \"%s\"\n", output_name, input_name); fprintf(stream, "int %s(", output_name); } else fprintf(stream, "int %s(", input_name); output->generate(types, ",", anonymous, true, false, false); fprintf(stream, "\n void\t///< One-way message: no output parameter\n);\n"); } if (!input && output && output_name) // (!input && output && bflag) { method_name = strstr(output_name + 1, "__"); if (method_name) method_name += 2; else method_name = output_name; if (protocol) fprintf(stream, serviceformat, prefix, "method-protocol", method_name, protocol); if (output->content && output->content->type) fprintf(stream, serviceformat, prefix, "method-mime-type", method_name, output->content->type); else if (style == document) fprintf(stream, serviceformat, prefix, "method-style", method_name, "document"); else fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc"); if (output->use == literal) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal"); else if (output->encodingStyle) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, output->encodingStyle); else fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded"); if (output && output->action && *output->action) fprintf(stream, serviceformat, prefix, "method-action", method_name, output->action); else if (action) { if (*action) fprintf(stream, serviceformat, prefix, "method-action", method_name, action); else fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\""); } for (vector<Message*>::const_iterator message = outfault.begin(); message != outfault.end(); ++message) { if ((*message)->message) { if ((*message)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, NULL, (*part).element)); else if ((*part).type) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, (*message)->URI, (*part).name)); } } else { if ((*message)->message->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if ((*message)->action) fprintf(stream, serviceformat, prefix, "method-fault-action", method_name, (*message)->action); } else if ((*message)->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if (output->multipartRelated) { for (vector<mime__part>::const_iterator outputmime = output->multipartRelated->part.begin(); outputmime != output->multipartRelated->part.end(); ++outputmime) { for (vector<soap__header>::const_iterator outputheader = (*outputmime).soap__header_.begin(); outputheader != (*outputmime).soap__header_.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<mime__content>::const_iterator content = (*outputmime).content.begin(); content != (*outputmime).content.end(); ++content) if ((*content).type) fprintf(stream, serviceformat, prefix, "method-mime-type", method_name, (*content).type); } } // TODO: add headerfault directives for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<wsoap__header>::const_iterator outputwheader = output->wheader.begin(); outputwheader != output->wheader.end(); ++outputwheader) { if ((*outputwheader).element) fprintf(stream, serviceformat, prefix, "method-header-part", method_name, types.aname(NULL, NULL, (*outputwheader).element)); } fprintf(stream, "int %s(", output_name); if (flag) { if (style == rpc && output->message && (*output->message->part.begin()).name) { fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*output->message->part.begin()).name), ""); fprintf(stream, "\t///< Output parameter"); } else output->generate(types, "", anonymous, true, true, false); } else { fprintf(stream, "\n struct %-28s%s", output_name, cflag ? "*" : "&"); fprintf(stream, "\t///< Output response struct parameter"); } fprintf(stream, "\n);\n"); } if (input && input_name) { method_name = strstr(input_name + 1, "__"); if (method_name) method_name += 2; else method_name = input_name; if (protocol) fprintf(stream, serviceformat, prefix, "method-protocol", method_name, protocol); if (input->content && input->content->type) fprintf(stream, serviceformat, prefix, "method-mime-type", method_name, input->content->type); else if (style == document) fprintf(stream, serviceformat, prefix, "method-style", method_name, "document"); else fprintf(stream, serviceformat, prefix, "method-style", method_name, "rpc"); if (output && output->content && output->content->type) fprintf(stream, serviceformat, prefix, "method-output-mime-type", method_name, output->content->type); if (!input || input->use == literal) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "literal"); else if (input->encodingStyle) fprintf(stream, serviceformat, prefix, "method-encoding", method_name, input->encodingStyle); else fprintf(stream, serviceformat, prefix, "method-encoding", method_name, "encoded"); if (output) { if (!input || input->use != output->use) { if (output->use == literal) fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "literal"); else if (output->encodingStyle) fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, output->encodingStyle); else fprintf(stream, serviceformat, prefix, "method-response-encoding", method_name, "encoded"); } if (style == rpc && (!input || (input->URI && output->URI && strcmp(input->URI, output->URI)))) fprintf(stream, schemaformat, types.nsprefix(NULL, output->URI), "namespace", output->URI); } if (input && input->action && *input->action) fprintf(stream, serviceformat, prefix, "method-input-action", method_name, input->action); else if (action) { if (*action) fprintf(stream, serviceformat, prefix, "method-action", method_name, action); else fprintf(stream, serviceformat, prefix, "method-action", method_name, "\"\""); } if (output && output->action && *output->action) fprintf(stream, serviceformat, prefix, "method-output-action", method_name, output->action); for (vector<Message*>::const_iterator message = outfault.begin(); message != outfault.end(); ++message) { if ((*message)->message) { if ((*message)->use == literal) { for (vector<wsdl__part>::const_iterator part = (*message)->message->part.begin(); part != (*message)->message->part.end(); ++part) { if ((*part).element) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, NULL, (*part).element)); else if ((*part).type) fprintf(stream, serviceformat, prefix, "method-fault", method_name, types.aname(NULL, (*message)->URI, (*part).name)); } } else { if ((*message)->message->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if ((*message)->action) fprintf(stream, serviceformat, prefix, "method-fault-action", method_name, (*message)->action); } else if ((*message)->name) fprintf(stream, serviceformat, prefix, "method-fault", method_name, (*message)->name); } if (input) { if (input->multipartRelated) { for (vector<mime__part>::const_iterator inputmime = input->multipartRelated->part.begin(); inputmime != input->multipartRelated->part.end(); ++inputmime) { for (vector<soap__header>::const_iterator inputheader = (*inputmime).soap__header_.begin(); inputheader != (*inputmime).soap__header_.end(); ++inputheader) { if ((*inputheader).part) { if ((*inputheader).use == encoded && (*inputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element)); } } for (vector<mime__content>::const_iterator content = (*inputmime).content.begin(); content != (*inputmime).content.end(); ++content) if ((*content).type) fprintf(stream, serviceformat, prefix, "method-input-mime-type", method_name, (*content).type); } } // TODO: add headerfault directives for (vector<soap__header>::const_iterator inputheader = input->header.begin(); inputheader != input->header.end(); ++inputheader) { if ((*inputheader).part) { if ((*inputheader).use == encoded && (*inputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, (*inputheader).namespace_, (*inputheader).part)); else if ((*inputheader).partPtr() && (*inputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputheader).partPtr()->element)); } } for (vector<wsoap__header>::const_iterator inputwheader = input->wheader.begin(); inputwheader != input->wheader.end(); ++inputwheader) { if ((*inputwheader).element) fprintf(stream, serviceformat, prefix, "method-input-header-part", method_name, types.aname(NULL, NULL, (*inputwheader).element)); } } if (output) { if (output->multipartRelated) { for (vector<mime__part>::const_iterator outputmime = output->multipartRelated->part.begin(); outputmime != output->multipartRelated->part.end(); ++outputmime) { for (vector<soap__header>::const_iterator outputheader = (*outputmime).soap__header_.begin(); outputheader != (*outputmime).soap__header_.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<mime__content>::const_iterator content = (*outputmime).content.begin(); content != (*outputmime).content.end(); ++content) if ((*content).type) fprintf(stream, serviceformat, prefix, "method-output-mime-type", method_name, (*content).type); } } for (vector<soap__header>::const_iterator outputheader = output->header.begin(); outputheader != output->header.end(); ++outputheader) { if ((*outputheader).part) { if ((*outputheader).use == encoded && (*outputheader).namespace_) fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, (*outputheader).namespace_, (*outputheader).part)); else if ((*outputheader).partPtr() && (*outputheader).partPtr()->element) fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputheader).partPtr()->element)); } } for (vector<wsoap__header>::const_iterator outputwheader = output->wheader.begin(); outputwheader != output->wheader.end(); ++outputwheader) { if ((*outputwheader).element) fprintf(stream, serviceformat, prefix, "method-output-header-part", method_name, types.aname(NULL, NULL, (*outputwheader).element)); } } if (input) fprintf(stream, "int %s(", input_name); else fprintf(stream, "int %s(", output_name); if (input) input->generate(types, ",", anonymous, true, false, false); if (output) { if (flag) { if (style == rpc && output->message && (*output->message->part.begin()).name) { fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.tname(NULL, NULL, (*output->message->part.begin()).type), cflag ? "*" : "&", types.aname(NULL, NULL, (*output->message->part.begin()).name), ""); fprintf(stream, "\t///< Output parameter"); } else output->generate(types, "", anonymous, true, true, false); } else { fprintf(stream, "\n struct %-28s%s", output_name, cflag ? "*" : "&"); fprintf(stream, "\t///< Output response struct parameter"); } fprintf(stream, "\n);\n"); } else fprintf(stream, "\n void\t///< One-way message: no output parameter\n);\n"); } } //////////////////////////////////////////////////////////////////////////////// // // Message methods // //////////////////////////////////////////////////////////////////////////////// void Message::generate(Types &types, const char *sep, bool anonymous, bool remark, bool response, bool optional) { if (message) { for (vector<wsdl__part>::const_iterator part = message->part.begin(); part != message->part.end(); ++part) { if (!(*part).name) fprintf(stderr, "\nError: no part name in message '%s'\n", message->name?message->name:""); else if (!body_parts || soap_tagsearch(body_parts, (*part).name)) { if (remark && (*part).documentation) comment("", (*part).name, "parameter", (*part).documentation); else fprintf(stream, "\n"); if ((*part).element) { if ((*part).elementPtr()) { const char *name, *type, *nameURI = NULL, *typeURI = NULL, *prefix = NULL; if (style == rpc && use == encoded) name = (*part).name; else { name = (*part).elementPtr()->name; if (style == document && (*part).elementPtr()->schemaPtr()) nameURI = (*part).elementPtr()->schemaPtr()->targetNamespace; } if ((*part).elementPtr()->type) type = (*part).elementPtr()->type; else { type = (*part).elementPtr()->name; prefix = "_"; if ((*part).elementPtr()->schemaPtr()) typeURI = (*part).elementPtr()->schemaPtr()->targetNamespace; } if ((*part).elementPtr()->xmime__expectedContentTypes) fprintf(stream, " /// MTOM attachment with content types %s\n", (*part).elementPtr()->xmime__expectedContentTypes); if (response) { const char *t = types.tname(prefix, typeURI, type); bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *")); fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, nameURI, name), sep); if (remark) fprintf(stream, "\t///< Output parameter"); } else { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(optional, prefix, typeURI, type), " ", types.aname(NULL, nameURI, name), sep); if (remark && *sep == ',') fprintf(stream, "\t///< Input parameter"); } } else { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(optional, NULL, NULL, (*part).element), " ", types.aname(NULL, NULL, (*part).element), sep); if (remark) fprintf(stream, "\t///< TODO: Check element type (imported type)"); } } else if ((*part).type) { if (response) { const char *t = types.tname(NULL, NULL, (*part).type); bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *")); fprintf(stream, anonymous ? anonformat : paraformat, t, flag ? " " : cflag ? "*" : "&", types.aname(NULL, NULL, (*part).name), sep); if (remark) fprintf(stream, "\t///< Output parameter"); } else { fprintf(stream, anonymous ? anonformat : paraformat, types.pname(optional, NULL, NULL, (*part).type), " ", types.aname(NULL, NULL, (*part).name), sep); if (remark && *sep == ',') fprintf(stream, "\t///< Input parameter"); } } else fprintf(stderr, "\nError: no wsdl:definitions/message/part/@type in part '%s'\n", (*part).name); } } } else if (element) // WSDL 2.0 { const char *prefix = NULL; const char *URI = NULL; const char *name = element->name; const char *type = element->type; if (!type) { type = name; prefix = "_"; } if (element->schemaPtr()) URI = element->schemaPtr()->targetNamespace; if (response) { const char *t = types.tname(prefix, URI, type); bool flag = (strchr(t, '*') && strcmp(t, "char*") && strcmp(t, "char *")); fprintf(stream, "\n"); fprintf(stream, paraformat, t, flag ? " " : cflag ? "*" : "&", anonymous ? "" : types.aname(NULL, URI, name), sep); if (remark) fprintf(stream, "\t///< Output parameter"); } else if (style == document || element->simpleTypePtr()) { // WSDL 2.0 document style fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.pname(optional, prefix, URI, type), " ", types.aname(NULL, URI, name), sep); if (remark && *sep == ',') fprintf(stream, "\t///< Input parameter"); } else if (element->complexTypePtr()) { // WSDL 2.0 RPC style xs__seqchoice *seq = element->complexTypePtr()->sequence; for (vector<xs__contents>::const_iterator i = seq->__contents.begin(); i != seq->__contents.end(); ++i) { if ((*i).__union == SOAP_UNION_xs__union_content_element) { name = (*i).__content.element->name; type = (*i).__content.element->type; if (!type) type = name; fprintf(stream, "\n"); fprintf(stream, anonymous ? anonformat : paraformat, types.pname(optional, prefix, URI, type), " ", types.aname(NULL, NULL, name), sep); if (remark && *sep == ',') fprintf(stream, "\t///< Input parameter"); } } } } } //////////////////////////////////////////////////////////////////////////////// // // Miscellaneous // //////////////////////////////////////////////////////////////////////////////// static const char *urienc(struct soap *soap, const char *uri) { const char *r, *s; char *t; size_t n = 0; if (!uri) return NULL; for (s = uri; *s; s++) if (!URI_CHAR(*s)) n++; if (!n) return uri; n = strlen(uri) + 2*n; r = t = (char*)soap_malloc(soap, n + 1); for (s = uri; *s; s++) { if (URI_CHAR(*s)) *t++ = *s; else { sprintf(t, "%%%.2x", *s); t += 3; } } *t = '\0'; return r; } static bool imported(const char *tag) { if (!tag || *tag != '"') return false; for (SetOfString::const_iterator u = exturis.begin(); u != exturis.end(); ++u) { size_t n = strlen(*u); if (!strncmp(*u, tag + 1, n) && tag[n+1] == '"') return true; } return false; } static void comment(const char *start, const char *middle, const char *end, const char *text) { if (text) { if (strchr(text, '\r') || strchr(text, '\n')) fprintf(stream, "\n/** %s %s %s documentation:\n%s\n*/\n\n", start, middle, end, text); else fprintf(stream, "\n/// %s %s %s: %s\n", start, middle, end, text); } } static void page(const char *page, const char *title, const char *text) { if (text) fprintf(stream, "\n@page %s%s \"%s\"\n", page, title, text); else fprintf(stream, "\n@page %s%s\n", page, title); } static void section(const char *section, const char *title, const char *text) { if (text) fprintf(stream, "\n@section %s%s \"%s\"\n", section, title, text); else fprintf(stream, "\n@section %s%s\n", section, title); } static void banner(const char *text) { int i; if (!text) return; fprintf(stream, "\n/"); for (i = 0; i < 78; i++) fputc('*', stream); fprintf(stream, "\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", text, ""); for (i = 0; i < 78; i++) fputc('*', stream); fprintf(stream, "/\n\n"); if (vflag) fprintf(stderr, "\n----<< %s >>----\n\n", text); } static void banner(const char *text1, const char *text2) { int i; if (!text1) return; fprintf(stream, "\n/"); for (i = 0; i < 78; i++) fputc('*', stream); if (text2) fprintf(stream, "\\\n *%76s*\n * %-75s*\n * %-73s*\n *%76s*\n\\", "", text1, text2, ""); else fprintf(stream, "\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", text1, ""); for (i = 0; i < 78; i++) fputc('*', stream); fprintf(stream, "/\n\n"); if (vflag) fprintf(stderr, "\n----<< %s: %s >>----\n\n", text1, text2?text2:""); } static void ident() { time_t t = time(NULL), *p = &t; char tmp[256]; int i; strftime(tmp, 256, "%Y-%m-%d %H:%M:%S GMT", gmtime(p)); fprintf(stream, "/* %s\n Generated by wsdl2h " WSDL2H_VERSION " from ", outfile?outfile:""); if (infiles) { for (i = 0; i < infiles; i++) fprintf(stream, "%s ", infile[i]); } else fprintf(stream, "(stdin) "); fprintf(stream, "and %s\n %s\n\n DO NOT INCLUDE THIS FILE DIRECTLY INTO YOUR PROJECT BUILDS\n USE THE soapcpp2-GENERATED SOURCE CODE FILES FOR YOUR PROJECT BUILDS\n\n gSOAP XML Web services tools.\n Copyright (C) 2000-2013 Robert van Engelen, Genivia Inc. All Rights Reserved.\n Part of this software is released under one of the following licenses:\n GPL or Genivia's license for commercial use.\n*/\n\n", mapfile, tmp); } void text(const char *text) { const char *s; if (!text) return; size_t k = 0; for (s = text; *s; s++, k++) { switch (*s) { case '\n': if (k) { fputc('\n', stream); k = 0; } break; case '\t': k = 8 * ((k + 8) / 8) - 1; fputc('\t', stream); break; case '/': fputc(*s, stream); if (s[1] == '*') fputc(' ', stream); break; case '*': fputc(*s, stream); if (s[1] == '/') fputc(' ', stream); break; case ' ': if (k >= 79) { fputc('\n', stream); k = 0; } else fputc(' ', stream); break; default: if (*s >= 32) fputc(*s, stream); } } if (k) fputc('\n', stream); } //////////////////////////////////////////////////////////////////////////////// // // WS-Policy // //////////////////////////////////////////////////////////////////////////////// static void gen_policy(Service& service, const vector<const wsp__Policy*>& policy, const char *text, Types& types) { if (!policy.empty()) { fprintf(stream, "\n - WS-Policy applicable to the %s:\n", text); for (vector<const wsp__Policy*>::const_iterator p = policy.begin(); p != policy.end(); ++p) if (*p) (*p)->generate(service, types, 0); } } static void gen_policy_enablers(const Service& service) { fprintf(stream, "\n/**\n"); page(service.name, " Binding", service.name); section(service.name, "_policy_enablers Policy Enablers of Binding ", service.name); fprintf(stream, "\nBased on policies, this service imports"); for (VectorOfString::const_iterator i = service.imports.begin(); i != service.imports.end(); ++i) fprintf(stream, " %s", *i); fprintf(stream, "\n\n - WS-Policy reminders and enablers:\n"); fprintf(stream, " - WS-Addressing 1.0 (2005/08, accepts 2004/08):\n\t@code\n\t#import \"wsa5.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsaapi.h\"\n\tsoap_register_plugin(soap, soap_wsa); // register the wsa plugin in your code\n\t// See the user guide gsoap/doc/wsa/html/index.html\n\t@endcode\n"); fprintf(stream, " - WS-Addressing (2004/08):\n\t@code\n\t#import \"wsa.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsaapi.h\"\n\tsoap_register_plugin(soap, soap_wsa); // register the wsa plugin in your code\n\t// See the user guide gsoap/doc/wsa/html/index.html\n\t@endcode\n"); fprintf(stream, " - WS-ReliableMessaging 1.0:\n\t@code\n\t#import \"wsrm5.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsrmapi.h\"\n\tsoap_register_plugin(soap, soap_wsa); // register the wsa plugin in your code\n\tsoap_register_plugin(soap, soap_wsrm); // register the wsrm plugin in your code\n\t// See the user guide gsoap/doc/wsrm/html/index.html\n\t@endcode\n"); fprintf(stream, " - WS-ReliableMessaging 1.1:\n\t@code\n\t#import \"wsrm.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsrmapi.h\"\n\tsoap_register_plugin(soap, soap_wsa); // register the wsa plugin in your code\n\tsoap_register_plugin(soap, soap_wsrm); // register the wsrm plugin in your code\n\t// See the user guide gsoap/doc/wsrm/html/index.html\n\t@endcode\n"); fprintf(stream, " - WS-Security (SOAP Message Security) 1.0 (accepts 1.1):\n\t@code\n\t#import \"wsse.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsseapi.h\"\n\tsoap_register_plugin(soap, soap_wsse); // register the wsse plugin in your code\n\t// See the user guide gsoap/doc/wsse/html/index.html\n\t@endcode\n"); fprintf(stream, " - WS-Security (SOAP Message Security) 1.1 (accepts 1.0):\n\t@code\n\t#import \"wsse11.h\" // to be added to this header file for the soapcpp2 build step\n\t@endcode\n\t@code\n\t#include \"plugin/wsseapi.h\"\n\tsoap_register_plugin(soap, soap_wsse); // register the wsse plugin in your code\n\t// See the user guide gsoap/doc/wsse/html/index.html\n\t@endcode\n"); fprintf(stream, " - HTTP Digest Authentication:\n\t@code\n\t#include \"plugin/httpda.h\"\n\tsoap_register_plugin(soap, soap_http_da); // register the HTTP DA plugin in your code\n\t// See the user guide gsoap/doc/httpda/html/index.html\n\t@endcode\n"); fprintf(stream, "*/\n\n"); for (VectorOfString::const_iterator i = service.imports.begin(); i != service.imports.end(); ++i) fprintf(stream, "#import \"%s\"\n", *i); }