この文章は Salesforce 機械翻訳システムを使用して翻訳されました。詳細はこちらをご参照ください。
英語に切り替える

Salesforce Connect のスタックオーバーフローカスタムアダプタ

次の例は、外部参照関係と複数のテーブルをサポートする方法を示しています。外部参照関係は、子の標準、カスタム、外部オブジェクトを親の外部オブジェクトに結び付けます。各テーブルを、Salesforce 組織の外部オブジェクトにすることができます。

この例を機能させるために、取引先責任者標準オブジェクトにカスタム項目を作成します。カスタム項目に「github_username」という名前を付け、External ID および Unique 属性を選択します。

StackOverflowDataSourceConnection クラス

1/**
2 *   Defines the connection to Stack Exchange API v2.2 to support
3 *   querying of Stack Overflow users (stackoverflowUser)
4 *   and posts (stackoverflowPost).
5 *   Extends the DataSource.Connection class to enable
6 *   Salesforce to sync the external system’s schema
7 *   and to handle queries of the external data.
8 **/
9global class StackOverflowDataSourceConnection extends
10        DataSource.Connection {
11    private DataSource.ConnectionParams connectionInfo;
12
13    /**
14     *   Constructor for StackOverflowDataSourceConnection
15     **/
16    global StackOverflowDataSourceConnection(
17            DataSource.ConnectionParams connectionInfo) {
18        this.connectionInfo = connectionInfo;
19    }
20
21    /**
22     *   Defines the schema for the external system. 
23     *   Called when the administrator clicks “Validate and Sync”
24     *   in the user interface for the external data source.
25     **/
26    override global List<DataSource.Table> sync() {
27        List<DataSource.Table> tables =
28                new List<DataSource.Table>();
29
30        // Defines columns for the table of Stack OverFlow posts
31        List<DataSource.Column> postColumns =
32          new List<DataSource.Column>();
33
34        // Defines the external lookup field.
35        postColumns.add(DataSource.Column.externalLookup(
36          'owner_id', 'stackoverflowUser__x'));
37        postColumns.add(DataSource.Column.text('title', 255));
38        postColumns.add(DataSource.Column.text('view_count', 255));
39        postColumns.add(DataSource.Column.text('question_id',255));
40        postColumns.add(DataSource.Column.text('creation_date',255));
41        postColumns.add(DataSource.Column.text('score',255));
42        postColumns.add(DataSource.Column.url('link'));
43        postColumns.add(DataSource.Column.url('DisplayUrl'));
44        postColumns.add(DataSource.Column.text('ExternalId',255));
45
46        tables.add(DataSource.Table.get('stackoverflowPost','title',
47          postColumns));
48
49        // Defines columns for the table of Stack OverFlow users
50        List<DataSource.Column> userColumns =
51          new List<DataSource.Column>();
52        userColumns.add(DataSource.Column.text('user_id', 255));
53        userColumns.add(DataSource.Column.text('display_name', 255));
54        userColumns.add(DataSource.Column.text('location',255));
55        userColumns.add(DataSource.Column.text('creation_date',255));
56        userColumns.add(DataSource.Column.url('website_url',255));
57        userColumns.add(DataSource.Column.text('reputation',255));
58        userColumns.add(DataSource.Column.url('link'));
59        userColumns.add(DataSource.Column.url('DisplayUrl'));
60        userColumns.add(DataSource.Column.text('ExternalId',255));
61
62        tables.add(DataSource.Table.get('stackoverflowUser',
63                'Display_name', userColumns));
64
65        return tables;
66    }
67
68    /**
69     *   Called to query and get results from the external
70     *   system for SOQL queries, list views, and detail pages
71     *   for an external object that’s associated with the
72     *   external data source.
73     *
74     *   The QueryContext argument represents the query to run
75     *   against a table in the external system.
76     *
77     *   Returns a list of rows as the query results.
78     **/
79    override global DataSource.TableResult query(
80            DataSource.QueryContext context) {
81        DataSource.Filter filter = context.tableSelection.filter;
82        String url;
83
84        // Sets the URL to query Stack Overflow posts
85        if (context.tableSelection.tableSelected
86.equals('stackoverflowPost')) {
87            if (filter != null) {
88                String thisColumnName = filter.columnName;
89                if (thisColumnName != null &&
90                        thisColumnName.equals('ExternalId'))
91                    url = 'https://api.stackexchange.com/2.2/'
92                            + 'questions/' + filter.columnValue
93                            + '?order=desc&sort=activity'
94                            + '&site=stackoverflow';
95                else
96                        url = 'https://api.stackexchange.com/2.2/'
97                                + 'questions'
98                                + '?order=desc&sort=activity'
99                                + '&site=stackoverflow';
100            } else {
101                url = 'https://api.stackexchange.com/2.2/'
102                        + 'questions'
103                        + '?order=desc&sort=activity'
104                        + '&site=stackoverflow';
105            }
106        // Sets the URL to query Stack Overflow users
107        } else if (context.tableSelection.tableSelected
108.equals('stackoverflowUser')) {
109            if (filter != null) {
110                String thisColumnName = filter.columnName;
111                if (thisColumnName != null &&
112                        thisColumnName.equals('ExternalId'))
113                    url = 'https://api.stackexchange.com/2.2/'
114                            + 'users/' + filter.columnValue
115                            + '?order=desc&sort=reputation'
116                            + '&site=stackoverflow';
117                else
118                    url = 'https://api.stackexchange.com/2.2/'
119                            + 'users' + 
120'?order=desc&sort=reputation&site=stackoverflow';
121            } else {
122                url = 'https://api.stackexchange.com/2.2/'
123                        + 'users' + '?order=desc&sort=reputation'
124                        + '&site=stackoverflow';
125            }
126        }
127
128        /**
129         * Filters, sorts, and applies limit and offset clauses.
130         **/
131        List<Map<String, Object>> rows =
132                DataSource.QueryUtils.process(context, getData(url));
133        return DataSource.TableResult.get(true, null,
134                context.tableSelection.tableSelected, rows);
135    }
136
137    /**
138     *   Helper method to parse the data.
139     *   The url argument is the URL of the external system.
140     *   Returns a list of rows from the external system.
141     **/
142    public List<Map<String, Object>> getData(String url) {
143        String response = getResponse(url);
144
145        List<Map<String, Object>> rows =
146                new List<Map<String, Object>>();
147
148        Map<String, Object> responseBodyMap = (Map<String, Object>)
149                JSON.deserializeUntyped(response);
150
151        /**
152         *   Checks errors.
153         **/
154        Map<String, Object> error =
155                (Map<String, Object>)responseBodyMap.get('error');
156        if (error!=null) {
157            List<Object> errorsList =
158                    (List<Object>)error.get('errors');
159            Map<String, Object> errors =
160                    (Map<String, Object>)errorsList[0];
161            String errorMessage = (String)errors.get('message');
162            throw new 
163                    DataSource.OAuthTokenExpiredException(errorMessage);
164        }
165
166        List<Object> fileItems=
167            (List<Object>)responseBodyMap.get('items');
168        if (fileItems != null) {
169            for (Integer i=0; i < fileItems.size(); i++) {
170                Map<String, Object> item =
171                        (Map<String, Object>)fileItems[i];
172                rows.add(createRow(item));
173            }
174        } else {
175            rows.add(createRow(responseBodyMap));
176        }
177
178        return rows;
179    }
180
181    /**
182     *   Helper method to populate the External ID and Display
183     *   URL fields on external object records based on the 'id'
184     *   value that’s sent by the external system.
185     *
186     *   The Map<String, Object> item parameter maps to the data
187     *   that represents a row.
188     *
189     *   Returns an updated map with the External ID and
190     *   Display URL values.
191     **/
192    public Map<String, Object> createRow(
193            Map<String, Object> item) {
194        Map<String, Object> row = new Map<String, Object>();
195        for ( String key : item.keySet() ) {
196            if (key.equals('question_id') || key.equals('user_id')) {
197                row.put('ExternalId', item.get(key));
198            } else if (key.equals('link')) {
199                row.put('DisplayUrl', item.get(key));
200            } else if (key.equals('owner')) {
201                Map<String, Object> ownerMap =
202                (Map<String, Object>)item.get(key);
203                row.put('owner_id', ownerMap.get('user_id'));
204            }
205
206            row.put(key, item.get(key));
207        }
208        return row;
209    }
210
211    /**
212     *   Helper method to make the HTTP GET call.
213     *   The url argument is the URL of the external system.
214     *   Returns the response from the external system.
215     **/
216    public String getResponse(String url) {
217        // Perform callouts for production (non-test) results.
218        Http httpProtocol = new Http();
219        HttpRequest request = new HttpRequest();
220        request.setEndPoint(url);
221        request.setMethod('GET');
222        HttpResponse response = httpProtocol.send(request);
223        return response.getBody();
224    }
225}

StackOverflowPostDataSourceProvider クラス

1/**
2 *   Extends the DataSource.Provider base class to create a
3 *   custom adapter for Salesforce Connect. The class informs
4 *   Salesforce of the functional and authentication
5 *   capabilities that are supported by or required to connect
6 *   to an external system.
7 **/
8global class StackOverflowPostDataSourceProvider
9        extends DataSource.Provider {
10
11    /**
12     *   For simplicity, this example declares that the external 
13     *   system doesn’t require authentication by returning
14     *   AuthenticationCapability.ANONYMOUS as the sole entry 
15     *   in the list of authentication capabilities.
16     **/
17    override global List<DataSource.AuthenticationCapability>
18    getAuthenticationCapabilities() {
19        List<DataSource.AuthenticationCapability> capabilities =
20                new List<DataSource.AuthenticationCapability>();
21        capabilities.add(
22                DataSource.AuthenticationCapability.ANONYMOUS);
23        return capabilities;
24    }
25
26    /**
27     *   Declares the functional capabilities that the
28     *   external system supports, in this case
29     *   only SOQL queries.
30     **/
31    override global List<DataSource.Capability>
32    getCapabilities() {
33        List<DataSource.Capability> capabilities =
34                new List<DataSource.Capability>();
35        capabilities.add(DataSource.Capability.ROW_QUERY);
36        return capabilities;
37    }
38
39    /**
40     *   Declares the associated DataSource.Connection class.
41     **/
42    override global DataSource.Connection getConnection(
43            DataSource.ConnectionParams connectionParams) {
44        return new 
45            StackOverflowDataSourceConnection(connectionParams);
46    }
47}