Lightning Connect Custom Adapters: Connecting Anything with Salesforce

download Lightning Connect Custom Adapters: Connecting Anything with Salesforce

If you can't read please download the document

  • date post

  • Category


  • view

  • download


Embed Size (px)

Transcript of Lightning Connect Custom Adapters: Connecting Anything with Salesforce

  • Lightning Connect Custom Adapters Connecting Anything with Salesforce

    Lawrence McAlpin Principal Member of Technical Staff @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, 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 products, and utilization and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of, 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., 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 getCapabilities() { List capabilities = new List(); capabilities.add(DataSource.Capability.ROW_QUERY); capabilities.add(DataSource.Capability.SEARCH); return capabilities; } override global List getAuthenticationCapabilities() { List capabilities = new List(); capabilities.add(DataSource.AuthenticationCapability.ANONYMOUS); return capabilities; } override global DataSource.Connection getConnection(DataSource.ConnectionParams connectionParams) { return new DummyDataSourceConnection(connectionParams); } }

  • DataSource.Provider

    override global List getCapabilities()


  • 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(''); 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


    // 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 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 search(DataSource.SearchContext c)

    called when executing SOSL or using the search functions in the UI

    override global List upsertRows(DataSource.UpsertContext c)

    called when executing insert or update DML; also called when editing a record in the UI

    override global List deleteRows(DataSource.DeleteContext c)

    called when executing delete DML; also called when deleting a record in the UI

  • Sync - DataSource.Table override global List sync() {

    List tables = new List();

    List columns;

    columns = new List();

    // next slide...

    tables.add(DataSource.Table.get('Looper', 'Name', columns));

    return tables;


  • Sync - DataSource.Column columns = new List();

    columns.add(DataSource.Column.text('ExternalId', 255));


    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 rows = getData(req); // dont forget the standard fields, especially ExternalId for (Map 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 columnsSelected Filter filter List order TableResult properties boolean su