Salesforce.com interface to directly access Salesforce.com
Dependencies: HTTPClient-SSL MbedJSONValue
Dependents: df-2014-salesforce-hrm-k64f
Fork of SalesforceInterface by
SalesforceInterface.h
- Committer:
- ansond
- Date:
- 2015-08-20
- Revision:
- 25:ab08e176abc0
- Parent:
- 22:3363752cd523
File content as of revision 25:ab08e176abc0:
/* 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, * 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_ // Logger #include "Logger.h" // SSL-based HTTP support #include "HTTPClient.h" // JSON parsing support #include "MbedJSONValue.h" // convenience macros #define DEFINE_BUFFER(x) char x[MAX_BUFFER_LENGTH+1] #define RESET_BUFFER(x) memset(x,0,MAX_BUFFER_LENGTH+1) #define ALLOC_BUFFER(x) DEFINE_BUFFER(x);RESET_BUFFER(x) #define DEFINE_SML_BUFFER(x) char x[MAX_SMALL_BUFFER_LENGTH+1] #define RESET_SML_BUFFER(x) memset(x,0,MAX_SMALL_BUFFER_LENGTH+1) #define ALLOC_SML_BUFFER(x) DEFINE_SML_BUFFER(x);RESET_SML_BUFFER(x) // Default salesforce API version (must be in XX.Y format and must be a string) #define SALESFORCE_API_VERSION_LENGTH 10 #ifndef SALESFORCE_API_VERSION #define SALESFORCE_API_VERSION "28.0" #endif // verbose debugging within SalesforceInterface #if ENABLE_DEBUG_LOGGING #define DEBUG(...) { LOG_CONSOLE(__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; // OAUTH structure typedef struct { bool valid; string id; string issued_at; string token_type; string instance_url; string signature; string access_token; } OauthToken; /** * Salesforce Interface * SalesforceInterface provides a simple C++ API into the REST-based Salesforce.com APIs * * Example Project: http://mbed.org/users/ansond/code/df-2014-salesforce-testharness-k64f/ * * @code #include "Definitions.h" // definitions including platform specifics... #include "Logger.h" // include salesforce.com credentials #include "sf_creds.h" // our Serial port #include "BufferedSerial.h" BufferedSerial pc(USBTX, USBRX); // Ethernet #include "EthernetInterface.h" EthernetInterface ethernet; // HTTP #include "HTTPClient.h" HTTPClient http; // Salesforce.com Interface #include "SalesforceInterface.h" // test case persistence char *object_name = NULL; char *account_name = NULL; char *updated_account_name = NULL; char *external_id_field_name = NULL; char *external_id_field_value = NULL; DEFINE_SML_BUFFER(record_id); // *************** Test Cases ************************ void Test_getSalesforceToken(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nGetting Salesforce Token..."); logger->turnLEDPurple(); // get the salesforce token char *id = sf->getSalesforceToken(); if (id != NULL && strlen(id) > 0) logger->log("Saleforce token: %s",id); else logger->log("Unable to get Saleforce token"); logger->turnLEDGreen(); } void Test_query(Logger *logger,SalesforceInterface *sf,char *query_str) { logger->log("\r\n\r\nExecuting test query: %s",query_str); logger->turnLEDPurple(); if (query_str != NULL && strlen(query_str) > 0) { ALLOC_BUFFER(response); char *answer = sf->query(query_str,response,MAX_BUFFER_LENGTH); if (answer != NULL) logger->log("query result: %s",answer); else logger->log("query - NULL result"); } else { logger->log("Unable to perform query as we do not have our salesforce token"); } logger->turnLEDGreen(); } void Test_create(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting create()"); logger->turnLEDPurple(); // create a new record MbedJSONValue new_record; new_record["name"] = account_name; // DEBUG logger->log("Create: new record: %s",new_record.serialize().c_str()); // create... MbedJSONValue response = sf->createRecord(object_name,new_record); // display the result char *result = (char *)response.serialize().c_str(); if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) { // save off the token if we succeeded logger->log("Create: result: %s",result); logger->log("Create: http_code=%d",sf->httpResponseCode()); RESET_SML_BUFFER(record_id); strcpy(record_id,(char *)response["id"].get<std::string>().c_str()); } else { // failure logger->log("Create: FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_read(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting read()"); logger->turnLEDPurple(); // DEBUG logger->log("Read: reading: %s from %s",record_id,object_name); // read... MbedJSONValue response = sf->readRecord(object_name,record_id); // display the result char *result = (char *)response.serialize().c_str(); if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) { // save off the token if we succeeded logger->log("Read: result: %s",result); logger->log("Read: http_code=%d",sf->httpResponseCode()); } else { // failure logger->log("Read: FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_create_external_id(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting create(ExternalID)"); logger->turnLEDPurple(); // create a new record MbedJSONValue new_record; new_record[external_id_field_name] = external_id_field_value; // DEBUG logger->log("create(ExternalID): new record: %s",new_record.serialize().c_str()); // create... MbedJSONValue response = sf->createRecord(object_name,new_record); // display the result char *result = (char *)response.serialize().c_str(); if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) { // save off the token if we succeeded logger->log("create(ExternalID): result: %s",result); logger->log("create(ExternalID): http_code=%d",sf->httpResponseCode()); RESET_SML_BUFFER(record_id); strcpy(record_id,(char *)response["id"].get<std::string>().c_str()); } else { // failure logger->log("create(ExternalID): FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_read_by_external_id_and_value(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting read(externalID)..."); logger->turnLEDPurple(); // DEBUG logger->log("read(externalID): reading: %s from %s with value %s",object_name,external_id_field_name,external_id_field_value); // read (external ID)... MbedJSONValue response = sf->readRecord(object_name,external_id_field_name,external_id_field_value); // display the result char *result = (char *)response.serialize().c_str(); if (result != NULL && strlen(result) > 0 && strcmp(result,"null") != 0) { // save off the token if we succeeded logger->log("read(externalID): result: %s",result); logger->log("read(externalID): http_code=%d",sf->httpResponseCode()); } else { // failure logger->log("read(externalID): FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_update(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting update()"); logger->turnLEDPurple(); // update am existing record - assume "name" is the proper key for the record you wish to update... MbedJSONValue changed_record; changed_record["name"] = updated_account_name; // DEBUG logger->log("Update: updated record: %s",changed_record.serialize().c_str()); // update... bool updated = sf->updateRecord(object_name,record_id,changed_record); // display the result if (updated) { // SUCCESS logger->log("Update: successful! http_code=%d",sf->httpResponseCode()); } else { // failure logger->log("Update: FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_upsert_external_id(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting upsert(ExternalID)"); logger->turnLEDPurple(); // update am existing record - assume "name" is the proper key for the record you wish to update... MbedJSONValue changed_record; changed_record["name"] = updated_account_name; // DEBUG logger->log("upsert(ExternalID): upserted record: %s",changed_record.serialize().c_str()); // Upsert... bool updated = sf->upsertRecord(object_name,external_id_field_name,external_id_field_value,changed_record); // display the result if (updated) { // SUCCESS logger->log("upsert(ExternalID): successful! http_code=%d",sf->httpResponseCode()); } else { // failure logger->log("upsert(ExternalID): FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_delete(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nExecuting delete()"); logger->turnLEDPurple(); // DEBUG logger->log("Delete: deleting: %s from %s",record_id,object_name); // delete... bool deleted = sf->deleteRecord(object_name,record_id); // display the result if (deleted) { // SUCCESS logger->log("Delete: successful! http_code=%d",sf->httpResponseCode()); } else { // failure logger->log("Delete: FAILED http_code=%d",sf->httpResponseCode()); } logger->turnLEDGreen(); } void Test_reset_auth(Logger *logger,SalesforceInterface *sf) { logger->log("\r\n\r\nForcing API to reset OAUTH token and Salesforce Token..."); logger->turnLEDPurple(); sf->resetSalesforceToken(); logger->turnLEDGreen(); } // *************** Test Cases ************************ // Main Task... void mainTask(void const *v) { // create our object instances Logger logger(&pc,NULL); SalesforceInterface *sf = NULL; // announce logger.log("\r\n\r\nARM Salesforce Interface Testharness v%s",APP_VERSION); logger.turnLEDBlue(); // initialize Ethernet logger.log("Initializing Ethernet..."); ethernet.init(); // get a DHCP address and bring the network interface up logger.log("Getting IP Address..."); logger.turnLEDOrange(); if (ethernet.connect() == 0) { // log our IP address (DHCP) logger.log("IP Address: %s",ethernet.getIPAddress()); // allocate the Salesforce.com interface logger.log("Allocating Saleforce.com interface..."); sf = new SalesforceInterface(&http,&logger); // set our Salesforce.com credentials sf->setCredentials(username,password,client_id,client_secret); // *************** BEGIN TEST CASES ***************** // configuration for the test cases object_name = "Account"; // use the account object account_name = "ARM"; // add this record (name) updated_account_name = "ARM Holdings"; // update the existing record's name to this external_id_field_name = "Device__c"; // External ID field name external_id_field_value = "ABC123"; // External ID field value RESET_SML_BUFFER(record_id); // buffer for the record's token // Perform a Create Test_create(&logger,sf); // Perform a Read Test_read(&logger,sf); // Perform a Query Test_query(&logger,sf,"SELECT Id,Name FROM Account LIMIT 5"); // Perform an Update Test_update(&logger,sf); // Perform a second Read to visually confirm the update above... Test_read(&logger,sf); // Perform a Create (External ID) Test_create_external_id(&logger,sf); // Perform an Upsert Test_upsert_external_id(&logger,sf); // Perform a read of the external ID'ed specified by a given value Test_read_by_external_id_and_value(&logger,sf); // force the API to re-acquire the OAUTH token and Salesforce Token Test_reset_auth(&logger,sf); // Perform a Read (should re-acquire the OAUTH token and Salesforce Token) Test_read(&logger,sf); // Perform a Delete Test_delete(&logger,sf); // reset the record token buffer // RESET_SML_BUFFER(record_id); // Perform a Read - should error out Test_read(&logger,sf); // reset the record token buffer RESET_SML_BUFFER(record_id); // *************** BEGIN TEST CASES ***************** // entering main loop logger.log("All tests complete...\r\nExiting..."); logger.turnLEDBlue(); exit(0); } else { logger.log("No Network... Exiting..."); logger.turnLEDRed(); exit(1); } } // main entry int main() { Thread workerTask(mainTask, NULL, osPriorityNormal, STACK_SIZE); while (true) { Thread::wait(10*WAIT_TIME_MS); } } * @endcode * */ class SalesforceInterface { private: Logger *m_logger; bool m_logger_internal; HTTPClient *m_http; char *m_username; char *m_password; 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]; char m_salesforce_id[MAX_BUFFER_LENGTH+1]; char m_salesforce_api[SALESFORCE_API_VERSION_LENGTH]; char m_error_buffer[MAX_SMALL_BUFFER_LENGTH+1]; public: /** Default constructor @param http HTTPClient instance @param pc optional RawSerial for debugging output. If NULL, there will be no debugging output */ SalesforceInterface(HTTPClient *http,RawSerial *pc = NULL); /** Alternative constructor @param http HTTPClient instance @param logger optional Logger instance (See Logger for more info). If NULL, there will be no debugging output */ SalesforceInterface(HTTPClient *http,Logger *logger = NULL); /** Default destructor */ virtual ~SalesforceInterface(); /** Establish salesforce.com credentials @param username salesforce.com account user name @param password salesforce.com account password. The password must be of the form [password][security token] @param client_id salesforce.com connected application "customer key" value @param client_secret salesforce.com connected application client secret value */ void setCredentials(char *username,char *password,char *client_id,char *client_secret); /** Get our salesforce.com token @param fetch boolean that will direct the interface to fetch the token if not already done (default = true) @return our salesforce token in JSON format or NULL if in error */ char *getSalesforceToken(bool fetch = true); /** Force the interface to re-acquire the OAUTH token and salesforce token */ void resetSalesforceToken(); /** Set our salesforce.com API version @param version integer value (positive) */ void setSalesforceAPIVersion(int version); /** Set our salesforce.com API version @param version string value (format "X.Y") */ void setSalesforceAPIVersion(char *version); /** Get our salesforce.com API version @return string containing our salesforce.com API version or NULL if in error */ char *getSalesforceAPIVersion(); /** Salesforce.com API SOQL QUERY method to invoke ad-hoc SOQL queries into salesforce.com @param query_str character string with the SOQL query to invoke @param output_buffer allocated result buffer to use @param output_buffer_length allocated result buffer length @return result of the SOQL query in JSON format or NULL if in error */ char *query(char *query_str,char *output_buffer,int output_buffer_length); /** Salesforce.com API record creation method to create a new record within a salesforce.com object @param object_name name of the salesforce.com object to create the record in (i.e. "Account") @param record MbedJSONValue json structure that the new record will be comprised with @return MbedJSONValue structure with the results of the creation operation in JSON format */ MbedJSONValue createRecord(char *object_name,MbedJSONValue &record); /** Salesforce.com API record read method to read a record within a salesforce.com object @param object_name name of the salesforce.com object to read the record in (i.e. "Account") @param record_id salesforce.com id of the record instance to read @param record_value salesforce.com id value of the record instance to read (for external ID usage - default is NULL for non-external IDs) @return MbedJSONValue structure with the results of the read operation in JSON format */ MbedJSONValue readRecord(char *object_name,char *record_id,char *record_value = NULL); /** Salesforce.com API record update method to update a record within a salesforce.com object @param object_name name of the salesforce.com object to update the record in (i.e. "Account") @param record_id salesforce.com id of the record instance to read @param record MbedJSONValue instance with updated data for the record @return true - success, false - failure */ bool updateRecord(char *object_name,char *record_id,MbedJSONValue &record); /** Salesforce.com API record upsert (update/insert) method to update a record within a salesforce.com object for External IDs @param object_name name of the salesforce.com External object to upsert the record in (i.e. "FooBar_c") @param external_id_field_name salesforce.com id of the External record instance to upsert @param external_id_field_value salesforce.com id value of the External record instance to upsert @param record MbedJSONValue instance with updated data for the record @return true - success, false - failure */ bool upsertRecord(char *object_name,char *external_id_field_name,char *external_id_field_value,MbedJSONValue &record); /** Salesforce.com API record delete method to delete a record within a salesforce.com object @param object_name name of the salesforce.com object to delete the record in (i.e. "Account") @param record_id salesforce.com id of the record instance to delete @return true - success, false - failure */ bool deleteRecord(char *object_name,char *record_id); /** Salesforce.com API invocation HTTP response code to aid in debugging error conditions @return http response code */ // HTTP Error code access int httpResponseCode(); /** Retrieve the last executed update, upsert, or delete response error detail @return http response code from last update, upsert, or delete operation */ MbedJSONValue getLastError(); protected: // do we have a valid salesforce token and OAUTH token? bool haveSalesforceToken(bool fetch = true); // CREATE: a record in Salesforce.com char *createRecord(char *object_name,char *json_data,char *output_buffer,int output_buffer_length); // READ: a specific record in Salesforce.com char *readRecord(char *object_name,char *record_id,char *record_value,char *output_buffer,int output_buffer_length); // UPDATE: a specific record in Salesforce.com bool updateRecord(char *object_name,char *record_id,char *json_data,char *output_buffer,int output_buffer_length); // UPSERT: update/insert a specific External record in Salesforce.com bool upsertRecord(char *object_name,char *external_id_field_name,char *external_id_field_value,char *json_data,char *output_buffer,int output_buffer_length); // DELETE: delete a specific record in Salesforce.com bool deleteRecord(char *object_name,char *record_id,char *output_buffer,int output_buffer_length); // raw invocation of REST calls into Salesforce.com char *invoke(const char *url,char *output_buffer,int output_buffer_length); // defaults to GET char *invoke(const char *url,char *output_buffer,int output_buffer_length,HttpVerb verb); // GET or DELETE with simple output char *invoke(const char *url,const char *input_data,const int input_data_len,char *output_buffer,int output_buffer_length); // defaults to POST with JSON 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_length); // 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_length,const HttpVerb verb); // full fidelity method // get our OAUTH Token void checkAndGetOauthToken(bool fetch = true); char *getOauthToken(char *output_buffer,int output_buffer_length); // convenience accessors Logger *logger(); HTTPClient *http(); OauthToken *oauth(); HTTPResult httpStatus(); // internal checkers bool haveCreds(); void resetOauthToken(); void fillOauthToken(char *token); bool validOauthToken(bool fetch = true); // get the specified URL from our Salesforce Token char *getSalesforceURL(char *key,char *url_buffer,int url_buffer_length); // simple char array replacement (modifies input string!) void replace(char *str,char orig_char,char new_char); // needed to replace substrings within std::string void replace(string& line, string& oldString, string& newString); // validate that http status is in the "n" range bool httpResponseCodeInRange(int n); // min() method int min(int value1,int value2); // look for a specific key value pair in a json message bool contains(char *json,char *key,char *value); // initialize void init(HTTPClient *http,Logger *logger,bool logger_internal); }; #endif // _SALESFORCE_INTERFACE_H_