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:
Wed Sep 17 21:36:19 2014 +0000
Child:
1:a7dca096e47d
Commit message:
updates

Changed in this revision

HTTPClient-SSL.lib Show annotated file Show diff for this revision Revisions of this file
MbedJSONValue.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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HTTPClient-SSL.lib	Wed Sep 17 21:36:19 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/ansond/code/HTTPClient-SSL/#debaeb6006a7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MbedJSONValue.lib	Wed Sep 17 21:36:19 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/samux/code/MbedJSONValue/#10a99cdf7846
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SalesforceInterface.cpp	Wed Sep 17 21:36:19 2014 +0000
@@ -0,0 +1,223 @@
+/* Copyright C2014 ARM, MIT License
+ *
+ * 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,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+  
+ // Tuneables
+ #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"
+ 
+ // Supported DataTypes for HTTPClient
+ #include "HTTPMap.h"
+ #include "HTTPJson.h"
+ 
+ // default constructor
+ SalesforceInterface::SalesforceInterface(ErrorHandler *logger,HTTPClient *http) {
+     this->m_logger = logger;
+     this->m_http = http;
+     this->m_username = NULL;
+     this->m_password = NULL;
+     this->m_client_id = NULL;
+     this->m_client_secret = NULL;
+     this->m_have_creds = false;
+ }
+ 
+ // destructor
+ SalesforceInterface::~SalesforceInterface() {
+ }
+ 
+ // set credentials
+ void SalesforceInterface::setCredentials(char *username,char *password,char *client_id,char *client_secret) {
+     this->m_username = NULL;
+     this->m_password = NULL;
+     this->m_client_id = NULL;
+     this->m_client_secret = NULL;
+     this->m_have_creds = false;
+     
+     if (username != NULL) {
+        this->m_username = username;
+        if (password != NULL) {
+            this->m_password = password;
+            if (client_id != NULL) {
+                this->m_client_id = client_id;
+                if (client_secret != NULL) {
+                    this->m_client_secret = client_secret;
+                    this->m_have_creds = true;
+                }
+            }
+        }
+     }
+ }
+ 
+ // convenience accessors
+ ErrorHandler *SalesforceInterface::logger() { return this->m_logger; }
+ HTTPClient *SalesforceInterface::http() { return this->m_http; }
+ bool SalesforceInterface::haveCreds() { return this->m_have_creds; }
+ 
+ //
+ // get OAUTH2 Token - taken from here: 
+ // 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
+ //
+ char *SalesforceInterface::getOauthToken(char *output_buffer,int output_buffer_length) {
+     if (this->haveCreds()) {
+         ALLOC_BUFFER(body);
+         
+         // construct the OAUTH2 Token request body
+         HTTPMap input;
+         
+         //
+         // FORMAT: Taken from URL above method signature:
+         //
+         // grant_type=password&client_id=<your_client_id>&client_secret=<your_client_secret>&username=<your_username>&password=<your_password>
+         //
+         // ContentType: application/x-www-form-urlencoded
+         //
+         input.put("grant_type","password");
+         input.put("client_id",this->m_client_id);
+         input.put("client_secret",this->m_client_secret);
+         input.put("username",this->m_username);
+         input.put("password",this->m_password);
+        
+         // prepare the output buffer
+         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);
+         
+         // check the result and return the token
+         DEBUG("getOauthToken: status(%d) response: %s",status,output_buffer);
+         if (status == 0) return output_buffer;
+     }
+     else {
+         // no credentials
+         this->logger()->log("no/incomplete salesforce.com credentials provided. Unable to acquire OAUTH2 token...");
+     }
+     return NULL;
+ }
+ 
+ // Salesforce.com Invoke: defaults to GET
+ char *SalesforceInterface::invoke(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) { 
+    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) { 
+    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;
+            
+     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());
+            
+            // 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);
+                    break;
+                case DELETE:
+                    status = this->http()->del(url,&output);
+                    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);
+                        }
+                        else {
+                            HTTPText input_text(input_data,input_data_len);
+                            status = this->http()->post(url,input_text,&output);
+                        }
+                    }
+                    else {
+                        // no input buffer!
+                        this->logger()->log("invoke: ERROR HTTP(POST) requested but no input data provided... returning NULL");
+                    }
+                    break;
+                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);
+                        }
+                        else {
+                            HTTPText input_text(input_data,input_data_len);
+                            status = this->http()->put(url,input_text,&output);
+                        }
+                    }
+                    else {
+                        // no input buffer!
+                        this->logger()->log("invoke: ERROR HTTP(PUT) requested but no input data provided... returning NULL");
+                    }
+                    break;
+                default:
+                    // invalid HTTP verb
+                    this->logger()->log("invoke: ERROR invalid HTTP verb (%d) provided... returning NULL",verb);
+                    break;
+            }
+        }
+     }
+     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);
+     
+     // return the response in the output buffer
+     if (status == 0) return output_buffer;
+     return NULL;
+ }
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SalesforceInterface.h	Wed Sep 17 21:36:19 2014 +0000
@@ -0,0 +1,91 @@
+/* Copyright C2014 ARM, MIT License
+ *
+ * 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,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
+ #ifndef _SALESFORCE_INTERFACE_H_
+ #define _SALESFORCE_INTERFACE_H_
+ 
+ // ErrorHandler
+ #include "ErrorHandler.h"
+ 
+ // SSL-based HTTP support
+ #include "HTTPClient.h"
+ 
+ // JSON parsing support
+ #include "MbedJSONValue.h"
+ 
+ // verbose debugging
+ #if ENABLE_DEBUG_LOGGING
+    #define DEBUG(...) { this->logger()->logConsole(__VA_ARGS__); }
+ #else
+    #define DEBUG(...)
+ #endif 
+
+ 
+ // HTTP Verbs
+ typedef enum {
+     GET,
+     PUT,
+     POST,
+     DELETE,
+     NUM_VERBS
+ } HttpVerb;
+ 
+ // Supported input data types for PUT and POST (Defined by HTTPClient-SSL/data support...)
+ typedef enum {
+     JSON,              // ContentType: application/json
+     PLAIN_TEXT,        // ContentType: plain/text
+     FORM_MAPPED,       // ContentType: application/x-www-form-urlencoded
+     NUM_TYPES
+ } InputDataTypes;
+ 
+ // This class provides an interface into the REST-based Salesforce.com APIs
+ class SalesforceInterface {
+    private:
+        ErrorHandler    *m_logger;
+        HTTPClient      *m_http;
+        char            *m_username;
+        char            *m_password;
+        char            *m_client_id;
+        char            *m_client_secret;
+        bool             m_have_creds;
+        
+    public:
+        // construction/destruction
+        SalesforceInterface(ErrorHandler *logger,HTTPClient *http); 
+        virtual ~SalesforceInterface();
+        
+        // set Salesforce.com credentials
+        void setCredentials(char *username,char *password,char *client_id,char *client_secret);
+        
+        // get our OAUTH Token
+        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();
+        bool haveCreds();
+ };
+ 
+ #endif // _SALESFORCE_INTERFACE_H_
\ No newline at end of file