Salesforce.com interface to directly access Salesforce.com

Dependencies:   HTTPClient-SSL MbedJSONValue

Dependents:   df-2014-salesforce-hrm-k64f

Fork of SalesforceInterface by Doug Anson

Revision:
9:a254fcd904be
Parent:
8:47db53cd5884
Child:
10:845ea6d00b65
--- a/SalesforceInterface.cpp	Mon Sep 22 04:28:02 2014 +0000
+++ b/SalesforceInterface.cpp	Tue Sep 23 05:40:18 2014 +0000
@@ -1,5 +1,7 @@
 /* Copyright C2014 ARM, MIT License
  *
+ * Author: Doug Anson (doug.anson@arm.com)
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
  * and associated documentation files the "Software", to deal in the Software without restriction,
  * including without limitation the rights to use, copy, modify, merge, publish, distribute,
@@ -50,10 +52,9 @@
      this->m_http_status = HTTP_OK;
      this->m_http_response_code = -1;
      RESET_BUFFER(this->m_http_redirection_url);
-     RESET_BUFFER(this->m_salesforce_id);
      memset(this->m_salesforce_api,0,SALESFORCE_API_VERSION_LENGTH);
      strcpy(this->m_salesforce_api,SALESFORCE_API_VERSION);
-     this->resetOauthToken();
+     this->resetSalesforceID();
  }
  
  // destructor
@@ -96,7 +97,7 @@
  
  // reset our oauth token
  void SalesforceInterface::resetOauthToken() {
-     //DEBUG("resetting OAUTH token...");
+     DEBUG("resetting OAUTH token...");
      this->m_oauth_token.valid              = false;
      this->m_oauth_token.id                 = "";
      this->m_oauth_token.issued_at          = "";
@@ -104,6 +105,7 @@
      this->m_oauth_token.instance_url       = "";
      this->m_oauth_token.signature          = "";
      this->m_oauth_token.access_token       = "";
+     if (this->http() != NULL) this->http()->oauthToken(NULL);
  }
  
  // fill our oauth token
@@ -130,37 +132,64 @@
  }
  
  // is our OAUTH token valid?
- bool SalesforceInterface::validOauthToken() {         
+ bool SalesforceInterface::validOauthToken(bool fetch) {         
     // make sure we have a valid OAUTH Token
-    this->checkAndGetOauthToken();
-    
-    // TODO: we currently only return fill status. Later we may want to check dates too...
+    this->checkAndGetOauthToken(fetch);
     return this->m_oauth_token.valid; 
  }
+ 
+ // reset our salesforce ID and OAUTH tokens
+ void SalesforceInterface::resetSalesforceID() {
+     this->resetOauthToken();
+     RESET_BUFFER(this->m_salesforce_id);
+ }
 
  // do we have a valid salesforce.com ID?
- bool SalesforceInterface::haveSalesforceID() {
+ bool SalesforceInterface::haveSalesforceID(bool fetch) {
      if (this->m_salesforce_id != NULL && strlen(this->m_salesforce_id) > 0) return true;
+     if (fetch) {
+        this->logger()->log("No Salesforce ID found... fetching...");
+        this->getSalesforceID();
+        return this->haveSalesforceID(false);
+     }
      return false;
  }
  
  // check and get our OAUTH token
- void SalesforceInterface::checkAndGetOauthToken() {
+ void SalesforceInterface::checkAndGetOauthToken(bool fetch) {
      DEBUG("checking for valid OAUTH token...");
-     if (this->m_oauth_token.valid == false) {
-         // re-initialize token
-         this->resetOauthToken();
-         
-         // get our Token
+     
+     // reset the token structure for sanity...
+     if (this->m_oauth_token.valid == false) this->resetOauthToken();   
+     
+     // should go fetch our token if we dont have one?
+     // just pass through if we already have a token
+     if (this->m_oauth_token.valid == true) {
+        DEBUG("valid OAUTH token found.");
+     }
+     else if (this->m_oauth_token.valid == false && fetch == true) {
+         // get our OAUTH token
+         DEBUG("No OAUTH token found. Acquiring OAUTH token...");
          ALLOC_BUFFER(output_buffer);
          char *token = this->getOauthToken(output_buffer,MAX_BUFFER_LENGTH);
-         
-         // fill
-         this->fillOauthToken(token);
-         return;
+         if (token != NULL && strlen(token) > 0) {
+            // fill
+            DEBUG("Saving OAUTH token...");
+            this->fillOauthToken(token);
+            return;
+         }
+         else {
+             // unable to get the token (reset for sanity)
+             this->logger()->log("error in acquiring OAUTH token http_code=%d status=%d",this->httpResponseCode(),this->httpStatus());
+             this->resetOauthToken();
+         }
      }
-     DEBUG("valid OAUTH token found.");
- }
+     
+     // else report that we dont have a token
+     else {
+         this->logger()->log("No OAUTH token found (fetch=false).");
+     }
+ }  
  
  //
  // get OAUTH2 Token - taken from here: 
@@ -192,8 +221,8 @@
          this->m_http_status = this->http()->post(SF_OAUTH_TOKEN_URL,input,&output);
 
          // check the result and return the token
-         if (this->m_http_status == HTTP_OK) return output_buffer;
-         this->logger()->log("oauth invocation failed. URL: %s",SF_OAUTH_TOKEN_URL);
+         if (this->httpStatus() == HTTP_OK || this->httpResponseCode() == 200) return output_buffer;
+         this->logger()->log("acquire oauth FAILED. URL: %s http_code=%d status=%d",SF_OAUTH_TOKEN_URL,this->httpResponseCode(),this->httpStatus());
      }
      else {
          // no credentials
@@ -203,9 +232,9 @@
  }
  
  // Salesforce.com: Get our ID
- char *SalesforceInterface::getSalesforceID() {
+ char *SalesforceInterface::getSalesforceID(bool fetch) {
     // proceed only if we have a valid OAUTH Token
-    if (this->validOauthToken() == true) {
+    if (this->validOauthToken(fetch) == true) {
         // pull the ID from salesforce
         RESET_BUFFER(this->m_salesforce_id);
         char *id = this->invoke(this->oauth()->id.c_str(),this->m_salesforce_id,MAX_BUFFER_LENGTH);
@@ -225,7 +254,7 @@
  char *SalesforceInterface::query(char *query_str,char *output_buffer,int output_buffer_length) {
      // first we have to ensure that we have valid salesforce ID
      if (this->haveSalesforceID()) {        
-        // get the QUERY URL
+        // get the query url
         ALLOC_BUFFER(url);
         char *sf_url = this->getSalesforceURL("query",url,MAX_BUFFER_LENGTH);
         if (sf_url != NULL && strlen(sf_url) > 0) {
@@ -259,29 +288,240 @@
      return NULL;
  }
  
+ // CREATE: a field in Salesforce.com
+ MbedJSONValue SalesforceInterface::createField(char *object_name,MbedJSONValue &field) { 
+    ALLOC_BUFFER(output_buffer);
+    char *reply = this->createField(object_name,(char *)field.serialize().c_str(),output_buffer,MAX_BUFFER_LENGTH);
+    MbedJSONValue response;
+    if (reply != NULL && strlen(reply) > 0) parse(response,reply);
+    return response;
+ }
+
+ // READ: a specific field in Salesforce.com
+ MbedJSONValue SalesforceInterface::readField(char *object_name,char *object_id) {
+    ALLOC_BUFFER(output_buffer);
+    char *reply = this->readField(object_name,object_id,output_buffer,MAX_BUFFER_LENGTH);
+    MbedJSONValue response;
+    if (reply != NULL && strlen(reply) > 0) parse(response,reply);
+    return response; 
+ }
+
+ // UPDATE: a specific field in Salesforce.com
+ bool SalesforceInterface::updateField(char *object_name,char *object_id,MbedJSONValue &field) {
+    return this->updateField(object_name,object_id,(char *)field.serialize().c_str());
+ }
+ 
+ // CREATE: a field in Salesforce.com
+ char *SalesforceInterface::createField(char *object_name,char *json_data,char *output_buffer,int output_buffer_length) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && json_data != NULL && strlen(json_data) > 0 && output_buffer != NULL && output_buffer_length > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // DEBUG
+                DEBUG("createField: URL: %s  DATA: %s",str_url.c_str(),json_data);
+                
+                // now invoke with POST with JSON data type
+                return this->invoke(str_url.c_str(),json_data,strlen(json_data)+1,output_buffer,output_buffer_length);
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("createField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("createField: error - invalid or NULL parameters...");
+     }
+     return NULL;
+ }
+
+ // READ: a specific field in Salesforce.com
+ char *SalesforceInterface::readField(char *object_name,char *object_id,char *output_buffer,int output_buffer_length) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && object_id != NULL && strlen(object_id) > 0 && output_buffer != NULL && output_buffer_length > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // DEBUG
+                DEBUG("readField: URL: %s",str_url.c_str());
+                
+                // now invoke with GET with JSON data type
+                return this->invoke(str_url.c_str(),output_buffer,output_buffer_length);
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("readField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("readField: error - invalid or NULL parameters...");
+     }
+     return NULL;
+ }
+
+ // UPDATE: a specific field in Salesforce.com
+ bool SalesforceInterface::updateField(char *object_name,char *object_id,char *json_data) {  
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && json_data != NULL && strlen(json_data) > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // HTTPClient does not support PATCH, so we have to use POST with a special added parameter
+                str_url += "?_HttpMethod=PATCH";
+                
+                // DEBUG
+                DEBUG("updateField: URL: %s DATA: %s",str_url.c_str(),json_data);
+                
+                // now invoke with POST with JSON data type
+                ALLOC_SML_BUFFER(output_buffer);
+                char *reply = this->invoke(str_url.c_str(),json_data,strlen(json_data)+1,output_buffer,MAX_SMALL_BUFFER_LENGTH);
+                
+                // DEBUG
+                DEBUG("updateField: http status=%d",this->httpResponseCode());
+                
+                // return our status
+                if (this->httpResponseCode() == 204) return true;
+                return false;
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("updateField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("updateField: error - invalid or NULL parameters...");
+     }
+     return false;  
+ }
+  
+ // DELETE: a specific field in Salesforce.com
+ bool SalesforceInterface::deleteField(char *object_name,char *object_id) {
+     // parameter check
+     if (object_name != NULL && strlen(object_name) > 0 && object_id != NULL && strlen(object_id) > 0) {
+         // first we have to ensure that we have valid salesforce ID
+         if (this->haveSalesforceID()) {        
+            // get the sobjects url
+            ALLOC_BUFFER(url);
+            char *sf_url = this->getSalesforceURL("sobjects",url,MAX_BUFFER_LENGTH);
+            if (sf_url != NULL && strlen(sf_url) > 0) {   
+                // convert to string
+                string str_url(sf_url);
+                         
+                // add object name that we want to create a field in
+                str_url += object_name;
+                
+                // add the field ID
+                str_url += "/";
+                str_url += object_id;
+                
+                // DEBUG
+                DEBUG("deleteField: URL: %s",str_url.c_str());
+                
+                // now invoke with DELETE 
+                ALLOC_SML_BUFFER(output_buffer);
+                char *reply = this->invoke(str_url.c_str(),output_buffer,MAX_SMALL_BUFFER_LENGTH,DELETE);
+                
+                // DEBUG
+                DEBUG("deleteField: http status=%d",this->httpResponseCode());
+                
+                // return our status
+                if (this->httpResponseCode() == 204) return true;
+                return false;
+            }
+         }
+         else {
+             // dont have a valid salesforce ID
+             this->logger()->log("deleteField: error - no valid salesforced ID was found...");
+         }
+     }
+     else {
+         // invalid or NULL parameters
+         this->logger()->log("deleteField: error - invalid or NULL parameters...");
+     }
+     return false;
+ }
+ 
  // Salesforce.com Invoke: defaults to GET
- char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_len) { 
-    return this->invoke(url,NUM_TYPES,NULL,0,output_buffer,output_buffer_len,GET); 
+ char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_length) { 
+    return this->invoke(url,output_buffer,output_buffer_length,GET); 
+ }
+ 
+ // Salesforce.com Invoke: GET or DELETE with simple output
+ char *SalesforceInterface::invoke(const char *url,char *output_buffer,int output_buffer_length,HttpVerb verb) { 
+    char *response = NULL;
+    switch(verb) {
+        case GET:
+        case DELETE:
+            // GET and DELETE only require an output buffer...
+            response = this->invoke(url,NUM_TYPES,NULL,0,output_buffer,output_buffer_length,verb); 
+            break;
+        default:
+            // wrong verb for this call interface...
+            this->logger()->log("invoke: invalid call: must be either GET or DELETE verb if only output buffer is provided");
+            break;
+    }
+    return response;
  }
  
  // Salesforce.com Invoke: defaults to POST with JSON input data type                                                  
- char *SalesforceInterface::invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len) { 
-    return this->invoke(url,JSON,input_data,input_data_len,output_buffer,output_buffer_len); 
+ char *SalesforceInterface::invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length) { 
+    return this->invoke(url,JSON,input_data,input_data_len,output_buffer,output_buffer_length); 
  }
  
  // Salesforce.com Invoke: defaults to POST with variable input data type                                                  
- 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) { 
-    return this->invoke(url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,POST); 
+ 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_length) { 
+    return this->invoke(url,input_type,input_data,input_data_len,output_buffer,output_buffer_length,POST); 
  }
  
  // Salesforce.com Invoke: full fidelity method
- 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) {     
+ 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_length,const HttpVerb verb) {     
      // initialize our invocation status and response code
      this->m_http_response_code = -1;
      this->m_http_status = HTTP_ERROR;
                  
      // param check: make sure that we at least have an output buffer and URL
-     if (url != NULL && strlen(url) > 0 && output_buffer != NULL && output_buffer_len > 0) {         
+     if (url != NULL && strlen(url) > 0 && output_buffer != NULL && output_buffer_length > 0) {         
         // proceed only if we have a valid OAUTH Token
         if (this->validOauthToken() == true) {                  
             // use OAUTH headers
@@ -292,30 +532,30 @@
             this->http()->setLocationBuf((char *)this->m_http_redirection_url,MAX_BUFFER_LENGTH);
 
             // create our output/response buffer
-            HTTPText output(output_buffer,output_buffer_len);
+            HTTPText output(output_buffer,output_buffer_length);
             
             // now make the HTTP(S) request
             switch(verb) {
                 case GET:
-                    DEBUG("invoking(GET) URL: %s...",url);
+                    DEBUG("invoke (GET) URL: %s...",url);
                     this->m_http_status = this->http()->get(url,&output);
                     this->m_http_response_code = this->http()->getHTTPResponseCode();
                     break;
                 case DELETE:
-                    DEBUG("invoking(DEL) URL: %s...",url);
+                    DEBUG("invoke (DEL) URL: %s...",url);
                     this->m_http_status = this->http()->del(url,&output);
                     this->m_http_response_code = this->http()->getHTTPResponseCode();
                     break;
                 case POST:
                     if (input_data != NULL && input_data_len > 0) {
                         if (input_type == JSON) {
-                            DEBUG("invoking(POST-JSON) URL: %s...",url);
+                            DEBUG("invoke (POST-JSON) URL: %s...",url);
                             HTTPJson input_json((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->post(url,input_json,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
                         }
                         else {
-                            DEBUG("invoking(POST-TEXT) URL: %s...",url);
+                            DEBUG("invoke (POST-TEXT) URL: %s...",url);
                             HTTPText input_text((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->post(url,input_text,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
@@ -329,13 +569,13 @@
                 case PUT:
                     if (input_data != NULL && input_data_len > 0) {
                         if (input_type == JSON) {
-                            DEBUG("invoking(PUT-JSON) URL: %s...",url);
+                            DEBUG("invoke (PUT-JSON) URL: %s...",url);
                             HTTPJson input_json((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->put(url,input_json,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
                         }
                         else {
-                            DEBUG("invoking(PUT-TEXT) URL: %s...",url);
+                            DEBUG("invoke (PUT-TEXT) URL: %s...",url);
                             HTTPText input_text((char *)input_data,(int)input_data_len);
                             this->m_http_status = this->http()->put(url,input_text,&output);
                             this->m_http_response_code = this->http()->getHTTPResponseCode();
@@ -367,7 +607,7 @@
          // do we have any redirections?
          if (this->httpResponseCode() == 302 /* REDIRECT */ && strlen(this->m_http_redirection_url) > 0) {
             // we have a redirect - so reset the output buffer
-            memset(output_buffer,0,output_buffer_len);
+            memset(output_buffer,0,output_buffer_length);
             
             // we have to make a copy of the redirection URL - this is because the subsequent invoke() will wipe our current one clean
             ALLOC_BUFFER(redirect_url);
@@ -375,7 +615,7 @@
                         
             // repeat with the redirection URL      
             DEBUG("invoke: redirecting to: %s",redirect_url);  
-            return this->invoke((const char *)redirect_url,input_type,input_data,input_data_len,output_buffer,output_buffer_len,verb);
+            return this->invoke((const char *)redirect_url,input_type,input_data,input_data_len,output_buffer,output_buffer_length,verb);
          }
          else if (this->httpResponseCode() == 302 /* REDIRECT */) {
             // error - got a redirect but have no URL
@@ -385,7 +625,7 @@
      }
           
      // return the response in the output buffer
-     if (this->httpStatus() == HTTP_OK) return output_buffer;
+     if (this->httpStatus() == HTTP_OK || this->httpStatus() == HTTP_REDIRECT) return output_buffer;
      else this->logger()->log("invocation failed with HTTP error code=%d status=%d",this->httpResponseCode(),this->httpStatus());
      return NULL;
  }
@@ -463,4 +703,4 @@
             line.insert( pos, newString );
         }
     }
-} 
\ No newline at end of file
+ }
\ No newline at end of file