Deep Dive into Salesforce Integrations: Mapping Engines

24
Deep dive into Salesforce Integrations: Mapping Engines Salesforce World Tour NYC June 18, 2015

Transcript of Deep Dive into Salesforce Integrations: Mapping Engines

Page 1: Deep Dive into Salesforce Integrations:  Mapping Engines

Deep dive into Salesforce Integrations: Mapping EnginesSalesforce World Tour NYC June 18, 2015

Page 2: Deep Dive into Salesforce Integrations:  Mapping Engines

Ami AssayagArchitect, CRM ScienceDeveloper UG Leader, PhillyForce

@AmiAssayag

Speakers

Page 3: Deep Dive into Salesforce Integrations:  Mapping Engines

Safe HarborSafe harbor statement under the Private Securities Litigation Reform Act of 1995: This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of our services. The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and other litigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This documents and others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site. Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.

Page 4: Deep Dive into Salesforce Integrations:  Mapping Engines

Agenda

• What is a mapping engine?• Architecture overview?• Support infrastructure• Mapping types• Code, code and more code!

Page 5: Deep Dive into Salesforce Integrations:  Mapping Engines

What is a Mapping Engine?

• For the user

– User interface that provide flexibility to how the integration interacts

with the org.

– Allows pre-configuration and changes without development

• Beind the scene

– Supported by a code that handles outbound and inbound

transactions.

Page 6: Deep Dive into Salesforce Integrations:  Mapping Engines

Why Use Mapping Engines for Integrations?

• Allows for more generic integrations

• Dynamic

– builds callout bodies

– Interprets incoming payloads

• Changes to external service can be handled without additional

development

Page 7: Deep Dive into Salesforce Integrations:  Mapping Engines

Architecture Overview (Outbound)

Salesforce Org

External System

Mapping Data

Callout Handler

InboundMapping Engine

OutboundMapping Engine

Org DataApex REST

Trigger/Job

1

23

4

5

Page 8: Deep Dive into Salesforce Integrations:  Mapping Engines

Architecture Overview (Inbound)

Salesforce Org

External System

Mapping Data

Callout Handler

InboundMapping Engine

OutboundMapping Engine

Org DataApex REST

Trigger/Job

12

3

4

Page 9: Deep Dive into Salesforce Integrations:  Mapping Engines

Pillars of Mapping Engine Code

• Use object data type instead of specific types

• Cast custom and standard objects to sobject

• Build soql queries dynamically

• Use DMLOptions

Page 10: Deep Dive into Salesforce Integrations:  Mapping Engines

Infrastructure Choices

• Mapping engines are database driven• Data infrastructure options

– Custom objects• Pro: easier to manage relationships• Con: more directly accessible to users

– Custom setting• Pro: can be protected, cached• Con: difficult to manage relationships, requires data configuration

– Custom Metadata Types• Pro: can include pre-configured data, can be protected, cached• Con : difficult to manage relationships

Page 11: Deep Dive into Salesforce Integrations:  Mapping Engines

Mapping Data Structure

• Important: The integration terminology is the “Master” terminology because Salesforce mapping can be changed.

Object Mapping ObjectIntegration ObjectSalesforce Object

Field Mapping ObjectIntegration ObjectIntegration FieldSalesforce FieldMapping Type

InboundOutbound

Value Mapping ObjectIntegration FieldIntegration ValueSalesforce Value

InboundOutbound

Page 12: Deep Dive into Salesforce Integrations:  Mapping Engines

Simplified Field Mapping Data Structure

• Each field mapping record represents the mapping of a single field between the two systems.

Field Mapping ObjectIntegration ObjectSalesforce ObjectIntegration FieldSalesforce FieldMapping Type

InboundOutbound

Values Example= prospect= Opportunity= person.first_name= Contact__r.Name= Value= true= true

Page 13: Deep Dive into Salesforce Integrations:  Mapping Engines

Mapping Types

• Regular Value – single value of any acceptable data type

• Constant – value that is defined by the mapping, not by the integration

• Value Map – sub mapping for value conversion (normally for picklists)

• Object – mapping of lookup relationships

• Related List – mapping of related list mapping

Page 14: Deep Dive into Salesforce Integrations:  Mapping Engines

Integration Trigger// Trigger to handle all callouts for the Opportunity objecttrigger ContactIntegration on Contact(after insert) { ProcessTrigger.sendInsertedRecords('Person', Trigger.newMap.keySet()); }

• Pass to static class– Integration object name (not salesforce name)– Triggered record ids (not actual objects because it is not

likely to contain all the information needed.

Page 15: Deep Dive into Salesforce Integrations:  Mapping Engines

Prepare the Field Mapping // property to hold field mappings per object private map<string, list<FieldMapping__c>> fieldMappings; public list<FieldMapping__c> getFieldMappings(string obj) { // make sure the variable is instantiated if (fieldMappings == null) fieldMappings = new map<string, list<FieldMapping__c>>();

// check if the object mappings was already fetched if (fieldMappings.get(obj) == null) { // get the mappings for the object fieldMappings.put(obj, [SELECT Name, SalesforceObject__c, SalesforceField__c, IntegrationField__c, MappingType__c, FROM FieldMapping__c WHERE IntegrationObject__c = :obj AND Incoming__c = true //can make this dynamic LIMIT 1000]); } // return the list of mappings for the requested object return fieldMappings.get(obj); }

Page 16: Deep Dive into Salesforce Integrations:  Mapping Engines

Re-Query the Triggered Records // prepare a set of strings to hold all the field names (set prevents dups) set<string> fieldsToSelect = new set<string>(); // get the field mapping for the specified object and collect the fields that need to be queried for (FieldMapping__c mapping : getFieldMappings(objectName)) { // exclude related list and constant mapping if (mapping.MappingType__c != 'Related List' && mapping.MappingType__c != ‘Constant') fieldsToSelect.add(mapping.SalesforceField__c); }

// start a query string and add the select fields string query = 'SELECT '; for (string fieldToSelect : fieldsToSelect) query += fieldToSelect + ','; // remove the last comma query = query.substring(0, query.length()-1);

// add the from and where clause query += ' FROM ' + objectName + ' WHERE Id IN :' + recordIds; // dynamically retrieve records into list of sobject list<sObject> records = database.query(query);

Page 17: Deep Dive into Salesforce Integrations:  Mapping Engines

Loop Through Records and Mappings // recieve a list of records and create a json body to call the integration public list<map<string, object>> processMapping(string objectName, list<sObject> records) { // define a list of maps that contain value pairs that can be built // dynamically and serialized. // the list represents the array of sent records // each map represents a single record // the map keyset represent the integration field names // the map values represent the field values in sfdc list<map<string, object>> jsonStructure = new list<map<string, object>>();

object fieldValue; // get the records from the database and loop through the records for (sObject record : records) {

// prepare a map to hold the value pairs for the current record map<string, object> outboundRecord = new map<string, object>();

// loop through each mapping record for this object for (FieldMapping__c mapping : getFieldMappings(objectName)) {

// assemble value pairs } } return jsonStructure ; }

Page 18: Deep Dive into Salesforce Integrations:  Mapping Engines

While Looping – Get the Value (Simple Value)// check if any of the value need to be accessed through a lookuplist<string> FieldParts = fieldName.split('\\.'); // loop through all the associated objects to drill down to the actual referenced object integer part = 0;while (part < FieldParts.size() - 1) { record = record.getSobject(FieldParts[part]); // go to next node if the record is valued if (record == null) break; else part += 1;} // make sure the record is not null (example: if accountId is null, Account.name will cause a an exception)if (record != null) { // get the value from the record retValue = record.get(FieldParts[part]); // the last part is the field itself, use a simple get to return the value as a string. // if value is null, don't process further (just return null) if (retValue != null) { // figure out the field type and do any conversion required by the integration } }}

Page 19: Deep Dive into Salesforce Integrations:  Mapping Engines

While Looping – Add Value Pair// split the integration field name - may need to add one or more nested objects before adding a value pair.list<string> node = mapping.IntegrationField__c.split('\\.'); // prepare a map to hold a parent object. start with the outbound record referencemap<string, object> currentObject = outboundRecord;// prepare a map to hold a nested objectmap<string, object> nestedObject; // loop through the integration nodes in the path and place each nested object/valuefor (integer i = 0; i < node.size(); i++) { if (i == node.size()-1) { // this is the last node in the path (the value), so add it unless a dependent field is null currentObject.put(node[i], fieldValue); } else { // check if the nested object already exists if (currentObject.containsKey(node[i])) nestedObject = (map<string, object>)(currentObject.get(node[i])); else // if the nested object was not found, instantiate one. nestedObject = new map<string, object>(); // add the nested object to the current object currentObject.put(node[i], nestedObject); // make the nested object the next current object currentObject = nestedObject; } }}

Page 20: Deep Dive into Salesforce Integrations:  Mapping Engines

Finish the loop and Serialize

. . . .

// if any field values were added for this record, add it to the // outbound body if (!outboundRecord.isEmpty()) jsonStructure.add(outboundRecord);}

// deserialize the list of map so it is ready to be sent. Remove empty objects if (!jsonStructure.isEmpty()) jsonBody = json.serialize(jsonStructure).remove('{}'); // returned the serialized structurereturn jsonBody;

Page 21: Deep Dive into Salesforce Integrations:  Mapping Engines

Ami AssayagArchitect, CRM ScienceUser Group Leader, PhillyForce

@AmiAssayag

Q & A

Page 22: Deep Dive into Salesforce Integrations:  Mapping Engines

Thank you

Page 23: Deep Dive into Salesforce Integrations:  Mapping Engines

Other Stuff

Page 24: Deep Dive into Salesforce Integrations:  Mapping Engines

While Looping – Get the Value (other types)// only process mappings that are not of type related list if (mapping.MappingType__c == 'Constant') { // this is a string value that is stored in the salesforce field fieldValue = mapping.SalesforceField__c; } else if (mapping.MappingType__c == 'Account' || mapping.MappingType__c == 'Contact') // this is a lookup to a related object // Get the Id and call processMapping recursively to get object’s value pairs;

} else { // Single Value or Value map // get the field value from the record fieldValue = retrieveValue(record, mapping.SalesforceField__c); // check if the retrieved value needs to be mapped to other values if (mapping.MappingType__c == 'Value Map') // get the mapped value from the custom setting fieldValue = getValueMapping(mapping.Name.toLowerCase(), string.valueof(fieldValue));}