/* FARGOS Development, LLC Sample Programs Copyright (C) 2002 FARGOS Development, LLC. All rights reserved. mailto:support@fargos.net for assistance. NOTE: in the future, enhanced versions of these classes may be added to the FARGOS/VISTA Object Management Environment core within the Standard namespace. Developers can avoid any potential conflict if they specify an explicit namespace when creating instances of the sample classes. */ %include class XMLsupport { /*! The class class=XMLsupport provides an inheritable set of utility functions that applications working with XML documents find useful. See class=WSDL and class=SOAPservice for examples. !*/ } inherits from Object; XMLsupport:create() {} XMLsupport:delete() {} XMLsupport:_convertToAssoc(array elem) { assoc result; int i; for(i=3;indexExists(elem, i) != 0;i+=2) { result[elem[i]] = elem[i + 1]; } return (result); } XMLsupport:_mapToOIL2type(string xmlType) { if (xmlType == "xsd:string") return ("string"); if (xmlType == "xsd:base64Binary") return ("string"); if (xmlType == "xsd:int") return ("int"); if (xmlType == "xsd:boolean") return ("int"); display("Unrecognized type ", xmlType, "\n"); return ("any"); } XMLsupport:_isArray(array elem) { int result; any subElem; assoc attr; //display("isArray elem=",elem); //display("elem[1]=",elem[1],"\n"); if ((elem[1] == "xsd:complexContent") || (elem[1] == "xsd:complexType")) { for subElem in elem[0] do { result = call "_isArray"(subElem); return (result); } } attr = call "_convertToAssoc"(elem); if (elem[1] == "xsd:restriction") { if (attr["base"] == "soapenc:Array") return (1); if (attr["base"] == "xsd:array") return (1); } if (elem[1] == "xsd:attribute") { if (attr["ref"] == "soapenc:arrayType") return (1); } return (0); } XMLsupport:convertBasicTypeToXML(any data, string elementName, string xmlTypeName) { set lines; lines += "\t<"; lines += elementName; lines += " xsi:type=\""; lines += xmlTypeName; lines += "\">"; // TO DO: handle conversion of complex types... if (xmlTypeName == "xsd:base64Binary") { lines = asciiToBase64(data, 0); } else if (xmlTypeName == "xsd:boolean") { if (data == 0) { lines += "false"; } else { lines += "true"; } } else { lines += makeAsString(data); } lines += "\n"; return (lines); } class WSDLtoOIL2 { /*! Compiles a Web Services Description Language file into an OIL2 source file. The resulting class implements methods for accessing SOAP-based services. !*/ string wsdlDoc; string outputFileSpec; string className; assoc messageDefs; assoc typeDefs; assoc bindingDefs; assoc portTypeDefs; } inherits from XMLsupport; WSDLtoOIL2:create(string sourceFile, optional string outFileName) { /*! The sourceFile argument identifies the source of the Web Services Description File. It is passed to an class=IOobject; however, if no scheme is specified, a "file:" prefix is added. If a "file:" scheme is used, a ",r" suffix will be added if needed. The optional outFileName can be used to specify the output file. If not provide, a default file name will be derived from the name of the service by adding a "cl" prefix and a ".oil" suffix.

After processing the source file, a class=WSDLtoOIL2 object automatically deletes itself. !*/ oid fileObj; assoc acl; any xml; string fileName; fileName = sourceFile; if (findSubstring(fileName, ":") == -1) { // no scheme fileName = "file:" + fileName; } if (findSubstring(fileName, "file:") == 0) { if (findSubstring(fileName, ",r") == -1) { fileName += ",r"; } } if (typeOf(outFileName) == string) { outputFileSpec = outFileName; } acl = makeDefaultACL(); fileObj = send "createObject"("IOobject", acl, fileName) to ObjectCreator; wsdlDoc = send "readBytes"(-1) to fileObj; send "deleteYourself" to fileObj; xml = parseXML(wsdlDoc); display("typeOf xml=", typeOf(xml), "\n"); display("XML parse=", xml); call "outputCode"(xml); send "deleteYourself" to thisObject; } WSDLtoOIL2:delete() {} WSDLtoOIL2:_getEncodeMethodName(string xmlType) { // default display("type name\n"); return ("convertBasicTypeToXML"); } WSDLtoOIL2:_getDecodeMethodName(string xmlType) { // default display("type name\n"); return ("convertBasicTypeToXML"); } WSDLtoOIL2:outputCode(array xml) { array elem; display("outputCode\n"); if (xml[1] != "definitions") { display("Not a definitions\n"); return (-1); } for elem in xml[0] do { if (elem[1] == "documentation") { } if (elem[1] == "types") { call "_noteTypes"(elem); } if (elem[1] == "message") { call "_noteMessage"(elem); } if (elem[1] == "portType") { call "_notePortType"(elem); } if (elem[1] == "binding") { call "_noteBinding"(elem); } if (elem[1] == "service") { call "_noteService"(elem); } } return (0); } WSDLtoOIL2:_noteService(array elem) { int rc, i; array portElem, typeRec; assoc attr, acl; oid outputFile; set lines; any messLines; display("noteService\n"); attr = call "_convertToAssoc"(elem); if (length(outputFileSpec) == 0) { outputFileSpec = makeAsString("file:cl", attr["name"],".oil,cwt"); } if (findSubstring(outputFileSpec, ":") == -1) { outputFileSpec = "file:" + outputFileSpec; } if (findSubstring(outputFileSpec, ",") == -1) { outputFileSpec += ",cwt"; } acl = makeDefaultACL(); outputFile = send "createObject"("IOobject", acl, outputFileSpec) to ObjectCreator; lines += "// WARNING: automatically generated by the OIL2 class WSDLtoOIL2\n"; lines += "%include \n\n"; className = attr["name"]; for portElem in elem[0] do { messLines = call "_outputPortWithBinding"(portElem); lines |= messLines; } for (i=nextIndex(typeDefs,0);i != 0;i=nextIndex(typeDefs,i)) { typeRec = typeDefs[i]; messLines = call "_outputComplexDecodeMethod"(typeRec); lines |= messLines; } lines += "// END OF GENERATED CODE\n"; display("LINES count=", elementCount(lines),"\n"); rc = send "writeVectorOfBytes"(0, lines) to outputFile; send "deleteYourself" to outputFile; return (0); } WSDLtoOIL2:_outputPortWithBinding(array portElem) { assoc portInfo, locInfo; array locElem; set lines; any messLines; portInfo = call "_convertToAssoc"(portElem); for locElem in portElem[0] do break; locInfo = call "_convertToAssoc"(locElem); display("outputPortWithBinding portInfo=",portInfo,"\n"); lines += "class "; lines += "Experimental . "; lines += className; lines += " {\n"; lines += "/*!\n"; lines += "Automatically generated by class=WSDLtoOIL2.\n"; lines += "!*/\n"; lines += "\tstring\ttargetURL;\n"; lines += "} inherits from SOAPservice, XMLsupport;\n\n"; lines += className; lines += ":create()\n{\n"; lines += "\ttargetURL = \""; lines += locInfo["location"]; lines += "\";\n"; lines += "}\n\n"; messLines = call "_outputBindingsToPort"(portInfo); lines |= messLines; return (lines); } WSDLtoOIL2:_outputBindingsToPort(assoc portInfo) { set lines; string bindingType, bindingName; any resultLines; int i; display("outputPort\n"); bindingType = portInfo["binding"]; if (indexExists(bindingDefs, bindingType) != 0) { bindingName = bindingType; } else { i = findSubstring(bindingType, ":"); i += 1; bindingName = midstr(bindingType, i, length(bindingType) - i); } if (indexExists(bindingDefs, bindingName) == 0) { display("No such binding for ", portInfo["name"], " binding=", bindingName, "\n"); return (""); } display("outputBindingsToPort bindingName=", bindingName,"\n"); resultLines = call "_outputBinding"(portInfo, bindingDefs[bindingName]); return (resultLines); } WSDLtoOIL2:_outputBinding(assoc portInfo, array bindingInfo) { array elem; set resultLines; any methodLines; display("outputBinding, bindingInfo=",bindingInfo); for elem in bindingInfo[0] do { if (elem[1] == "soap:binding") { } if (elem[1] == "operation") { methodLines = call "_outputOperation"(portInfo, bindingInfo, elem); resultLines |= methodLines; } } return (resultLines); } WSDLtoOIL2:_outputOperation(assoc portInfo, array bindingInfo, array operationInfo) { string opName, portTypeName; set lines; assoc attr; any methodLines; array opElem, portTypeElem; int hadFault; display("outputOperation portInfo=",portInfo,"\nopInfo=",operationInfo); portTypeName = portInfo["name"]; if (indexExists(portTypeDefs, portTypeName) == 0) { display("No portType for ",portTypeName, "\n"); return (""); } portTypeElem = portTypeDefs[portTypeName]; display("portTypeElem=", portTypeElem); for opElem in portTypeElem[0] do { methodLines = call "_outputOperationCode"(portInfo, bindingInfo, operationInfo, opElem); lines |= methodLines; } return (lines); } WSDLtoOIL2:_outputOperationCode(assoc portInfo, array bindingInfo, array operationInfo, array messageElem) { string opName, portTypeName, messName; string encodeName, decodeName; set lines; assoc attr, attr2, portOperations; any methodData, argLine; array opElem, portOpElem; int hadFault; // operationInfo determines method to output attr = call "_convertToAssoc"(operationInfo); opName = attr["name"]; attr = call "_convertToAssoc"(messageElem); messName = attr["name"]; if (opName != messName) { display("opName-", opName, " vs. messName-", messName, "\n"); return (""); // skip } display("outputOperationCode opName=",opName,"\n"); display("operationInfo=", operationInfo); display("messageElem=", messageElem); for opElem in messageElem[0] do { display("opElem[1]=", opElem[1], "\n"); if (opElem[1] == "input") { methodData = call "_outputEncodeMethod"(portInfo, bindingInfo, attr, opElem); encodeName = methodData[1]; argLine = methodData[2]; lines |= methodData[0]; } if (opElem[1] == "output") { methodData = call "_outputDecodeMethod"(portInfo, bindingInfo, attr, opElem); decodeName = methodData[1]; lines |= methodData[0]; } if (opElem[1] == "fault") { hadFault = 1; methodData = call "_outputDecodeMethod"(portInfo, bindingInfo, attr, opElem); lines |= methodData[0]; } } lines += className; lines += ":"; lines += opName; lines += "("; // method args lines |= argLine; lines += ")\n{\n"; lines += "/*!\n"; lines += "Top-level RPC-style invocation.\n"; lines += "!*/\n"; lines += "\tstring\tpacket;\n"; lines += "\tint\trc;\n"; lines += "\tany\tresult, response;\n"; lines += "\n"; lines += "\tpacket = call \"_encode_"; lines += encodeName; lines += "\"(arrayToSet(argv));\n"; lines += "\trc = call \"issueRequest\"(targetURL, packet);\n"; lines += "\tresponse = call \"receiveResponse\"();\n"; lines += "\tif (response == nil) return (nil);\n"; lines += "\tresult = call \"_decode_"; lines += decodeName; lines += "\"(response);\n"; lines += "\treturn(result);\n"; lines += "}\n\n"; return (lines); } WSDLtoOIL2:_outputEncodeMethod(assoc portInfo, array bindingInfo, assoc opInfo, array methodInfo) { string opName, messName, mName; set lines, argLine; assoc attr, partAttr, bindingAttr; any methodData, bindingData; array result, partInfo, messDef, bindingRec, opRec, mElem; int i, count; display("outputEncodeMethod methodInfo=",methodInfo); opName = opInfo["name"]; display("top opName=",opName,"\n"); display("BINDING INFO=", bindingInfo); attr = call "_convertToAssoc"(methodInfo); messName = attr["message"]; if (indexExists(messageDefs, messName) == 0) { i = findSubstring(messName, ":"); i += 1; messName = midstr(messName, i, length(messName) - i); if (indexExists(messageDefs, messName) == 0) { display("No message def for ", messName, "\n"); return (""); } } messDef = messageDefs[messName]; display("messageName=", messName, "\nmessDef=", messDef); for bindingRec in bindingInfo[0] do { display("bindingRec[1]=", bindingRec[1], "\n"); if (bindingRec[1] != "operation") continue; bindingAttr = call "_convertToAssoc"(bindingRec); display("binding name=", bindingAttr["name"], " vs. opName=", opName, "\n"); if (bindingAttr["name"] != opName) continue; for opRec in bindingRec[0] do { display("OPREC=",opRec); if (opRec[1] != methodInfo[1]) continue; for bindingData in opRec[0] do break; } if (bindingData != nil) break; } display("BINDING DATA=", bindingData, "\n"); if (bindingData == nil) { display("Cannot find binding data for ", attr["name"], "\n"); return (""); } bindingAttr = call "_convertToAssoc"(bindingData); lines += className; lines += ":_encode_"; lines += messName; lines += "("; count = 0; for partInfo in messDef[0] do { partAttr = call "_convertToAssoc"(partInfo); if (count != 0) argLine += ", "; argLine += call "_mapToOIL2type"(partAttr["type"]); argLine += " "; argLine += partAttr["name"]; argLine += "ARG"; // avoid collisions with keywords count += 1; } lines |= argLine; lines += ")\n{\n"; // method body lines += "\tset\txmlLines;\n"; lines += "\tstring\tresult;\n"; lines += "\tany\tparamLine;\n"; lines += "\n"; lines += "\tparamLine = call \"getSOAPenvelopeHeader\"("; lines += "\""; lines += opName; // operation name == envelope body lines += "\",\n\t\t"; lines += "\""; lines += bindingAttr["namespace"]; lines += "\",\n\t\t"; lines += "\""; lines += bindingAttr["encodingStyle"]; lines += "\");\n"; lines += "\txmlLines |= paramLine;\n"; // encode each argument... for partInfo in messDef[0] do { partAttr = call "_convertToAssoc"(partInfo); mName = call "_getEncodeMethodName"(partAttr["type"]); lines += "\tparamLine = call \""; lines += mName; lines += "\"("; lines += partAttr["name"]; lines += "ARG"; // avoid collisions with keywords lines += ", \""; lines += partAttr["name"]; lines += "\", \""; lines += partAttr["type"]; lines += "\");\n"; lines += "\txmlLines |= paramLine;\n"; } lines += "\tparamLine = call \"getSOAPenvelopeClosing\"("; lines += "\""; lines += opName; lines += "\");\n"; lines += "\txmlLines |= paramLine;\n"; lines += "\tresult = makeAsString(xmlLines);\n"; lines += "\treturn (result);\n"; lines += "}\n\n"; result[0] = lines; result[1] = messName; result[2] = argLine; return (result); } WSDLtoOIL2:_outputDecodeMethod(assoc portInfo, assoc bindingInfo, assoc opInfo, array methodInfo) { string opName, messName, assignment; set lines; assoc attr, partAttr; any methodData; array result, partInfo, messDef; int i, count; opName = opInfo["name"]; display("top opName=",opName,"\n"); attr = call "_convertToAssoc"(methodInfo); messName = attr["message"]; if (indexExists(messageDefs, messName) == 0) { i = findSubstring(messName, ":"); i += 1; messName = midstr(messName, i, length(messName) - i); if (indexExists(messageDefs, messName) == 0) { display("No message def for ", messName, "\n"); return (""); } } messDef = messageDefs[messName]; lines += className; lines += ":_decode_"; lines += messName; lines += "(array xmlParse)\n"; lines += "{\n"; lines += "\tassoc\tresult;\n"; lines += "\tany\telem;\n"; lines += "\n"; // method body lines += "\tfor elem in xmlParse[0] do {\n"; for partInfo in messDef[0] do { if (partInfo[1] == "xsd:all") { methodData = call "_outputConversionFromXML"(partInfo, "allElem = "); lines |= methodData; lines += "\treturn (allElem);\n"; lines += "\t\t}\n"; lines += "}\n"; return (lines); } partAttr = call "_convertToAssoc"(partInfo); lines += "\t\tif (elem[1] == \""; lines += partAttr["name"]; lines += "\") {\n"; assignment = makeAsString("\t\t\tresult[\"", partAttr["name"], "\"] = "); methodData = call "_outputConversionFromXML"(partInfo, assignment); lines |= methodData; lines += "\t\t}\n"; } lines += "\t}\n"; lines += "\treturn (result);\n"; lines += "}\n\n"; result[0] = lines; result[1] = messName; return (result); } WSDLtoOIL2:_outputConversionFromXML(array partInfo, string finalAssignment, optional array topLevel, optional string elemNameArg) { array subElem; assoc partAttr, attr; set lines; string typeName, subAssign, elemName; int i, isArray; any lineData; if (length(elemNameArg) > 0) { elemName = elemNameArg; } else { elemName = "elem"; } if (partInfo[1] == "xsd:complexContent") { isArray = call "_isArray"(partInfo); lines += "// xsd:complexContent "; lines += thisMethod; lines += makeAsString(" array=",isArray); lines += "\n"; if (isArray != 0) { subAssign = "\t\t\tresultArray[count] = "; } else { subAssign = finalAssignment; } for subElem in partInfo[0] do { lineData = call "_outputConversionFromXML"(subElem, subAssign, partInfo, "elem"); lines |= lineData; if (isArray != 0) { lines += "\t\tcount += 1;\n"; } else { lines += "\t\tbreak;\n"; } break; } return (lines); } partAttr = call "_convertToAssoc"(partInfo); if (partInfo[1] == "xsd:restriction") { typeName = partAttr["base"]; for subElem in partInfo[0] do { subAssign = "resultArray[count] = "; lineData = call "_outputConversionFromXML"(subElem, finalAssignment, partInfo, elemName); lines |= lineData; break; } return (lines); } if (partInfo[1] == "xsd:all") { lines += "// xsd:all\n"; lines += "\tfor subElem in elem[0] do {\n"; lines += "\t\tattr = call \"_convertToAssoc\"(subElem);\n"; for subElem in partInfo[0] do { attr = call "_convertToAssoc"(subElem); subAssign = makeAsString("\t\t\tresult[\"", attr["name"], "\"] = "); lines += "\t\tattr = call \"_convertToAssoc\"(elem);\n"; lines += "\t\tif (attr[\"name\"] == \""; lines += attr["name"]; lines += "\") {\n"; lineData = call "_outputConversionFromXML"(subElem, subAssign, elemName); lines |= lineData; lines += "\t\t}\n"; } lines += "\t}\n"; lines += finalAssignment; lines += "allAssoc;\n"; return (lines); } display("Output FromXML partInfo=", partInfo, " partAttr=", partAttr); if (partInfo[1] == "xsd:attribute") { attr = call "_convertToAssoc"(partInfo); if (indexExists(attr, "wsdl:arrayType") != 0) typeName = attr["wsdl:arrayType"]; } else { if (indexExists(partAttr, "type") != 0) typeName = partAttr["type"]; else if (indexExists(partAttr, "type") != 0) typeName = partAttr["type"]; } if (length(typeName) == 0) { display("NEED TO SUPPORT: ", partInfo[1], "\n"); return (""); } if ((typeName == "xsd:int") || (typeName == "xsd:unsignedInt") || (typeName == "xsd:short") || (typeName == "xsd:unsignedShort")) { lines += finalAssignment; lines += "stringToNumber(elem[2], int);\n"; return (lines); } if ((typeName == "xsd:long") || (typeName == "xsd:unsignedLong")) { lines += finalAssignment; lines += "stringToNumber(elem[2], int64);\n"; return (lines); } if (typeName == "xsd:boolean") { lines += "\tif ((elem[2] == 0) || (elem[2] == \"false\")) "; lines += finalAssignment; lines += "0;\n\telse "; lines += finalAssignment; lines += "1;\n"; return (lines); } if (typeName == "xsd:float") { lines += finalAssignment; lines += "stringToNumber(elem[2], float);\n"; return (lines); } if (typeName == "xsd:double") { lines += finalAssignment; lines += "stringToNumber(elem[2], double);\n"; return (lines); } if (typeName == "xsd:decimal") { lines += finalAssignment; lines += "stringToNumber(elem[2], fixed);\n"; return (lines); } if ((typeName == "xsd:byte") || (typeName == "xsd:unsignedByte")) { lines += finalAssignment; lines += "midchar(elem[2], 0);\n"; return (lines); } if (typeName == "xsd:base64Binary") { lines += finalAssignment; lines += "base64ToASCII(elem[2]);\n"; return (lines); } if (typeName == "xsd:hexBinary") { lines += finalAssignment; lines += "makeAsHexString(elem[2]);\n"; return (lines); } if ((typeName == "xsd:string") || (typeName == "normalizedString") || (typeName == "xsd:token")) { lines += finalAssignment; lines += "elem[2];\n"; return (lines); } if (indexExists(typeDefs, typeName) == 0) { i = findSubstring(typeName, ":"); if (i != -1) { i += 1; typeName = midstr(typeName, i, length(typeName) - i); } i = findSubstring(typeName, "[]"); if (i != -1) { typeName = midstr(typeName, 0, i); } } display("typeName=",typeName,"\n"); display("typeDefs=",typeDefs); if (indexExists(typeDefs, typeName) != 0) { //lines += makeAsString("// COMPLEX ", typeName, "\n"); lines += finalAssignment; lines += "call \"_decodeComplex_"; lines += typeName; lines += makeAsString("\"(",elemName,");\n"); return (lines); } lines += makeAsString("// UNKNOWN ", partAttr["type"], "\n"); // default, copy as-is lines += finalAssignment; lines += "elem[2];\n"; return (lines); } WSDLtoOIL2:_noteTypes(array elem) { array topElem, typeElem; assoc info, attr; //display("Note types=", elem); for topElem in elem[0] do { info = call "_convertToAssoc"(topElem); for typeElem in topElem[0] do { attr = call "_convertToAssoc"(typeElem); typeDefs[attr["name"]] = typeElem; } } return (0); } WSDLtoOIL2:_noteBinding(array elem) { assoc attr; attr = call "_convertToAssoc"(elem); bindingDefs[attr["name"]] = elem; return (0); } WSDLtoOIL2:_noteMessage(array elem) { assoc attr; attr = call "_convertToAssoc"(elem); messageDefs[attr["name"]] = elem; return (0); } WSDLtoOIL2:_notePortType(array elem) { assoc attr; attr = call "_convertToAssoc"(elem); portTypeDefs[attr["name"]] = elem; return (0); } WSDLtoOIL2:_outputComplexDecodeMethod(array typeElem) { set lines; assoc attr, attr2; string typeName, assignment; array subElem, elem2; any methodData; int outputConvert, isArray; attr = call "_convertToAssoc"(typeElem); typeName = attr["name"]; lines += className; lines += ":_decodeComplex_"; lines += typeName; lines += "(array xmlParse) // "; lines += thisMethod; lines += "\n{\n"; lines += "\tassoc\tresult, attr;\n"; lines += "\tarray\tresultArray;\n"; lines += "\tint\tcount;\n"; lines += "\tany\telem, subElem, complexResult;\n"; lines += "\n"; //lines += makeAsString("display(\"",typeName," argv=\",argv);\n"); lines += "\tfor elem in xmlParse[0] do {\n"; //lines += makeAsString("// ", typeElem[1], " ", typeElem[4], "\n"); for subElem in typeElem[0] do { //display("SUB ELEM=", subElem); attr = call "_convertToAssoc"(subElem); if (subElem[1] == "xsd:all") { for elem2 in subElem[0] do { //display("ELEM2=", subElem); attr2 = call "_convertToAssoc"(elem2); assignment = makeAsString("\t\t\tresult[\"", attr2["name"], "\"] = "); lines += "\t\tif (elem[1] == \""; lines += attr2["name"]; lines += "\") {\n"; methodData = call "_outputConversionFromXML"(elem2, assignment); lines |= methodData; lines += "\t\t}\n"; } break; } if (subElem[1] = "xsd:complexContent") { assignment = "\t\t\tcomplexResult = "; methodData = call "_outputConversionFromXML"(subElem, assignment); lines |= methodData; isArray = call "_isArray"(subElem); if (isArray == 0) { lines += "\t\t\treturn (complexResult); // done\n"; } break; } assignment = makeAsString("\tresult[\"", attr["name"], "\"] = "); if (outputConvert == 0) { // once only lines += "\t\tattr = call \"_convertToAssoc\"(elem);\n"; lines += "display(attr);\n"; outputConvert = 1; } lines += "\t\tif (attr[\"name\"] == \""; lines += attr["name"]; lines += "\") {\n"; methodData = call "_outputConversionFromXML"(subElem, assignment); lines |= methodData; lines += "\t\t}\n"; } lines += "\t}\n"; if (isArray == 1) { lines += "\treturn (resultArray);\n"; } else { lines += "\treturn (result);\n"; } lines += "}\n\n"; return (lines); }