/**
* @file Manages method call to SOAP endpoint
* @author Shinichi Tomita <shinichi.tomita@gmail.com>
*/
var _ = require('underscore'),
xml2js = require('xml2js'),
request = require('./request');
/**
* Class for SOAP endpoint of Salesforce
*
* @protected
* @class
* @constructor
* @param {Object} options - SOAP endpoint setting options
* @param {String} options.serverUrl - SOAP endpoint URL
* @param {String} options.sessionId - Salesforce session ID
* @param {String} [options.xmlns] - XML namespace for method call (default is "urn:partner.soap.sforce.com")
*/
var SOAP = module.exports = function(options) {
this.serverUrl = options.serverUrl;
this.sessionId = options.sessionId;
this.xmlns = options.xmlns || 'urn:partner.soap.sforce.com';
};
/**
* Invoke SOAP call using method and arguments
*
* @param {String} method - Method name
* @param {Object} args - Arguments for the method call
* @param {Callback.<Object>} [callback] - Callback function
* @returns {Promise.<Object>}
*/
SOAP.prototype.invoke = function(method, args, callback) {
var message = {};
message[method] = args;
var soapEnvelope = this._createEnvelope(message);
return request({
method: 'POST',
url: this.serverUrl,
headers: {
'Content-Type': 'text/xml',
'SOAPAction': '""'
},
body: soapEnvelope
}).then(function(res) {
var ret = null;
xml2js.parseString(res.body, { explicitArray: false }, function(err, value) { ret = value; });
if (ret) {
var error = lookupValue(ret, [ /:Envelope$/, /:Body$/, /:Fault$/, /faultstring$/ ]);
if (error) {
throw new Error(error);
}
return lookupValue(ret, [ /:Envelope$/, /:Body$/, /.+/ ]);
}
throw new Error("invalid response");
}).thenCall(callback);
};
/**
* @private
*/
function lookupValue(obj, propRegExps) {
var regexp = propRegExps.shift();
if (!regexp) {
return obj;
}
else {
for (var prop in obj) {
if (regexp.test(prop)) {
return lookupValue(obj[prop], propRegExps);
}
}
return null;
}
}
/**
* @private
*/
function toXML(name, value) {
if (_.isObject(name)) {
value = name;
name = null;
}
if (_.isArray(value)) {
return _.map(value, function(v) { return toXML(name, v); }).join('');
} else {
var attrs = [];
var elems = [];
if (_.isObject(value)) {
for (var k in value) {
var v = value[k];
if (k[0] === '@') {
k = k.substring(1);
attrs.push(k + '="' + v + '"');
} else {
elems.push(toXML(k, v));
}
}
value = elems.join('');
} else {
value = String(value);
}
var startTag = name ? '<' + name + (attrs.length > 0 ? ' ' + attrs.join(' ') : '') + '>' : '';
var endTag = name ? '</' + name + '>' : '';
return startTag + value + endTag;
}
}
/**
* @private
*/
SOAP.prototype._createEnvelope = function(message) {
return [
'<?xml version="1.0" encoding="UTF-8"?>',
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"',
' xmlns:xsd="http://www.w3.org/2001/XMLSchema"',
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">',
'<soapenv:Header xmlns="' + this.xmlns + '">',
'<SessionHeader>',
'<sessionId>' + this.sessionId + '</sessionId>',
'</SessionHeader>',
'</soapenv:Header>',
'<soapenv:Body xmlns="' + this.xmlns + '">',
toXML(message),
'</soapenv:Body>',
'</soapenv:Envelope>'
].join('');
};