📄 webservice.js
字号:
} // look through each schemaSet for a schema of this name for (var i = 0; i < schemaSets.length; i++) { var schema = schemaSets[i].getSchema(name, schemaType); if (schema) return schema; } // finally, look globally. This is key for discovering schema loaded from separate // files via separate calls to loadXMLSchema. return isc.DS.get(name, null, null, schemaType); }, // get the request or response message schema getRequestMessage : function (operationName) { var operation = this.getOperation(operationName); return this.messages.find("ID", "message:" + operation.inputMessage); }, getResponseMessage : function (operationName) { var operation = this.getOperation(operationName); return this.messages.find("ID", "message:" + operation.outputMessage); }, getBodyPartNames : function (operationName, isOutput) { var operation = this.getOperation(operationName), bodyParts = isOutput ? operation.outputParts : operation.inputParts; if (bodyParts == null || isc.isAn.emptyString(bodyParts)) { // all body parts should be used var message = isOutput ? this.getResponseMessage(operationName) : this.getRequestMessage(operationName); return message.getFieldNames(); } else { return bodyParts.split(" "); } }, //> @attr webService.globalNamespaces (Object : ... : IRW) // @include dataSource.globalNamespaces //< globalNamespaces : { xsi: "http://www.w3.org/2001/XMLSchema-instance", xsd: "http://www.w3.org/2001/XMLSchema" }, //> @method webService.callOperation() // Invoke a web service operation. // <P> // The <code>data</code> parameter will be serialized to XML to form the input message for // the operation, as described by +link{method:DataSource.xmlSerialize()}. Namespacing, // element ordering, and SOAP encoding rules are automatically followed. If the web // service you are trying to contact requires a complicated nested structure, consider // using +link{wsRequest.useFlatFields} to simplify the required JavaScript input data. // <P> // The <code>resultType</code> selects what part of the message should be decoded to // JavaScript and made available as the "data" variable in the callback. The // <code>resultType</code> parameter can be either: // <ul> // <li> an XPath. "data" will be always be an Array, containing the selected elements as // decoded by +link{XMLTools.toJS()}. All properties will have String value. // <li> the name of an XML Schema type found somewhere in the response. You can use the // WSDL tab of the Developer Console to analyze the WSDL file for an appropriate type name. // "data" will be an Array, containing the decoded elements as decoded by // +link{dataSource.recordsFromXML()}. In this case, since the XML Schema type of the // selected data is known, properties will have correct type (eg "date" fields will // have JavaScript Date objects) // <li> null. "data" will an Object representing the entire <SOAP:Body> as decoded // to JavaScript. As above, properties will have correct type. // </ul> // In the callback, you also receive the XML document returned by the web service as // "xmlDoc". // <P> // NOTE: <code>callOperation()</code> is appropriate for simple operations that do not // involve DataBound Components, such as logging into a web service, or retrieving simple // String data. <code>callOperation()</code> can also be used to retrieve small, read-only // datasets such as the option list for a SelectItem, but only if the dataset is guaranteed // to remain small enough for paging to be unnecessary. For any larger datasets or // anything that will be edited, DataSource integration is more appropriate. // // @param operationName (String) Name of the operation to invoke // @param data (Object) data to serialize as XML to form the inbound message of // the operation // @param resultType (Type or ElementName or XPath) Type, Element name, or XPath that // should be selected from the result // @param callback (Callback) Callback to invoke on completion. Signature // callback(data, xmlDoc, rpcResponse, wsRequest) // @param requestProperties (WSRequest) Additional properties for the WSRequest, such // as HTTPHeaders // // @group webService // @visibility xmlBinding // @example wsdlOperation //< callOperation : function (operationName, data, resultType, callback, requestProperties) { var operation = this.getOperation(operationName); if (operation == null) { this.logWarn("No such operation: " + operationName); return; } requestProperties = requestProperties || isc.emptyObject; var wsRequest = isc.addProperties({ actionURL: this.getDataURL(operationName), httpMethod: "POST", contentType: "text/xml", data : data, serviceNamespace : this.serviceNamespace, wsOperation : operationName }, requestProperties); wsRequest.headerData = requestProperties.headerData || this.getHeaderData(wsRequest); wsRequest.httpHeaders = isc.addProperties({}, requestProperties.httpHeaders, { SOAPAction : operation.soapAction || '""' }); // create the SOAP message based on the WSRequest wsRequest.data = this.getSoapMessage(wsRequest); wsRequest.clientContext = { _callOperationCallback : callback, _operationName : operationName, _resultType : resultType, // special flag to return selected XML nodes without JS translation _xmlResult : requestProperties.xmlResult }; if (this.spoofResponses) { var sampleResponse = this.getSampleResponse(operationName); if (this.logIsDebugEnabled("xmlBinding")) { this.logDebug("spoofed response:\n" + sampleResponse, "xmlBinding"); } this.delayCall("_callOperationReply", [isc.xml.parseXML(sampleResponse), sampleResponse, {status:0, clientContext:wsRequest.clientContext, httpResponseCode:200, httpResponseText:sampleResponse}, wsRequest]); return; } wsRequest.callback = { target:this, methodName:"_callOperationReply" }; isc.xml.getXMLResponse(wsRequest); }, _callOperationReply : function (xmlDoc, xmlText, rpcResponse, rpcRequest) { var context = rpcRequest.clientContext, operationName = context._operationName, resultType = context._resultType; xmlDoc.addNamespaces(this.getOutputNamespaces(operationName)); // we were passed a type (FIXME crude detection) var passedXPath = resultType != null && resultType.contains("/"), xPath = (passedXPath ? resultType : null), data; if (passedXPath) { // apply XPath selector if passed one or passed resultType data = xmlDoc.selectNodes(xPath); } else if (resultType) { data = this.selectByType(xmlDoc, operationName, resultType); } else { // if no XPath or resultType was given, select the soap body data = xmlDoc.selectNodes("//s:Body/*", { s:"http://schemas.xmlsoap.org/soap/envelope/" }); // don't create a spurious Array for the most common case of a singular body // element if (data.length == 1) data = data[0]; } if (context._xmlResult) { // just return the raw XML nodes this.fireCallback(context._callOperationCallback, "data,xmlDoc,rpcResponse,wsRequest", [data,xmlDoc,rpcResponse,rpcRequest]); return; } // transform to JS var schema; if (passedXPath) { // if an xpath was passed, we don't know the schema of the selected elements, just // use schemaless transform schema = null; } else if (resultType) { // if we were passed a resultType, use that as the schema to transform nodes with // correct typing schema = this.getSchema(context._resultType); } else { // passed neither an xPath nor a resultType, so we selected the whole SOAP body. // We can use the message schema to decode the entire SOAP body, with correct // typing. var messageSchema = this.getSchema("message:"+this.getOperation(operationName).outputMessage); if (this.getSoapStyle(operationName) != "document") { schema = messageSchema; } else { var firstField = messageSchema.getFieldNames().first(); schema = messageSchema.getSchema(messageSchema.getField(firstField).type); } } //this.logWarn("transforming reply for operation: " + operationName + // " toJS using schema " + schema); data = isc.xml.toJS(data, null, schema); this.fireCallback(context._callOperationCallback, "data,xmlDoc,rpcResponse,wsRequest", [data,xmlDoc,rpcResponse,rpcRequest]); }, // when applying an XPath selector to the output of a web service, our default namespacing // strategy of providing all the namespaces declared on the document element // generally fails because we just get SOAP-related namespaces. Furthermore, the web // service may use auto-generated prefixes for namespaces, so in general we can't rely on // the returned document alone for reasonable namespace prefixes. Instead, provide the // schema namespace from the outermost element, and the service namespace getOutputNamespaces : function (operation, namespaces) { var schema = this.getDefaultOutputDS(operation); return isc.addProperties({ "default" : schema.schemaNamespace || this.serviceNamespace, schema : schema.schemaNamespace, service : this.serviceNamespace }, namespaces); }, getDataURL : function (operationName) { // NOTE: per-operation URLs can't be defined in WSDL, this is here for spoofing var operation = this.getOperation(operationName); if (operation && operation.dataURL) return operation.dataURL; return this.dataURL; }, // SOAP message serialization // --------------------------------------------------------------------------------------- //> @method webService.getMessageSerializer() [A] // Get the schema used to serialize the entire request // // @param operationName (String or WSRequest) name of the web service operation, or a // WSRequest specifying it // @param forResponse (boolean) whether a serializer is request for the response message, // as opposed to the request message (the default) // @return (DataSource) schema used for serialization //< getMessageSerializer : function (operationName, forResponse) { var serializer = forResponse ? this.getResponseMessage(operationName) : this.getRequestMessage(operationName); if (serializer == null) { this.logWarn("no " + (forResponse ? "response" : "request") + " message definition found for operation: '" + operationName); return; } // in rpc-style soap, the outermost element of the body is named after the message // name. In document-style soap, there is no element that corresponds to the message // name, only it's contents. Therefore for document-style SOAP if there is exactly one // subelement of the message (the most common style by far), use that as the input // schema. This means that when a message is supposed to look like this: // <login> // <username>bob</username> // <password>mebob</password> // </login> // The JS data you need to pass is: // { username:"bob", password:"mebob" } // .. instead of the surprising and less obvious: // { login : { username:"bob", password:"mebob" } } if (this.getSoapStyle(operationName) != "document") return serializer; var fieldNames = serializer.getFieldNames(); if (fieldNames.length == 1 && serializer.fieldIsComplexType(fieldNames[0])) { var field = serializer.getField(fieldNames[0]); //this.logWarn("skipping message element and using field: " + this.echo(field)); serializer = serializer.getSchema(field.type, field.xsElementRef ? "element" : null); if (serializer == null) { this.logWarn("can't find schema: " + field.type + ", part of " + (forResponse ? "response" : "request") +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -