blob: f80e157a73b123de1446090721fcd57c1425cbe2 [file] [log] [blame]
/*
wsdl.cpp
WSDL 1.1 binding schema implementation
--------------------------------------------------------------------------------
gSOAP XML Web services tools
Copyright (C) 2001-2006, Robert van Engelen, Genivia Inc. All Rights Reserved.
This software is released under one of the following two 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
--------------------------------------------------------------------------------
*/
#include "wsdlH.h"
using namespace std;
const char *qname_token(const char *QName, const char *URI)
{ if (QName && URI && *QName == '"') // QNames are stored in the format "URI":name, unless the URI is in the nsmap
{ int n = strlen(URI);
if (!strncmp(QName + 1, URI, n) && QName[n + 1] == '"')
return QName + n + 3;
}
else if (QName && (!URI || !*URI) && *QName != '"' && !strchr(QName, ':')) // Empty namespace
return QName;
return NULL;
}
int is_builtin_qname(const char *QName)
{ if (iflag)
return 1;
if (QName)
{ if (*QName != '"')
return 1; // if the QName does not start with a ", it must be in the nsmap
const char *s = strchr(QName + 1, '"');
if (s)
{ size_t n = s - QName - 1;
for (SetOfString::const_iterator i = exturis.begin(); i != exturis.end(); ++i)
if (strlen(*i) == n && !strncmp(QName + 1, *i, n))
return 1; // QName is in exturis
}
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
//
// wsdl
//
////////////////////////////////////////////////////////////////////////////////
int warn_ignore(struct soap*, const char*);
int show_ignore(struct soap*, const char*);
wsdl__definitions::wsdl__definitions()
{ soap = soap_new1(SOAP_XML_TREE | SOAP_C_UTFSTRING);
#ifdef WITH_OPENSSL
soap_ssl_client_context(soap, SOAP_SSL_NO_AUTHENTICATION, NULL, NULL, NULL, NULL, NULL);
#endif
#ifdef WITH_NONAMESPACES
soap_set_namespaces(soap, namespaces);
#endif
soap_default(soap);
if (vflag)
soap->fignore = show_ignore;
else
soap->fignore = warn_ignore;
soap->encodingStyle = NULL;
soap->proxy_host = proxy_host;
soap->proxy_port = proxy_port;
name = NULL;
targetNamespace = "";
documentation = NULL;
types = NULL;
updated = false;
redirs = 0;
}
wsdl__definitions::wsdl__definitions(struct soap *copy, const char *cwd, const char *loc)
{ soap = soap_copy(copy);
soap->socket = SOAP_INVALID_SOCKET;
soap->recvfd = 0;
soap->sendfd = 1;
strcpy(soap->host, copy->host);
soap_default(soap);
soap->fignore = warn_ignore;
soap->encodingStyle = NULL;
updated = false;
redirs = 0;
read(cwd, loc);
}
wsdl__definitions::~wsdl__definitions()
{ soap_destroy(soap);
soap_end(soap);
soap_done(soap);
free(soap);
}
int wsdl__definitions::get(struct soap *soap)
{ return preprocess();
}
int wsdl__definitions::read(int num, char **loc)
{ if (num <= 0)
return read((const char*)NULL, (const char*)NULL);
if (num == 1)
return read((const char*)NULL, loc[0]);
wsdl__import im;
im.namespace_ = NULL;
for (int i = 0; i < num; i++)
{ im.location = loc[i];
import.push_back(im);
}
return preprocess();
}
int wsdl__definitions::read(const char *cwd, const char *loc)
{ if (vflag)
fprintf(stderr, "Opening WSDL/XSD '%s' from '%s'\n", loc?loc:"", cwd?cwd:"");
if (loc)
{ if (!strncmp(loc, "http://", 7) || !strncmp(loc, "https://", 8))
{ fprintf(stderr, "Connecting to '%s' to retrieve WSDL/XSD... ", loc);
location = soap_strdup(soap, loc);
if (soap_connect_command(soap, SOAP_GET, location, NULL))
{ fprintf(stderr, "connection failed\n");
soap_print_fault(soap, stderr);
exit(1);
}
fprintf(stderr, "connected, receiving...\n");
}
else if (cwd && (!strncmp(cwd, "http://", 7) || !strncmp(cwd, "https://", 8)))
{ char *s;
location = (char*)soap_malloc(soap, strlen(cwd) + strlen(loc) + 2);
strcpy(location, cwd);
s = strrchr(location, '/');
if (s)
*s = '\0';
strcat(location, "/");
strcat(location, loc);
fprintf(stderr, "Connecting to '%s' to retrieve relative '%s' WSDL/XSD... ", location, loc);
if (soap_connect_command(soap, SOAP_GET, location, NULL))
{ fprintf(stderr, "connection failed\n");
exit(1);
}
fprintf(stderr, "connected, receiving...\n");
}
else
{ soap->recvfd = open(loc, O_RDONLY, 0);
if (soap->recvfd < 0)
{ if (cwd)
{ char *s;
location = (char*)soap_malloc(soap, strlen(cwd) + strlen(loc) + 2);
strcpy(location, cwd);
s = strrchr(location, '/');
if (s)
*s = '\0';
strcat(location, "/");
strcat(location, loc);
soap->recvfd = open(location, O_RDONLY, 0);
}
if (soap->recvfd < 0 && import_path)
{ location = (char*)soap_malloc(soap, strlen(import_path) + strlen(loc) + 2);
strcpy(location, import_path);
strcat(location, "/");
strcat(location, loc);
soap->recvfd = open(location, O_RDONLY, 0);
}
if (soap->recvfd < 0)
{ fprintf(stderr, "Cannot open '%s'\n", loc);
exit(1);
}
}
else
location = soap_strdup(soap, loc);
fprintf(stderr, "Reading file '%s'\n", location);
}
}
if (!soap_begin_recv(soap))
this->soap_in(soap, "wsdl:definitions", NULL);
if (soap->error)
{ // deal with sloppy WSDLs that import schemas at the top level rather than importing them in <types>
if (soap->error == SOAP_TAG_MISMATCH && soap->level == 0)
{ soap_retry(soap);
xs__schema *schema = new xs__schema(soap);
schema->soap_in(soap, "xs:schema", NULL);
if (soap->error)
{ fprintf(stderr, "An error occurred while parsing WSDL or XSD from '%s'\n", loc?loc:"");
soap_print_fault(soap, stderr);
soap_print_fault_location(soap, stderr);
exit(1);
}
name = NULL;
targetNamespace = schema->targetNamespace;
if (vflag)
cerr << "Found schema " << (targetNamespace?targetNamespace:"") << " when expecting WSDL" << endl;
types = new wsdl__types();
types->documentation = NULL;
types->xs__schema_.push_back(schema);
}
else if ((soap->error >= 301 && soap->error <= 303) || soap->error == 307) // HTTP redirect, socket was closed
{ int r = SOAP_ERR;
fprintf(stderr, "Redirected to '%s'\n", soap->endpoint);
if (redirs++ < 10)
r = read(cwd, soap->endpoint);
else
fprintf(stderr, "Max redirects exceeded\n");
redirs--;
return r;
}
else
{ fprintf(stderr, "An error occurred while parsing WSDL from '%s'\n", loc?loc:"");
soap_print_fault(soap, stderr);
soap_print_fault_location(soap, stderr);
exit(1);
}
}
if (vflag)
fprintf(stderr, "Done reading '%s'\n", loc);
soap_end_recv(soap);
if (soap->recvfd >= 0)
{ close(soap->recvfd);
soap->recvfd = -1;
}
else
soap_closesock(soap);
return SOAP_OK;
}
int wsdl__definitions::preprocess()
{ // process import
for (vector<wsdl__import>::iterator im1 = import.begin(); im1 != import.end(); ++im1)
(*im1).preprocess(*this);
// merge nested imported WSDLs into single import list
again:
for (vector<wsdl__import>::iterator im2 = import.begin(); im2 != import.end(); ++im2)
{ if ((*im2).definitionsPtr())
{ for (vector<wsdl__import>::iterator i = (*im2).definitionsPtr()->import.begin(); i != (*im2).definitionsPtr()->import.end(); ++i)
{ bool found = false;
for (vector<wsdl__import>::iterator j = import.begin(); j != import.end(); ++j)
{ if (((*i).definitionsPtr() == (*j).definitionsPtr())
|| ((*i).location && (*j).location && !strcmp((*i).location, (*j).location)))
{ found = true;
break;
}
}
if (!found)
{ if (vflag)
cerr << "Adding imported WSDL " << ((*i).location?(*i).location:"") << " to " << (name?name:"") << " namespace " << (targetNamespace?targetNamespace:"") << endl;
import.push_back(*i);
goto again;
}
}
}
}
// merge <types>
for (vector<wsdl__import>::iterator im3 = import.begin(); im3 != import.end(); ++im3)
{ if ((*im3).definitionsPtr() && (*im3).definitionsPtr()->types)
{ if (!types)
{ types = soap_new_wsdl__types(soap, -1);
types->soap_default(soap);
}
// merge <types>, check for duplicates, add namespaces for sloppy imports
for (vector<xs__schema*>::const_iterator i = (*im3).definitionsPtr()->types->xs__schema_.begin(); i != (*im3).definitionsPtr()->types->xs__schema_.end(); ++i)
{ bool found = false;
if (!(*i)->targetNamespace)
cerr << "Warning: Schema without namespace, assigning " << (targetNamespace?targetNamespace:"") << endl;
if (!(*i)->targetNamespace)
(*i)->targetNamespace = targetNamespace;
else
{ for (vector<xs__schema*>::const_iterator j = types->xs__schema_.begin(); j != types->xs__schema_.end(); ++j)
{ if ((*j)->targetNamespace && !strcmp((*i)->targetNamespace, (*j)->targetNamespace))
{ found = true;
break;
}
}
}
if (!found)
{ if (vflag)
cerr << "Adding schema " << ((*i)->targetNamespace?(*i)->targetNamespace:"") << " to types in WSDL " << (name?name:"") << " namespace " << (targetNamespace?targetNamespace:"") << endl;
types->xs__schema_.push_back(*i);
}
}
}
}
if (types)
types->preprocess(*this);
return SOAP_OK;
}
int wsdl__definitions::traverse()
{ if (vflag)
cerr << "Analyzing wsdl definitions '" << (name?name:"") << "' targetNamespace " << (targetNamespace?targetNamespace:"?") << endl;
if (updated)
return SOAP_OK;
updated = true;
if (!targetNamespace)
{ if (vflag)
fprintf(stderr, "Warning: WSDL '%s' has no targetNamespace\n", name?name:"");
targetNamespace = "";
}
// process import first
for (vector<wsdl__import>::iterator im = import.begin(); im != import.end(); ++im)
(*im).traverse(*this);
// then process the types
if (types)
types->traverse(*this);
// process messages before portTypes
for (vector<wsdl__message>::iterator mg = message.begin(); mg != message.end(); ++mg)
(*mg).traverse(*this);
// process portTypes before bindings
for (vector<wsdl__portType>::iterator pt = portType.begin(); pt != portType.end(); ++pt)
(*pt).traverse(*this);
// process bindings
for (vector<wsdl__binding>::iterator bg = binding.begin(); bg != binding.end(); ++bg)
(*bg).traverse(*this);
// process services
for (vector<wsdl__service>::iterator sv = service.begin(); sv != service.end(); ++sv)
(*sv).traverse(*this);
if (vflag)
cerr << "End of wsdl definitions '" << (name?name:"") << "' targetNamespace " << (targetNamespace?targetNamespace:"?") << endl;
return SOAP_OK;
}
const char *wsdl__definitions::sourceLocation()
{ return location;
}
int wsdl__definitions::error()
{ return soap->error;
}
void wsdl__definitions::print_fault()
{ soap_print_fault(soap, stderr);
soap_print_fault_location(soap, stderr);
}
void wsdl__definitions::builtinType(const char *type)
{ builtinTypeSet.insert(type);
}
void wsdl__definitions::builtinTypes(const SetOfString& types)
{ for (SetOfString::const_iterator tp = types.begin(); tp != types.end(); ++tp)
builtinTypeSet.insert(*tp);
}
void wsdl__definitions::builtinElement(const char *element)
{ builtinElementSet.insert(element);
}
void wsdl__definitions::builtinElements(const SetOfString& elements)
{ for (SetOfString::const_iterator el = elements.begin(); el != elements.end(); ++el)
builtinElementSet.insert(*el);
}
void wsdl__definitions::builtinAttribute(const char *attribute)
{ builtinAttributeSet.insert(attribute);
}
void wsdl__definitions::builtinAttributes(const SetOfString& attributes)
{ for (SetOfString::const_iterator at = attributes.begin(); at != attributes.end(); ++at)
builtinAttributeSet.insert(*at);
}
const SetOfString& wsdl__definitions::builtinTypes() const
{ return builtinTypeSet;
}
const SetOfString& wsdl__definitions::builtinElements() const
{ return builtinElementSet;
}
const SetOfString& wsdl__definitions::builtinAttributes() const
{ return builtinAttributeSet;
}
int wsdl__service::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl service " << (name?name:"") << endl;
// process ports
for (vector<wsdl__port>::iterator i = port.begin(); i != port.end(); ++i)
(*i).traverse(definitions);
return SOAP_OK;
}
wsdl__port::wsdl__port()
{ bindingRef = NULL;
}
int wsdl__port::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl port" << endl;
// search binding name
const char *token = qname_token(binding, definitions.targetNamespace);
bindingRef = NULL;
if (token)
{ for (vector<wsdl__binding>::iterator binding = definitions.binding.begin(); binding != definitions.binding.end(); ++binding)
{ if ((*binding).name && !strcmp((*binding).name, token))
{ bindingRef = &(*binding);
if (vflag)
cerr << "Found port " << (name?name:"") << " binding " << (token?token:"") << endl;
break;
}
}
}
else
{ for (vector<wsdl__import>::iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
{ wsdl__definitions *importdefinitions = (*import).definitionsPtr();
if (importdefinitions)
{ token = qname_token(binding, importdefinitions->targetNamespace);
if (token)
{ for (vector<wsdl__binding>::iterator binding = importdefinitions->binding.begin(); binding != importdefinitions->binding.end(); ++binding)
{ if ((*binding).name && !strcmp((*binding).name, token))
{ bindingRef = &(*binding);
if (vflag)
cerr << "Found port " << (name?name:"") << " binding " << (token?token:"") << endl;
break;
}
}
}
}
}
}
if (!bindingRef)
cerr << "Warning: no port '" << (name?name:"") << "' binding '" << (binding?binding:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
return SOAP_OK;
}
void wsdl__port::bindingPtr(wsdl__binding *binding)
{ bindingRef = binding;
}
wsdl__binding *wsdl__port::bindingPtr() const
{ return bindingRef;
}
wsdl__binding::wsdl__binding()
{ portTypeRef = NULL;
}
int wsdl__binding::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl bindings" << endl;
const char *token = qname_token(type, definitions.targetNamespace);
portTypeRef = NULL;
if (token)
{ for (vector<wsdl__portType>::iterator portType = definitions.portType.begin(); portType != definitions.portType.end(); ++portType)
{ if ((*portType).name && !strcmp((*portType).name, token))
{ portTypeRef = &(*portType);
if (vflag)
cerr << "Found binding " << (name?name:"") << " portType " << (token?token:"") << endl;
break;
}
}
}
else
{ for (vector<wsdl__import>::iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
{ wsdl__definitions *importdefinitions = (*import).definitionsPtr();
if (importdefinitions)
{ token = qname_token(type, importdefinitions->targetNamespace);
if (token)
{ for (vector<wsdl__portType>::iterator portType = importdefinitions->portType.begin(); portType != importdefinitions->portType.end(); ++portType)
{ if ((*portType).name && !strcmp((*portType).name, token))
{ portTypeRef = &(*portType);
if (vflag)
cerr << "Found binding " << (name?name:"") << " portType " << (token?token:"") << endl;
break;
}
}
}
}
}
}
if (!portTypeRef)
cerr << "Warning: no binding '" << (name?name:"") << "' portType '" << (type?type:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
for (vector<wsdl__binding_operation>::iterator i = operation.begin(); i != operation.end(); ++i)
(*i).traverse(definitions, portTypeRef);
return SOAP_OK;
}
void wsdl__binding::portTypePtr(wsdl__portType *portType)
{ portTypeRef = portType;
}
wsdl__portType *wsdl__binding::portTypePtr() const
{ return portTypeRef;
}
wsdl__binding_operation::wsdl__binding_operation()
{ operationRef = NULL;
}
int wsdl__binding_operation::traverse(wsdl__definitions& definitions, wsdl__portType *portTypeRef)
{ if (vflag)
cerr << "Analyzing wsdl binding operation" << endl;
if (input)
input->traverse(definitions);
if (output)
output->traverse(definitions);
for (vector<wsdl__ext_fault>::iterator i = fault.begin(); i != fault.end(); ++i)
(*i).traverse(definitions);
operationRef = NULL;
if (name && portTypeRef)
{ for (vector<wsdl__operation>::iterator i = portTypeRef->operation.begin(); i != portTypeRef->operation.end(); ++i)
{ if ((*i).name && !strcmp((*i).name, name))
{ operationRef = &(*i);
if (vflag)
cerr << "Found operation " << (name?name:"") << endl;
break;
}
}
}
if (!operationRef)
cerr << "Warning: no operation '" << (name?name:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
else
{ for (vector<wsdl__ext_fault>::iterator i = fault.begin(); i != fault.end(); ++i)
{ if ((*i).name)
{ for (vector<wsdl__fault>::iterator j = operationRef->fault.begin(); j != operationRef->fault.end(); ++j)
{ if ((*j).name && !strcmp((*j).name, (*i).name))
{ (*i).messagePtr((*j).messagePtr());
if (vflag)
cerr << "Found fault " << ((*j).name?(*j).name:"") << " message " << endl;
break;
}
}
}
else if ((*i).soap__fault_ && (*i).soap__fault_->name) // try the soap:fault name, this is not elegant, but neither is WSDL 1.1
{ for (vector<wsdl__fault>::iterator j = operationRef->fault.begin(); j != operationRef->fault.end(); ++j)
{ if ((*j).name && !strcmp((*j).name, (*i).soap__fault_->name))
{ (*i).messagePtr((*j).messagePtr());
if (vflag)
cerr << "Found fault " << ((*j).name?(*j).name:"") << " message " << endl;
break;
}
}
}
if (!(*i).messagePtr())
cerr << "Warning: no soap:fault message in WSDL definitions '" << (definitions.name?definitions.name:"") << "' operation '" << (name?name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
}
}
return SOAP_OK;
}
void wsdl__binding_operation::operationPtr(wsdl__operation *operation)
{ operationRef = operation;
}
wsdl__operation *wsdl__binding_operation::operationPtr() const
{ return operationRef;
}
int wsdl__ext_input::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl ext input" << endl;
for (vector<soap__header>::iterator hd = soap__header_.begin(); hd != soap__header_.end(); ++hd)
(*hd).traverse(definitions);
if (mime__multipartRelated_)
mime__multipartRelated_->traverse(definitions);
return SOAP_OK;
}
int wsdl__ext_output::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl ext output" << endl;
for (vector<soap__header>::iterator hd = soap__header_.begin(); hd != soap__header_.end(); ++hd)
(*hd).traverse(definitions);
if (mime__multipartRelated_)
mime__multipartRelated_->traverse(definitions);
return SOAP_OK;
}
wsdl__ext_fault::wsdl__ext_fault()
{ messageRef = NULL;
}
int wsdl__ext_fault::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl ext fault" << endl;
messageRef = NULL;
return SOAP_OK;
}
void wsdl__ext_fault::messagePtr(wsdl__message *message)
{ messageRef = message;
}
wsdl__message *wsdl__ext_fault::messagePtr() const
{ return messageRef;
}
int wsdl__portType::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl portType" << endl;
for (vector<wsdl__operation>::iterator i = operation.begin(); i != operation.end(); ++i)
(*i).traverse(definitions);
return SOAP_OK;
}
int wsdl__operation::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl operation" << endl;
if (input)
input->traverse(definitions);
if (output)
output->traverse(definitions);
for (vector<wsdl__fault>::iterator i = fault.begin(); i != fault.end(); ++i)
(*i).traverse(definitions);
return SOAP_OK;
}
wsdl__input::wsdl__input()
{ messageRef = NULL;
}
int wsdl__input::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl input" << endl;
const char *token = qname_token(message, definitions.targetNamespace);
messageRef = NULL;
if (token)
{ for (vector<wsdl__message>::iterator message = definitions.message.begin(); message != definitions.message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found input " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
else
{ for (vector<wsdl__import>::iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
{ wsdl__definitions *importdefinitions = (*import).definitionsPtr();
if (importdefinitions)
{ token = qname_token(message, importdefinitions->targetNamespace);
if (token)
{ for (vector<wsdl__message>::iterator message = importdefinitions->message.begin(); message != importdefinitions->message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found input " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
}
}
}
if (!messageRef)
cerr << "Warning: no input '" << (name?name:"") << "' message '" << (message?message:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
return SOAP_OK;
}
void wsdl__input::messagePtr(wsdl__message *message)
{ messageRef = message;
}
wsdl__message *wsdl__input::messagePtr() const
{ return messageRef;
}
wsdl__output::wsdl__output()
{ messageRef = NULL;
}
int wsdl__output::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl output" << endl;
const char *token = qname_token(message, definitions.targetNamespace);
messageRef = NULL;
if (token)
{ for (vector<wsdl__message>::iterator message = definitions.message.begin(); message != definitions.message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found output " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
else
{ for (vector<wsdl__import>::iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
{ wsdl__definitions *importdefinitions = (*import).definitionsPtr();
if (importdefinitions)
{ token = qname_token(message, importdefinitions->targetNamespace);
if (token)
{ for (vector<wsdl__message>::iterator message = importdefinitions->message.begin(); message != importdefinitions->message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found output " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
}
}
}
if (!messageRef)
cerr << "Warning: no output '" << (name?name:"") << "' message '" << (message?message:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
return SOAP_OK;
}
void wsdl__output::messagePtr(wsdl__message *message)
{ messageRef = message;
}
wsdl__message *wsdl__output::messagePtr() const
{ return messageRef;
}
wsdl__fault::wsdl__fault()
{ messageRef = NULL;
}
int wsdl__fault::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl fault" << endl;
const char *token = qname_token(message, definitions.targetNamespace);
messageRef = NULL;
if (token)
{ for (vector<wsdl__message>::iterator message = definitions.message.begin(); message != definitions.message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found fault " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
else
{ for (vector<wsdl__import>::iterator import = definitions.import.begin(); import != definitions.import.end(); ++import)
{ wsdl__definitions *importdefinitions = (*import).definitionsPtr();
if (importdefinitions)
{ token = qname_token(message, importdefinitions->targetNamespace);
if (token)
{ for (vector<wsdl__message>::iterator message = importdefinitions->message.begin(); message != importdefinitions->message.end(); ++message)
{ if ((*message).name && !strcmp((*message).name, token))
{ messageRef = &(*message);
if (vflag)
cerr << "Found output " << (name?name:"") << " message " << (token?token:"") << endl;
break;
}
}
}
}
}
}
if (!messageRef)
cerr << "Warning: no fault '" << (name?name:"") << "' message '" << (message?message:"") << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
return SOAP_OK;
}
void wsdl__fault::messagePtr(wsdl__message *message)
{ messageRef = message;
}
wsdl__message *wsdl__fault::messagePtr() const
{ return messageRef;
}
int wsdl__message::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl message" << endl;
for (vector<wsdl__part>::iterator i = part.begin(); i != part.end(); ++i)
(*i).traverse(definitions);
return SOAP_OK;
}
wsdl__part::wsdl__part()
{ elementRef = NULL;
simpleTypeRef = NULL;
complexTypeRef = NULL;
}
int wsdl__part::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl part" << endl;
elementRef = NULL;
simpleTypeRef = NULL;
complexTypeRef = NULL;
if (definitions.types)
{ for (vector<xs__schema*>::iterator schema = definitions.types->xs__schema_.begin(); schema != definitions.types->xs__schema_.end(); ++schema)
{ const char *token = qname_token(element, (*schema)->targetNamespace);
if (token)
{ for (vector<xs__element>::iterator element = (*schema)->element.begin(); element != (*schema)->element.end(); ++element)
{ if ((*element).name && !strcmp((*element).name, token))
{ elementRef = &(*element);
if (vflag)
cerr << "Found part " << (name?name:"") << " element " << (token?token:"") << endl;
break;
}
}
}
token = qname_token(type, (*schema)->targetNamespace);
if (token)
{ for (vector<xs__simpleType>::iterator simpleType = (*schema)->simpleType.begin(); simpleType != (*schema)->simpleType.end(); ++simpleType)
{ if ((*simpleType).name && !strcmp((*simpleType).name, token))
{ simpleTypeRef = &(*simpleType);
if (vflag)
cerr << "Found part " << (name?name:"") << " simpleType " << (token?token:"") << endl;
break;
}
}
}
token = qname_token(type, (*schema)->targetNamespace);
if (token)
{ for (vector<xs__complexType>::iterator complexType = (*schema)->complexType.begin(); complexType != (*schema)->complexType.end(); ++complexType)
{ if ((*complexType).name && !strcmp((*complexType).name, token))
{ complexTypeRef = &(*complexType);
if (vflag)
cerr << "Found part " << (name?name:"") << " complexType " << (token?token:"") << endl;
break;
}
}
}
}
}
if (!elementRef && !simpleTypeRef && !complexTypeRef)
{ if (element)
{ if (is_builtin_qname(element))
definitions.builtinElement(element);
else
cerr << "Warning: no part '" << (name?name:"") << "' element '" << element << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
}
else if (type)
{ if (is_builtin_qname(type))
definitions.builtinType(type);
else
cerr << "Warning: no part '" << (name?name:"") << "' type '" << type << "' in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
}
else
cerr << "Warning: no part '" << (name?name:"") << "' element or type in WSDL definitions '" << (definitions.name?definitions.name:"") << "' namespace " << (definitions.targetNamespace?definitions.targetNamespace:"") << endl;
}
return SOAP_OK;
}
void wsdl__part::elementPtr(xs__element *element)
{ elementRef = element;
}
void wsdl__part::simpleTypePtr(xs__simpleType *simpleType)
{ simpleTypeRef = simpleType;
}
void wsdl__part::complexTypePtr(xs__complexType *complexType)
{ complexTypeRef = complexType;
}
xs__element *wsdl__part::elementPtr() const
{ return elementRef;
}
xs__simpleType *wsdl__part::simpleTypePtr() const
{ return simpleTypeRef;
}
xs__complexType *wsdl__part::complexTypePtr() const
{ return complexTypeRef;
}
int wsdl__types::preprocess(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Preprocessing wsdl types" << endl;
// set the location of each schema in <types> to the WSDL's location
for (vector<xs__schema*>::iterator schema0 = xs__schema_.begin(); schema0 != xs__schema_.end(); ++schema0)
{ if (!(*schema0)->sourceLocation())
(*schema0)->sourceLocation(definitions.sourceLocation());
}
again:
// link imported schemas, need to repeat when <types> is extended with new imported schema (from inside another schema, etc.)
for (vector<xs__schema*>::iterator schema1 = xs__schema_.begin(); schema1 != xs__schema_.end(); ++schema1)
{ for (vector<xs__import>::iterator import = (*schema1)->import.begin(); import != (*schema1)->import.end(); ++import)
{ if ((*import).namespace_ && !(*import).schemaPtr())
{ for (vector<xs__schema*>::const_iterator schema2 = xs__schema_.begin(); schema2 != xs__schema_.end(); ++schema2)
{ if ((*schema2)->targetNamespace && !strcmp((*import).namespace_, (*schema2)->targetNamespace))
{ (*import).schemaPtr(*schema2);
break;
}
}
}
}
}
// if a schema is imported but not in <types> then get it
for (vector<xs__schema*>::iterator schema2 = xs__schema_.begin(); schema2 != xs__schema_.end(); ++schema2)
{ for (vector<xs__import>::iterator import = (*schema2)->import.begin(); import != (*schema2)->import.end(); ++import)
{ bool found = false;
if ((*import).namespace_)
{ if ((*import).schemaPtr())
found = true;
else
{ for (vector<xs__schema*>::const_iterator schema3 = xs__schema_.begin(); schema3 != xs__schema_.end(); ++schema3)
{ if ((*schema3)->targetNamespace && !strcmp((*import).namespace_, (*schema3)->targetNamespace))
{ found = true;
break;
}
}
}
if (!found)
{ for (SetOfString::const_iterator i = exturis.begin(); i != exturis.end(); ++i)
{ if (!soap_tag_cmp((*import).namespace_, *i))
{ found = true;
break;
}
}
}
}
if (!found && !iflag) // don't import any of the schemas in the .nsmap table (or when -i option is used)
{ xs__schema *importschema;
importschema = (*import).schemaPtr();
if (!importschema)
{ const char *s = (*import).schemaLocation;
if (!s)
s = (*import).namespace_;
importschema = new xs__schema(definitions.soap, (*schema2)->sourceLocation(), s);
if (!importschema->targetNamespace)
importschema->targetNamespace = (*import).namespace_;
else if ((*import).namespace_ && strcmp(importschema->targetNamespace, (*import).namespace_))
cerr << "Schema import namespace " << ((*import).namespace_?(*import).namespace_:"") << " does not correspond to imported targetNamespace " << importschema->targetNamespace << endl;
}
for (vector<xs__schema*>::const_iterator schema3 = xs__schema_.begin(); schema3 != xs__schema_.end(); ++schema3)
{ if ((*schema3)->targetNamespace && !strcmp((*import).namespace_, (*schema3)->targetNamespace))
{ found = true;
(*import).schemaPtr(*schema3);
break;
}
}
if (!found)
{ (*import).schemaPtr(importschema);
xs__schema_.push_back(importschema);
goto again;
}
}
}
}
return SOAP_OK;
}
int wsdl__types::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl types" << endl;
for (vector<xs__schema*>::iterator schema3 = xs__schema_.begin(); schema3 != xs__schema_.end(); ++schema3)
{ // artificially extend the <import> of each schema to include others so when we traverse schemas we can resolve references
for (vector<xs__schema*>::iterator importschema = xs__schema_.begin(); importschema != xs__schema_.end(); ++importschema)
{ if (schema3 != importschema && (*importschema)->targetNamespace)
{ xs__import *import = new xs__import();
import->namespace_ = (*importschema)->targetNamespace;
import->schemaPtr(*importschema);
(*schema3)->import.push_back(*import);
}
}
// check and report
for (vector<xs__import>::iterator import = (*schema3)->import.begin(); import != (*schema3)->import.end(); ++import)
{ if ((*import).namespace_)
{ bool found = false;
for (vector<xs__schema*>::const_iterator importschema = xs__schema_.begin(); importschema != xs__schema_.end(); ++importschema)
{ if ((*importschema)->targetNamespace && !strcmp((*import).namespace_, (*importschema)->targetNamespace))
{ found = true;
break;
}
}
if (!found && vflag)
cerr << "Schema import namespace " << (*import).namespace_ << " refers to a known external Schema" << endl;
}
else
cerr << "Warning: Schema import " << ((*import).schemaLocation ? (*import).schemaLocation : "") << " has no namespace" << endl;
}
}
// traverse the schemas
for (vector<xs__schema*>::iterator schema4 = xs__schema_.begin(); schema4 != xs__schema_.end(); ++schema4)
(*schema4)->traverse();
// find all built-in types, elements, and attributes
for (vector<xs__schema*>::iterator schema5 = xs__schema_.begin(); schema5 != xs__schema_.end(); ++schema5)
{ if (vflag)
for (SetOfString::const_iterator i = (*schema5)->builtinTypes().begin(); i != (*schema5)->builtinTypes().end(); ++i)
cerr << "Found built-in schema type: " << (*i) << endl;
definitions.builtinTypes((*schema5)->builtinTypes());
definitions.builtinElements((*schema5)->builtinElements());
definitions.builtinAttributes((*schema5)->builtinAttributes());
}
return SOAP_OK;
}
int wsdl__import::preprocess(wsdl__definitions& definitions)
{ bool found = false;
if (vflag)
cerr << "Preprocess wsdl import " << (location?location:"") << endl;
definitionsRef = NULL;
if (namespace_)
{ for (SetOfString::const_iterator i = exturis.begin(); i != exturis.end(); ++i)
{ if (!soap_tag_cmp(namespace_, *i))
{ found = true;
break;
}
}
}
if (!found && location)
{ // parse imported definitions
definitionsRef = new wsdl__definitions(definitions.soap, definitions.sourceLocation(), location);
if (!definitionsRef)
return SOAP_EOF;
if (!namespace_)
namespace_ = definitionsRef->targetNamespace;
else if (!definitionsRef->targetNamespace || !*definitionsRef->targetNamespace)
definitionsRef->targetNamespace = namespace_;
else if (strcmp(namespace_, definitionsRef->targetNamespace))
cerr << "Error: WSDL definitions/import " << location << " namespace " << namespace_ << " does not match imported targetNamespace " << definitionsRef->targetNamespace << endl;
}
else if (!found)
cerr << "WSDL definitions/import has no location attribute" << endl;
return SOAP_OK;
}
int wsdl__import::traverse(wsdl__definitions& definitions)
{ if (vflag)
cerr << "Analyzing wsdl import " << (location?location:"") << endl;
if (definitionsRef)
{ for (vector<wsdl__message>::iterator mg = definitionsRef->message.begin(); mg != definitionsRef->message.end(); ++mg)
(*mg).traverse(definitions);
// process portTypes before bindings
for (vector<wsdl__portType>::iterator pt = definitionsRef->portType.begin(); pt != definitionsRef->portType.end(); ++pt)
(*pt).traverse(definitions);
// process bindings
for (vector<wsdl__binding>::iterator bg = definitionsRef->binding.begin(); bg != definitionsRef->binding.end(); ++bg)
(*bg).traverse(definitions);
// process services
for (vector<wsdl__service>::iterator sv = definitionsRef->service.begin(); sv != definitionsRef->service.end(); ++sv)
(*sv).traverse(definitions);
}
return SOAP_OK;
}
void wsdl__import::definitionsPtr(wsdl__definitions *definitions)
{ definitionsRef = definitions;
}
wsdl__definitions *wsdl__import::definitionsPtr() const
{ return definitionsRef;
}
wsdl__import::wsdl__import()
{ definitionsRef = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// streams
//
////////////////////////////////////////////////////////////////////////////////
ostream &operator<<(ostream &o, const wsdl__definitions &e)
{ if (!e.soap)
{ struct soap soap;
soap_init2(&soap, SOAP_IO_DEFAULT, SOAP_XML_TREE | SOAP_C_UTFSTRING);
#ifdef WITH_NONAMESPACES
soap_set_namespaces(&soap, namespaces);
#endif
e.soap_serialize(&soap);
soap_begin_send(&soap);
e.soap_out(&soap, "wsdl:definitions", 0, NULL);
soap_end_send(&soap);
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
}
else
{ ostream *os = e.soap->os;
e.soap->os = &o;
e.soap_serialize(e.soap);
soap_begin_send(e.soap);
e.soap_out(e.soap, "wsdl:definitions", 0, NULL);
soap_end_send(e.soap);
e.soap->os = os;
}
return o;
}
istream &operator>>(istream &i, wsdl__definitions &e)
{ if (!e.soap)
e.soap = soap_new1(SOAP_XML_TREE | SOAP_C_UTFSTRING);
#ifdef WITH_NONAMESPACES
soap_set_namespaces(e.soap, namespaces);
#endif
istream *is = e.soap->is;
e.soap->is = &i;
if (soap_begin_recv(e.soap)
|| !e.soap_in(e.soap, "wsdl:definitions", NULL)
|| soap_end_recv(e.soap))
{ // handle error? Note: e.soap->error is set and app should check
}
e.soap->is = is;
return i;
}
////////////////////////////////////////////////////////////////////////////////
//
// Miscellaneous
//
////////////////////////////////////////////////////////////////////////////////
int warn_ignore(struct soap *soap, const char *tag)
{ // We don't warn if the omitted element was an annotation or a documentation in an unexpected place
if (soap_match_tag(soap, tag, "xs:annotation") && soap_match_tag(soap, tag, "xs:documentation"))
fprintf(stderr, "Warning: element '%s' at level %d was not recognized and will be ignored\n", tag, soap->level);
return SOAP_OK;
}
int show_ignore(struct soap *soap, const char *tag)
{ warn_ignore(soap, tag);
soap_print_fault_location(soap, stderr);
return SOAP_OK;
}