Skip to content

Commit

Permalink
Merge pull request #18728 from asselitx/samplexml-hpcc-31936
Browse files Browse the repository at this point in the history
HPCC-31936 WsEcl unable to get sample request or response XML

Reviewed-By: Ken Rowland <[email protected]>
Reviewed-by: Gavin Halliday <[email protected]>
Merged-by: Gavin Halliday <[email protected]>
  • Loading branch information
ghalliday authored Jun 11, 2024
2 parents ae3c8a8 + 17b49b1 commit 58aa3e6
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 12 deletions.
9 changes: 5 additions & 4 deletions esp/bindings/http/platform/httpbinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1764,7 +1764,9 @@ void EspHttpBinding::getServiceSchema(IEspContext& context, CHttpRequest* reque
StringBuffer xmlFilename;
if (!getServiceXmlFilename(xmlFilename))
{
throw MakeStringException(-1, "Unable to get service XML filename");
// Allow subclassed specialized implementation that doesn't use ESDL
getSchema(schema, context, request, serviceQName, methodQName, true);
return;
}

StringBuffer nstr;
Expand Down Expand Up @@ -1841,8 +1843,7 @@ int EspHttpBinding::getServiceWsdlOrXsd(IEspContext &context, CHttpRequest* requ
}

StringBuffer schema;
getServiceSchema(context, request, serviceQName, methodQName,
version, isWsdl, false, schema);
getServiceSchema(context, request, serviceQName, methodQName, version, isWsdl, false, schema);

response->setContent(schema.length(), schema.str());
response->setContentType(HTTP_TYPE_APPLICATION_XML_UTF8);
Expand Down Expand Up @@ -1937,7 +1938,7 @@ void EspHttpBinding::generateSampleXml(bool isRequest, IEspContext &context, CHt
content.appendf("<Error>generateSampleXml schema error: %s::%s</Error>", serv, method);
return;
}

getServiceSchema(context, request, serviceQName, methodQName, getVersion(context), false, false, schemaXml);

Owned<IXmlSchema> schema;
Expand Down
178 changes: 171 additions & 7 deletions esp/services/ws_ecl/ws_ecl_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1403,7 +1403,7 @@ int CWsEclBinding::getXsdDefinition(IEspContext &context, CHttpRequest *request,
}


bool CWsEclBinding::getSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, WsEclWuInfo &wsinfo)
bool CWsEclBinding::getSimpleSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, WsEclWuInfo &wsinfo)
{
Owned<IPropertyTree> namespaces = createPTree();
appendSchemaNamespaces(namespaces, ctx, req, wsinfo);
Expand Down Expand Up @@ -1453,6 +1453,94 @@ bool CWsEclBinding::getSchema(StringBuffer& schema, IEspContext &ctx, CHttpReque
return true;
}

// Moved from the prior implementation in EspHttpBinding which now relies on ESDL to generate the schema.
// However, since WsEcl is acting a front-end for roxie queries, it needs this custom implementation
// that uses the information from the roxie instead of ESDL.
bool CWsEclBinding::getSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, const char *service, const char *method,bool standalone)
{
StringBuffer serviceQName;
StringBuffer methodQName;

if (!qualifyServiceName(ctx, service, method, serviceQName, &methodQName))
return false;

const char *sqName = serviceQName.str();
const char *mqName = methodQName.str();

Owned<IPropertyTree> namespaces = createPTree();
appendSchemaNamespaces(namespaces, ctx, req, service, method);
Owned<IPropertyTreeIterator> nsiter = namespaces->getElements("namespace");

StringBuffer nstr;
generateNamespace(ctx, req, sqName, mqName, nstr);
schema.appendf("<xsd:schema elementFormDefault=\"qualified\" targetNamespace=\"%s\" ", nstr.str());
if (standalone)
schema.appendf(" xmlns:tns=\"%s\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"", nstr.str());
ForEach(*nsiter)
{
IPropertyTree &ns = nsiter->query();
schema.appendf(" xmlns:%s=\"%s\"", ns.queryProp("@nsvar"), ns.queryProp("@ns"));
}
schema.append(">\n");
ForEach(*nsiter)
{
IPropertyTree &ns = nsiter->query();
if (ns.hasProp("@import"))
schema.appendf("<xsd:import namespace=\"%s\" schemaLocation=\"%s\"/>", ns.queryProp("@ns"), ns.queryProp("@location"));
}


schema.append(
"<xsd:complexType name=\"EspException\">"
"<xsd:all>"
"<xsd:element name=\"Code\" type=\"xsd:string\" minOccurs=\"0\"/>"
"<xsd:element name=\"Audience\" type=\"xsd:string\" minOccurs=\"0\"/>"
"<xsd:element name=\"Source\" type=\"xsd:string\" minOccurs=\"0\"/>"
"<xsd:element name=\"Message\" type=\"xsd:string\" minOccurs=\"0\"/>"
"</xsd:all>"
"</xsd:complexType>\n"
"<xsd:complexType name=\"ArrayOfEspException\">"
"<xsd:sequence>"
"<xsd:element name=\"Source\" type=\"xsd:string\" minOccurs=\"0\"/>"
"<xsd:element name=\"Exception\" type=\"tns:EspException\" minOccurs=\"0\" maxOccurs=\"unbounded\"/>"
"</xsd:sequence>"
"</xsd:complexType>\n"
"<xsd:element name=\"Exceptions\" type=\"tns:ArrayOfEspException\"/>\n"
);

if (ctx.queryOptions()&ESPCTX_WSDL_EXT)
{
schema.append(
"<xsd:complexType name=\"EspSecurityInfo\">"
"<xsd:all>"
"<xsd:element name=\"UsernameToken\" minOccurs=\"0\">"
"<xsd:complexType>"
"<xsd:all>"
"<xsd:element name=\"Username\" minOccurs=\"0\"/>"
"<xsd:element name=\"Password\" minOccurs=\"0\"/>"
"</xsd:all>"
"</xsd:complexType>"
"</xsd:element>"
"<xsd:element name=\"RealmToken\" minOccurs=\"0\">"
"<xsd:complexType>"
"<xsd:all>"
"<xsd:element name=\"Realm\" minOccurs=\"0\"/>"
"</xsd:all>"
"</xsd:complexType>"
"</xsd:element>"
"</xsd:all>"
"</xsd:complexType>"
"<xsd:element name=\"Security\" type=\"tns:EspSecurityInfo\"/>\n"
);
}

bool mda=(req->queryParameters()->getPropInt("mda")!=0);
getXsdDefinition(ctx, req, schema, sqName, mqName, mda);
schema.append("<xsd:element name=\"string\" nillable=\"true\" type=\"xsd:string\" />\n");
schema.append("</xsd:schema>");
return true;
}

int CWsEclBinding::getGenForm(IEspContext &context, CHttpRequest* request, CHttpResponse* response, WsEclWuInfo &wuinfo, bool box)
{
IConstWorkUnit *wu = wuinfo.ensureWorkUnit();
Expand Down Expand Up @@ -1513,7 +1601,7 @@ int CWsEclBinding::getGenForm(IEspContext &context, CHttpRequest* request, CHttp
}
}
else
getSchema(formxml, context, request, wuinfo);
getSimpleSchema(formxml, context, request, wuinfo);

formxml.append("<CustomViews>");
if (web)
Expand Down Expand Up @@ -1621,7 +1709,7 @@ void CWsEclBinding::getWsEcl2XmlRequest(StringBuffer& soapmsg, IEspContext &cont
element.append(wsinfo.queryname.str()).append("Request");

StringBuffer schemaXml;
getSchema(schemaXml, context, request, wsinfo);
getSimpleSchema(schemaXml, context, request, wsinfo);
ESPLOG(LogMax,"request schema: %s", schemaXml.str());
Owned<IXmlSchema> schema = createXmlSchemaFromString(schemaXml);
if (schema.get())
Expand Down Expand Up @@ -1657,7 +1745,7 @@ void CWsEclBinding::getWsEclJsonRequest(StringBuffer& jsonmsg, IEspContext &cont
element.append("Request");

StringBuffer schemaXml;
getSchema(schemaXml, context, request, wsinfo);
getSimpleSchema(schemaXml, context, request, wsinfo);
ESPLOG(LogMax,"request schema: %s", schemaXml.str());
Owned<IXmlSchema> schema = createXmlSchemaFromString(schemaXml);
if (schema.get())
Expand Down Expand Up @@ -2290,20 +2378,96 @@ int CWsEclBinding::getWsdlBindings(IEspContext &context, CHttpRequest *request,
int CWsEclBinding::onGetWsdl(IEspContext &context, CHttpRequest* request, CHttpResponse* response, WsEclWuInfo &wsinfo)
{
context.setBindingValue(&wsinfo);
EspHttpBinding::onGetWsdl(context, request, response, wsinfo.qsetname.str(), wsinfo.queryname.str());
getWsdlOrXsd(context, request, response, wsinfo.qsetname.str(), wsinfo.queryname.str(), true);
context.setBindingValue(NULL);
return 0;
}

int CWsEclBinding::onGetXsd(IEspContext &context, CHttpRequest* request, CHttpResponse* response, WsEclWuInfo &wsinfo)
{
context.setBindingValue(&wsinfo);
EspHttpBinding::onGetXsd(context, request, response, wsinfo.qsetname.str(), wsinfo.queryname.str());
getWsdlOrXsd(context, request, response, wsinfo.qsetname.str(), wsinfo.queryname.str(), false);
context.setBindingValue(NULL);

return 0;
}

int CWsEclBinding::getWsdlOrXsd(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method, bool isWsdl)
{
bool mda=(request->queryParameters()->getPropInt("mda")!=0);
try
{
StringBuffer serviceQName;
StringBuffer methodQName;

if (!qualifyServiceName(context, service, method, serviceQName, &methodQName))
{
return onGetNotFound(context, request, response, service);
}
else
{
const char *sqName = serviceQName.str();
const char *mqName = methodQName.str();
StringBuffer ns;
generateNamespace(context, request, serviceQName.str(), methodQName.str(), ns);

StringBuffer content("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
if (context.queryRequestParameters()->hasProp("display"))
content.append("<?xml-stylesheet type=\"text/xsl\" href=\"/esp/xslt/xmlformatter.xsl\"?>");
else if (isWsdl && context.queryRequestParameters()->hasProp("wsdlviewer"))
content.append("<?xml-stylesheet type=\"text/xsl\" href=\"/esp/xslt/wsdl-viewer.xsl\"?>");
if (isWsdl)
{
content.appendf("<definitions xmlns=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\" xmlns:http=\"http://schemas.xmlsoap.org/wsdl/http/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
" xmlns:mime=\"http://schemas.xmlsoap.org/wsdl/mime/\" xmlns:tns=\"%s\""
" targetNamespace=\"%s\">", ns.str(), ns.str());
content.append("<types>");
}

getSchema(content,context,request,service,method,!isWsdl);

if (isWsdl)
{
content.append("</types>");

getWsdlMessages(context, request, content, sqName, mqName, mda);
getWsdlPorts(context, request, content, sqName, mqName, mda);
getWsdlBindings(context, request, content, sqName, mqName, mda);

StringBuffer location(getWsdlAddress());
if (request->queryParameters()->hasProp("wsdl_destination_path"))
location.append(request->queryParameters()->queryProp("wsdl_destination_path"));
else
location.append('/').append(sqName).appendf("?ver_=%g", context.getClientVersion());

if (request->queryParameters()->hasProp("encode_results"))
{
const char *encval = request->queryParameters()->queryProp("encode_results");
location.append("&amp;").appendf("encode_=%s", (encval && *encval) ? encval : "1");
}

content.appendf("<service name=\"%s\">", sqName);
content.appendf("<port name=\"%sServiceSoap\" binding=\"tns:%sServiceSoap\">", sqName, sqName);
content.appendf("<soap:address location=\"%s\"/>", location.str());
content.append("</port>");
content.append("</service>");
content.append("</definitions>");
}

response->setContent(content.length(), content.str());
response->setContentType(HTTP_TYPE_APPLICATION_XML_UTF8);
response->setStatus(HTTP_STATUS_OK);
}
}
catch (IException *e)
{
return onGetException(context, request, response, *e);
}

response->send();
return 0;
}


int CWsEclBinding::getWsEclDefinition(CHttpRequest* request, CHttpResponse* response, const char *thepath)
{
Expand Down Expand Up @@ -2423,7 +2587,7 @@ int CWsEclBinding::getRestURL(IEspContext *ctx, CHttpRequest *request, CHttpResp

StringBuffer schemaXml;

getSchema(schemaXml, *ctx, request, wsinfo);
getSimpleSchema(schemaXml, *ctx, request, wsinfo);
Owned<IXmlSchema> schema = createXmlSchemaFromString(schemaXml);
if (schema.get())
{
Expand Down
8 changes: 7 additions & 1 deletion esp/services/ws_ecl/ws_ecl_service.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ class CWsEclBinding : public CHttpSoapBinding
private:
CWsEclService *wsecl;

protected:
bool getSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, const char *service, const char *method,bool standalone) override;
int getWsdlOrXsd(IEspContext &context, CHttpRequest* request, CHttpResponse* response, const char *service, const char *method, bool isWsdl);
// Does not provide all the flexibility of the getSchema override. Consider refactoring out to use getSchema in its place.
bool getSimpleSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, WsEclWuInfo &wsinfo) ;

public:
CWsEclBinding(IPropertyTree *cfg, const char *bindname, const char *procname) :
CHttpSoapBinding(cfg, bindname, procname), wsecl(NULL)
Expand Down Expand Up @@ -199,7 +205,7 @@ class CWsEclBinding : public CHttpSoapBinding
bool qualifyServiceName(IEspContext &context, const char *servname, const char *methname, StringBuffer &servQName, StringBuffer *methQName){servQName.clear().append(servname); if (methQName) methQName->clear().append(methname); return true;}

int getXsdDefinition(IEspContext &context, CHttpRequest *request, StringBuffer &content, WsEclWuInfo &wsinfo);
bool getSchema(StringBuffer& schema, IEspContext &ctx, CHttpRequest* req, WsEclWuInfo &wsinfo) ;

void appendSchemaNamespaces(IPropertyTree *namespaces, IEspContext &ctx, CHttpRequest* req, WsEclWuInfo &wsinfo);
void appendSchemaNamespaces(IPropertyTree *namespaces, IEspContext &ctx, CHttpRequest* req, const char *service, const char *method);

Expand Down

0 comments on commit 58aa3e6

Please sign in to comment.