Newer Version Available
Salesforce Connect の Google ドライブ™ カスタムアダプタ
この例は、コールアウトと OAuth を使用して外部システム (この場合は Google ドライブ™ オンラインストレージサービス) に接続する方法を示しています。また、この例は、テストメソッドの疑似応答を返すことによって Web サービスコールアウトのテストの失敗を回避する方法も示しています。
この例を確実に機能させるには、OAuth を設定するときにオフラインアクセスを要求して、Salesforce が接続の更新トークンを取得および維持できるようにします。
DriveDataSourceConnection クラス
1/**
2 * Extends the DataSource.Connection class to enable
3 * Salesforce to sync the external system’s schema
4 * and to handle queries and searches of the external data.
5 **/
6global class DriveDataSourceConnection extends
7 DataSource.Connection {
8 private DataSource.ConnectionParams connectionInfo;
9
10 /**
11 * Constructor for DriveDataSourceConnection.
12 **/
13 global DriveDataSourceConnection(
14 DataSource.ConnectionParams connectionInfo) {
15 this.connectionInfo = connectionInfo;
16 }
17
18 /**
19 * Called when an external object needs to get a list of
20 * schema from the external data source, for example when
21 * the administrator clicks “Validate and Sync” in the
22 * user interface for the external data source.
23 **/
24 override global List<DataSource.Table> sync() {
25 List<DataSource.Table> tables =
26 new List<DataSource.Table>();
27 List<DataSource.Column> columns;
28 columns = new List<DataSource.Column>();
29 columns.add(DataSource.Column.text('title', 255));
30 columns.add(DataSource.Column.text('description',255));
31 columns.add(DataSource.Column.text('createdDate',255));
32 columns.add(DataSource.Column.text('modifiedDate',255));
33 columns.add(DataSource.Column.url('selfLink'));
34 columns.add(DataSource.Column.url('DisplayUrl'));
35 columns.add(DataSource.Column.text('ExternalId',255));
36 tables.add(DataSource.Table.get('googleDrive','title',
37 columns));
38 return tables;
39 }
40
41 /**
42 * Called to query and get results from the external
43 * system for SOQL queries, list views, and detail pages
44 * for an external object that’s associated with the
45 * external data source.
46 *
47 * The QueryContext argument represents the query to run
48 * against a table in the external system.
49 *
50 * Returns a list of rows as the query results.
51 **/
52 override global DataSource.TableResult query(
53 DataSource.QueryContext context) {
54 DataSource.Filter filter = context.tableSelection.filter;
55 String url;
56 if (filter != null) {
57 String thisColumnName = filter.columnName;
58 if (thisColumnName != null &&
59 thisColumnName.equals('ExternalId'))
60 url = 'https://www.googleapis.com/drive/v2/'
61 + 'files/' + filter.columnValue;
62 else
63 url = 'https://www.googleapis.com/drive/v2/'
64 + 'files';
65 } else {
66 url = 'https://www.googleapis.com/drive/v2/'
67 + 'files';
68 }
69
70 /**
71 * Filters, sorts, and applies limit and offset clauses.
72 **/
73 List<Map<String, Object>> rows =
74 DataSource.QueryUtils.process(context, getData(url));
75 return DataSource.TableResult.get(true, null,
76 context.tableSelection.tableSelected, rows);
77 }
78
79 /**
80 * Called to do a full text search and get results from
81 * the external system for SOSL queries and Salesforce
82 * global searches.
83 *
84 * The SearchContext argument represents the query to run
85 * against a table in the external system.
86 *
87 * Returns results for each table that the SearchContext
88 * requested to be searched.
89 **/
90 override global List<DataSource.TableResult> search(
91 DataSource.SearchContext context) {
92 List<DataSource.TableResult> results =
93 new List<DataSource.TableResult>();
94
95 for (Integer i =0;i< context.tableSelections.size();i++) {
96 String entity = context.tableSelections[i].tableSelected;
97 String url =
98 'https://www.googleapis.com/drive/v2/files'+
99 '?q=fullText+contains+\''+context.searchPhrase+'\'';
100 results.add(DataSource.TableResult.get(
101 true, null, entity, getData(url)));
102 }
103
104 return results;
105 }
106
107 /**
108 * Helper method to parse the data.
109 * The url argument is the URL of the external system.
110 * Returns a list of rows from the external system.
111 **/
112 public List<Map<String, Object>> getData(String url) {
113 String response = getResponse(url);
114
115 List<Map<String, Object>> rows =
116 new List<Map<String, Object>>();
117
118 Map<String, Object> responseBodyMap = (Map<String, Object>)
119 JSON.deserializeUntyped(response);
120
121 /**
122 * Checks errors.
123 **/
124 Map<String, Object> error =
125 (Map<String, Object>)responseBodyMap.get('error');
126 if (error!=null) {
127 List<Object> errorsList =
128 (List<Object>)error.get('errors');
129 Map<String, Object> errors =
130 (Map<String, Object>)errorsList[0];
131 String errorMessage = (String)errors.get('message');
132 throw new DataSource.OAuthTokenExpiredException(errorMessage);
133 }
134
135 List<Object> fileItems=(List<Object>)responseBodyMap.get('items');
136 if (fileItems != null) {
137 for (Integer i=0; i < fileItems.size(); i++) {
138 Map<String, Object> item =
139 (Map<String, Object>)fileItems[i];
140 rows.add(createRow(item));
141 }
142 } else {
143 rows.add(createRow(responseBodyMap));
144 }
145
146 return rows;
147 }
148
149 /**
150 * Helper method to populate the External ID and Display
151 * URL fields on external object records based on the 'id'
152 * value that’s sent by the external system.
153 *
154 * The Map<String, Object> item parameter maps to the data
155 * that represents a row.
156 *
157 * Returns an updated map with the External ID and
158 * Display URL values.
159 **/
160 public Map<String, Object> createRow(
161 Map<String, Object> item){
162 Map<String, Object> row = new Map<String, Object>();
163 for ( String key : item.keySet() ) {
164 if (key == 'id') {
165 row.put('ExternalId', item.get(key));
166 } else if (key=='selfLink') {
167 row.put(key, item.get(key));
168 row.put('DisplayUrl', item.get(key));
169 } else {
170 row.put(key, item.get(key));
171 }
172 }
173 return row;
174 }
175
176 static String mockResponse = '{' +
177 ' "kind": "drive#file",' +
178 ' "id": "12345",' +
179 ' "selfLink": "files/12345",' +
180 ' "title": "Mock File",' +
181 ' "mimeType": "application/text",' +
182 ' "description": "Mock response that’s used during tests",' +
183 ' "createdDate": "2016-04-20",' +
184 ' "modifiedDate": "2016-04-20",' +
185 ' "version": 1' +
186 '}';
187
188 /**
189 * Helper method to make the HTTP GET call.
190 * The url argument is the URL of the external system.
191 * Returns the response from the external system.
192 **/
193 public String getResponse(String url) {
194 if (System.Test.isRunningTest()) {
195 // Avoid callouts during tests. Return mock data instead.
196 return mockResponse;
197 } else {
198 // Perform callouts for production (non-test) results.
199 Http httpProtocol = new Http();
200 HttpRequest request = new HttpRequest();
201 request.setEndPoint(url);
202 request.setMethod('GET');
203 request.setHeader('Authorization', 'Bearer '+
204 this.connectionInfo.oauthToken);
205 HttpResponse response = httpProtocol.send(request);
206 return response.getBody();
207 }
208 }
209}DriveDataSourceProvider クラス
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 DriveDataSourceProvider
9 extends DataSource.Provider {
10
11 /**
12 * Declares the types of authentication that can be used
13 * to access the external system.
14 **/
15 override global List<DataSource.AuthenticationCapability>
16 getAuthenticationCapabilities() {
17 List<DataSource.AuthenticationCapability> capabilities =
18 new List<DataSource.AuthenticationCapability>();
19 capabilities.add(
20 DataSource.AuthenticationCapability.OAUTH);
21 capabilities.add(
22 DataSource.AuthenticationCapability.ANONYMOUS);
23 return capabilities;
24 }
25
26 /**
27 * Declares the functional capabilities that the
28 * external system supports.
29 **/
30 override global List<DataSource.Capability>
31 getCapabilities() {
32 List<DataSource.Capability> capabilities =
33 new List<DataSource.Capability>();
34 capabilities.add(DataSource.Capability.ROW_QUERY);
35 capabilities.add(DataSource.Capability.SEARCH);
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 DriveDataSourceConnection(connectionParams);
45 }
46}