Salesforce.com interface to directly access Salesforce.com

Dependencies:   HTTPClient-SSL MbedJSONValue

Dependents:   df-2014-salesforce-hrm-k64f

Fork of SalesforceInterface by Doug Anson

Files at this revision

API Documentation at this revision

Comitter:
ansond
Date:
Sun Sep 21 07:08:51 2014 +0000
Parent:
6:8f50a973fe66
Child:
8:47db53cd5884
Commit message:
fixes and updates for initial id extraction

Changed in this revision

HTTPClient-SSL.lib Show annotated file Show diff for this revision Revisions of this file
SalesforceInterface.cpp Show annotated file Show diff for this revision Revisions of this file
SalesforceInterface.h Show annotated file Show diff for this revision Revisions of this file
--- a/HTTPClient-SSL.lib	Fri Sep 19 22:07:44 2014 +0000
+++ b/HTTPClient-SSL.lib	Sun Sep 21 07:08:51 2014 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/ansond/code/HTTPClient-SSL/#abd90d8a363f
+http://mbed.org/users/ansond/code/HTTPClient-SSL/#7cd69cc809b8
--- a/SalesforceInterface.cpp	Fri Sep 19 22:07:44 2014 +0000
+++ b/SalesforceInterface.cpp	Sun Sep 21 07:08:51 2014 +0000
@@ -20,10 +20,6 @@
  #define  SF_OAUTH_TOKEN_URL    "https://login.salesforce.com/services/oauth2/token"
  #define  SF_OAUTH_REQUEST_BODY "grant_type=password&client_id=%s&client_secret=%s&username=%s&password=%s"
  #define  SF_HTTP_AUTH_HEADER   "Authorization: Bearer %s"
- #define  MAX_BUFFER_LENGTH     1024
- 
- // convenience macros
- #define  ALLOC_BUFFER(x)       char x[MAX_BUFFER_LENGTH+1];memset(x,0,MAX_BUFFER_LENGTH+1);
  
  // include class definition
  #include "SalesforceInterface.h"
@@ -41,6 +37,10 @@
      this->m_client_id = NULL;
      this->m_client_secret = NULL;
      this->m_have_creds = false;
+     this->m_http_status = HTTP_OK;
+     this->m_http_response_code = -1;
+     RESET_BUFFER(this->m_http_redirection_url);
+     this->resetOauthToken();
  }
  
  // destructor
@@ -73,7 +73,72 @@
  // convenience accessors
  ErrorHandler *SalesforceInterface::logger() { return this->m_logger; }
  HTTPClient *SalesforceInterface::http() { return this->m_http; }
+ OauthToken *SalesforceInterface::oauth() { return &this->m_oauth_token; }
  bool SalesforceInterface::haveCreds() { return this->m_have_creds; }
+ HTTPResult SalesforceInterface::httpStatus() { return this->m_http_status; }
+ int SalesforceInterface::httpResponseCode() { return this->m_http_response_code; }
+ 
+ // reset our oauth token
+ void SalesforceInterface::resetOauthToken() {
+     //DEBUG("resetting OAUTH token...");
+     this->m_oauth_token.valid              = false;
+     this->m_oauth_token.id                 = "";
+     this->m_oauth_token.issued_at          = "";
+     this->m_oauth_token.token_type         = "";
+     this->m_oauth_token.instance_url       = "";
+     this->m_oauth_token.signature          = "";
+     this->m_oauth_token.access_token       = "";
+ }
+ 
+ // fill our oauth token
+ void SalesforceInterface::fillOauthToken(char *token) {
+     if (token != NULL && strlen(token) > 0) {
+         // parse JSON
+         MbedJSONValue parsed_token;
+         parse(parsed_token,token);
+         
+         // fill our OAUTH token
+         this->m_oauth_token.id             = parsed_token["id"].get<std::string>();
+         this->m_oauth_token.issued_at      = parsed_token["issued_at"].get<std::string>();
+         this->m_oauth_token.token_type     = parsed_token["token_type"].get<std::string>();
+         this->m_oauth_token.instance_url   = parsed_token["instance_url"].get<std::string>();
+         this->m_oauth_token.signature      = parsed_token["signature"].get<std::string>();
+         this->m_oauth_token.access_token   = parsed_token["access_token"].get<std::string>();
+         
+         // we have an OAUTH token now
+         this->m_oauth_token.valid = true;
+         DEBUG("valid OAUTH token acquired.");
+         return;
+     }
+     DEBUG("error: invalid or null OAUTH token fill attempt.");
+ }
+ 
+ // is our OAUTH token valid?
+ bool SalesforceInterface::validOauthToken() {         
+    // 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...
+    return this->m_oauth_token.valid; 
+}
+ 
+ // check and get our OAUTH token
+ void SalesforceInterface::checkAndGetOauthToken() {
+     DEBUG("checking for valid OAUTH token...");
+     if (this->m_oauth_token.valid == false) {
+         // re-initialize token
+         this->resetOauthToken();
+         
+         // get our Token
+         ALLOC_BUFFER(output_buffer);
+         char *token = this->getOauthToken(output_buffer,MAX_BUFFER_LENGTH);
+         
+         // fill
+         this->fillOauthToken(token);
+         return;
+     }
+     DEBUG("valid OAUTH token found.");
+ }
  
  //
  // get OAUTH2 Token - taken from here: 
@@ -101,12 +166,12 @@
          HTTPText output(output_buffer,output_buffer_length);
          
          // HTTP POST call to gett he token 
-         DEBUG("getOauthToken: Calling %s...",SF_OAUTH_TOKEN_URL);
-         HTTPResult status = this->http()->post(SF_OAUTH_TOKEN_URL,input,&output);
-         
+         DEBUG("Getting OAUTH Token...");
+         this->m_http_status = this->http()->post(SF_OAUTH_TOKEN_URL,input,&output);
+
          // check the result and return the token
-         DEBUG("getOauthToken: status(%d) response: %s",status,output_buffer);
-         if (status == 0) return output_buffer;
+         if (this->m_http_status == HTTP_OK) return output_buffer;
+         this->logger()->log("oauth invocation failed. URL: %s",SF_OAUTH_TOKEN_URL);
      }
      else {
          // no credentials
@@ -115,66 +180,84 @@
      return NULL;
  }
  
+ // Salesforce.com: Get our ID
+ char *SalesforceInterface::getSalesforceID(char *output_buffer,int output_buffer_length) {
+    // proceed only if we have a valid OAUTH Token
+    if (this->validOauthToken() == true) {
+        // pull the ID from salesforce
+        char *id = this->invoke(this->oauth()->id.c_str(),output_buffer,output_buffer_length);
+        
+        // log any error status and return what we have...
+        if (this->httpStatus() != HTTP_OK) this->logger()->log("Unable to get Salesforce ID: status=%d httpCode=%d",this->httpStatus(),this->httpResponseCode());
+        return id;
+    }
+    else {
+        // unable to get ID - no OAUTH token
+        this->logger()->log("Unable to get Salesforce ID: no valid OAUTH token.");
+    }
+    return NULL;
+ }
+ 
  // Salesforce.com Invoke: defaults to GET
- char *SalesforceInterface::invoke(char *url,char *output_buffer,int output_buffer_len) { 
+ 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); 
  }
  
  // Salesforce.com Invoke: defaults to POST with JSON input data type                                                  
- char *SalesforceInterface::invoke(char *url,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len) { 
+ 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); 
  }
  
  // Salesforce.com Invoke: defaults to POST with variable input data type                                                  
- char *SalesforceInterface::invoke(char *url,InputDataTypes input_type,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len) { 
+ 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); 
  }
  
  // Salesforce.com Invoke: full fidelity method
- char *SalesforceInterface::invoke(char *url,InputDataTypes input_type,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len,HttpVerb verb) {     
-     // initialize our invocation status
-     HTTPResult status = HTTP_ERROR;
+ 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) {     
+     // 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) {         
+        // proceed only if we have a valid OAUTH Token
+        if (this->validOauthToken() == true) {                  
+            // use OAUTH headers
+            this->http()->oauthToken(this->oauth()->access_token.c_str());
             
-     if (this->haveCreds() && output_buffer != NULL && output_buffer_len > 0) {
-        // first we have to get our OAUTH2 Token
-        ALLOC_BUFFER(token_buffer);
-     
-        // get the OAUTH2 token
-        char *token = this->getOauthToken(token_buffer,sizeof(token_buffer));
-        if (token != NULL) {
-            // Parse the OAUTH2 token
-            MbedJSONValue parsed_token;
-            parse(parsed_token,token);
-            
-            // extract the OAUTH2 token
-            string access_token = parsed_token["access_token"].get<std::string>();
-            
-            // DEBUG
-            this->logger()->log("OAUTH: %s",access_token.c_str());
-            
-            // use OAUTH headers
-            this->http()->oauthToken(access_token.c_str());
-            
+            // reset the redirection url buffer in case we get a redirect...
+            RESET_BUFFER(this->m_http_redirection_url);
+            this->http()->setLocationBuf((char *)this->m_http_redirection_url,MAX_BUFFER_LENGTH);
+
             // create our output/response buffer
             HTTPText output(output_buffer,output_buffer_len);
             
             // now make the HTTP(S) request
             switch(verb) {
                 case GET:
-                    status = this->http()->get(url,&output);
+                    DEBUG("invoking(GET) URL: %s...",url);
+                    this->m_http_status = this->http()->get(url,&output);
+                    this->m_http_response_code = this->http()->getHTTPResponseCode();
                     break;
                 case DELETE:
-                    status = this->http()->del(url,&output);
+                    DEBUG("invoking(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) {
-                            HTTPJson input_json(input_data,input_data_len);
-                            status = this->http()->post(url,input_json,&output);
+                            DEBUG("invoking(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 {
-                            HTTPText input_text(input_data,input_data_len);
-                            status = this->http()->post(url,input_text,&output);
+                            DEBUG("invoking(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();
                         }
                     }
                     else {
@@ -185,12 +268,16 @@
                 case PUT:
                     if (input_data != NULL && input_data_len > 0) {
                         if (input_type == JSON) {
-                            HTTPJson input_json(input_data,input_data_len);
-                            status = this->http()->put(url,input_json,&output);
+                            DEBUG("invoking(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 {
-                            HTTPText input_text(input_data,input_data_len);
-                            status = this->http()->put(url,input_text,&output);
+                            DEBUG("invoking(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();
                         }
                     }
                     else {
@@ -204,18 +291,41 @@
                     break;
             }
         }
+        else {
+            // no OAUTH Token
+            this->logger()->log("unable to acquire OAUTH token for credentials provided. Unable to invoke API...");
+        }
      }
      else {
          // no credentials
          this->logger()->log("no/incomplete salesforce.com credentials provided. Unable to invoke API...");
      }
      
-     // DEBUG
-     if (status == 0) this->logger()->log("invoke: SUCCESS!");
-     else this->logger()->log("invoke: FAILURE (%d)",status);
-     
+     // process any return results that we have
+     if (this->httpStatus() == HTTP_OK || this->httpStatus() == HTTP_REDIRECT) {
+         // 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);
+            
+            // 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);
+            strcpy(redirect_url,this->m_http_redirection_url);
+                        
+            // 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);
+         }
+         else if (this->httpResponseCode() == 302 /* REDIRECT */) {
+            // error - got a redirect but have no URL
+            this->logger()->log("invoke error: received redirect but no URL...");
+            this->m_http_status = HTTP_ERROR;
+         }
+     }
+          
      // return the response in the output buffer
-     if (status == 0) return output_buffer;
+     if (this->httpStatus() == HTTP_OK) return output_buffer;
+     else this->logger()->log("invocation failed with HTTP error code=%d status=%d",this->httpResponseCode(),this->httpStatus());
      return NULL;
  }
  
\ No newline at end of file
--- a/SalesforceInterface.h	Fri Sep 19 22:07:44 2014 +0000
+++ b/SalesforceInterface.h	Sun Sep 21 07:08:51 2014 +0000
@@ -34,7 +34,10 @@
  #else
     #define DEBUG(...)
  #endif 
-
+ 
+ // convenience macros
+ #define  RESET_BUFFER(x)       memset(x,0,MAX_BUFFER_LENGTH+1)
+ #define  ALLOC_BUFFER(x)       char x[MAX_BUFFER_LENGTH+1];RESET_BUFFER(x)
  
  // HTTP Verbs
  typedef enum {
@@ -53,6 +56,17 @@
      NUM_TYPES
  } InputDataTypes;
  
+ // OAUTH structure
+ typedef struct {
+     bool   valid;
+     string id;
+     string issued_at;
+     string token_type;
+     string instance_url;
+     string signature;
+     string access_token;
+ } OauthToken;
+        
  // This class provides an interface into the REST-based Salesforce.com APIs
  class SalesforceInterface {
     private:
@@ -63,6 +77,10 @@
         char            *m_client_id;
         char            *m_client_secret;
         bool             m_have_creds;
+        OauthToken       m_oauth_token;
+        HTTPResult       m_http_status;
+        int              m_http_response_code;
+        char             m_http_redirection_url[MAX_BUFFER_LENGTH+1];
         
     public:
         // construction/destruction
@@ -72,20 +90,32 @@
         // set Salesforce.com credentials
         void setCredentials(char *username,char *password,char *client_id,char *client_secret);
         
+        // get our ID structure from Salesforce
+        char *getSalesforceID(char *output_buffer,int output_buffer_length);
+                        
+        // invoke REST calls into Salesforce.com
+        char *invoke(const char *url,char *output_buffer,int output_buffer_len);                                                                               // defaults to GET
+        char *invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len);                                           // defaults to POST with JSON input data type                                                                              // defaults to GET
+        char *invoke(const char *url,const InputDataTypes input_type,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_len);                  // defaults to POST with variable input data type
+        char *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);    // full fidelity method
+        
+    private:
         // get our OAUTH Token
+        void checkAndGetOauthToken();
         char *getOauthToken(char *output_buffer,int output_buffer_length);
         
-        // invoke REST calls into Salesforce.com
-        char *invoke(char *url,char *output_buffer,int output_buffer_len);                                                                               // defaults to GET
-        char *invoke(char *url,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len);                                           // defaults to POST with JSON input data type                                                                              // defaults to GET
-        char *invoke(char *url,InputDataTypes input_type,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len);                  // defaults to POST with variable input data type
-        char *invoke(char *url,InputDataTypes input_type,char *input_data,int input_data_len,char *output_buffer,int output_buffer_len,HttpVerb verb);    // full fidelity method
-        
-    private:
         // convenience accessors
         ErrorHandler *logger();
         HTTPClient *http();
+        OauthToken *oauth();
+        HTTPResult httpStatus();
+        int httpResponseCode();
+        
+        // internal checkers
         bool haveCreds();
+        void resetOauthToken();
+        void fillOauthToken(char *token);
+        bool validOauthToken();
  };
  
  #endif // _SALESFORCE_INTERFACE_H_
\ No newline at end of file