SlideShare una empresa de Scribd logo
1 de 34
Descargar para leer sin conexión
Lightning Connect Custom
Adapters
Connecting Anything with Salesforce
​ Lawrence McAlpin
​ Principal Member of Technical Staff
​ lmcalpin@salesforce.com
​ @lmcalpin
​ 
​ Safe 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 any
litigation, risks associated with completed and any 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-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter.
These 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.
Safe Harbor
Agenda
​  Background on External Data Sources
​  Custom Adapter Framework Overview
​  Demo
​  Provider Implementation
​  Connection Implementation
​  Pagination
​  Search
​  DML
​  Q&A
Background
●  Simplifies integration with
external systems
●  No magic
○  data is still remote
●  Ideal for use cases:
○  data is infrequently
accessed (such as
archival data)
○  you do not want to present
stale data
○  single point of truth
External Data Sources
• Data must be in a format we understand
▪  OData v2
▪  OData v4
▪  Salesforce
• Apex Custom Adapter Framework
▪  write your own!
• Data must be accessible to Salesforce
Custom Adapter Framework
Allows you to write your own Lightning Connect adapters
Custom Adapter Framework
●  Standard Governor limits apply
●  No limit to the number of Apex custom adapter classes you can define
●  Need Lightning Connect license to configure an External Data Source to use the
custom adapter
Demo
Custom Adapter Framework
●  DataSource.Provider
o  describes the capabilities of the external data source
o  creates the Connection class
●  DataSource.Connection
o  called whenever you import the metadata
o  called when you execute SOQL, SOSL, DML or equivalent UI interactions
DataSource.Provider
global class DummyDataSourceProvider extends DataSource.Provider {
override global List<DataSource.Capability> getCapabilities() {
List<DataSource.Capability> capabilities = new List<DataSource.Capability>();
capabilities.add(DataSource.Capability.ROW_QUERY);
capabilities.add(DataSource.Capability.SEARCH);
return capabilities;
}
override global List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() {
List<DataSource.AuthenticationCapability> capabilities = new
List<DataSource.AuthenticationCapability>();
capabilities.add(DataSource.AuthenticationCapability.ANONYMOUS);
return capabilities;
}
override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) {
return new DummyDataSourceConnection(connectionParams);
}
}
DataSource.Provider
override global List<DataSource.Capability> getCapabilities()
​  ROW_QUERY
​  ROW_CREATE
​  ROW_UPDATE
​  ROW_DELETE
​  SEARCH
​  REQUIRE_ENDPOINT
​  REQUIRE_HTTPS
​  QUERY_TOTAL_SIZE
​  QUERY_PAGINATION_SERVER_DRIVEN
DataSource.Provider
getAuthenticationCapabilities
ANONYMOUS
BASIC
CERTIFICATE
OAUTH
DataSource.Provider
override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) {
return new DummyDataSourceConnection(connectionParams);
}
ConnectionParams properties
String username
String password
String oauthToken
AuthenticationProtocol protocol
String endpoint
String repository
IdentityType principalType
String certificateName
	
  
Callouts
Data may be retrieved using HTTP or Web service callouts
●  Authentication must be handled manually
o  throw OAuthTokenExpiredException to refresh the stored access token
o  all callout endpoints need to be registered in Remote Site Settings
HttpRequest req = new HttpRequest();
req.setEndpoint('http://www.wherever.com');
req.setMethod('GET');
if (protocol == DataSource.AuthenticationProtocol.PASSWORD) {
String username = connectionParams.username;
String password = connectionParams.password;
Blob headerValue = Blob.valueOf(username + ':' + password);
String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue);
req.setHeader('Authorization', authorizationHeader);
} else if (protocol == DataSource.AuthenticationProtocol.OAUTH) {
req.setHeader('Authorization', 'Bearer ' + connectionParams.oauthToken);
}
Http http = new Http();
HTTPResponse res = http.send(req);
if (res.getStatusCode() == 401)
throw new OAuthTokenExpiredException();
Callouts with Named Credentials
Named Credentials are more flexible
but require additional setup
●  no direct access to credentials
●  no need to add to Remote Site
Settings
HttpRequest req = new HttpRequest();
req.setEndpoint(‘callout:test’);
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
Callouts with Named Credentials
Merge fields {!$CREDENTIAL.xxx}
●  USERNAME
●  PASSWORD
●  OAUTHTOKEN
●  AUTHORIZATIONMETHOD (BASIC, OAUTH)
●  AUTHORIZATIONHEADERVALUE (Base64 encoded username+password or Oauth token)
●  OAUTHCONSUMERKEY
// Concur expects OAuth to prefix the access token, instead of Bearer
req.setHeader(‘Authorization’, ‘OAuth {!$Credential.OAuthToken}’);
// non-standard authentication
req.setHeader(‘X-Username’, ‘{!$Credential.UserName}’);
req.setHeader(‘X-Password’, ‘{!$Credential.Password}’);
// you can also use it in the body
req.setBody(‘Dear {!$Credential.UserName}, I am a Salesforce Prince and as a Prince of Salesforce I
naturally own a metric crap ton of RSUs. If you send me 10,000 of teh bitcoins now I will deliver my
stock to you as it vests which wil be totes winwin.’);
DataSource.Connection
override global List<DataSource.Table> sync()
enumerates the list of Tables that this data source knows about
override global DataSource.TableResult query(DataSource.QueryContext c)
called when executing SOQL or visiting the List or Details pages in the UI
override global List<DataSource.TableResult> search(DataSource.SearchContext c)
called when executing SOSL or using the search functions in the UI
override global List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext c)
called when executing insert or update DML; also called when editing a record in the UI
override global List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext c)
called when executing delete DML; also called when deleting a record in the UI
Sync - DataSource.Table
override global List<DataSource.Table> sync() {
List<DataSource.Table> tables = new List<DataSource.Table>();
List<DataSource.Column> columns;
columns = new List<DataSource.Column>();
// next slide...
tables.add(DataSource.Table.get('Looper', 'Name', columns));
return tables;
}
Sync - DataSource.Column
columns = new List<DataSource.Column>();
columns.add(DataSource.Column.text('ExternalId', 255));
columns.add(DataSource.Column.url('DisplayUrl'));
columns.add(DataSource.Column.text('Name', 255));
columns.add(DataSource.Column.number('NumberOfEmployees', 18, 0));
Query
override global DataSource.TableResult query(DataSource.QueryContext c) {
HttpRequest req = prepareCallout(c);
List<Map<String,Object>> rows = getData(req);
// don’t forget the standard fields, especially ExternalId
for (Map<String,Object> row : rows) {
row.put('ExternalId', row.get(‘key’));
row.put('DisplayUrl', connectionParams.url + ‘/record/’ +
row.get(‘key’));
rows.add(row);
}
return DataSource.TableResult.get(c,rows);
}
QueryContext properties
TableSelection tableSelection
Integer offset
Integer maxResults
TableSelection properties
string tableSelected
List<ColumnSelection> columnsSelected
Filter filter
List<Order> order
TableResult properties
boolean success
String errorMessage
String tableName
List<Map<String,Object>> rows
integer totalSize
String queryMoreToken
Query Filters
/** Compound types **/
NOT_,
AND_,
OR_,
private string getSoqlFilter(string query,
DataSource.Filter filter) {
if (filter == null) { return query; }
DataSource.FilterType type = filter.type;
List<Map<String,Object>> retainedRows = new
List<Map<String,Object>>();
if (type == DataSource.FilterType.NOT_) {
DataSource.Filter subfilter =
filter.subfilters.get(0);
return ‘NOT ‘ +
getSoqlFilterExpression(subfilter);
} else if (type == DataSource.FilterType.AND_) {
return join('AND', filter.subfilters);
} else if (type == DataSource.FilterType.OR_) {
return join('OR', filter.subfilters);
}
return getSoqlFilterExpression(filter);
}
/** Simple comparative types **/
EQUALS,
NOT_EQUALS,
LESS_THAN,
GREATER_THAN,
private string getSoqlFilterExpression(DataSource.Filter filter) {
string op;
string columnName = filter.columnName;
object expectedValue = filter.columnValue;
if (filter.type == DataSource.FilterType.EQUALS) {
op = '=';
} else if (filter.type == DataSource.FilterType.NOT_EQUALS) {
op = '<>';
} else if (filter.type == DataSource.FilterType.LESS_THAN) {
op = '<';
} else if (filter.type == DataSource.FilterType.GREATER_THAN) {
op = '>';
} else if (filter.type == DataSource.FilterType.LESS_THAN_OR_EQUAL_TO) {
op = '<=';
} else if (filter.type == DataSource.FilterType.GREATER_THAN_OR_EQUAL_TO) {
op = '>=';
} else if (filter.type == DataSource.FilterType.STARTS_WITH) {
return mapColumnName(columnName) + ' LIKE '' + String.valueOf(expectedValue) + '%
'';
} else if (filter.type == DataSource.FilterType.ENDS_WITH) {
return mapColumnName(columnName) + ' LIKE '%' + String.valueOf(expectedValue) +
''';
} else {
throwException('DF15SpeakerWasLazyException: unimplemented filter type' +
filter.type);
}
return mapColumnName(columnName) + ' ' + op + ' ' + wrapValue(expectedValue);
}
LESS_THAN_OR_EQUAL_TO,
GREATER_THAN_OR_EQUAL_TO,
STARTS_WITH,
ENDS_WITH,
CONTAINS,
LIKE_
QueryMore
​  Can’t return all results in a single batch!
​  Not all external data sources handle pagination the same way
•  page number
•  token
•  limit, offset
​  Three strategies to handle pagination:
•  client driven, known total size
•  client driven, unknown total size
•  server driven
​  Driven by comabination of capabilities:
•  QUERY_TOTAL_SIZE
•  QUERY_SERVER_DRIVEN_PAGINATION
QueryMore - Client Driven, Known Total Size
​  Provider class declares QUERY_TOTAL_SIZE
​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x
​  query
•  QueryContext maxResults = 1000
•  TableResult should have 1000 records as requested!!!
​  API call returns
{
"totalSize" => 1500,
"done" => false,
"nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000",
"records" => [ … 1000 RECORDS … ]
}
​  queryMore call to /services/data/v35.0/query/xxx
​  query
•  QueryContext maxResults = 1000, and offset = 1000
•  TableResult should have 500 records
​  API call returns
{
"totalSize" => 1500,
"done" => true,
"records" => [ … 500 RECORDS … ]
}
QueryMore - Client Driven, Unknown Query Result Size
​  Default strategy used when provider does not support QUERY_TOTAL_SIZE or QUERY_SERVER_DRIVEN_PAGINATION
​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x
​  query
•  QueryContext maxResults = 1001
•  TableResult should return 1001 records as requested!!!
​  SFDC API call returns
{
"totalSize" => -1,
"done" => false,
"nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000",
"records" => [ … 1000 RECORDS … ]
}
​  queryMore call to /services/data/v35.0/query/xxx
​  query
•  QueryContext maxResults = 1001, and offset = 1000
•  TableResult should have 500 records
​  API call returns
{
"totalSize" => 1500,
"done" => true,
"records" => [ … 500 RECORDS … ]
}
QueryMore - Server Driven
​  Provider class declares QUERY_SERVER_DRIVEN_PAGINATION
​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x
​  query
•  QueryContext maxResults = 0
•  TableResult should have however many records you want
•  TableResult must provide a queryMoreToken
​  API call returns the following if queryMoreToken is not null
{
"totalSize" => -1 or 1500, # depends on QUERY_TOTAL_SIZE support
"done" => false,
"nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000",
"records" => [ … ??? RECORDS … ]
}
​  queryMore call to /services/data/v35.0/query/xxx
​  query
•  QueryContext queryMoreToken will be set to the token previously supplied
•  TableResult should have however many records you want
​  API call returns the following when queryMoreToken is null
{
"totalSize" => 1500,
"done" => true,
"records" => [ … ??? RECORDS … ]
}
Search
●  SOSL and Search UI operations invoke the search method on your Connection class
●  Multiple tables for a single connector may be searched in a single call
●  Display URL is intended to point to the search results in the external system
​ SearchContext properties
​ List<TableSelection> tableSelections
​ String searchPhrase
global static List<DataSource.TableResult> search(SearchContext c) {
List<DataSource.TableResult> results = new List<DataSource.TableResult>();
for (DataSource.TableSelection tableSelection : c.tableSelections) {
QueryContext ctx = new QueryContext();
ctx.tableSelection = tableSelection;
Table table = c.getTableMetadata(ctx.tableSelection);
tableSelection.filter = new Filter(FilterType.CONTAINS, ctx.tableSelection.tableSelected,
table.nameColumn, c.searchPhrase);
results.add(query(ctx));
}
return results;
}
Search
Inserts, Updates, Deletes
Requires DML capabilities in DataSource.Provider
●  ROW_CREATE
●  ROW_UPDATE
●  ROW_DELETE
Requires ID mapping
Requires Allow Create, Edit, and Delete selection on External Data Source
Insert, Updates
override global List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext c) {
List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>();
List<Map<String,Object>> rows = c.rows;
for (Map<String,Object> row : rows) {
String externalId = String.valueOf(row.get('ExternalId'));
// insert or update record in the external system
boolean success = // insert or update record
if (success) {
results.add(DataSource.UpsertResult.success(id));
} else {
results.add(DataSource.UpsertResult.failure(id, 'An error occurred updating this record'));
}
}
return results;
}
UpsertContext properties
String tableSelected
List<Map<string,object>> rows
UpsertResult properties
Boolean success
String errorMessage
String externalId
Deletes
override global List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext c) {
Set<Id> externalIds = new Set<Id>();
List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>();
for (String externalId : c.externalIds) {
boolean success = // delete record in external system
if (result.success) {
results.add(DataSource.DeleteResult.success(id));
} else {
results.add(DataSource.DeleteResult.failure(id, 'An error occurred
updating this record'));
}
}
return results;
}
DeleteContext properties
String tableSelected
List<String> externalIds
DeleteResult properties
Boolean success
String errorMessage
String externalId
DML
●  New Database methods used for external objects (only)
○  insertAsync
○  updateAsync
○  deleteAsync
●  DML operations are asynchronous
●  call getAsyncResult later to get results
Order__x x = new Order__x();
Database.SaveResult locator = Database.insertAsync(x);
if (!locator.isSuccess() && locator.getAsyncLocator() != null) {
// save was queued up for execution, when the result is ready, do some additional processing
completeOrderCreation(asyncLocator);
}
// must be in another transaction!!!
@future
public void completeOrderCreation(String asyncLocator) {
Database.SaveResult sr = Database.getAsyncResult(asyncLocator);
if (sr.isSuccess()) { … }
}
DML Callbacks
●  Callbacks to handle post-save processing
global class XdsSaveCallback extends DataSource.AsyncSaveCallback {
virtual global void processSave(Database.SaveResult sr) {
if (sr.isSuccess()) { … }
}
}
XdsSaveCallback cb = new XdsSaveCallback();
Order__x x = new Order__x();
Database.insertAsync(x, cb);
DML Callbacks
●  Callbacks to handle post-delete processing
global class XdsDeleteCallback extends DataSource.AsyncDeleteCallback {
virtual global void processDelete(Database.DeleteResult dr) {}
}
XdsDeleteCallback cb = new XdsDeleteCallback();
Xds__x x = [SELECT Id FROM Xds__x WHERE ExternalId = ‘...’];
Database.deleteAsync(x, cb);
Lawrence McAlpinLawrence McAlpin
Principal Member of Technical Staff
lmcalpin@salesforce.com
@lmcalpin

Más contenido relacionado

La actualidad más candente

Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewDhanik Sahni
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce IntegrationJoshua Hoskins
 
Salesforce Consulting Services
Salesforce Consulting ServicesSalesforce Consulting Services
Salesforce Consulting ServicesManasa Nuguri
 
Mule salesforce integration solutions
Mule  salesforce integration solutionsMule  salesforce integration solutions
Mule salesforce integration solutionshimajareddys
 
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15Paris Salesforce Developer Group
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectSalesforce Developers
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce OrgSalesforce Admins
 
Salesforce data model
Salesforce data modelSalesforce data model
Salesforce data modelJean Brenda
 
Demystify Salesforce Bulk API
Demystify Salesforce Bulk APIDemystify Salesforce Bulk API
Demystify Salesforce Bulk APIDhanik Sahni
 
Salesforce.com Sandbox management
Salesforce.com Sandbox management Salesforce.com Sandbox management
Salesforce.com Sandbox management Ali Akbar
 
Salesforce Integration Patterns
Salesforce Integration PatternsSalesforce Integration Patterns
Salesforce Integration Patternsusolutions
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce dataSalesforce Developers
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and TestingSalesforce Developers
 
Real Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsReal Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsSalesforce Developers
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best PracticesVivek Chawla
 
SAP and Salesforce Integration
SAP and Salesforce IntegrationSAP and Salesforce Integration
SAP and Salesforce IntegrationGlenn Johnson
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceSalesforce Developers
 
Sap integration salesforce_presentation
Sap integration salesforce_presentationSap integration salesforce_presentation
Sap integration salesforce_presentationSalesforce Deutschland
 
Salesforce for Beginners
Salesforce for BeginnersSalesforce for Beginners
Salesforce for BeginnersEdureka!
 

La actualidad más candente (20)

Salesforce Integration Pattern Overview
Salesforce Integration Pattern OverviewSalesforce Integration Pattern Overview
Salesforce Integration Pattern Overview
 
Salesforce Integration
Salesforce IntegrationSalesforce Integration
Salesforce Integration
 
Salesforce Consulting Services
Salesforce Consulting ServicesSalesforce Consulting Services
Salesforce Consulting Services
 
Mule salesforce integration solutions
Mule  salesforce integration solutionsMule  salesforce integration solutions
Mule salesforce integration solutions
 
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15
Introducing salesforce shield - Paris Salesforce Developer Group - Oct 15
 
Integrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS ConnectIntegrate CMS Content Into Lightning Communities with CMS Connect
Integrate CMS Content Into Lightning Communities with CMS Connect
 
Security and Your Salesforce Org
Security and Your Salesforce OrgSecurity and Your Salesforce Org
Security and Your Salesforce Org
 
Salesforce data model
Salesforce data modelSalesforce data model
Salesforce data model
 
Demystify Salesforce Bulk API
Demystify Salesforce Bulk APIDemystify Salesforce Bulk API
Demystify Salesforce Bulk API
 
Salesforce.com Sandbox management
Salesforce.com Sandbox management Salesforce.com Sandbox management
Salesforce.com Sandbox management
 
Salesforce Integration Patterns
Salesforce Integration PatternsSalesforce Integration Patterns
Salesforce Integration Patterns
 
Lightning web components episode 2- work with salesforce data
Lightning web components   episode 2- work with salesforce dataLightning web components   episode 2- work with salesforce data
Lightning web components episode 2- work with salesforce data
 
Lightning web components - Episode 4 : Security and Testing
Lightning web components  - Episode 4 : Security and TestingLightning web components  - Episode 4 : Security and Testing
Lightning web components - Episode 4 : Security and Testing
 
Salesforce APIs
Salesforce APIsSalesforce APIs
Salesforce APIs
 
Real Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform EventsReal Time Integration with Salesforce Platform Events
Real Time Integration with Salesforce Platform Events
 
Salesforce Development Best Practices
Salesforce Development Best PracticesSalesforce Development Best Practices
Salesforce Development Best Practices
 
SAP and Salesforce Integration
SAP and Salesforce IntegrationSAP and Salesforce Integration
SAP and Salesforce Integration
 
Maximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component PerformanceMaximizing Salesforce Lightning Experience and Lightning Component Performance
Maximizing Salesforce Lightning Experience and Lightning Component Performance
 
Sap integration salesforce_presentation
Sap integration salesforce_presentationSap integration salesforce_presentation
Sap integration salesforce_presentation
 
Salesforce for Beginners
Salesforce for BeginnersSalesforce for Beginners
Salesforce for Beginners
 

Destacado

Lightning Out: Components for the Rest of the World
Lightning Out: Components for the Rest of the WorldLightning Out: Components for the Rest of the World
Lightning Out: Components for the Rest of the WorldSalesforce Developers
 
Access External Data in Real-time with Lightning Connect
Access External Data in Real-time with Lightning ConnectAccess External Data in Real-time with Lightning Connect
Access External Data in Real-time with Lightning ConnectSalesforce Developers
 
Introduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorIntroduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorSalesforce Developers
 
Lightning strikes twice- SEDreamin
Lightning strikes twice- SEDreaminLightning strikes twice- SEDreamin
Lightning strikes twice- SEDreaminMohith Shrivastava
 
Secure Salesforce: Lightning Components Best Practices
Secure Salesforce: Lightning Components Best PracticesSecure Salesforce: Lightning Components Best Practices
Secure Salesforce: Lightning Components Best PracticesSalesforce Developers
 
Real-time SQL Access to Your Salesforce.com Data Using Progress Data Direct
Real-time SQL Access to Your Salesforce.com Data Using Progress Data DirectReal-time SQL Access to Your Salesforce.com Data Using Progress Data Direct
Real-time SQL Access to Your Salesforce.com Data Using Progress Data DirectSalesforce Developers
 
Introduction to Analytics Cloud
Introduction to Analytics CloudIntroduction to Analytics Cloud
Introduction to Analytics CloudMohith Shrivastava
 
Apex Connector for Lightning Connect: Make Anything a Salesforce Object
Apex Connector for Lightning Connect: Make Anything a Salesforce ObjectApex Connector for Lightning Connect: Make Anything a Salesforce Object
Apex Connector for Lightning Connect: Make Anything a Salesforce ObjectSalesforce Developers
 
Go Faster with Process Builder
Go Faster with Process BuilderGo Faster with Process Builder
Go Faster with Process Builderandyinthecloud
 
Force.com Canvas in the Publisher and Chatter Feed
Force.com Canvas in the Publisher and Chatter FeedForce.com Canvas in the Publisher and Chatter Feed
Force.com Canvas in the Publisher and Chatter FeedSalesforce Developers
 
Building strong foundations apex enterprise patterns
Building strong foundations apex enterprise patternsBuilding strong foundations apex enterprise patterns
Building strong foundations apex enterprise patternsandyinthecloud
 
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any PlatformSalesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any Platformandyinthecloud
 
SAP Integration White Paper
SAP Integration White PaperSAP Integration White Paper
SAP Integration White PaperSaleem Rauf
 
Salesforce.com Org Migration Overview
Salesforce.com Org Migration OverviewSalesforce.com Org Migration Overview
Salesforce.com Org Migration OverviewShell Black
 
Multiorg Collaboration Using Salesforce S2S
Multiorg Collaboration Using Salesforce S2SMultiorg Collaboration Using Salesforce S2S
Multiorg Collaboration Using Salesforce S2SMayur Shintre
 
Dreamforce14 Multi Org Collaboration Architecture
Dreamforce14  Multi Org Collaboration ArchitectureDreamforce14  Multi Org Collaboration Architecture
Dreamforce14 Multi Org Collaboration ArchitectureRichard Clark
 
Continuous Deployment: The Dirty Details
Continuous Deployment: The Dirty DetailsContinuous Deployment: The Dirty Details
Continuous Deployment: The Dirty DetailsMike Brittain
 
SAP Marketing Runs Hybris Marketing By Andreas Starke
SAP Marketing Runs Hybris Marketing By Andreas StarkeSAP Marketing Runs Hybris Marketing By Andreas Starke
SAP Marketing Runs Hybris Marketing By Andreas StarkeMarTech Conference
 
Digital Transformation: Thinking Beyond CRM
Digital Transformation: Thinking Beyond CRMDigital Transformation: Thinking Beyond CRM
Digital Transformation: Thinking Beyond CRMSAP Customer Experience
 

Destacado (20)

Lightning Out: Components for the Rest of the World
Lightning Out: Components for the Rest of the WorldLightning Out: Components for the Rest of the World
Lightning Out: Components for the Rest of the World
 
Access External Data in Real-time with Lightning Connect
Access External Data in Real-time with Lightning ConnectAccess External Data in Real-time with Lightning Connect
Access External Data in Real-time with Lightning Connect
 
Introduction to External Objects and the OData Connector
Introduction to External Objects and the OData ConnectorIntroduction to External Objects and the OData Connector
Introduction to External Objects and the OData Connector
 
Lightning Connect: Lessons Learned
Lightning Connect: Lessons LearnedLightning Connect: Lessons Learned
Lightning Connect: Lessons Learned
 
Lightning strikes twice- SEDreamin
Lightning strikes twice- SEDreaminLightning strikes twice- SEDreamin
Lightning strikes twice- SEDreamin
 
Secure Salesforce: Lightning Components Best Practices
Secure Salesforce: Lightning Components Best PracticesSecure Salesforce: Lightning Components Best Practices
Secure Salesforce: Lightning Components Best Practices
 
Real-time SQL Access to Your Salesforce.com Data Using Progress Data Direct
Real-time SQL Access to Your Salesforce.com Data Using Progress Data DirectReal-time SQL Access to Your Salesforce.com Data Using Progress Data Direct
Real-time SQL Access to Your Salesforce.com Data Using Progress Data Direct
 
Introduction to Analytics Cloud
Introduction to Analytics CloudIntroduction to Analytics Cloud
Introduction to Analytics Cloud
 
Apex Connector for Lightning Connect: Make Anything a Salesforce Object
Apex Connector for Lightning Connect: Make Anything a Salesforce ObjectApex Connector for Lightning Connect: Make Anything a Salesforce Object
Apex Connector for Lightning Connect: Make Anything a Salesforce Object
 
Go Faster with Process Builder
Go Faster with Process BuilderGo Faster with Process Builder
Go Faster with Process Builder
 
Force.com Canvas in the Publisher and Chatter Feed
Force.com Canvas in the Publisher and Chatter FeedForce.com Canvas in the Publisher and Chatter Feed
Force.com Canvas in the Publisher and Chatter Feed
 
Building strong foundations apex enterprise patterns
Building strong foundations apex enterprise patternsBuilding strong foundations apex enterprise patterns
Building strong foundations apex enterprise patterns
 
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any PlatformSalesforce World Tour 2016 : Lightning Out : Components on any Platform
Salesforce World Tour 2016 : Lightning Out : Components on any Platform
 
SAP Integration White Paper
SAP Integration White PaperSAP Integration White Paper
SAP Integration White Paper
 
Salesforce.com Org Migration Overview
Salesforce.com Org Migration OverviewSalesforce.com Org Migration Overview
Salesforce.com Org Migration Overview
 
Multiorg Collaboration Using Salesforce S2S
Multiorg Collaboration Using Salesforce S2SMultiorg Collaboration Using Salesforce S2S
Multiorg Collaboration Using Salesforce S2S
 
Dreamforce14 Multi Org Collaboration Architecture
Dreamforce14  Multi Org Collaboration ArchitectureDreamforce14  Multi Org Collaboration Architecture
Dreamforce14 Multi Org Collaboration Architecture
 
Continuous Deployment: The Dirty Details
Continuous Deployment: The Dirty DetailsContinuous Deployment: The Dirty Details
Continuous Deployment: The Dirty Details
 
SAP Marketing Runs Hybris Marketing By Andreas Starke
SAP Marketing Runs Hybris Marketing By Andreas StarkeSAP Marketing Runs Hybris Marketing By Andreas Starke
SAP Marketing Runs Hybris Marketing By Andreas Starke
 
Digital Transformation: Thinking Beyond CRM
Digital Transformation: Thinking Beyond CRMDigital Transformation: Thinking Beyond CRM
Digital Transformation: Thinking Beyond CRM
 

Similar a Lightning Connect Custom Adapters: Connecting Anything with Salesforce

OData: A Standard API for Data Access
OData: A Standard API for Data AccessOData: A Standard API for Data Access
OData: A Standard API for Data AccessPat Patterson
 
Exploring SQL Server Azure Database Relationships Using Lightning Connect
Exploring SQL Server Azure Database Relationships Using Lightning ConnectExploring SQL Server Azure Database Relationships Using Lightning Connect
Exploring SQL Server Azure Database Relationships Using Lightning ConnectSalesforce Developers
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKSalesforce Developers
 
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...Tom Gersic
 
Intro to AppExchange - Building Composite Apps
Intro to AppExchange - Building Composite AppsIntro to AppExchange - Building Composite Apps
Intro to AppExchange - Building Composite Appsdreamforce2006
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced WorkshopJoshua Birk
 
Quickly Create Data Sets for the Analytics Cloud
Quickly Create Data Sets for the Analytics CloudQuickly Create Data Sets for the Analytics Cloud
Quickly Create Data Sets for the Analytics CloudSalesforce Developers
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Joshua Birk
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with HerokuPat Patterson
 
Tour of Heroku + Salesforce Integration Methods
Tour of Heroku + Salesforce Integration MethodsTour of Heroku + Salesforce Integration Methods
Tour of Heroku + Salesforce Integration MethodsSalesforce Developers
 
Hca advanced developer workshop
Hca advanced developer workshopHca advanced developer workshop
Hca advanced developer workshopDavid Scruggs
 
Dreamforce 2017: Salesforce DX - an Admin's Perspective
Dreamforce 2017:  Salesforce DX - an Admin's PerspectiveDreamforce 2017:  Salesforce DX - an Admin's Perspective
Dreamforce 2017: Salesforce DX - an Admin's PerspectiveMike White
 
Understanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformUnderstanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformSalesforce Developers
 
Introduction to the Wave Platform API
Introduction to the Wave Platform APIIntroduction to the Wave Platform API
Introduction to the Wave Platform APISalesforce Developers
 
Lightning components performance best practices
Lightning components performance best practicesLightning components performance best practices
Lightning components performance best practicesSalesforce Developers
 
How We Built AppExchange and our Communities on the App Cloud (Platform)
How We Built AppExchange and our Communities on the App Cloud (Platform)How We Built AppExchange and our Communities on the App Cloud (Platform)
How We Built AppExchange and our Communities on the App Cloud (Platform)Dreamforce
 
Understanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We DoUnderstanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We DoSalesforce Developers
 
Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsRitesh Aswaney
 
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...JAX London
 

Similar a Lightning Connect Custom Adapters: Connecting Anything with Salesforce (20)

OData: A Standard API for Data Access
OData: A Standard API for Data AccessOData: A Standard API for Data Access
OData: A Standard API for Data Access
 
Exploring SQL Server Azure Database Relationships Using Lightning Connect
Exploring SQL Server Azure Database Relationships Using Lightning ConnectExploring SQL Server Azure Database Relationships Using Lightning Connect
Exploring SQL Server Azure Database Relationships Using Lightning Connect
 
Introduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDKIntroduction to Developing Android Apps With the Salesforce Mobile SDK
Introduction to Developing Android Apps With the Salesforce Mobile SDK
 
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...
Developing Offline Mobile Apps with the Salesforce.com Mobile SDK SmartStore,...
 
Intro to AppExchange - Building Composite Apps
Intro to AppExchange - Building Composite AppsIntro to AppExchange - Building Composite Apps
Intro to AppExchange - Building Composite Apps
 
ELEVATE Advanced Workshop
ELEVATE Advanced WorkshopELEVATE Advanced Workshop
ELEVATE Advanced Workshop
 
Quickly Create Data Sets for the Analytics Cloud
Quickly Create Data Sets for the Analytics CloudQuickly Create Data Sets for the Analytics Cloud
Quickly Create Data Sets for the Analytics Cloud
 
Detroit ELEVATE Track 2
Detroit ELEVATE Track 2Detroit ELEVATE Track 2
Detroit ELEVATE Track 2
 
Integrating Force.com with Heroku
Integrating Force.com with HerokuIntegrating Force.com with Heroku
Integrating Force.com with Heroku
 
Tour of Heroku + Salesforce Integration Methods
Tour of Heroku + Salesforce Integration MethodsTour of Heroku + Salesforce Integration Methods
Tour of Heroku + Salesforce Integration Methods
 
Hca advanced developer workshop
Hca advanced developer workshopHca advanced developer workshop
Hca advanced developer workshop
 
Dreamforce 2017: Salesforce DX - an Admin's Perspective
Dreamforce 2017:  Salesforce DX - an Admin's PerspectiveDreamforce 2017:  Salesforce DX - an Admin's Perspective
Dreamforce 2017: Salesforce DX - an Admin's Perspective
 
ELEVATE Paris
ELEVATE ParisELEVATE Paris
ELEVATE Paris
 
Understanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce PlatformUnderstanding Multitenancy and the Architecture of the Salesforce Platform
Understanding Multitenancy and the Architecture of the Salesforce Platform
 
Introduction to the Wave Platform API
Introduction to the Wave Platform APIIntroduction to the Wave Platform API
Introduction to the Wave Platform API
 
Lightning components performance best practices
Lightning components performance best practicesLightning components performance best practices
Lightning components performance best practices
 
How We Built AppExchange and our Communities on the App Cloud (Platform)
How We Built AppExchange and our Communities on the App Cloud (Platform)How We Built AppExchange and our Communities on the App Cloud (Platform)
How We Built AppExchange and our Communities on the App Cloud (Platform)
 
Understanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We DoUnderstanding the Salesforce Architecture: How We Do the Magic We Do
Understanding the Salesforce Architecture: How We Do the Magic We Do
 
Visualforce Hack for Junction Objects
Visualforce Hack for Junction ObjectsVisualforce Hack for Junction Objects
Visualforce Hack for Junction Objects
 
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...
Java Tech & Tools | Deploying Java & Play Framework Apps to the Cloud | Sande...
 

Más de Salesforce Developers

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSalesforce Developers
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base ComponentsSalesforce Developers
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsSalesforce Developers
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaSalesforce Developers
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentSalesforce Developers
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsSalesforce Developers
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsSalesforce Developers
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsSalesforce Developers
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilitySalesforce Developers
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionSalesforce Developers
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPSalesforce Developers
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceSalesforce Developers
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureSalesforce Developers
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DXSalesforce Developers
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesSalesforce Developers
 

Más de Salesforce Developers (20)

Sample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce DevelopersSample Gallery: Reference Code and Best Practices for Salesforce Developers
Sample Gallery: Reference Code and Best Practices for Salesforce Developers
 
Local development with Open Source Base Components
Local development with Open Source Base ComponentsLocal development with Open Source Base Components
Local development with Open Source Base Components
 
TrailheaDX India : Developer Highlights
TrailheaDX India : Developer HighlightsTrailheaDX India : Developer Highlights
TrailheaDX India : Developer Highlights
 
Why developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX IndiaWhy developers shouldn’t miss TrailheaDX India
Why developers shouldn’t miss TrailheaDX India
 
CodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local DevelopmentCodeLive: Build Lightning Web Components faster with Local Development
CodeLive: Build Lightning Web Components faster with Local Development
 
CodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web ComponentsCodeLive: Converting Aura Components to Lightning Web Components
CodeLive: Converting Aura Components to Lightning Web Components
 
Enterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web ComponentsEnterprise-grade UI with open source Lightning Web Components
Enterprise-grade UI with open source Lightning Web Components
 
TrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer HighlightsTrailheaDX and Summer '19: Developer Highlights
TrailheaDX and Summer '19: Developer Highlights
 
Live coding with LWC
Live coding with LWCLive coding with LWC
Live coding with LWC
 
LWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura InteroperabilityLWC Episode 3- Component Communication and Aura Interoperability
LWC Episode 3- Component Communication and Aura Interoperability
 
Lightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An IntroductionLightning web components - Episode 1 - An Introduction
Lightning web components - Episode 1 - An Introduction
 
Migrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCPMigrating CPQ to Advanced Calculator and JSQCP
Migrating CPQ to Advanced Calculator and JSQCP
 
Scale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in SalesforceScale with Large Data Volumes and Big Objects in Salesforce
Scale with Large Data Volumes and Big Objects in Salesforce
 
Replicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data CaptureReplicate Salesforce Data in Real Time with Change Data Capture
Replicate Salesforce Data in Real Time with Change Data Capture
 
Modern Development with Salesforce DX
Modern Development with Salesforce DXModern Development with Salesforce DX
Modern Development with Salesforce DX
 
Get Into Lightning Flow Development
Get Into Lightning Flow DevelopmentGet Into Lightning Flow Development
Get Into Lightning Flow Development
 
Introduction to MuleSoft
Introduction to MuleSoftIntroduction to MuleSoft
Introduction to MuleSoft
 
Modern App Dev: Modular Development Strategies
Modern App Dev: Modular Development StrategiesModern App Dev: Modular Development Strategies
Modern App Dev: Modular Development Strategies
 
Dreamforce Developer Recap
Dreamforce Developer RecapDreamforce Developer Recap
Dreamforce Developer Recap
 
Vs Code for Salesforce Developers
Vs Code for Salesforce DevelopersVs Code for Salesforce Developers
Vs Code for Salesforce Developers
 

Último

Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESmohitsingh558521
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsPixlogix Infotech
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenHervé Boutemy
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxBkGupta21
 

Último (20)

Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICESSALESFORCE EDUCATION CLOUD | FEXLE SERVICES
SALESFORCE EDUCATION CLOUD | FEXLE SERVICES
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
The Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and ConsThe Ultimate Guide to Choosing WordPress Pros and Cons
The Ultimate Guide to Choosing WordPress Pros and Cons
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
DevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache MavenDevoxxFR 2024 Reproducible Builds with Apache Maven
DevoxxFR 2024 Reproducible Builds with Apache Maven
 
Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
unit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptxunit 4 immunoblotting technique complete.pptx
unit 4 immunoblotting technique complete.pptx
 

Lightning Connect Custom Adapters: Connecting Anything with Salesforce

  • 1. Lightning Connect Custom Adapters Connecting Anything with Salesforce ​ Lawrence McAlpin ​ Principal Member of Technical Staff ​ lmcalpin@salesforce.com ​ @lmcalpin ​ 
  • 2. ​ Safe 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 any litigation, risks associated with completed and any 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-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter. These 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. Safe Harbor
  • 3. Agenda ​  Background on External Data Sources ​  Custom Adapter Framework Overview ​  Demo ​  Provider Implementation ​  Connection Implementation ​  Pagination ​  Search ​  DML ​  Q&A
  • 4. Background ●  Simplifies integration with external systems ●  No magic ○  data is still remote ●  Ideal for use cases: ○  data is infrequently accessed (such as archival data) ○  you do not want to present stale data ○  single point of truth
  • 5. External Data Sources • Data must be in a format we understand ▪  OData v2 ▪  OData v4 ▪  Salesforce • Apex Custom Adapter Framework ▪  write your own! • Data must be accessible to Salesforce
  • 6. Custom Adapter Framework Allows you to write your own Lightning Connect adapters
  • 7. Custom Adapter Framework ●  Standard Governor limits apply ●  No limit to the number of Apex custom adapter classes you can define ●  Need Lightning Connect license to configure an External Data Source to use the custom adapter
  • 9. Custom Adapter Framework ●  DataSource.Provider o  describes the capabilities of the external data source o  creates the Connection class ●  DataSource.Connection o  called whenever you import the metadata o  called when you execute SOQL, SOSL, DML or equivalent UI interactions
  • 10. DataSource.Provider global class DummyDataSourceProvider extends DataSource.Provider { override global List<DataSource.Capability> getCapabilities() { List<DataSource.Capability> capabilities = new List<DataSource.Capability>(); capabilities.add(DataSource.Capability.ROW_QUERY); capabilities.add(DataSource.Capability.SEARCH); return capabilities; } override global List<DataSource.AuthenticationCapability> getAuthenticationCapabilities() { List<DataSource.AuthenticationCapability> capabilities = new List<DataSource.AuthenticationCapability>(); capabilities.add(DataSource.AuthenticationCapability.ANONYMOUS); return capabilities; } override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) { return new DummyDataSourceConnection(connectionParams); } }
  • 11. DataSource.Provider override global List<DataSource.Capability> getCapabilities() ​  ROW_QUERY ​  ROW_CREATE ​  ROW_UPDATE ​  ROW_DELETE ​  SEARCH ​  REQUIRE_ENDPOINT ​  REQUIRE_HTTPS ​  QUERY_TOTAL_SIZE ​  QUERY_PAGINATION_SERVER_DRIVEN
  • 13. DataSource.Provider override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) { return new DummyDataSourceConnection(connectionParams); } ConnectionParams properties String username String password String oauthToken AuthenticationProtocol protocol String endpoint String repository IdentityType principalType String certificateName  
  • 14. Callouts Data may be retrieved using HTTP or Web service callouts ●  Authentication must be handled manually o  throw OAuthTokenExpiredException to refresh the stored access token o  all callout endpoints need to be registered in Remote Site Settings HttpRequest req = new HttpRequest(); req.setEndpoint('http://www.wherever.com'); req.setMethod('GET'); if (protocol == DataSource.AuthenticationProtocol.PASSWORD) { String username = connectionParams.username; String password = connectionParams.password; Blob headerValue = Blob.valueOf(username + ':' + password); String authorizationHeader = 'BASIC ' + EncodingUtil.base64Encode(headerValue); req.setHeader('Authorization', authorizationHeader); } else if (protocol == DataSource.AuthenticationProtocol.OAUTH) { req.setHeader('Authorization', 'Bearer ' + connectionParams.oauthToken); } Http http = new Http(); HTTPResponse res = http.send(req); if (res.getStatusCode() == 401) throw new OAuthTokenExpiredException();
  • 15. Callouts with Named Credentials Named Credentials are more flexible but require additional setup ●  no direct access to credentials ●  no need to add to Remote Site Settings HttpRequest req = new HttpRequest(); req.setEndpoint(‘callout:test’); req.setMethod('GET'); Http http = new Http(); HTTPResponse res = http.send(req);
  • 16. Callouts with Named Credentials Merge fields {!$CREDENTIAL.xxx} ●  USERNAME ●  PASSWORD ●  OAUTHTOKEN ●  AUTHORIZATIONMETHOD (BASIC, OAUTH) ●  AUTHORIZATIONHEADERVALUE (Base64 encoded username+password or Oauth token) ●  OAUTHCONSUMERKEY // Concur expects OAuth to prefix the access token, instead of Bearer req.setHeader(‘Authorization’, ‘OAuth {!$Credential.OAuthToken}’); // non-standard authentication req.setHeader(‘X-Username’, ‘{!$Credential.UserName}’); req.setHeader(‘X-Password’, ‘{!$Credential.Password}’); // you can also use it in the body req.setBody(‘Dear {!$Credential.UserName}, I am a Salesforce Prince and as a Prince of Salesforce I naturally own a metric crap ton of RSUs. If you send me 10,000 of teh bitcoins now I will deliver my stock to you as it vests which wil be totes winwin.’);
  • 17. DataSource.Connection override global List<DataSource.Table> sync() enumerates the list of Tables that this data source knows about override global DataSource.TableResult query(DataSource.QueryContext c) called when executing SOQL or visiting the List or Details pages in the UI override global List<DataSource.TableResult> search(DataSource.SearchContext c) called when executing SOSL or using the search functions in the UI override global List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext c) called when executing insert or update DML; also called when editing a record in the UI override global List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext c) called when executing delete DML; also called when deleting a record in the UI
  • 18. Sync - DataSource.Table override global List<DataSource.Table> sync() { List<DataSource.Table> tables = new List<DataSource.Table>(); List<DataSource.Column> columns; columns = new List<DataSource.Column>(); // next slide... tables.add(DataSource.Table.get('Looper', 'Name', columns)); return tables; }
  • 19. Sync - DataSource.Column columns = new List<DataSource.Column>(); columns.add(DataSource.Column.text('ExternalId', 255)); columns.add(DataSource.Column.url('DisplayUrl')); columns.add(DataSource.Column.text('Name', 255)); columns.add(DataSource.Column.number('NumberOfEmployees', 18, 0));
  • 20. Query override global DataSource.TableResult query(DataSource.QueryContext c) { HttpRequest req = prepareCallout(c); List<Map<String,Object>> rows = getData(req); // don’t forget the standard fields, especially ExternalId for (Map<String,Object> row : rows) { row.put('ExternalId', row.get(‘key’)); row.put('DisplayUrl', connectionParams.url + ‘/record/’ + row.get(‘key’)); rows.add(row); } return DataSource.TableResult.get(c,rows); } QueryContext properties TableSelection tableSelection Integer offset Integer maxResults TableSelection properties string tableSelected List<ColumnSelection> columnsSelected Filter filter List<Order> order TableResult properties boolean success String errorMessage String tableName List<Map<String,Object>> rows integer totalSize String queryMoreToken
  • 21. Query Filters /** Compound types **/ NOT_, AND_, OR_, private string getSoqlFilter(string query, DataSource.Filter filter) { if (filter == null) { return query; } DataSource.FilterType type = filter.type; List<Map<String,Object>> retainedRows = new List<Map<String,Object>>(); if (type == DataSource.FilterType.NOT_) { DataSource.Filter subfilter = filter.subfilters.get(0); return ‘NOT ‘ + getSoqlFilterExpression(subfilter); } else if (type == DataSource.FilterType.AND_) { return join('AND', filter.subfilters); } else if (type == DataSource.FilterType.OR_) { return join('OR', filter.subfilters); } return getSoqlFilterExpression(filter); } /** Simple comparative types **/ EQUALS, NOT_EQUALS, LESS_THAN, GREATER_THAN, private string getSoqlFilterExpression(DataSource.Filter filter) { string op; string columnName = filter.columnName; object expectedValue = filter.columnValue; if (filter.type == DataSource.FilterType.EQUALS) { op = '='; } else if (filter.type == DataSource.FilterType.NOT_EQUALS) { op = '<>'; } else if (filter.type == DataSource.FilterType.LESS_THAN) { op = '<'; } else if (filter.type == DataSource.FilterType.GREATER_THAN) { op = '>'; } else if (filter.type == DataSource.FilterType.LESS_THAN_OR_EQUAL_TO) { op = '<='; } else if (filter.type == DataSource.FilterType.GREATER_THAN_OR_EQUAL_TO) { op = '>='; } else if (filter.type == DataSource.FilterType.STARTS_WITH) { return mapColumnName(columnName) + ' LIKE '' + String.valueOf(expectedValue) + '% ''; } else if (filter.type == DataSource.FilterType.ENDS_WITH) { return mapColumnName(columnName) + ' LIKE '%' + String.valueOf(expectedValue) + '''; } else { throwException('DF15SpeakerWasLazyException: unimplemented filter type' + filter.type); } return mapColumnName(columnName) + ' ' + op + ' ' + wrapValue(expectedValue); } LESS_THAN_OR_EQUAL_TO, GREATER_THAN_OR_EQUAL_TO, STARTS_WITH, ENDS_WITH, CONTAINS, LIKE_
  • 22. QueryMore ​  Can’t return all results in a single batch! ​  Not all external data sources handle pagination the same way •  page number •  token •  limit, offset ​  Three strategies to handle pagination: •  client driven, known total size •  client driven, unknown total size •  server driven ​  Driven by comabination of capabilities: •  QUERY_TOTAL_SIZE •  QUERY_SERVER_DRIVEN_PAGINATION
  • 23. QueryMore - Client Driven, Known Total Size ​  Provider class declares QUERY_TOTAL_SIZE ​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x ​  query •  QueryContext maxResults = 1000 •  TableResult should have 1000 records as requested!!! ​  API call returns { "totalSize" => 1500, "done" => false, "nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000", "records" => [ … 1000 RECORDS … ] } ​  queryMore call to /services/data/v35.0/query/xxx ​  query •  QueryContext maxResults = 1000, and offset = 1000 •  TableResult should have 500 records ​  API call returns { "totalSize" => 1500, "done" => true, "records" => [ … 500 RECORDS … ] }
  • 24. QueryMore - Client Driven, Unknown Query Result Size ​  Default strategy used when provider does not support QUERY_TOTAL_SIZE or QUERY_SERVER_DRIVEN_PAGINATION ​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x ​  query •  QueryContext maxResults = 1001 •  TableResult should return 1001 records as requested!!! ​  SFDC API call returns { "totalSize" => -1, "done" => false, "nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000", "records" => [ … 1000 RECORDS … ] } ​  queryMore call to /services/data/v35.0/query/xxx ​  query •  QueryContext maxResults = 1001, and offset = 1000 •  TableResult should have 500 records ​  API call returns { "totalSize" => 1500, "done" => true, "records" => [ … 500 RECORDS … ] }
  • 25. QueryMore - Server Driven ​  Provider class declares QUERY_SERVER_DRIVEN_PAGINATION ​  /services/data/v35.0/query?q=SELECT...FROM+Xds__x ​  query •  QueryContext maxResults = 0 •  TableResult should have however many records you want •  TableResult must provide a queryMoreToken ​  API call returns the following if queryMoreToken is not null { "totalSize" => -1 or 1500, # depends on QUERY_TOTAL_SIZE support "done" => false, "nextRecordsUrl" => "/services/data/v35.0/query/01gxx000000B4WAAA0-1000", "records" => [ … ??? RECORDS … ] } ​  queryMore call to /services/data/v35.0/query/xxx ​  query •  QueryContext queryMoreToken will be set to the token previously supplied •  TableResult should have however many records you want ​  API call returns the following when queryMoreToken is null { "totalSize" => 1500, "done" => true, "records" => [ … ??? RECORDS … ] }
  • 26. Search ●  SOSL and Search UI operations invoke the search method on your Connection class ●  Multiple tables for a single connector may be searched in a single call ●  Display URL is intended to point to the search results in the external system
  • 27. ​ SearchContext properties ​ List<TableSelection> tableSelections ​ String searchPhrase global static List<DataSource.TableResult> search(SearchContext c) { List<DataSource.TableResult> results = new List<DataSource.TableResult>(); for (DataSource.TableSelection tableSelection : c.tableSelections) { QueryContext ctx = new QueryContext(); ctx.tableSelection = tableSelection; Table table = c.getTableMetadata(ctx.tableSelection); tableSelection.filter = new Filter(FilterType.CONTAINS, ctx.tableSelection.tableSelected, table.nameColumn, c.searchPhrase); results.add(query(ctx)); } return results; } Search
  • 28. Inserts, Updates, Deletes Requires DML capabilities in DataSource.Provider ●  ROW_CREATE ●  ROW_UPDATE ●  ROW_DELETE Requires ID mapping Requires Allow Create, Edit, and Delete selection on External Data Source
  • 29. Insert, Updates override global List<DataSource.UpsertResult> upsertRows(DataSource.UpsertContext c) { List<DataSource.UpsertResult> results = new List<DataSource.UpsertResult>(); List<Map<String,Object>> rows = c.rows; for (Map<String,Object> row : rows) { String externalId = String.valueOf(row.get('ExternalId')); // insert or update record in the external system boolean success = // insert or update record if (success) { results.add(DataSource.UpsertResult.success(id)); } else { results.add(DataSource.UpsertResult.failure(id, 'An error occurred updating this record')); } } return results; } UpsertContext properties String tableSelected List<Map<string,object>> rows UpsertResult properties Boolean success String errorMessage String externalId
  • 30. Deletes override global List<DataSource.DeleteResult> deleteRows(DataSource.DeleteContext c) { Set<Id> externalIds = new Set<Id>(); List<DataSource.DeleteResult> results = new List<DataSource.DeleteResult>(); for (String externalId : c.externalIds) { boolean success = // delete record in external system if (result.success) { results.add(DataSource.DeleteResult.success(id)); } else { results.add(DataSource.DeleteResult.failure(id, 'An error occurred updating this record')); } } return results; } DeleteContext properties String tableSelected List<String> externalIds DeleteResult properties Boolean success String errorMessage String externalId
  • 31. DML ●  New Database methods used for external objects (only) ○  insertAsync ○  updateAsync ○  deleteAsync ●  DML operations are asynchronous ●  call getAsyncResult later to get results Order__x x = new Order__x(); Database.SaveResult locator = Database.insertAsync(x); if (!locator.isSuccess() && locator.getAsyncLocator() != null) { // save was queued up for execution, when the result is ready, do some additional processing completeOrderCreation(asyncLocator); } // must be in another transaction!!! @future public void completeOrderCreation(String asyncLocator) { Database.SaveResult sr = Database.getAsyncResult(asyncLocator); if (sr.isSuccess()) { … } }
  • 32. DML Callbacks ●  Callbacks to handle post-save processing global class XdsSaveCallback extends DataSource.AsyncSaveCallback { virtual global void processSave(Database.SaveResult sr) { if (sr.isSuccess()) { … } } } XdsSaveCallback cb = new XdsSaveCallback(); Order__x x = new Order__x(); Database.insertAsync(x, cb);
  • 33. DML Callbacks ●  Callbacks to handle post-delete processing global class XdsDeleteCallback extends DataSource.AsyncDeleteCallback { virtual global void processDelete(Database.DeleteResult dr) {} } XdsDeleteCallback cb = new XdsDeleteCallback(); Xds__x x = [SELECT Id FROM Xds__x WHERE ExternalId = ‘...’]; Database.deleteAsync(x, cb);
  • 34. Lawrence McAlpinLawrence McAlpin Principal Member of Technical Staff lmcalpin@salesforce.com @lmcalpin