001/** 002 * Copyright (c) 2010-2019 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 com.restfb.util.UrlUtils.extractParametersFromQueryString; 025import static java.lang.String.format; 026import static java.util.Collections.unmodifiableList; 027 028import java.util.ArrayList; 029import java.util.Date; 030import java.util.List; 031import java.util.Map; 032 033import com.restfb.batch.BatchRequest; 034import com.restfb.batch.BatchResponse; 035import com.restfb.exception.FacebookException; 036import com.restfb.exception.FacebookOAuthException; 037import com.restfb.exception.FacebookSignedRequestParsingException; 038import com.restfb.exception.FacebookSignedRequestVerificationException; 039import com.restfb.exception.devicetoken.FacebookDeviceTokenCodeExpiredException; 040import com.restfb.exception.devicetoken.FacebookDeviceTokenDeclinedException; 041import com.restfb.exception.devicetoken.FacebookDeviceTokenPendingException; 042import com.restfb.exception.devicetoken.FacebookDeviceTokenSlowdownException; 043import com.restfb.json.JsonObject; 044import com.restfb.scope.ScopeBuilder; 045import com.restfb.types.AbstractFacebookType; 046import com.restfb.types.DeviceCode; 047import com.restfb.util.ReflectionUtils; 048 049/** 050 * Specifies how a <a href="http://developers.facebook.com/docs/api">Facebook Graph API</a> client must operate. 051 * <p> 052 * If you'd like to... 053 * 054 * <ul> 055 * <li>Fetch an object: use {@link #fetchObject(String, Class, Parameter...)} or 056 * {@link #fetchObjects(List, Class, Parameter...)}</li> 057 * <li>Fetch a connection: use {@link #fetchConnection(String, Class, Parameter...)}</li> 058 * <li>Execute operations in batch: use {@link #executeBatch(BatchRequest...)} or {@link #executeBatch(List, List)}</li> 059 * <li>Publish data: use {@link #publish(String, Class, Parameter...)} or 060 * {@link #publish(String, Class, BinaryAttachment, Parameter...)}</li> 061 * <li>Delete an object: use {@link #deleteObject(String, Parameter...)}</li> 062 * </ul> 063 * 064 * <p> 065 * You may also perform some common access token operations. If you'd like to... 066 * 067 * <ul> 068 * <li>Extend the life of an access token: use {@link #obtainExtendedAccessToken(String, String, String)}</li> 069 * <li>Obtain an access token for use on behalf of an application instead of a user, use 070 * {@link #obtainAppAccessToken(String, String)}.</li> 071 * <li>Convert old-style session keys to OAuth access tokens: use 072 * {@link #convertSessionKeysToAccessTokens(String, String, String...)}</li> 073 * <li>Verify and extract data from a signed request: use {@link #parseSignedRequest(String, String, Class)}</li> 074 * </ul> 075 * 076 * @author <a href="http://restfb.com">Mark Allen</a> 077 * @author Scott Hernandez 078 * @author Mattia Tommasone 079 * @author <a href="http://ex-nerd.com">Chris Petersen</a> 080 * @author Josef Gierbl 081 * @author Broc Seib 082 */ 083public interface FacebookClient { 084 /** 085 * Fetches a single <a href="http://developers.facebook.com/docs/reference/api/">Graph API object</a>, mapping the 086 * result to an instance of {@code objectType}. 087 * 088 * @param <T> 089 * Java type to map to. 090 * @param object 091 * ID of the object to fetch, e.g. {@code "me"}. 092 * @param objectType 093 * Object type token. 094 * @param parameters 095 * URL parameters to include in the API call (optional). 096 * @return An instance of type {@code objectType} which contains the requested object's data. 097 * @throws FacebookException 098 * If an error occurs while performing the API call. 099 */ 100 <T> T fetchObject(String object, Class<T> objectType, Parameter... parameters); 101 102 /** 103 * Fetches multiple <a href="http://developers.facebook.com/docs/reference/api/">Graph API objects</a> in a single 104 * call, mapping the results to an instance of {@code objectType}. 105 * <p> 106 * You'll need to write your own container type ({@code objectType}) to hold the results. See 107 * <a href="http://restfb.com">http://restfb.com</a> for an example of how to do this. 108 * 109 * @param <T> 110 * Java type to map to. 111 * @param ids 112 * IDs of the objects to fetch, e.g. {@code "me", "arjun"}. 113 * @param objectType 114 * Object type token. 115 * @param parameters 116 * URL parameters to include in the API call (optional). 117 * @return An instance of type {@code objectType} which contains the requested objects' data. 118 * @throws FacebookException 119 * If an error occurs while performing the API call. 120 */ 121 <T> T fetchObjects(List<String> ids, Class<T> objectType, Parameter... parameters); 122 123 /** 124 * Fetches a Graph API {@code Connection} type, mapping the result to an instance of {@code connectionType}. 125 * 126 * @param <T> 127 * Java type to map to. 128 * @param connection 129 * The name of the connection, e.g. {@code "me/feed"}. 130 * @param connectionType 131 * Connection type token. 132 * @param parameters 133 * URL parameters to include in the API call (optional). 134 * @return An instance of type {@code connectionType} which contains the requested Connection's data. 135 * @throws FacebookException 136 * If an error occurs while performing the API call. 137 */ 138 <T> Connection<T> fetchConnection(String connection, Class<T> connectionType, Parameter... parameters); 139 140 /** 141 * Fetches a previous/next page of a Graph API {@code Connection} type, mapping the result to an instance of 142 * {@code connectionType}. 143 * 144 * @param <T> 145 * Java type to map to. 146 * @param connectionPageUrl 147 * The URL of the connection page to fetch, usually retrieved via {@link Connection#getPreviousPageUrl()} or 148 * {@link Connection#getNextPageUrl()}. 149 * @param connectionType 150 * Connection type token. 151 * @return An instance of type {@code connectionType} which contains the requested Connection's data. 152 * @throws FacebookException 153 * If an error occurs while performing the API call. 154 */ 155 <T> Connection<T> fetchConnectionPage(String connectionPageUrl, Class<T> connectionType); 156 157 /** 158 * Executes operations as a batch using the <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch 159 * API</a>. 160 * 161 * @param batchRequests 162 * The operations to execute. 163 * @return The execution results in the order in which the requests were specified. 164 */ 165 List<BatchResponse> executeBatch(BatchRequest... batchRequests); 166 167 /** 168 * Executes operations as a batch using the <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch 169 * API</a>. 170 * 171 * @param batchRequests 172 * The operations to execute. 173 * @return The execution results in the order in which the requests were specified. 174 */ 175 List<BatchResponse> executeBatch(List<BatchRequest> batchRequests); 176 177 /** 178 * Executes operations as a batch with binary attachments using the 179 * <a href="https://developers.facebook.com/docs/reference/api/batch/">Batch API</a>. 180 * 181 * @param batchRequests 182 * The operations to execute. 183 * @param binaryAttachments 184 * Binary attachments referenced by the batch requests. 185 * @return The execution results in the order in which the requests were specified. 186 * @since 1.6.5 187 */ 188 List<BatchResponse> executeBatch(List<BatchRequest> batchRequests, List<BinaryAttachment> binaryAttachments); 189 190 /** 191 * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the 192 * given {@code connection}, mapping the result to an instance of {@code objectType}. 193 * 194 * @param <T> 195 * Java type to map to. 196 * @param connection 197 * The Connection to publish to. 198 * @param objectType 199 * Object type token. 200 * @param parameters 201 * URL parameters to include in the API call. 202 * @return An instance of type {@code objectType} which contains the Facebook response to your publish request. 203 * @throws FacebookException 204 * If an error occurs while performing the API call. 205 */ 206 <T> T publish(String connection, Class<T> objectType, Parameter... parameters); 207 208 /** 209 * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the 210 * given {@code connection} and includes some files - photos, for example - in the publish request, and mapping the 211 * result to an instance of {@code objectType}. 212 * 213 * @param <T> 214 * Java type to map to. 215 * @param connection 216 * The Connection to publish to. 217 * @param objectType 218 * Object type token. 219 * @param binaryAttachments 220 * The files to include in the publish request. 221 * @param parameters 222 * URL parameters to include in the API call. 223 * @return An instance of type {@code objectType} which contains the Facebook response to your publish request. 224 * @throws FacebookException 225 * If an error occurs while performing the API call. 226 */ 227 <T> T publish(String connection, Class<T> objectType, List<BinaryAttachment> binaryAttachments, 228 Parameter... parameters); 229 230 /** 231 * Performs a <a href="http://developers.facebook.com/docs/api#publishing">Graph API publish</a> operation on the 232 * given {@code connection} and includes a file - a photo, for example - in the publish request, and mapping the 233 * result to an instance of {@code objectType}. 234 * 235 * @param <T> 236 * Java type to map to. 237 * @param connection 238 * The Connection to publish to. 239 * @param objectType 240 * Object type token. 241 * @param binaryAttachment 242 * The file to include in the publish request. 243 * @param parameters 244 * URL parameters to include in the API call. 245 * @return An instance of type {@code objectType} which contains the Facebook response to your publish request. 246 * @throws FacebookException 247 * If an error occurs while performing the API call. 248 */ 249 <T> T publish(String connection, Class<T> objectType, BinaryAttachment binaryAttachment, Parameter... parameters); 250 251 /** 252 * Performs a <a href="http://developers.facebook.com/docs/api#deleting">Graph API delete</a> operation on the given 253 * {@code object}. 254 * 255 * @param object 256 * The ID of the object to delete. 257 * @param parameters 258 * URL parameters to include in the API call. 259 * @return {@code true} if Facebook indicated that the object was successfully deleted, {@code false} otherwise. 260 * @throws FacebookException 261 * If an error occurred while attempting to delete the object. 262 */ 263 boolean deleteObject(String object, Parameter... parameters); 264 265 /** 266 * Converts an arbitrary number of {@code sessionKeys} to OAuth access tokens. 267 * <p> 268 * See the <a href="http://developers.facebook.com/docs/guides/upgrade">Facebook Platform Upgrade Guide</a> for 269 * details on how this process works and why you should convert your application's session keys if you haven't 270 * already. 271 * 272 * @param appId 273 * A Facebook application ID. 274 * @param secretKey 275 * A Facebook application secret key. 276 * @param sessionKeys 277 * The Old REST API session keys to be converted to OAuth access tokens. 278 * @return A list of access tokens ordered to correspond to the {@code sessionKeys} argument list. 279 * @throws FacebookException 280 * If an error occurs while attempting to convert the session keys to API keys. 281 * @since 1.6 282 */ 283 List<AccessToken> convertSessionKeysToAccessTokens(String appId, String secretKey, String... sessionKeys); 284 285 /** 286 * Obtains an access token which can be used to perform Graph API operations on behalf of a user. 287 * <p> 288 * See <a href="https://developers.facebook.com/docs/facebook-login/access-tokens">Access Tokens</a>. 289 * 290 * @param appId 291 * The ID of the app for which you'd like to obtain an access token. 292 * @param appSecret 293 * The secret for the app for which you'd like to obtain an access token. 294 * @param redirectUri 295 * The redirect URI which was used to obtain the {@code verificationCode}. 296 * @param verificationCode 297 * The verification code in the Graph API callback to the redirect URI. 298 * @return The access token for the user identified by {@code appId}, {@code appSecret}, {@code redirectUri} and 299 * {@code verificationCode}. 300 * @throws FacebookException 301 * If an error occurs while attempting to obtain an access token. 302 * @since 1.8.0 303 */ 304 AccessToken obtainUserAccessToken(String appId, String appSecret, String redirectUri, String verificationCode); 305 306 /** 307 * Obtains an access token which can be used to perform Graph API operations on behalf of an application instead of a 308 * user. 309 * <p> 310 * See <a href="https://developers.facebook.com/docs/authentication/applications/" >Facebook's authenticating as an 311 * app documentation</a>. 312 * 313 * @param appId 314 * The ID of the app for which you'd like to obtain an access token. 315 * @param appSecret 316 * The secret for the app for which you'd like to obtain an access token. 317 * @return The access token for the application identified by {@code appId} and {@code appSecret}. 318 * @throws FacebookException 319 * If an error occurs while attempting to obtain an access token. 320 * @since 1.6.10 321 */ 322 AccessToken obtainAppAccessToken(String appId, String appSecret); 323 324 /** 325 * Obtains an extended access token for the given existing, non-expired, short-lived access_token. 326 * <p> 327 * See <a href="https://developers.facebook.com/roadmap/offline-access-removal/#extend_token">Facebook's extend access 328 * token documentation</a>. 329 * 330 * @param appId 331 * The ID of the app for which you'd like to obtain an extended access token. 332 * @param appSecret 333 * The secret for the app for which you'd like to obtain an extended access token. 334 * @param accessToken 335 * The non-expired, short-lived access token to extend. 336 * @return An extended access token for the given {@code accessToken}. 337 * @throws FacebookException 338 * If an error occurs while attempting to obtain an extended access token. 339 * @since 1.6.10 340 */ 341 AccessToken obtainExtendedAccessToken(String appId, String appSecret, String accessToken); 342 343 /** 344 * Generates an {@code appsecret_proof} value. 345 * <p> 346 * See <a href="https://developers.facebook.com/docs/graph-api/securing-requests">Facebook's 'securing requests' 347 * documentation</a> for more info. 348 * 349 * @param accessToken 350 * The access token required to generate the {@code appsecret_proof} value. 351 * @param appSecret 352 * The secret for the app for which you'd like to generate the {@code appsecret_proof} value. 353 * @return A hex-encoded SHA256 hash as a {@code String}. 354 * @throws IllegalStateException 355 * If creating the {@code appsecret_proof} fails. 356 * @since 1.6.13 357 */ 358 String obtainAppSecretProof(String accessToken, String appSecret); 359 360 /** 361 * Convenience method which invokes {@link #obtainExtendedAccessToken(String, String, String)} with the current access 362 * token. 363 * 364 * @param appId 365 * The ID of the app for which you'd like to obtain an extended access token. 366 * @param appSecret 367 * The secret for the app for which you'd like to obtain an extended access token. 368 * @return An extended access token for the given {@code accessToken}. 369 * @throws FacebookException 370 * If an error occurs while attempting to obtain an extended access token. 371 * @throws IllegalStateException 372 * If this instance was not constructed with an access token. 373 * @since 1.6.10 374 */ 375 AccessToken obtainExtendedAccessToken(String appId, String appSecret); 376 377 /** 378 * Parses a signed request and verifies it against your App Secret. 379 * <p> 380 * See <a href="http://developers.facebook.com/docs/howtos/login/signed-request/">Facebook's signed request 381 * documentation</a>. 382 * 383 * @param signedRequest 384 * The signed request to parse. 385 * @param appSecret 386 * The secret for the app that can read this signed request. 387 * @param objectType 388 * Object type token. 389 * @param <T> 390 * class of objectType 391 * @return An instance of type {@code objectType} which contains the decoded object embedded within 392 * {@code signedRequest}. 393 * @throws FacebookSignedRequestParsingException 394 * If an error occurs while trying to process {@code signedRequest}. 395 * @throws FacebookSignedRequestVerificationException 396 * If {@code signedRequest} fails verification against {@code appSecret}. 397 * @since 1.6.13 398 */ 399 <T> T parseSignedRequest(String signedRequest, String appSecret, Class<T> objectType); 400 401 /** 402 * Method to initialize the device access token generation. 403 * 404 * You receive a {@link DeviceCode} instance and have to show the user the {@link DeviceCode#getVerificationUri()} and 405 * the {@link DeviceCode#getUserCode()}. The user have to enter the user code at the verification url. 406 * 407 * Save the {@link DeviceCode#getCode()} to use it later, when polling Facebook with the 408 * {@link #obtainDeviceAccessToken(java.lang.String)} method. 409 * 410 * @param scope 411 * List of Permissions to request from the person using your app. 412 * @return Instance of {@code DeviceCode} including the information to obtain the Device access token 413 */ 414 DeviceCode fetchDeviceCode(ScopeBuilder scope); 415 416 /** 417 * Method to poll Facebook and fetch the Device Access Token. 418 * 419 * You have to use this method to check if the user confirms the authorization. 420 * 421 * {@link FacebookOAuthException} can be thrown if the authorization is declined or still pending. 422 * 423 * @param code 424 * The device 425 * @return An extended access token for the given {@link AccessToken}. 426 * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenCodeExpiredException 427 * the {@link DeviceCode#getCode()} is expired, please fetch a new {@link DeviceCode}. 428 * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenPendingException 429 * the user has not finished the authorisation process, yet. Please poll again later. 430 * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenDeclinedException 431 * the user declined the authorisation. You have to handle this problem. 432 * @throws com.restfb.exception.devicetoken.FacebookDeviceTokenSlowdownException 433 * you tried too often to fetch the device access token. You have to use a larger interval 434 * @since 1.12.0 435 */ 436 AccessToken obtainDeviceAccessToken(String code) throws FacebookDeviceTokenCodeExpiredException, 437 FacebookDeviceTokenPendingException, FacebookDeviceTokenDeclinedException, FacebookDeviceTokenSlowdownException; 438 439 /** 440 * <p> 441 * When working with access tokens, you may need to check what information is associated with them, such as its user 442 * or expiry. To get this information you can use the debug tool in the developer site, or you can use this function. 443 * </p> 444 * 445 * <p> 446 * You must instantiate your FacebookClient using your App Access Token, or a valid User Access Token from a developer 447 * of the app. 448 * </p> 449 * 450 * <p> 451 * Note that if your app is set to Native/Desktop in the Advanced settings of your App Dashboard, the underlying 452 * GraphAPI endpoint will not work with your app token unless you change the "App Secret in Client" setting to NO. If 453 * you do not see this setting, make sure your "App Type" is set to Native/Desktop and then press the save button at 454 * the bottom of the page. This will not affect apps set to Web. 455 * </p> 456 * 457 * <p> 458 * The response of the API call is a JSON array containing data and a map of fields. For example: 459 * </p> 460 * 461 * <pre> 462 * {@code 463 * { 464 * "data": { 465 * "app_id": 138483919580948, 466 * "application": "Social Cafe", 467 * "expires_at": 1352419328, 468 * "is_valid": true, 469 * "issued_at": 1347235328, 470 * "metadata": { 471 * "sso": "iphone-safari" 472 * }, 473 * "scopes": [ 474 * "email", 475 * "publish_actions" 476 * ], 477 * "user_id": 1207059 478 * } 479 * } 480 * } 481 * </pre> 482 * 483 * <p> 484 * Note that the {@code issued_at} field is not returned for short-lived access tokens. 485 * </p> 486 * 487 * <p> 488 * See <a href="https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/"> Debugging an Access 489 * Token</a> 490 * </p> 491 * 492 * @param inputToken 493 * The Access Token to debug. 494 * 495 * @return A JsonObject containing the debug information for the accessToken. 496 * @since 1.6.13 497 */ 498 DebugTokenInfo debugToken(String inputToken); 499 500 /** 501 * Gets the {@code JsonMapper} used to convert Facebook JSON to Java objects. 502 * 503 * @return The {@code JsonMapper} used to convert Facebook JSON to Java objects. 504 * @since 1.6.7 505 */ 506 JsonMapper getJsonMapper(); 507 508 /** 509 * Gets the {@code WebRequestor} used to talk to the Facebook API endpoints. 510 * 511 * @return The {@code WebRequestor} used to talk to the Facebook API endpoints. 512 * @since 1.6.7 513 */ 514 WebRequestor getWebRequestor(); 515 516 /** 517 * generates an logout url 518 * 519 * @param next 520 * may be null, url the webpage should redirect after logout 521 * @return the logout url 522 * @since 1.9.0 523 */ 524 String getLogoutUrl(String next); 525 526 /** 527 * generates the login dialog url 528 * 529 * @param appId 530 * The ID of your app, found in your app's dashboard. 531 * @param redirectUri 532 * The URL that you want to redirect the person logging in back to. This URL will capture the response from 533 * the Login Dialog. If you are using this in a webview within a desktop app, this must be set to 534 * <code>https://www.facebook.com/connect/login_success.html</code>. 535 * @param scope 536 * List of Permissions to request from the person using your app. 537 * @param additionalParameters 538 * List of additional parameters 539 * @since 1.9.0 540 * @return the login dialog url 541 */ 542 String getLoginDialogUrl(String appId, String redirectUri, ScopeBuilder scope, Parameter... additionalParameters); 543 544 /** 545 * Represents an access token/expiration date pair. 546 * <p> 547 * Facebook returns these types when performing access token-related operations - see 548 * {@link com.restfb.FacebookClient#convertSessionKeysToAccessTokens(String, String, String...)}, 549 * {@link com.restfb.FacebookClient#obtainAppAccessToken(String, String)}, and 550 * {@link com.restfb.FacebookClient#obtainExtendedAccessToken(String, String, String)} for details. 551 * 552 * @author <a href="http://restfb.com">Mark Allen</a> 553 */ 554 class AccessToken { 555 @Facebook("access_token") 556 private String accessToken; 557 558 @Facebook("expires_in") 559 private Long rawExpires; 560 561 private Long expires; 562 563 @Facebook("token_type") 564 private String tokenType; 565 566 /** 567 * Given a query string of the form {@code access_token=XXX} or {@code access_token=XXX&expires=YYY}, return an 568 * {@code AccessToken} instance. 569 * <p> 570 * The {@code queryString} is required to contain an {@code access_token} parameter with a non-{@code null} value. 571 * The {@code expires} value is optional and should be the number of seconds since the epoch. If the {@code expires} 572 * value cannot be parsed, the returned {@code AccessToken} will have a {@code null} {@code expires} value. 573 * 574 * @param queryString 575 * The Facebook query string out of which to parse an {@code AccessToken} instance. 576 * @return An {@code AccessToken} instance which corresponds to the given {@code queryString}. 577 * @throws IllegalArgumentException 578 * If no {@code access_token} parameter is present in the query string. 579 * @since 1.6.10 580 */ 581 public static AccessToken fromQueryString(String queryString) { 582 // Query string can be of the form 'access_token=XXX' or 583 // 'access_token=XXX&expires=YYY' 584 Map<String, List<String>> urlParameters = extractParametersFromQueryString(queryString); 585 586 String extendedAccessToken = null; 587 String tokenType = null; 588 589 if (urlParameters.containsKey("access_token")) { 590 extendedAccessToken = urlParameters.get("access_token").get(0); 591 } 592 593 if (urlParameters.containsKey("token_type")) { 594 tokenType = urlParameters.get("token_type").get(0); 595 } 596 597 if (extendedAccessToken == null) { 598 throw new IllegalArgumentException(format( 599 "Was expecting a query string of the form 'access_token=XXX' or 'access_token=XXX&expires=YYY'. Instead, the query string was '%s'", 600 queryString)); 601 } 602 603 Long expires = null; 604 605 // If an expires or expires_in value was provided and it's a valid long, great - use it. 606 // Otherwise ignore it. 607 String rawExpires = null; 608 609 if (urlParameters.containsKey("expires")) { 610 rawExpires = urlParameters.get("expires").get(0); 611 } 612 613 if (urlParameters.containsKey("expires_in")) { 614 rawExpires = urlParameters.get("expires_in").get(0); 615 } 616 617 if (rawExpires != null) { 618 try { 619 expires = Long.valueOf(rawExpires); 620 } catch (NumberFormatException e) { 621 // rawExpires is not a number, NumberFormatException ignored 622 } 623 if (expires != null) { 624 expires = new Date().getTime() + 1000L * expires; 625 } 626 } 627 628 AccessToken accessToken = new AccessToken(); 629 accessToken.accessToken = extendedAccessToken; 630 accessToken.expires = expires; 631 accessToken.tokenType = tokenType; 632 return accessToken; 633 } 634 635 @Override 636 public int hashCode() { 637 return ReflectionUtils.hashCode(this); 638 } 639 640 @Override 641 public boolean equals(Object that) { 642 return ReflectionUtils.equals(this, that); 643 } 644 645 @Override 646 public String toString() { 647 return ReflectionUtils.toString(this); 648 } 649 650 /** 651 * The access token's value. 652 * 653 * @return The access token's value. 654 */ 655 public String getAccessToken() { 656 return accessToken; 657 } 658 659 /** 660 * The date on which the access token expires. 661 * 662 * @return The date on which the access token expires. 663 */ 664 public Date getExpires() { 665 return expires == null ? null : new Date(expires); 666 } 667 668 /** 669 * The token type of this access token provided by Facebook 670 * 671 * @return the access token type 672 */ 673 public String getTokenType() { 674 return tokenType; 675 } 676 677 @JsonMapper.JsonMappingCompleted 678 void convertExpires() { 679 if (rawExpires != null) { 680 expires = new Date().getTime() + 1000L * rawExpires; 681 } 682 } 683 684 } 685 686 /** 687 * <p> 688 * Represents the result of a {@link FacebookClient#debugToken(String)} inquiry. 689 * </p> 690 * 691 * FIXME does this class belong here? 692 * 693 * <p> 694 * See <a href="https://developers.facebook.com/docs/howtos/login/debugging-access-tokens/">Debug access tokens</a> 695 * 696 * @author Broc Seib 697 */ 698 class DebugTokenInfo extends AbstractFacebookType { 699 700 private static final long serialVersionUID = 1L; 701 702 /** 703 * The ID of the application this access token is for. 704 */ 705 @Facebook("app_id") 706 private String appId; 707 708 /** 709 * Name of the application this access token is for. 710 */ 711 @Facebook 712 private String application; 713 714 /** 715 * Timestamp when this access token expires. 716 */ 717 @Facebook("expires_at") 718 private Date expiresAt; 719 720 /** 721 * Timestamp when app's access to user data expires. 722 */ 723 @Facebook("data_access_expires_at") 724 private Date dataAccessExpiresAt; 725 726 /** 727 * Timestamp when this access token was issued. 728 */ 729 @Facebook("issued_at") 730 private Date issuedAt; 731 732 /** 733 * Whether the access token is still valid or not. 734 */ 735 @Facebook("is_valid") 736 private Boolean isValid; 737 738 /** 739 * The ID of the user this access token is for. 740 */ 741 @Facebook("user_id") 742 private String userId; 743 744 /** 745 * For impersonated access tokens, the ID of the page this token contains. 746 */ 747 @Facebook("profile_id") 748 private String profileId; 749 750 /** 751 * General metadata associated with the access token. Can contain data like 'sso', 'auth_type', 'auth_nonce' 752 */ 753 @Facebook 754 private JsonObject metadata; 755 756 /** 757 * Any error that a request to the graph api would return due to the access token. 758 */ 759 @Facebook 760 private DebugTokenError error; 761 762 /** 763 * List of permissions that the user has granted for the app in this access token. 764 */ 765 @Facebook 766 private List<String> scopes = new ArrayList<>(); 767 768 @Facebook 769 private String type; 770 771 /** 772 * The application id. 773 * 774 * @return The id of the application. 775 */ 776 public String getAppId() { 777 return appId; 778 } 779 780 /** 781 * The application name. 782 * 783 * @return The name of the application. 784 */ 785 public String getApplication() { 786 return application; 787 } 788 789 /** 790 * The date on which the access token expires. 791 * 792 * @return The date on which the access token expires. 793 */ 794 public Date getExpiresAt() { 795 return expiresAt; 796 } 797 798 /** 799 * Timestamp when app's access to user data expires. 800 * 801 * @return The date when app's access to user data expires. 802 */ 803 public Date getDataAccessExpiresAt() { 804 return dataAccessExpiresAt; 805 } 806 807 /** 808 * The date on which the access token was issued. 809 * 810 * @return The date on which the access token was issued. 811 */ 812 public Date getIssuedAt() { 813 return issuedAt; 814 } 815 816 /** 817 * Whether or not the token is valid. 818 * 819 * @return Whether or not the token is valid. 820 */ 821 public Boolean isValid() { 822 return isValid; 823 } 824 825 /** 826 * The user id. 827 * 828 * @return The user id. 829 */ 830 public String getUserId() { 831 return userId; 832 } 833 834 /** 835 * List of scopes the access token 'contains' 836 * 837 * @return list of scopes 838 */ 839 public List<String> getScopes() { 840 return unmodifiableList(scopes); 841 } 842 843 /** 844 * General metadata associated with the access token. Can contain data like 'sso', 'auth_type', 'auth_nonce' 845 * 846 * @return General metadata associated with the access token 847 */ 848 public JsonObject getMetaData() { 849 return metadata; 850 } 851 852 /** 853 * All Error data associated with access token debug. 854 * 855 * @return debug token error 856 */ 857 public DebugTokenError getDebugTokenError() { 858 return error; 859 } 860 861 public String getType() { 862 return type; 863 } 864 } 865 866 class DebugTokenError extends AbstractFacebookType { 867 868 private static final long serialVersionUID = 1L; 869 870 /** 871 * The error code for the error. 872 */ 873 @Facebook 874 private Integer code; 875 876 /** 877 * The error message for the error. 878 */ 879 @Facebook 880 private String message; 881 882 /** 883 * The error subcode for the error. 884 */ 885 @Facebook 886 private Integer subcode; 887 888 /** 889 * The error code for the error. 890 * 891 * @return The error code for the error. 892 */ 893 public Integer getCode() { 894 return code; 895 } 896 897 /** 898 * The error message for the error. 899 * 900 * @return The error message for the error. 901 */ 902 public String getMessage() { 903 return message; 904 } 905 906 /** 907 * The error subcode for the error. 908 * 909 * @return The error subcode for the error. 910 */ 911 public Integer getSubcode() { 912 return subcode; 913 } 914 915 } 916}