Salesforce.com interface to directly access Salesforce.com

Dependencies:   HTTPClient-SSL MbedJSONValue

Dependents:   df-2014-salesforce-hrm-k64f

Fork of SalesforceInterface by Doug Anson

Committer:
ansond
Date:
Mon Sep 22 04:28:02 2014 +0000
Revision:
8:47db53cd5884
Parent:
7:97ea5ef906f7
Child:
9:a254fcd904be
fixes to enable query to work

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ansond 0:518b1ca956fc 1 /* Copyright C2014 ARM, MIT License
ansond 0:518b1ca956fc 2 *
ansond 0:518b1ca956fc 3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
ansond 0:518b1ca956fc 4 * and associated documentation files the "Software", to deal in the Software without restriction,
ansond 0:518b1ca956fc 5 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
ansond 0:518b1ca956fc 6 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
ansond 0:518b1ca956fc 7 * furnished to do so, subject to the following conditions:
ansond 0:518b1ca956fc 8 *
ansond 0:518b1ca956fc 9 * The above copyright notice and this permission notice shall be included in all copies or
ansond 0:518b1ca956fc 10 * substantial portions of the Software.
ansond 0:518b1ca956fc 11 *
ansond 0:518b1ca956fc 12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
ansond 0:518b1ca956fc 13 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
ansond 0:518b1ca956fc 14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
ansond 0:518b1ca956fc 15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ansond 0:518b1ca956fc 16 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
ansond 0:518b1ca956fc 17 */
ansond 0:518b1ca956fc 18
ansond 0:518b1ca956fc 19 // Tuneables
ansond 0:518b1ca956fc 20 #define SF_OAUTH_TOKEN_URL "https://login.salesforce.com/services/oauth2/token"
ansond 0:518b1ca956fc 21 #define SF_OAUTH_REQUEST_BODY "grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s"
ansond 0:518b1ca956fc 22 #define SF_HTTP_AUTH_HEADER "Authorization: Bearer %s"
ansond 0:518b1ca956fc 23
ansond 8:47db53cd5884 24 // search tokens for URLS in salesforce ID
ansond 8:47db53cd5884 25 #define SF_URLS_START_TOKEN "\"urls\":"
ansond 8:47db53cd5884 26 #define SF_URLS_STOP_TOKEN "},"
ansond 8:47db53cd5884 27
ansond 8:47db53cd5884 28 // salesforce QUERY specifier within URL
ansond 8:47db53cd5884 29 #define SF_QUERY_URL_SPECIFIER "q="
ansond 8:47db53cd5884 30
ansond 8:47db53cd5884 31 // salesforce URL API version token
ansond 8:47db53cd5884 32 #define SF_URL_API_VER_TOKEN "{version}"
ansond 8:47db53cd5884 33
ansond 0:518b1ca956fc 34 // include class definition
ansond 0:518b1ca956fc 35 #include "SalesforceInterface.h"
ansond 0:518b1ca956fc 36
ansond 0:518b1ca956fc 37 // Supported DataTypes for HTTPClient
ansond 0:518b1ca956fc 38 #include "HTTPMap.h"
ansond 0:518b1ca956fc 39 #include "HTTPJson.h"
ansond 0:518b1ca956fc 40
ansond 0:518b1ca956fc 41 // default constructor
ansond 0:518b1ca956fc 42 SalesforceInterface::SalesforceInterface(ErrorHandler *logger,HTTPClient *http) {
ansond 0:518b1ca956fc 43 this->m_logger = logger;
ansond 0:518b1ca956fc 44 this->m_http = http;
ansond 0:518b1ca956fc 45 this->m_username = NULL;
ansond 0:518b1ca956fc 46 this->m_password = NULL;
ansond 0:518b1ca956fc 47 this->m_client_id = NULL;
ansond 0:518b1ca956fc 48 this->m_client_secret = NULL;
ansond 0:518b1ca956fc 49 this->m_have_creds = false;
ansond 7:97ea5ef906f7 50 this->m_http_status = HTTP_OK;
ansond 7:97ea5ef906f7 51 this->m_http_response_code = -1;
ansond 7:97ea5ef906f7 52 RESET_BUFFER(this->m_http_redirection_url);
ansond 8:47db53cd5884 53 RESET_BUFFER(this->m_salesforce_id);
ansond 8:47db53cd5884 54 memset(this->m_salesforce_api,0,SALESFORCE_API_VERSION_LENGTH);
ansond 8:47db53cd5884 55 strcpy(this->m_salesforce_api,SALESFORCE_API_VERSION);
ansond 7:97ea5ef906f7 56 this->resetOauthToken();
ansond 0:518b1ca956fc 57 }
ansond 0:518b1ca956fc 58
ansond 0:518b1ca956fc 59 // destructor
ansond 0:518b1ca956fc 60 SalesforceInterface::~SalesforceInterface() {
ansond 0:518b1ca956fc 61 }
ansond 0:518b1ca956fc 62
ansond 0:518b1ca956fc 63 // set credentials
ansond 0:518b1ca956fc 64 void SalesforceInterface::setCredentials(char *username,char *password,char *client_id,char *client_secret) {
ansond 0:518b1ca956fc 65 this->m_username = NULL;
ansond 0:518b1ca956fc 66 this->m_password = NULL;
ansond 0:518b1ca956fc 67 this->m_client_id = NULL;
ansond 0:518b1ca956fc 68 this->m_client_secret = NULL;
ansond 0:518b1ca956fc 69 this->m_have_creds = false;
ansond 0:518b1ca956fc 70
ansond 0:518b1ca956fc 71 if (username != NULL) {
ansond 0:518b1ca956fc 72 this->m_username = username;
ansond 0:518b1ca956fc 73 if (password != NULL) {
ansond 0:518b1ca956fc 74 this->m_password = password;
ansond 0:518b1ca956fc 75 if (client_id != NULL) {
ansond 0:518b1ca956fc 76 this->m_client_id = client_id;
ansond 0:518b1ca956fc 77 if (client_secret != NULL) {
ansond 0:518b1ca956fc 78 this->m_client_secret = client_secret;
ansond 0:518b1ca956fc 79 this->m_have_creds = true;
ansond 0:518b1ca956fc 80 }
ansond 0:518b1ca956fc 81 }
ansond 0:518b1ca956fc 82 }
ansond 0:518b1ca956fc 83 }
ansond 0:518b1ca956fc 84 }
ansond 0:518b1ca956fc 85
ansond 0:518b1ca956fc 86 // convenience accessors
ansond 0:518b1ca956fc 87 ErrorHandler *SalesforceInterface::logger() { return this->m_logger; }
ansond 0:518b1ca956fc 88 HTTPClient *SalesforceInterface::http() { return this->m_http; }
ansond 7:97ea5ef906f7 89 OauthToken *SalesforceInterface::oauth() { return &this->m_oauth_token; }
ansond 0:518b1ca956fc 90 bool SalesforceInterface::haveCreds() { return this->m_have_creds; }
ansond 7:97ea5ef906f7 91 HTTPResult SalesforceInterface::httpStatus() { return this->m_http_status; }
ansond 7:97ea5ef906f7 92 int SalesforceInterface::httpResponseCode() { return this->m_http_response_code; }
ansond 8:47db53cd5884 93 void SalesforceInterface::setSalesforceAPIVersion(int version) { sprintf(this->m_salesforce_api,"%d",version); }
ansond 8:47db53cd5884 94 void SalesforceInterface::setSalesforceAPIVersion(char *version) { if (version != NULL && strlen(version) > 0 && strlen(version) < SALESFORCE_API_VERSION_LENGTH) strcpy(this->m_salesforce_api,version); }
ansond 8:47db53cd5884 95 char *SalesforceInterface::getSalesforceAPIVersion() { return this->m_salesforce_api; }
ansond 7:97ea5ef906f7 96
ansond 7:97ea5ef906f7 97 // reset our oauth token
ansond 7:97ea5ef906f7 98 void SalesforceInterface::resetOauthToken() {
ansond 7:97ea5ef906f7 99 //DEBUG("resetting OAUTH token...");
ansond 7:97ea5ef906f7 100 this->m_oauth_token.valid = false;
ansond 7:97ea5ef906f7 101 this->m_oauth_token.id = "";
ansond 7:97ea5ef906f7 102 this->m_oauth_token.issued_at = "";
ansond 7:97ea5ef906f7 103 this->m_oauth_token.token_type = "";
ansond 7:97ea5ef906f7 104 this->m_oauth_token.instance_url = "";
ansond 7:97ea5ef906f7 105 this->m_oauth_token.signature = "";
ansond 7:97ea5ef906f7 106 this->m_oauth_token.access_token = "";
ansond 7:97ea5ef906f7 107 }
ansond 7:97ea5ef906f7 108
ansond 7:97ea5ef906f7 109 // fill our oauth token
ansond 7:97ea5ef906f7 110 void SalesforceInterface::fillOauthToken(char *token) {
ansond 7:97ea5ef906f7 111 if (token != NULL && strlen(token) > 0) {
ansond 7:97ea5ef906f7 112 // parse JSON
ansond 7:97ea5ef906f7 113 MbedJSONValue parsed_token;
ansond 7:97ea5ef906f7 114 parse(parsed_token,token);
ansond 7:97ea5ef906f7 115
ansond 7:97ea5ef906f7 116 // fill our OAUTH token
ansond 7:97ea5ef906f7 117 this->m_oauth_token.id = parsed_token["id"].get<std::string>();
ansond 7:97ea5ef906f7 118 this->m_oauth_token.issued_at = parsed_token["issued_at"].get<std::string>();
ansond 7:97ea5ef906f7 119 this->m_oauth_token.token_type = parsed_token["token_type"].get<std::string>();
ansond 7:97ea5ef906f7 120 this->m_oauth_token.instance_url = parsed_token["instance_url"].get<std::string>();
ansond 7:97ea5ef906f7 121 this->m_oauth_token.signature = parsed_token["signature"].get<std::string>();
ansond 7:97ea5ef906f7 122 this->m_oauth_token.access_token = parsed_token["access_token"].get<std::string>();
ansond 7:97ea5ef906f7 123
ansond 7:97ea5ef906f7 124 // we have an OAUTH token now
ansond 7:97ea5ef906f7 125 this->m_oauth_token.valid = true;
ansond 7:97ea5ef906f7 126 DEBUG("valid OAUTH token acquired.");
ansond 7:97ea5ef906f7 127 return;
ansond 7:97ea5ef906f7 128 }
ansond 7:97ea5ef906f7 129 DEBUG("error: invalid or null OAUTH token fill attempt.");
ansond 7:97ea5ef906f7 130 }
ansond 7:97ea5ef906f7 131
ansond 7:97ea5ef906f7 132 // is our OAUTH token valid?
ansond 7:97ea5ef906f7 133 bool SalesforceInterface::validOauthToken() {
ansond 7:97ea5ef906f7 134 // make sure we have a valid OAUTH Token
ansond 7:97ea5ef906f7 135 this->checkAndGetOauthToken();
ansond 7:97ea5ef906f7 136
ansond 7:97ea5ef906f7 137 // TODO: we currently only return fill status. Later we may want to check dates too...
ansond 7:97ea5ef906f7 138 return this->m_oauth_token.valid;
ansond 8:47db53cd5884 139 }
ansond 8:47db53cd5884 140
ansond 8:47db53cd5884 141 // do we have a valid salesforce.com ID?
ansond 8:47db53cd5884 142 bool SalesforceInterface::haveSalesforceID() {
ansond 8:47db53cd5884 143 if (this->m_salesforce_id != NULL && strlen(this->m_salesforce_id) > 0) return true;
ansond 8:47db53cd5884 144 return false;
ansond 8:47db53cd5884 145 }
ansond 7:97ea5ef906f7 146
ansond 7:97ea5ef906f7 147 // check and get our OAUTH token
ansond 7:97ea5ef906f7 148 void SalesforceInterface::checkAndGetOauthToken() {
ansond 7:97ea5ef906f7 149 DEBUG("checking for valid OAUTH token...");
ansond 7:97ea5ef906f7 150 if (this->m_oauth_token.valid == false) {
ansond 7:97ea5ef906f7 151 // re-initialize token
ansond 7:97ea5ef906f7 152 this->resetOauthToken();
ansond 7:97ea5ef906f7 153
ansond 7:97ea5ef906f7 154 // get our Token
ansond 7:97ea5ef906f7 155 ALLOC_BUFFER(output_buffer);
ansond 7:97ea5ef906f7 156 char *token = this->getOauthToken(output_buffer,MAX_BUFFER_LENGTH);
ansond 7:97ea5ef906f7 157
ansond 7:97ea5ef906f7 158 // fill
ansond 7:97ea5ef906f7 159 this->fillOauthToken(token);
ansond 7:97ea5ef906f7 160 return;
ansond 7:97ea5ef906f7 161 }
ansond 7:97ea5ef906f7 162 DEBUG("valid OAUTH token found.");
ansond 7:97ea5ef906f7 163 }
ansond 0:518b1ca956fc 164
ansond 0:518b1ca956fc 165 //
ansond 0:518b1ca956fc 166 // get OAUTH2 Token - taken from here:
ansond 0:518b1ca956fc 167 // https://developer.salesforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com#Obtaining_a_Token_in_an_Autonomous_Client_.28Username_and_Password_Flow.29
ansond 0:518b1ca956fc 168 //
ansond 0:518b1ca956fc 169 char *SalesforceInterface::getOauthToken(char *output_buffer,int output_buffer_length) {
ansond 1:a7dca096e47d 170 if (this->haveCreds()) {
ansond 0:518b1ca956fc 171 // construct the OAUTH2 Token request body
ansond 0:518b1ca956fc 172 HTTPMap input;
ansond 0:518b1ca956fc 173
ansond 0:518b1ca956fc 174 //
ansond 0:518b1ca956fc 175 // FORMAT: Taken from URL above method signature:
ansond 0:518b1ca956fc 176 //
ansond 0:518b1ca956fc 177 // grant_type=password&client_id=<your_client_id>&client_secret=<your_client_secret>&username=<your_username>&password=<your_password>
ansond 0:518b1ca956fc 178 //
ansond 0:518b1ca956fc 179 // ContentType: application/x-www-form-urlencoded
ansond 0:518b1ca956fc 180 //
ansond 0:518b1ca956fc 181 input.put("grant_type","password");
ansond 0:518b1ca956fc 182 input.put("client_id",this->m_client_id);
ansond 0:518b1ca956fc 183 input.put("client_secret",this->m_client_secret);
ansond 0:518b1ca956fc 184 input.put("username",this->m_username);
ansond 0:518b1ca956fc 185 input.put("password",this->m_password);
ansond 1:a7dca096e47d 186
ansond 0:518b1ca956fc 187 // prepare the output buffer
ansond 0:518b1ca956fc 188 HTTPText output(output_buffer,output_buffer_length);
ansond 0:518b1ca956fc 189
ansond 0:518b1ca956fc 190 // HTTP POST call to gett he token
ansond 7:97ea5ef906f7 191 DEBUG("Getting OAUTH Token...");
ansond 7:97ea5ef906f7 192 this->m_http_status = this->http()->post(SF_OAUTH_TOKEN_URL,input,&output);
ansond 7:97ea5ef906f7 193
ansond 0:518b1ca956fc 194 // check the result and return the token
ansond 7:97ea5ef906f7 195 if (this->m_http_status == HTTP_OK) return output_buffer;
ansond 7:97ea5ef906f7 196 this->logger()->log("oauth invocation failed. URL: %s",SF_OAUTH_TOKEN_URL);
ansond 0:518b1ca956fc 197 }
ansond 0:518b1ca956fc 198 else {
ansond 0:518b1ca956fc 199 // no credentials
ansond 0:518b1ca956fc 200 this->logger()->log("no/incomplete salesforce.com credentials provided. Unable to acquire OAUTH2 token...");
ansond 0:518b1ca956fc 201 }
ansond 0:518b1ca956fc 202 return NULL;
ansond 0:518b1ca956fc 203 }
ansond 0:518b1ca956fc 204
ansond 7:97ea5ef906f7 205 // Salesforce.com: Get our ID
ansond 8:47db53cd5884 206 char *SalesforceInterface::getSalesforceID() {
ansond 7:97ea5ef906f7 207 // proceed only if we have a valid OAUTH Token
ansond 7:97ea5ef906f7 208 if (this->validOauthToken() == true) {
ansond 7:97ea5ef906f7 209 // pull the ID from salesforce
ansond 8:47db53cd5884 210 RESET_BUFFER(this->m_salesforce_id);
ansond 8:47db53cd5884 211 char *id = this->invoke(this->oauth()->id.c_str(),this->m_salesforce_id,MAX_BUFFER_LENGTH);
ansond 7:97ea5ef906f7 212
ansond 7:97ea5ef906f7 213 // log any error status and return what we have...
ansond 7:97ea5ef906f7 214 if (this->httpStatus() != HTTP_OK) this->logger()->log("Unable to get Salesforce ID: status=%d httpCode=%d",this->httpStatus(),this->httpResponseCode());
ansond 7:97ea5ef906f7 215 return id;
ansond 7:97ea5ef906f7 216 }
ansond 7:97ea5ef906f7 217 else {
ansond 7:97ea5ef906f7 218 // unable to get ID - no OAUTH token
ansond 7:97ea5ef906f7 219 this->logger()->log("Unable to get Salesforce ID: no valid OAUTH token.");
ansond 7:97ea5ef906f7 220 }
ansond 7:97ea5ef906f7 221 return NULL;
ansond 7:97ea5ef906f7 222 }
ansond 7:97ea5ef906f7 223
ansond 8:47db53cd5884 224 // QUERY: Salesforce.com
ansond 8:47db53cd5884 225 char *SalesforceInterface::query(char *query_str,char *output_buffer,int output_buffer_length) {
ansond 8:47db53cd5884 226 // first we have to ensure that we have valid salesforce ID
ansond 8:47db53cd5884 227 if (this->haveSalesforceID()) {
ansond 8:47db53cd5884 228 // get the QUERY URL
ansond 8:47db53cd5884 229 ALLOC_BUFFER(url);
ansond 8:47db53cd5884 230 char *sf_url = this->getSalesforceURL("query",url,MAX_BUFFER_LENGTH);
ansond 8:47db53cd5884 231 if (sf_url != NULL && strlen(sf_url) > 0) {
ansond 8:47db53cd5884 232 // make sure that the query string is ready to ship...
ansond 8:47db53cd5884 233 ALLOC_SML_BUFFER(tmp_query);
ansond 8:47db53cd5884 234
ansond 8:47db53cd5884 235 // replace all spaces in query with "+"
ansond 8:47db53cd5884 236 strcpy(tmp_query,query_str);
ansond 8:47db53cd5884 237 this->replace(tmp_query,' ','+'); // will modify tmp_query directly...
ansond 8:47db53cd5884 238
ansond 8:47db53cd5884 239 // customize the URL with our (formatted) query string
ansond 8:47db53cd5884 240 string str_url(sf_url);
ansond 8:47db53cd5884 241 str_url[str_url.length()-1] = '?'; // remove the slash and add a ?
ansond 8:47db53cd5884 242 str_url = str_url + SF_QUERY_URL_SPECIFIER + tmp_query; // add the query specifier
ansond 8:47db53cd5884 243
ansond 8:47db53cd5884 244 // DEBUG - show the query URL
ansond 8:47db53cd5884 245 DEBUG("query URL: %s",str_url.c_str());
ansond 8:47db53cd5884 246
ansond 8:47db53cd5884 247 // invoke with GET
ansond 8:47db53cd5884 248 return this->invoke((const char *)str_url.c_str(),output_buffer,output_buffer_length);
ansond 8:47db53cd5884 249 }
ansond 8:47db53cd5884 250 else {
ansond 8:47db53cd5884 251 // unable to find the query URL...
ansond 8:47db53cd5884 252 this->logger()->log("query: error - unable to find query URL in salesforce ID...");
ansond 8:47db53cd5884 253 }
ansond 8:47db53cd5884 254 }
ansond 8:47db53cd5884 255 else {
ansond 8:47db53cd5884 256 // dont have a valid salesforce ID
ansond 8:47db53cd5884 257 this->logger()->log("query: error - no valid salesforced ID was found...");
ansond 8:47db53cd5884 258 }
ansond 8:47db53cd5884 259 return NULL;
ansond 8:47db53cd5884 260 }
ansond 8:47db53cd5884 261
ansond 0:518b1ca956fc 262 // Salesforce.com Invoke: defaults to GET
ansond 7:97ea5ef906f7 263 char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_len) {
ansond 0:518b1ca956fc 264 return this->invoke(url,NUM_TYPES,NULL,0,output_buffer,output_buffer_len,GET);
ansond 0:518b1ca956fc 265 }
ansond 0:518b1ca956fc 266
ansond 0:518b1ca956fc 267 // Salesforce.com Invoke: defaults to POST with JSON input data type
ansond 7:97ea5ef906f7 268 char *SalesforceInterface::invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len) {
ansond 0:518b1ca956fc 269 return this->invoke(url,JSON,input_data,input_data_len,output_buffer,output_buffer_len);
ansond 0:518b1ca956fc 270 }
ansond 0:518b1ca956fc 271
ansond 0:518b1ca956fc 272 // Salesforce.com Invoke: defaults to POST with variable input data type
ansond 7:97ea5ef906f7 273 char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len) {
ansond 0:518b1ca956fc 274 return this->invoke(url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,POST);
ansond 0:518b1ca956fc 275 }
ansond 0:518b1ca956fc 276
ansond 0:518b1ca956fc 277 // Salesforce.com Invoke: full fidelity method
ansond 7:97ea5ef906f7 278 char *SalesforceInterface::invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len,const HttpVerb verb) {
ansond 7:97ea5ef906f7 279 // initialize our invocation status and response code
ansond 7:97ea5ef906f7 280 this->m_http_response_code = -1;
ansond 7:97ea5ef906f7 281 this->m_http_status = HTTP_ERROR;
ansond 7:97ea5ef906f7 282
ansond 7:97ea5ef906f7 283 // param check: make sure that we at least have an output buffer and URL
ansond 7:97ea5ef906f7 284 if (url != NULL && strlen(url) > 0 && output_buffer != NULL && output_buffer_len > 0) {
ansond 7:97ea5ef906f7 285 // proceed only if we have a valid OAUTH Token
ansond 7:97ea5ef906f7 286 if (this->validOauthToken() == true) {
ansond 7:97ea5ef906f7 287 // use OAUTH headers
ansond 7:97ea5ef906f7 288 this->http()->oauthToken(this->oauth()->access_token.c_str());
ansond 0:518b1ca956fc 289
ansond 7:97ea5ef906f7 290 // reset the redirection url buffer in case we get a redirect...
ansond 7:97ea5ef906f7 291 RESET_BUFFER(this->m_http_redirection_url);
ansond 7:97ea5ef906f7 292 this->http()->setLocationBuf((char *)this->m_http_redirection_url,MAX_BUFFER_LENGTH);
ansond 7:97ea5ef906f7 293
ansond 0:518b1ca956fc 294 // create our output/response buffer
ansond 0:518b1ca956fc 295 HTTPText output(output_buffer,output_buffer_len);
ansond 0:518b1ca956fc 296
ansond 0:518b1ca956fc 297 // now make the HTTP(S) request
ansond 0:518b1ca956fc 298 switch(verb) {
ansond 0:518b1ca956fc 299 case GET:
ansond 7:97ea5ef906f7 300 DEBUG("invoking(GET) URL: %s...",url);
ansond 7:97ea5ef906f7 301 this->m_http_status = this->http()->get(url,&output);
ansond 7:97ea5ef906f7 302 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 303 break;
ansond 0:518b1ca956fc 304 case DELETE:
ansond 7:97ea5ef906f7 305 DEBUG("invoking(DEL) URL: %s...",url);
ansond 7:97ea5ef906f7 306 this->m_http_status = this->http()->del(url,&output);
ansond 7:97ea5ef906f7 307 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 308 break;
ansond 0:518b1ca956fc 309 case POST:
ansond 0:518b1ca956fc 310 if (input_data != NULL && input_data_len > 0) {
ansond 0:518b1ca956fc 311 if (input_type == JSON) {
ansond 7:97ea5ef906f7 312 DEBUG("invoking(POST-JSON) URL: %s...",url);
ansond 7:97ea5ef906f7 313 HTTPJson input_json((char *)input_data,(int)input_data_len);
ansond 7:97ea5ef906f7 314 this->m_http_status = this->http()->post(url,input_json,&output);
ansond 7:97ea5ef906f7 315 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 316 }
ansond 0:518b1ca956fc 317 else {
ansond 7:97ea5ef906f7 318 DEBUG("invoking(POST-TEXT) URL: %s...",url);
ansond 7:97ea5ef906f7 319 HTTPText input_text((char *)input_data,(int)input_data_len);
ansond 7:97ea5ef906f7 320 this->m_http_status = this->http()->post(url,input_text,&output);
ansond 7:97ea5ef906f7 321 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 322 }
ansond 0:518b1ca956fc 323 }
ansond 0:518b1ca956fc 324 else {
ansond 0:518b1ca956fc 325 // no input buffer!
ansond 0:518b1ca956fc 326 this->logger()->log("invoke: ERROR HTTP(POST) requested but no input data provided... returning NULL");
ansond 0:518b1ca956fc 327 }
ansond 0:518b1ca956fc 328 break;
ansond 0:518b1ca956fc 329 case PUT:
ansond 0:518b1ca956fc 330 if (input_data != NULL && input_data_len > 0) {
ansond 0:518b1ca956fc 331 if (input_type == JSON) {
ansond 7:97ea5ef906f7 332 DEBUG("invoking(PUT-JSON) URL: %s...",url);
ansond 7:97ea5ef906f7 333 HTTPJson input_json((char *)input_data,(int)input_data_len);
ansond 7:97ea5ef906f7 334 this->m_http_status = this->http()->put(url,input_json,&output);
ansond 7:97ea5ef906f7 335 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 336 }
ansond 0:518b1ca956fc 337 else {
ansond 7:97ea5ef906f7 338 DEBUG("invoking(PUT-TEXT) URL: %s...",url);
ansond 7:97ea5ef906f7 339 HTTPText input_text((char *)input_data,(int)input_data_len);
ansond 7:97ea5ef906f7 340 this->m_http_status = this->http()->put(url,input_text,&output);
ansond 7:97ea5ef906f7 341 this->m_http_response_code = this->http()->getHTTPResponseCode();
ansond 0:518b1ca956fc 342 }
ansond 0:518b1ca956fc 343 }
ansond 0:518b1ca956fc 344 else {
ansond 0:518b1ca956fc 345 // no input buffer!
ansond 0:518b1ca956fc 346 this->logger()->log("invoke: ERROR HTTP(PUT) requested but no input data provided... returning NULL");
ansond 0:518b1ca956fc 347 }
ansond 0:518b1ca956fc 348 break;
ansond 0:518b1ca956fc 349 default:
ansond 0:518b1ca956fc 350 // invalid HTTP verb
ansond 0:518b1ca956fc 351 this->logger()->log("invoke: ERROR invalid HTTP verb (%d) provided... returning NULL",verb);
ansond 0:518b1ca956fc 352 break;
ansond 0:518b1ca956fc 353 }
ansond 0:518b1ca956fc 354 }
ansond 7:97ea5ef906f7 355 else {
ansond 7:97ea5ef906f7 356 // no OAUTH Token
ansond 7:97ea5ef906f7 357 this->logger()->log("unable to acquire OAUTH token for credentials provided. Unable to invoke API...");
ansond 7:97ea5ef906f7 358 }
ansond 0:518b1ca956fc 359 }
ansond 0:518b1ca956fc 360 else {
ansond 0:518b1ca956fc 361 // no credentials
ansond 0:518b1ca956fc 362 this->logger()->log("no/incomplete salesforce.com credentials provided. Unable to invoke API...");
ansond 0:518b1ca956fc 363 }
ansond 0:518b1ca956fc 364
ansond 7:97ea5ef906f7 365 // process any return results that we have
ansond 7:97ea5ef906f7 366 if (this->httpStatus() == HTTP_OK || this->httpStatus() == HTTP_REDIRECT) {
ansond 7:97ea5ef906f7 367 // do we have any redirections?
ansond 7:97ea5ef906f7 368 if (this->httpResponseCode() == 302 /* REDIRECT */ && strlen(this->m_http_redirection_url) > 0) {
ansond 7:97ea5ef906f7 369 // we have a redirect - so reset the output buffer
ansond 7:97ea5ef906f7 370 memset(output_buffer,0,output_buffer_len);
ansond 7:97ea5ef906f7 371
ansond 7:97ea5ef906f7 372 // we have to make a copy of the redirection URL - this is because the subsequent invoke() will wipe our current one clean
ansond 7:97ea5ef906f7 373 ALLOC_BUFFER(redirect_url);
ansond 7:97ea5ef906f7 374 strcpy(redirect_url,this->m_http_redirection_url);
ansond 7:97ea5ef906f7 375
ansond 7:97ea5ef906f7 376 // repeat with the redirection URL
ansond 7:97ea5ef906f7 377 DEBUG("invoke: redirecting to: %s",redirect_url);
ansond 7:97ea5ef906f7 378 return this->invoke((const char *)redirect_url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,verb);
ansond 7:97ea5ef906f7 379 }
ansond 7:97ea5ef906f7 380 else if (this->httpResponseCode() == 302 /* REDIRECT */) {
ansond 7:97ea5ef906f7 381 // error - got a redirect but have no URL
ansond 7:97ea5ef906f7 382 this->logger()->log("invoke error: received redirect but no URL...");
ansond 7:97ea5ef906f7 383 this->m_http_status = HTTP_ERROR;
ansond 7:97ea5ef906f7 384 }
ansond 7:97ea5ef906f7 385 }
ansond 7:97ea5ef906f7 386
ansond 0:518b1ca956fc 387 // return the response in the output buffer
ansond 7:97ea5ef906f7 388 if (this->httpStatus() == HTTP_OK) return output_buffer;
ansond 7:97ea5ef906f7 389 else this->logger()->log("invocation failed with HTTP error code=%d status=%d",this->httpResponseCode(),this->httpStatus());
ansond 0:518b1ca956fc 390 return NULL;
ansond 0:518b1ca956fc 391 }
ansond 8:47db53cd5884 392
ansond 8:47db53cd5884 393 // find the specific URL in our salesforce ID
ansond 8:47db53cd5884 394 char *SalesforceInterface::getSalesforceURL(char *key,char *url_buffer,int url_buffer_length) {
ansond 8:47db53cd5884 395 // due to MbedJSONValue limitations - we have to manually pull out the specific JSON from our salesforce ID
ansond 8:47db53cd5884 396 int start = (int)strstr(this->m_salesforce_id,SF_URLS_START_TOKEN);
ansond 8:47db53cd5884 397 if (start >= 0) {
ansond 8:47db53cd5884 398 start += strlen(SF_URLS_START_TOKEN);
ansond 8:47db53cd5884 399 int stop = (int)strstr((char *)start,SF_URLS_STOP_TOKEN);
ansond 8:47db53cd5884 400 if (stop >= 0 && stop > start) {
ansond 8:47db53cd5884 401 // calculate the length
ansond 8:47db53cd5884 402 int length = stop - start + 1;
ansond 8:47db53cd5884 403
ansond 8:47db53cd5884 404 // copy over the "urls" json from the salesforce ID
ansond 8:47db53cd5884 405 ALLOC_BUFFER(urls);
ansond 8:47db53cd5884 406 int start_index = (start - (int)this->m_salesforce_id);
ansond 8:47db53cd5884 407 for(int i=0;i<length;++i) urls[i] = this->m_salesforce_id[start_index+i];
ansond 8:47db53cd5884 408
ansond 8:47db53cd5884 409 // use MbedJSONValue to parse the "urls" json
ansond 8:47db53cd5884 410 MbedJSONValue parsed_urls;
ansond 8:47db53cd5884 411 parse(parsed_urls,urls);
ansond 8:47db53cd5884 412
ansond 8:47db53cd5884 413 // find the appropriate URL and copy it
ansond 8:47db53cd5884 414 string target_url = parsed_urls[key].get<std::string>();
ansond 8:47db53cd5884 415
ansond 8:47db53cd5884 416 // replace the version of the string with our selected salesforce API version
ansond 8:47db53cd5884 417 string sf_version(this->getSalesforceAPIVersion());
ansond 8:47db53cd5884 418 string version_tag(SF_URL_API_VER_TOKEN);
ansond 8:47db53cd5884 419 this->replace(target_url,version_tag,sf_version);
ansond 8:47db53cd5884 420
ansond 8:47db53cd5884 421 // copy the final URL to our putput
ansond 8:47db53cd5884 422 memset(url_buffer,0,url_buffer_length);
ansond 8:47db53cd5884 423 strcpy(url_buffer,target_url.c_str());
ansond 8:47db53cd5884 424
ansond 8:47db53cd5884 425 // return the URL
ansond 8:47db53cd5884 426 return url_buffer;
ansond 8:47db53cd5884 427 }
ansond 8:47db53cd5884 428 }
ansond 8:47db53cd5884 429 return NULL;
ansond 8:47db53cd5884 430 }
ansond 8:47db53cd5884 431
ansond 8:47db53cd5884 432 // simple char array replacement (modifies input string!)
ansond 8:47db53cd5884 433 void SalesforceInterface::replace(char *str,char orig_char,char new_char) {
ansond 8:47db53cd5884 434 int length = strlen(str);
ansond 8:47db53cd5884 435 for(int i=0;i<length;++i) if (str[i] == orig_char) str[i] = new_char;
ansond 8:47db53cd5884 436 }
ansond 8:47db53cd5884 437
ansond 8:47db53cd5884 438 //
ansond 8:47db53cd5884 439 // substring replacement
ansond 8:47db53cd5884 440 // Credit: http://stackoverflow.com/questions/4643512/replace-substring-with-another-substring-c
ansond 8:47db53cd5884 441 //
ansond 8:47db53cd5884 442 void SalesforceInterface::replace(string& line, string& oldString, string& newString) {
ansond 8:47db53cd5884 443 const size_t oldSize = oldString.length();
ansond 8:47db53cd5884 444
ansond 8:47db53cd5884 445 // do nothing if line is shorter than the string to find
ansond 8:47db53cd5884 446 if( oldSize > line.length() ) return;
ansond 8:47db53cd5884 447
ansond 8:47db53cd5884 448 const size_t newSize = newString.length();
ansond 8:47db53cd5884 449 for( size_t pos = 0; ; pos += newSize ) {
ansond 8:47db53cd5884 450
ansond 8:47db53cd5884 451 // Locate the substring to replace
ansond 8:47db53cd5884 452 pos = line.find( oldString, pos );
ansond 8:47db53cd5884 453 if( pos == string::npos ) return;
ansond 8:47db53cd5884 454 if( oldSize == newSize ) {
ansond 8:47db53cd5884 455
ansond 8:47db53cd5884 456 // if they're same size, use std::string::replace
ansond 8:47db53cd5884 457 line.replace( pos, oldSize, newString );
ansond 8:47db53cd5884 458 }
ansond 8:47db53cd5884 459 else {
ansond 8:47db53cd5884 460
ansond 8:47db53cd5884 461 // if not same size, replace by erasing and inserting
ansond 8:47db53cd5884 462 line.erase( pos, oldSize );
ansond 8:47db53cd5884 463 line.insert( pos, newString );
ansond 8:47db53cd5884 464 }
ansond 8:47db53cd5884 465 }
ansond 8:47db53cd5884 466 }