001/*
002 * Copyright (c) 2010-2024 Mark Allen, Norbert Bartels.
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020 * THE SOFTWARE.
021 */
022package com.restfb;
023
024import static java.lang.String.format;
025
026import java.util.*;
027
028import com.restfb.batch.BatchRequest;
029import com.restfb.batch.BatchResponse;
030import com.restfb.exception.FacebookException;
031import com.restfb.exception.FacebookOAuthException;
032import com.restfb.exception.FacebookSignedRequestParsingException;
033import com.restfb.exception.FacebookSignedRequestVerificationException;
034import com.restfb.exception.devicetoken.FacebookDeviceTokenCodeExpiredException;
035import com.restfb.exception.devicetoken.FacebookDeviceTokenDeclinedException;
036import com.restfb.exception.devicetoken.FacebookDeviceTokenPendingException;
037import com.restfb.exception.devicetoken.FacebookDeviceTokenSlowdownException;
038import com.restfb.scope.ScopeBuilder;
039import com.restfb.types.DebugTokenInfo;
040import com.restfb.types.DeviceCode;
041
042/**
043 * Specifies how a <a href="http://developers.facebook.com/docs/api">Facebook Graph API</a> client must operate.
044 * <p>
045 * If you'd like to...
046 * 
047 * <ul>
048 * <li>Fetch an object: use {@link #fetchObject(String, Class, Parameter...)} or
049 * {@link #fetchObjects(List, Class, Parameter...)}</li>
050 * <li>Fetch a connection: use {@link #fetchConnection(String, Class, Parameter...)}</li>
051 * <li>Execute operations in batch: use {@link #executeBatch(BatchRequest...)} or {@link #executeBatch(List, List)}</li>
052 * <li>Publish data: use {@link #publish(String, Class, Parameter...)} or
053 * {@link #publish(String, Class, BinaryAttachment, Parameter...)}</li>
054 * <li>Delete an object: use {@link #deleteObject(String, Parameter...)}</li>
055 * </ul>
056 * 
057 * <p>
058 * You may also perform some common access token operations. If you'd like to...
059 * 
060 * <ul>
061 * <li>Extend the life of an access token: use {@link #obtainExtendedAccessToken(String, String, String)}</li>
062 * <li>Obtain an access token for use on behalf of an application instead of a user, use
063 * {@link #obtainAppAccessToken(String, String)}.</li>
064 * <li>Convert old-style session keys to OAuth access tokens: use
065 * {@link #convertSessionKeysToAccessTokens(String, String, String...)}</li>
066 * <li>Verify and extract data from a signed request: use {@link #parseSignedRequest(String, String, Class)}</li>
067 * </ul>
068 * 
069 * @author <a href="http://restfb.com">Mark Allen</a>
070 * @author Scott Hernandez
071 * @author Mattia Tommasone
072 * @author <a href="http://ex-nerd.com">Chris Petersen</a>
073 * @author Josef Gierbl
074 * @author Broc Seib
075 */
076public interface FacebookClient {
077  /**
078   * Fetches a single <a href="http://developers.facebook.com/docs/reference/api/">Graph API object</a>, mapping the
079   * result to an instance of {@code objectType}.
080   * 
081   * @param <T>
082   *          Java type to map to.
083   * @param object
084   *          ID of the object to fetch, e.g. {@code "me"}.
085   * @param objectType
086   *          Object type token.
087   * @param parameters
088   *          URL parameters to include in the API call (optional).
089   * @return An instance of type {@code objectType} which contains the requested object's data.
090   * @throws FacebookException
091   *           If an error occurs while performing the API call.
092   */
093  <T> T fetchObject(String object, Class<T> objectType, Parameter... parameters);
094
095  /**
096   * creates a new <code>FacebookClient</code> from a old one.
097   * 
098   * App secret and and api version are taken from the original client.
099   *
100   * @param accessToken
101   *          this accesstoken is used for the new client
102   * @return a new Facebookclient
103   */
104  FacebookClient createClientWithAccessToken(String accessToken);
105
106  /**
107   * Fetches multiple <a href="http://developers.facebook.com/docs/reference/api/">Graph API objects</a> in a single
108   * call, mapping the results to an instance of {@code objectType}.
109   * <p>
110   * You'll need to write your own container type ({@code objectType}) to hold the results. See
111   * <a href="http://restfb.com">http://restfb.com</a> for an example of how to do this.
112   * 
113   * @param <T>
114   *          Java type to map to.
115   * @param ids
116   *          IDs of the objects to fetch, e.g. {@code "me", "arjun"}.
117   * @param objectType
118   *          Object type token.
119   * @param parameters
120   *          URL parameters to include in the API call (optional).
121   * @return An instance of type {@code objectType} which contains the requested objects' data.
122   * @throws FacebookException
123   *           If an error occurs while performing the API call.
124   */
125  <T> T fetchObjects(List<String> ids, Class<T> objectType, Parameter... parameters);
126
127  /**
128   * Fetches a Graph API {@code Connection} type, mapping the result to an instance of {@code connectionType}.
129   * 
130   * @param <T>
131   *          Java type to map to.
132   * @param connection
133   *          The name of the connection, e.g. {@code "me/feed"}.
134   * @param connectionType
135   *          Connection type token.
136   * @param parameters
137   *          URL parameters to include in the API call (optional).
138   * @return An instance of type {@code connectionType} which contains the requested Connection's data.
139   * @throws FacebookException
140   *           If an error occurs while performing the API call.
141   */
142  <T> Connection<T> fetchConnection(String connection, Class<T> connectionType, Parameter... parameters);
143
144  /**
145   * Fetches a previous/next page of a Graph API {@code Connection} type, mapping the result to an instance of
146   * {@code connectionType}.
147   * 
148   * @param <T>
149   *          Java type to map to.
150   * @param connectionPageUrl
151   *          The URL of the connection page to fetch, usually retrieved via {@link Connection#getPreviousPageUrl()} or
152   *          {@link Connection#getNextPageUrl()}.
153   * @param connectionType
154   *          Connection type token.
155   * @return An instance of type {@code connectionType} which contains the requested Connection's data.
156   * @throws FacebookException
157   *           If an error occurs while performing the API call.
158   */
159  <T> Connection<T> fetchConnectionPage(String connectionPageUrl, Class<T> connectionType);
160
161  /**
162   * Executes operations as a batch using the <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch
163   * API</a>.
164   * 
165   * @param batchRequests
166   *          The operations to execute.
167   * @return The execution results in the order in which the requests were specified.
168   */
169  List<BatchResponse> executeBatch(BatchRequest... batchRequests);
170
171  /**
172   * Executes operations as a batch using the <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch
173   * API</a>.
174   * 
175   * @param batchRequests
176   *          The operations to execute.
177   * @return The execution results in the order in which the requests were specified.
178   */
179  List<BatchResponse> executeBatch(List<BatchRequest> batchRequests);
180
181  /**
182   * Executes operations as a batch with binary attachments using the
183   * <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch API</a>.
184   * 
185   * @param batchRequests
186   *          The operations to execute.
187   * @param binaryAttachments
188   *          Binary attachments referenced by the batch requests.
189   * @return The execution results in the order in which the requests were specified.
190   * @since 1.6.5
191   */
192  List<BatchResponse> executeBatch(List<BatchRequest> batchRequests, List<BinaryAttachment> binaryAttachments);
193
194  /**
195   * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the
196   * given {@code connection}, mapping the result to an instance of {@code objectType}.
197   * 
198   * @param <T>
199   *          Java type to map to.
200   * @param connection
201   *          The Connection to publish to.
202   * @param objectType
203   *          Object type token.
204   * @param parameters
205   *          URL parameters to include in the API call.
206   * @return An instance of type {@code objectType} which contains the Facebook response to your publish request.
207   * @throws FacebookException
208   *           If an error occurs while performing the API call.
209   */
210  <T> T publish(String connection, Class<T> objectType, Parameter... parameters);
211
212  /**
213   * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the
214   * given {@code connection} and includes some files - photos, for example - in the publish request, and mapping the
215   * result to an instance of {@code objectType}.
216   * 
217   * @param <T>
218   *          Java type to map to.
219   * @param connection
220   *          The Connection to publish to.
221   * @param objectType
222   *          Object type token.
223   * @param binaryAttachments
224   *          The files to include in the publish request.
225   * @param parameters
226   *          URL parameters to include in the API call.
227   * @return An instance of type {@code objectType} which contains the Facebook response to your publish request.
228   * @throws FacebookException
229   *           If an error occurs while performing the API call.
230   */
231  <T> T publish(String connection, Class<T> objectType, List<BinaryAttachment> binaryAttachments,
232      Parameter... parameters);
233
234  /**
235   * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the
236   * given {@code connection} and includes a file - a photo, for example - in the publish request, and mapping the
237   * result to an instance of {@code objectType}.
238   * 
239   * @param <T>
240   *          Java type to map to.
241   * @param connection
242   *          The Connection to publish to.
243   * @param objectType
244   *          Object type token.
245   * @param binaryAttachment
246   *          The file to include in the publish request.
247   * @param parameters
248   *          URL parameters to include in the API call.
249   * @return An instance of type {@code objectType} which contains the Facebook response to your publish request.
250   * @throws FacebookException
251   *           If an error occurs while performing the API call.
252   */
253  <T> T publish(String connection, Class<T> objectType, BinaryAttachment binaryAttachment, Parameter... parameters);
254
255  /**
256   * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the
257   * given {@code connection} and includes special body in the publish request, and mapping the
258   * result to an instance of {@code objectType}.
259   *
260   * @param <T>
261   *          Java type to map to.
262   * @param connection
263   *          The Connection to publish to.
264   * @param objectType
265   *          Object type token.
266   * @param body
267   *          The body used in the POST request.
268   * @param parameters
269   *          URL parameters to include in the API call.
270   * @return An instance of type {@code objectType} which contains the Facebook response to your publish request.
271   * @throws FacebookException
272   *           If an error occurs while performing the API call.
273   */
274  <T> T publish(String connection, Class<T> objectType, Body body, Parameter... parameters);
275
276  /**
277   * Performs a <a href="http://developers.facebook.com/docs/api#deleting">Graph API delete</a> operation on the given
278   * {@code object}.
279   * 
280   * @param object
281   *          The ID of the object to delete.
282   * @param parameters
283   *          URL parameters to include in the API call.
284   * @return {@code true} if Facebook indicated that the object was successfully deleted, {@code false} otherwise.
285   * @throws FacebookException
286   *           If an error occurred while attempting to delete the object.
287   */
288  boolean deleteObject(String object, Parameter... parameters);
289
290  /**
291   * Converts an arbitrary number of {@code sessionKeys} to OAuth access tokens.
292   * <p>
293   * See the <a href="http://developers.facebook.com/docs/guides/upgrade">Facebook Platform Upgrade Guide</a> for
294   * details on how this process works and why you should convert your application's session keys if you haven't
295   * already.
296   * 
297   * @param appId
298   *          A Facebook application ID.
299   * @param secretKey
300   *          A Facebook application secret key.
301   * @param sessionKeys
302   *          The Old REST API session keys to be converted to OAuth access tokens.
303   * @return A list of access tokens ordered to correspond to the {@code sessionKeys} argument list.
304   * @throws FacebookException
305   *           If an error occurs while attempting to convert the session keys to API keys.
306   * @since 1.6
307   */
308  List<AccessToken> convertSessionKeysToAccessTokens(String appId, String secretKey, String... sessionKeys);
309
310  /**
311   * Obtains an access token which can be used to perform Graph API operations on behalf of a user.
312   * <p>
313   * See <a href="https://developers.facebook.com/docs/facebook-login/access-tokens">Access Tokens</a>.
314   *
315   * @param appId
316   *          The ID of the app for which you'd like to obtain an access token.
317   * @param appSecret
318   *          The secret for the app for which you'd like to obtain an access token.
319   * @param redirectUri
320   *          The redirect URI which was used to obtain the {@code verificationCode}.
321   * @param verificationCode
322   *          The verification code in the Graph API callback to the redirect URI.
323   * @return The access token for the user identified by {@code appId}, {@code appSecret}, {@code redirectUri} and
324   *         {@code verificationCode}.
325   * @throws FacebookException
326   *           If an error occurs while attempting to obtain an access token.
327   * @since 1.8.0
328   */
329  AccessToken obtainUserAccessToken(String appId, String appSecret, String redirectUri, String verificationCode);
330
331  /**
332   * Obtains an access token which can be used to perform Graph API operations on behalf of an application instead of a
333   * user.
334   * <p>
335   * See <a href="https://developers.facebook.com/docs/authentication/applications/" >Facebook's authenticating as an
336   * app documentation</a>.
337   * 
338   * @param appId
339   *          The ID of the app for which you'd like to obtain an access token.
340   * @param appSecret
341   *          The secret for the app for which you'd like to obtain an access token.
342   * @return The access token for the application identified by {@code appId} and {@code appSecret}.
343   * @throws FacebookException
344   *           If an error occurs while attempting to obtain an access token.
345   * @since 1.6.10
346   */
347  AccessToken obtainAppAccessToken(String appId, String appSecret);
348
349  /**
350   * Obtains an extended access token for the given existing, non-expired, short-lived access_token.
351   * <p>
352   * See <a href="https://developers.facebook.com/roadmap/offline-access-removal/#extend_token">Facebook's extend access
353   * token documentation</a>.
354   * 
355   * @param appId
356   *          The ID of the app for which you'd like to obtain an extended access token.
357   * @param appSecret
358   *          The secret for the app for which you'd like to obtain an extended access token.
359   * @param accessToken
360   *          The non-expired, short-lived access token to extend.
361   * @return An extended access token for the given {@code accessToken}.
362   * @throws FacebookException
363   *           If an error occurs while attempting to obtain an extended access token.
364   * @since 1.6.10
365   */
366  AccessToken obtainExtendedAccessToken(String appId, String appSecret, String accessToken);
367
368  /**
369   * Generates an {@code appsecret_proof} value.
370   * <p>
371   * See <a href="https://developers.facebook.com/docs/graph-api/securing-requests">Facebook's 'securing requests'
372   * documentation</a> for more info.
373   * 
374   * @param accessToken
375   *          The access token required to generate the {@code appsecret_proof} value.
376   * @param appSecret
377   *          The secret for the app for which you'd like to generate the {@code appsecret_proof} value.
378   * @return A hex-encoded SHA256 hash as a {@code String}.
379   * @throws IllegalStateException
380   *           If creating the {@code appsecret_proof} fails.
381   * @since 1.6.13
382   */
383  String obtainAppSecretProof(String accessToken, String appSecret);
384
385  /**
386   * Convenience method which invokes {@link #obtainExtendedAccessToken(String, String, String)} with the current access
387   * token.
388   * 
389   * @param appId
390   *          The ID of the app for which you'd like to obtain an extended access token.
391   * @param appSecret
392   *          The secret for the app for which you'd like to obtain an extended access token.
393   * @return An extended access token for the given {@code accessToken}.
394   * @throws FacebookException
395   *           If an error occurs while attempting to obtain an extended access token.
396   * @throws IllegalStateException
397   *           If this instance was not constructed with an access token.
398   * @since 1.6.10
399   */
400  AccessToken obtainExtendedAccessToken(String appId, String appSecret);
401
402  /**
403   * Parses a signed request and verifies it against your App Secret.
404   * <p>
405   * See <a href="http://developers.facebook.com/docs/howtos/login/signed-request/">Facebook's signed request
406   * documentation</a>.
407   * 
408   * @param signedRequest
409   *          The signed request to parse.
410   * @param appSecret
411   *          The secret for the app that can read this signed request.
412   * @param objectType
413   *          Object type token.
414   * @param <T>
415   *          class of objectType
416   * @return An instance of type {@code objectType} which contains the decoded object embedded within
417   *         {@code signedRequest}.
418   * @throws FacebookSignedRequestParsingException
419   *           If an error occurs while trying to process {@code signedRequest}.
420   * @throws FacebookSignedRequestVerificationException
421   *           If {@code signedRequest} fails verification against {@code appSecret}.
422   * @since 1.6.13
423   */
424  <T> T parseSignedRequest(String signedRequest, String appSecret, Class<T> objectType);
425
426  /**
427   * Method to initialize the device access token generation.
428   *
429   * You receive a {@link DeviceCode} instance and have to show the user the {@link DeviceCode#getVerificationUri()} and
430   * the {@link DeviceCode#getUserCode()}. The user have to enter the user code at the verification url.
431   *
432   * Save the {@link DeviceCode#getCode()} to use it later, when polling Facebook with the
433   * {@link #obtainDeviceAccessToken(java.lang.String)} method.
434   *
435   * @param scope
436   *          List of Permissions to request from the person using your app.
437   * @return Instance of {@code DeviceCode} including the information to obtain the Device access token
438   */
439  DeviceCode fetchDeviceCode(ScopeBuilder scope);
440
441  /**
442   * Method to poll Facebook and fetch the Device Access Token.
443   *
444   * You have to use this method to check if the user confirms the authorization.
445   *
446   * {@link FacebookOAuthException} can be thrown if the authorization is declined or still pending.
447   *
448   * @param code
449   *          The device
450   * @return An extended access token for the given {@link AccessToken}.
451   * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenCodeExpiredException
452   *           the {@link DeviceCode#getCode()} is expired, please fetch a new {@link DeviceCode}.
453   * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenPendingException
454   *           the user has not finished the authorisation process, yet. Please poll again later.
455   * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenDeclinedException
456   *           the user declined the authorisation. You have to handle this problem.
457   * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenSlowdownException
458   *           you tried too often to fetch the device access token. You have to use a larger interval
459   * @since 1.12.0
460   */
461  AccessToken obtainDeviceAccessToken(String code) throws FacebookDeviceTokenCodeExpiredException,
462      FacebookDeviceTokenPendingException, FacebookDeviceTokenDeclinedException, FacebookDeviceTokenSlowdownException;
463
464  /**
465   * <p>
466   * When working with access tokens, you may need to check what information is associated with them, such as its user
467   * or expiry. To get this information you can use the debug tool in the developer site, or you can use this function.
468   * </p>
469   * 
470   * <p>
471   * You must instantiate your FacebookClient using your App Access Token, or a valid User Access Token from a developer
472   * of the app.
473   * </p>
474   * 
475   * <p>
476   * Note that if your app is set to Native/Desktop in the Advanced settings of your App Dashboard, the underlying
477   * GraphAPI endpoint will not work with your app token unless you change the "App Secret in Client" setting to NO. If
478   * you do not see this setting, make sure your "App Type" is set to Native/Desktop and then press the save button at
479   * the bottom of the page. This will not affect apps set to Web.
480   * </p>
481   * 
482   * <p>
483   * The response of the API call is a JSON array containing data and a map of fields. For example:
484   * </p>
485   * 
486   * <pre>
487   * {@code
488   * {
489   *     "data": {
490   *         "app_id": 138483919580948, 
491   *         "application": "Social Cafe", 
492   *         "expires_at": 1352419328, 
493   *         "is_valid": true, 
494   *         "issued_at": 1347235328, 
495   *         "metadata": {
496   *             "sso": "iphone-safari"
497   *         }, 
498   *         "scopes": [
499   *             "email", 
500   *             "publish_actions"
501   *         ], 
502   *         "user_id": 1207059
503   *     }
504   * }
505   * }
506   * </pre>
507   * 
508   * <p>
509   * Note that the {@code issued_at} field is not returned for short-lived access tokens.
510   * </p>
511   * 
512   * <p>
513   * See <a href="https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/"> Debugging an Access
514   * Token</a>
515   * </p>
516   * 
517   * @param inputToken
518   *          The Access Token to debug.
519   * 
520   * @return A JsonObject containing the debug information for the accessToken.
521   * @since 1.6.13
522   */
523  DebugTokenInfo debugToken(String inputToken);
524
525  /**
526   * Gets the {@code JsonMapper} used to convert Facebook JSON to Java objects.
527   * 
528   * @return The {@code JsonMapper} used to convert Facebook JSON to Java objects.
529   * @since 1.6.7
530   */
531  JsonMapper getJsonMapper();
532
533  /**
534   * Gets the {@code WebRequestor} used to talk to the Facebook API endpoints.
535   * 
536   * @return The {@code WebRequestor} used to talk to the Facebook API endpoints.
537   * @since 1.6.7
538   */
539  WebRequestor getWebRequestor();
540
541  /**
542   * generates an logout url
543   * 
544   * @param next
545   *          may be null, url the webpage should redirect after logout
546   * @return the logout url
547   * @since 1.9.0
548   */
549  String getLogoutUrl(String next);
550
551  /**
552   * generates the login dialog url
553   * 
554   * @param appId
555   *          The ID of your app, found in your app's dashboard.
556   * @param redirectUri
557   *          The URL that you want to redirect the person logging in back to. This URL will capture the response from
558   *          the Login Dialog. If you are using this in a webview within a desktop app, this must be set to
559   *          <code>https://www.facebook.com/connect/login_success.html</code>.
560   * @param scope
561   *          List of Permissions to request from the person using your app.
562   * @param additionalParameters
563   *          List of additional parameters
564   * @since 1.9.0
565   * @return the login dialog url
566   */
567  String getLoginDialogUrl(String appId, String redirectUri, ScopeBuilder scope, Parameter... additionalParameters);
568
569}