From 0ccbd46c19dd5960428c4d0901bc0e075b64885c Mon Sep 17 00:00:00 2001 From: Ty Smith Date: Thu, 2 Jun 2016 15:57:38 -0700 Subject: [PATCH] [Gradle Release Plugin] - pre tag commit: 'v0.5.0'. --- CHANGELOG.md | 33 + README.md | 92 +- build.gradle | 22 + gradle.properties | 24 +- gradle/wrapper/gradle-wrapper.properties | 24 +- samples/build.gradle | 22 + samples/cmdline-sample/build.gradle | 22 + samples/cmdline-sample/gradle.properties | 22 + .../rides/samples/cmdline/GetUserProfile.java | 85 +- samples/servlet-sample/build.gradle | 22 + samples/servlet-sample/gradle.properties | 22 + .../servlet/OAuth2CallbackServlet.java | 6 +- .../rides/samples/servlet/SampleServlet.java | 31 +- .../sdk/rides/samples/servlet/Server.java | 26 +- sdk/build.gradle | 59 +- sdk/config/checkstyle/checkstyle-main.xml | 22 + sdk/config/checkstyle/checkstyle-test.xml | 22 + .../com/uber/sdk/core/auth/AccessToken.java | 154 +++ .../core/auth/AccessTokenAuthenticator.java | 146 +++ .../auth/AccessTokenStorage.java} | 37 +- .../auth/Authenticator.java} | 43 +- .../java/com/uber/sdk/core/auth/Scope.java | 173 ++++ .../sdk/core/auth/internal/OAuth2Service.java | 37 + .../auth/internal/OAuthScopes.java} | 17 +- .../auth/internal/OAuthScopesAdapter.java | 42 + .../uber/sdk/rides/auth/AuthException.java | 2 +- .../rides/auth/CredentialsAuthenticator.java | 108 ++ .../sdk/rides/auth/OAuth2Credentials.java | 95 +- .../com/uber/sdk/rides/auth/OAuth2Helper.java | 76 -- .../rides/auth/ServerTokenAuthenticator.java | 65 ++ .../sdk/rides/client/AccessTokenSession.java | 21 + .../sdk/rides/client/CredentialsSession.java | 21 + .../com/uber/sdk/rides/client/Response.java | 93 -- .../sdk/rides/client/ServerTokenSession.java | 19 + .../com/uber/sdk/rides/client/Session.java | 184 +--- .../rides/client/SessionConfiguration.java | 354 +++++++ .../uber/sdk/rides/client/UberRidesApi.java | 164 +++ .../rides/client/UberRidesAsyncService.java | 293 ------ .../sdk/rides/client/UberRidesServices.java | 184 ---- .../rides/client/UberRidesSyncService.java | 264 ----- .../{ApiException.java => ApiError.java} | 44 +- .../sdk/rides/client/error/ClientError.java | 64 +- .../CompatibilityApiError.java} | 36 +- .../sdk/rides/client/error/ErrorParser.java | 89 ++ .../com/uber/sdk/rides/client/error/Meta.java | 47 + .../rides/client/error/SurgeConfirmation.java | 84 ++ .../rides/client/internal/ApiInterceptor.java | 68 ++ .../client/internal/PrimitiveAdapter.java | 60 ++ .../RefreshAuthenticator.java} | 53 +- .../client/internal/RetrofitAdapter.java | 642 ------------ .../internal/RetrofitUberRidesClient.java | 239 ----- .../uber/sdk/rides/client/model/Driver.java | 2 +- .../uber/sdk/rides/client/model/Location.java | 2 +- .../sdk/rides/client/model/PaymentMethod.java | 22 + .../client/model/PaymentMethodsResponse.java | 22 + .../uber/sdk/rides/client/model/Place.java | 22 + .../rides/client/model/PlaceParameters.java | 22 + .../sdk/rides/client/model/PriceEstimate.java | 2 +- .../client/model/PriceEstimatesResponse.java | 2 +- .../uber/sdk/rides/client/model/Product.java | 2 +- .../rides/client/model/ProductsResponse.java | 2 +- .../sdk/rides/client/model/Promotion.java | 2 +- .../com/uber/sdk/rides/client/model/Ride.java | 2 +- .../sdk/rides/client/model/RideEstimate.java | 2 +- .../uber/sdk/rides/client/model/RideMap.java | 2 +- .../sdk/rides/client/model/RideReceipt.java | 22 + .../client/model/RideRequestParameters.java | 2 +- .../client/model/RideUpdateParameters.java | 22 + .../SandboxProductRequestParameters.java | 2 +- .../model/SandboxRideRequestParameters.java | 2 +- .../sdk/rides/client/model/TimeEstimate.java | 2 +- .../client/model/TimeEstimatesResponse.java | 2 +- .../sdk/rides/client/model/UserActivity.java | 2 +- .../rides/client/model/UserActivityPage.java | 2 +- .../sdk/rides/client/model/UserProfile.java | 2 +- .../uber/sdk/rides/client/model/Vehicle.java | 2 +- .../RidesService.java} | 186 ++-- .../sdk/rides/client/utils/Preconditions.java | 100 ++ .../auth/AccessTokenAuthenticatorTest.java | 193 ++++ .../com/uber/sdk/core/auth/ScopeTest.java | 102 ++ .../core/auth/internal/OAuth2ServiceTest.java | 94 ++ .../auth/internal/OAuthScopesAdapterTest.java | 76 ++ .../sdk/rides/auth/OAuth2CredentialsTest.java | 32 +- .../uber/sdk/rides/auth/OAuth2HelperTest.java | 190 ---- .../client/SessionConfigurationTest.java | 160 +++ .../uber/sdk/rides/client/SessionTest.java | 129 +-- .../sdk/rides/client/UberRidesApiTest.java | 148 +++ .../rides/client/UberRidesServicesTest.java | 188 ---- .../rides/client/error/ErrorParserTest.java | 88 ++ .../client/internal/ApiInterceptorTest.java | 107 ++ .../client/internal/PrimitiveAdapterTest.java | 57 + .../client/internal/PrimitiveModel.java} | 25 +- .../internal/RefreshAuthenticatorTest.java | 92 ++ .../client/internal/RetrofitAdapterTest.java | 81 -- ...etrofitUberRidesClientIntegrationTest.java | 970 ------------------ .../internal/RetrofitUberRidesClientTest.java | 123 --- .../model/RideRequestParametersTest.java | 22 + .../model/RideUpdateParametersTest.java | 22 + .../test/resources/__files/token_token.json | 8 + settings.gradle | 22 + 100 files changed, 3947 insertions(+), 4012 deletions(-) create mode 100644 sdk/src/main/java/com/uber/sdk/core/auth/AccessToken.java create mode 100644 sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenAuthenticator.java rename sdk/src/main/java/com/uber/sdk/{rides/client/error/NetworkException.java => core/auth/AccessTokenStorage.java} (68%) rename sdk/src/main/java/com/uber/sdk/{rides/client/Callback.java => core/auth/Authenticator.java} (57%) create mode 100644 sdk/src/main/java/com/uber/sdk/core/auth/Scope.java create mode 100644 sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuth2Service.java rename sdk/src/main/java/com/uber/sdk/{rides/client/UberRidesService.java => core/auth/internal/OAuthScopes.java} (78%) create mode 100644 sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapter.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/auth/CredentialsAuthenticator.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Helper.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/auth/ServerTokenAuthenticator.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/AccessTokenSession.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/CredentialsSession.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/Response.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/ServerTokenSession.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/SessionConfiguration.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/UberRidesApi.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/UberRidesAsyncService.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/UberRidesServices.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/UberRidesSyncService.java rename sdk/src/main/java/com/uber/sdk/rides/client/error/{ApiException.java => ApiError.java} (58%) rename sdk/src/main/java/com/uber/sdk/rides/client/{Header.java => error/CompatibilityApiError.java} (69%) create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/error/ErrorParser.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/error/Meta.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeConfirmation.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/internal/ApiInterceptor.java create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/internal/PrimitiveAdapter.java rename sdk/src/main/java/com/uber/sdk/rides/client/{error/SurgeError.java => internal/RefreshAuthenticator.java} (53%) delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitAdapter.java delete mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClient.java rename sdk/src/main/java/com/uber/sdk/rides/client/{internal/RetrofitUberRidesService.java => services/RidesService.java} (60%) create mode 100644 sdk/src/main/java/com/uber/sdk/rides/client/utils/Preconditions.java create mode 100644 sdk/src/test/java/com/uber/sdk/core/auth/AccessTokenAuthenticatorTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/core/auth/ScopeTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuth2ServiceTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapterTest.java delete mode 100644 sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2HelperTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/SessionConfigurationTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/UberRidesApiTest.java delete mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/UberRidesServicesTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/error/ErrorParserTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/ApiInterceptorTest.java create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveAdapterTest.java rename sdk/src/{main/java/com/uber/sdk/rides/client/error/UberError.java => test/java/com/uber/sdk/rides/client/internal/PrimitiveModel.java} (73%) create mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/RefreshAuthenticatorTest.java delete mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitAdapterTest.java delete mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientIntegrationTest.java delete mode 100644 sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientTest.java create mode 100644 sdk/src/test/resources/__files/token_token.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f3a1f..9800526 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,36 @@ +v0.5.0 - 6/2/2016 +------------------ +This release sets up the Java SDK for the Uber Android SDK to utilize it as a third party dependency by adding common interfaces and removing heavier weight components. + +### Added + +#### SessionConfiguration +SessionConfiguration is a new class to hold on to client information for authentication. This is used by underlying components. + +#### UberRidesApi + +`UberServices` has been replaced with `UberRidesApi`, which uses a `Session` to construct Api Services + +#### Sessions +`AccessTokenSession`, `ServerTokenSession`, and `CredentialSession` have been added for the three types of authentication. + +#### AccessTokenStorage +A common interface to store access tokens + +#### RidesService +Replaces `UberRidesSyncService` and `UberRidesAsyncService` with a Retrofit 2 based API Service. Both sync and async can be utilized directly on the resulting `Call` + +### Changed + - Split packaging into core and rides + - `Oauth2Credentials` now accepts a `SessionConfiguration` + - Updated from Retrofit 1 to Retrofit 2 + - Updated from OkHttp2 to OkHttp3 + - Removed Gauva dependency + +### Breaking + - Removed `UberServices` in favor of `UberRidesApi` + - Removed `UberRidesSyncService` and `UberRidesAsyncService` in favor of `RidesService` + v0.3.0 - 5/9/2016 ------------------ - Merged #7 diff --git a/README.md b/README.md index 2f6a572..05ed3bb 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ This SDK helps your Java App make HTTP requests to the Uber Rides API. #### Before you begin Register your app in the [Uber developer dashboard](https://developer.uber.com/dashboard). Notice that the app gets a client ID, secret, and server token required for authenticating with the API. -Note: This Java SDK is not suitable for Android development. We will release an official Android SDK soon. +Note: Using Android? Be sure to checkout the [Uber Android SDK](github.com/uber/rides-android-sdk) in addition, which has native authentication mechanisms. #### Gradle If using Gradle, add this to your project’s `build.gradle` file: ```gradle dependencies { - compile 'com.uber.sdk:rides:0.3.0' + compile 'com.uber.sdk:rides:0.5.0' } ``` @@ -24,20 +24,23 @@ If using Maven, add this to your project's `pom.xml` file: com.uber.sdk rides - 0.3.0 + 0.5.0 ``` ### Authenticating and creating a session -To make calls, you need to create an authenticated session with the API. While operations on behalf of users require a user-authorized token using OAuth 2, general requests can use server-token authentication. +To make calls, you need to create an authenticated session with the API. While operations on behalf of users require a user-authorized token using OAuth 2, general requests can use server-token authentication. + #### Create a session using a server token ```java // Get the server token for your app from the developer dashboard. -Session session = new Session.Builder() +SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("YOUR_CLIENT_ID") .setServerToken("YOUR_SERVER_TOKEN") - .setEnvironment(Environment.PRODUCTION) .build(); + +ServerTokenSession session = new ServerTokenSession(config)); ``` #### Create a session using the OAuth 2 flow In an OAuth session, the app first asks the user to authorize and then exchanges the authorization code for an access token from Uber. @@ -45,11 +48,17 @@ Note: Make sure the redirect URI matches the callback URI in the developer dashb **Step 1**. Create an OAuth2Credentials object with your client ID, client secret, scopes, and a redirect callback URI to capture the user’s authorization code. ```java -OAuth2Credentials credentials = new OAuth2Credentials.Builder() - .setClientSecrets(clientId, clientSecret) +SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("YOUR_CLIENT_ID") + .setClientSecret("YOUR_CLIENT_SECRET") .setScopes(yourScopes) .setRedirectUri(redirectUri) .build(); + +OAuth2Credentials credentials = new OAuth2Credentials.Builder() + .setSessionConfiguration(config) + .build(); + ``` **Step 2**. Navigate the user to the authorization URL from the OAuth2Credentials object. ```java @@ -61,19 +70,51 @@ Credential credential = credentials.authenticate(authorizationCode, userId); ``` **Step 4**. Create a session object using the credential object. ```java -Session session = new Session.Builder() - .setCredential(credential) - .setEnvironment(Environment.PRODUCTION) - .build(); +CredentialsSession session = new CredentialsSession(config, credential) ``` **Step 5**. Instantiate a service using a session to start making calls. ```java -UberRidesSyncService service = UberRidesServices.createSync(session); +RidesService service = UberRidesApi.with(session).createService(); ``` Note: Keep each user's access token in a secure data store. Reuse the same token to make API calls on behalf of your user without repeating the authorization flow each time they visit your app. The SDK handles the token refresh automatically when it makes API requests with an `UberRidesService`. ## Sync vs. Async Calls -Both synchronous and asynchronous calls work with the Uber rides Java SDK. Instantiate your service appropriately with `UberRidesServices.createSync(session)` or `UberRidesServices.createAsync(session)`. Asynchronous calls are returned on a platform appropriate thread accessible through callbacks. +Both synchronous and asynchronous calls work with the Uber rides Java SDK. The networking stack for the Uber SDK is powered by [Retrofit 2](https://github.com/square/retrofit) and the same model of threading is available. + +#### Sync +```java +Response response = service.getUserProfile().execute(); +if (response.isSuccessful()) { + //Success + UserProfile profile = response.body(); +} else { + //Failure + ApiError error = ErrorParser.parseError(response); +} + +``` + +#### Async +```java +service.getUserProfile().enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (response.isSuccessful()) { + //Success + UserProfile profile = response.body(); + } else { + //Api Failure + ApiError error = ErrorParser.parseError(response); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + //Network Failure + } +}); +``` + ## Samples for Common Calls Use the Java classes in the [samples](https://github.com/uber/rides-java-sdk/tree/master/samples/cmdline-sample) folder to test standard requests. Alternatively, you can download a sample from the [releases page](https://github.com/uber/rides-java-sdk/releases/tag/v0.1.0) to try them out. @@ -83,8 +124,8 @@ For full documentation, visit our [Developer Site](https://developer.uber.com/v1 ### Get available products ```java // Get a list of products for a specific location in GPS coordinates, example: 37.79f, -122.39f. -ProductsResponse productsResponse = service.getProducts(37.79f, -122.39f).getBody(); -List products = productsResponse.getProducts(); +Response> response = service.getProducts(37.79f, -122.39f).execute(); +List products = response.body(); String productId = products.get(0).getProductId(); ``` @@ -95,14 +136,18 @@ RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder( .setProductId(productId) .setDropoffCoordinates(37.49f, -122.41f) .build(); -Ride ride = service.requestRide(rideRequestParameters).getBody(); +Ride ride = service.requestRide(rideRequestParameters).execute().body(); String rideId = ride.getRideId(); ``` **Warning**: This real-world request can send an Uber driver to the specified start location. To develop and test against endpoints in a sandbox environment, instantiate your `UberRidesService` with a `Session` whose `Environment` is set to `SANDBOX`. +This will take an existing session and generate a new one pointing to `SANDBOX`. ```java -Session session = new Session.Builder().setCredential(credential).setEnvironment(Environment.SANDBOX).build(); -UberRidesSyncService service = UberRidesServices.createSync(session); + +SessionConfiguration config = existingConfig.newBuilder().setEnvironment(Environment.SANDBOX).build() + +CredentialsSession session = new CredentialsSession(config, credential)); +RidesService service = UberRidesApi.with(session); ``` See our [documentation](https://developer.uber.com/v1/sandbox/) to learn more about the sandbox environment. @@ -110,15 +155,18 @@ See our [documentation](https://developer.uber.com/v1/sandbox/) to learn more ab If you request a ride in the sandbox, you can step through the different states of the ride. ```java SandboxRideRequestParameters rideParameters = new SandboxRideRequestParameters.Builder().setStatus(“accepted”).build(); -Response response = client.updateSandboxRide(rideId, rideParameters); +Response response = service.updateSandboxRide(rideId, rideParameters).execute(); ``` -A successful update returns a 204 for `response.getStatus()`. +A successful update returns a 204 for `response.code()`. -Note: The `updateSandboxRide` method is not valid in the `PRODUCTION` `Environment`, where the ride status changes automatically. In a `PRODUCTION` `Environment`, the call throws an `IllegalStateException`. +Note: The `updateSandboxRide` method is not valid in the `PRODUCTION` `Environment`, where the ride status changes automatically. In a `PRODUCTION` `Environment`, the call will fail. ## Getting Help Uber developers actively monitor the [uber-api tag](http://stackoverflow.com/questions/tagged/uber-api) on StackOverflow. If you need help installing or using the library, ask a question there. Make sure to tag your question with `uber-api` and `java`! +## Migrating from a previous version +As the Uber SDK get closer to a 1.0 release, the API's will become more stable. In the meantime, be sure to check out the changelog to know what differs! + ## Contributing We :heart: contributions. If you find a bug in the library or would like to add new features, go ahead and open issues or pull requests against this repo. Before you do so, please sign the diff --git a/build.gradle b/build.gradle index 6f29997..5fd931a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + apply plugin: 'distribution' apply plugin: 'net.researchgate.release' apply plugin: 'co.riiid.gradle' diff --git a/gradle.properties b/gradle.properties index 2fd46ba..56151a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,27 @@ +# +# Copyright (c) 2016 Uber Technologies, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + group=com.uber.sdk groupId=com.uber.sdk artifactId=rides githubDownloadPrefix=https://github.com/uber/rides-java-sdk/releases/download/ -version=0.3.1-SNAPSHOT +version=0.5.0 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 179dd79..a72365a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,28 @@ +# +# Copyright (c) 2016 Uber Technologies, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + #Wed Apr 10 15:27:10 PDT 2013 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-all.zip diff --git a/samples/build.gradle b/samples/build.gradle index 35c5fb5..5e1a1e3 100644 --- a/samples/build.gradle +++ b/samples/build.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + subprojects { configure(install.repositories.mavenInstaller) { pom.project { diff --git a/samples/cmdline-sample/build.gradle b/samples/cmdline-sample/build.gradle index e74fb68..87cd34f 100644 --- a/samples/cmdline-sample/build.gradle +++ b/samples/cmdline-sample/build.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + apply plugin: 'application' targetCompatibility = JavaVersion.VERSION_1_7 diff --git a/samples/cmdline-sample/gradle.properties b/samples/cmdline-sample/gradle.properties index 20eaf0b..82a6c7a 100644 --- a/samples/cmdline-sample/gradle.properties +++ b/samples/cmdline-sample/gradle.properties @@ -1 +1,23 @@ +# +# Copyright (c) 2016 Uber Technologies, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + description=Command line sample \ No newline at end of file diff --git a/samples/cmdline-sample/src/main/java/com/uber/sdk/rides/samples/cmdline/GetUserProfile.java b/samples/cmdline-sample/src/main/java/com/uber/sdk/rides/samples/cmdline/GetUserProfile.java index c985925..08c587b 100644 --- a/samples/cmdline-sample/src/main/java/com/uber/sdk/rides/samples/cmdline/GetUserProfile.java +++ b/samples/cmdline-sample/src/main/java/com/uber/sdk/rides/samples/cmdline/GetUserProfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,16 +27,22 @@ import com.google.api.client.util.store.AbstractDataStoreFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.uber.sdk.rides.auth.OAuth2Credentials; -import com.uber.sdk.rides.client.Session; -import com.uber.sdk.rides.client.UberRidesServices; -import com.uber.sdk.rides.client.UberRidesSyncService; +import com.uber.sdk.rides.client.CredentialsSession; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.UberRidesApi; +import com.uber.sdk.rides.client.error.ApiError; +import com.uber.sdk.rides.client.error.ClientError; +import com.uber.sdk.rides.client.error.ErrorParser; import com.uber.sdk.rides.client.model.UserProfile; +import com.uber.sdk.rides.client.services.RidesService; import java.io.File; import java.io.FileReader; import java.io.InputStream; import java.util.Properties; +import retrofit2.Response; + /** * Demonstrates how to authenticate the user and load their profile via the command line. */ @@ -48,21 +54,30 @@ private GetUserProfile() {} public static void main(String[] args) throws Exception { // Create or load a credential for the user. - Credential credential = authenticate(System.getProperty("user.name")); - - // Create session for the user - Session session = new Session.Builder() - .setCredential(credential) - .setEnvironment(Session.Environment.SANDBOX) - .build(); + SessionConfiguration config = createSessionConfiguration(); + Credential credential = authenticate(System.getProperty("user.name"), config); + //Create an authenticator for Credential to use in our Session + CredentialsSession session = new CredentialsSession(config, credential); // Create the Uber API service object once the User is authenticated - UberRidesSyncService uberRidesService = UberRidesServices.createSync(session); + UberRidesApi uberRidesApi = UberRidesApi.with(session).build(); + RidesService service = uberRidesApi.createService(); // Fetch the user's profile. System.out.println("Calling API to get the user's profile"); - UserProfile userProfile = uberRidesService.getUserProfile().getBody(); + Response response = service.getUserProfile().execute(); + + ApiError apiError = ErrorParser.parseError(response); + if (apiError != null) { + // Handle error. + ClientError clientError = apiError.getClientErrors().get(0); + System.out.printf("Unable to fetch profile. %s", clientError.getTitle()); + System.exit(0); + return; + } + // Success! + UserProfile userProfile = response.body(); System.out.printf("Logged in as %s%n", userProfile.getEmail()); System.exit(0); } @@ -72,9 +87,8 @@ public static void main(String[] args) throws Exception { * should exist on your server so that the client ID and secret are not shared with the end * user. */ - private static Credential authenticate(String userId) throws Exception { - - OAuth2Credentials oAuth2Credentials = createOAuth2Credentials(); + private static Credential authenticate(String userId, SessionConfiguration config) throws Exception { + OAuth2Credentials oAuth2Credentials = createOAuth2Credentials(config); // First try to load an existing Credential. If that credential is null, authenticate the user. Credential credential = oAuth2Credentials.loadCredential(userId); @@ -106,7 +120,28 @@ private static Credential authenticate(String userId) throws Exception { /** * Creates an {@link OAuth2Credentials} object that can be used by any of the servlets. */ - public static OAuth2Credentials createOAuth2Credentials() throws Exception { + public static OAuth2Credentials createOAuth2Credentials(SessionConfiguration sessionConfiguration) throws Exception { + + + + + // Store the users OAuth2 credentials in their home directory. + File credentialDirectory = + new File(System.getProperty("user.home") + File.separator + ".uber_credentials"); + credentialDirectory.setReadable(true, true); + credentialDirectory.setWritable(true, true); + // If you'd like to store them in memory or in a DB, any DataStoreFactory can be used. + AbstractDataStoreFactory dataStoreFactory = new FileDataStoreFactory(credentialDirectory); + + // Build an OAuth2Credentials object with your secrets. + return new OAuth2Credentials.Builder() + .setCredentialDataStoreFactory(dataStoreFactory) + .setRedirectUri(sessionConfiguration.getRedirectUri()) + .setClientSecrets(sessionConfiguration.getClientId(), sessionConfiguration.getClientSecret()) + .build(); + } + + public static SessionConfiguration createSessionConfiguration() throws Exception { // Load the client ID and secret from {@code resources/secrets.properties}. Ideally, your // secrets would not be kept local. Instead, have your server accept the redirect and return // you the accessToken for a userId. @@ -120,24 +155,16 @@ public static OAuth2Credentials createOAuth2Credentials() throws Exception { "Please enter your client ID and secret in the resources/secrets.properties file."); } - // Store the users OAuth2 credentials in their home directory. - File credentialDirectory = - new File(System.getProperty("user.home") + File.separator + ".uber_credentials"); - credentialDirectory.setReadable(true, true); - credentialDirectory.setWritable(true, true); - // If you'd like to store them in memory or in a DB, any DataStoreFactory can be used. - AbstractDataStoreFactory dataStoreFactory = new FileDataStoreFactory(credentialDirectory); - // Start a local server to listen for the OAuth2 redirect. localServerReceiver = new LocalServerReceiver.Builder().setPort(8181).build(); String redirectUri = localServerReceiver.getRedirectUri(); - // Build an OAuth2Credentials object with your secrets. - return new OAuth2Credentials.Builder() - .setCredentialDataStoreFactory(dataStoreFactory) + return new SessionConfiguration.Builder() + .setClientId(clientId) + .setClientSecret(clientSecret) .setRedirectUri(redirectUri) - .setClientSecrets(clientId, clientSecret) .build(); + } /** diff --git a/samples/servlet-sample/build.gradle b/samples/servlet-sample/build.gradle index e3ae3be..23d8ea4 100644 --- a/samples/servlet-sample/build.gradle +++ b/samples/servlet-sample/build.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + apply plugin: 'application' targetCompatibility = JavaVersion.VERSION_1_7 diff --git a/samples/servlet-sample/gradle.properties b/samples/servlet-sample/gradle.properties index 7001559..b398116 100644 --- a/samples/servlet-sample/gradle.properties +++ b/samples/servlet-sample/gradle.properties @@ -1 +1,23 @@ +# +# Copyright (c) 2016 Uber Technologies, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + description=Servlet sample \ No newline at end of file diff --git a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/OAuth2CallbackServlet.java b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/OAuth2CallbackServlet.java index d7c13c2..30e8568 100644 --- a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/OAuth2CallbackServlet.java +++ b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/OAuth2CallbackServlet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,7 @@ import com.google.api.client.auth.oauth2.AuthorizationCodeResponseUrl; import com.uber.sdk.rides.auth.OAuth2Credentials; +import com.uber.sdk.rides.client.SessionConfiguration; import java.io.IOException; import java.util.Random; @@ -44,7 +45,8 @@ public class OAuth2CallbackServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (oAuth2Credentials == null) { - oAuth2Credentials = Server.createOAuth2Credentials(); + SessionConfiguration config = Server.createSessionConfiguration(); + oAuth2Credentials = Server.createOAuth2Credentials(config); } HttpSession httpSession = req.getSession(true); diff --git a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/SampleServlet.java b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/SampleServlet.java index 11df80e..d8e233f 100644 --- a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/SampleServlet.java +++ b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/SampleServlet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,10 +24,11 @@ import com.google.api.client.auth.oauth2.Credential; import com.uber.sdk.rides.auth.OAuth2Credentials; -import com.uber.sdk.rides.client.Session; -import com.uber.sdk.rides.client.UberRidesServices; -import com.uber.sdk.rides.client.UberRidesSyncService; +import com.uber.sdk.rides.client.CredentialsSession; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.UberRidesApi; import com.uber.sdk.rides.client.model.UserProfile; +import com.uber.sdk.rides.client.services.RidesService; import java.io.IOException; import java.util.Random; @@ -45,7 +46,7 @@ public class SampleServlet extends HttpServlet { private OAuth2Credentials oAuth2Credentials; private Credential credential; - private UberRidesSyncService uberRidesService; + private RidesService uberRidesService; /** * Clear the in memory credential and Uber API service once a call has ended. @@ -64,8 +65,9 @@ public void destroy() { */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { + SessionConfiguration config = Server.createSessionConfiguration(); if (oAuth2Credentials == null) { - oAuth2Credentials = Server.createOAuth2Credentials(); + oAuth2Credentials = Server.createOAuth2Credentials(config); } // Load the user from their user ID (derived from the request). @@ -76,15 +78,14 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws credential = oAuth2Credentials.loadCredential(httpSession.getAttribute(Server.USER_SESSION_ID).toString()); if (credential != null && credential.getAccessToken() != null) { + if (uberRidesService == null) { - // Create the session - Session session = new Session.Builder() - .setCredential(credential) - .setEnvironment(Session.Environment.PRODUCTION) - .build(); - - // Set up the Uber API Service once the user is authenticated. - uberRidesService = UberRidesServices.createSync(session); + + CredentialsSession session = new CredentialsSession(config, credential); + +// Set up the Uber API Service once the user is authenticated. + UberRidesApi api = UberRidesApi.with(session).build(); + uberRidesService = api.createService(); } super.service(req, resp); @@ -96,7 +97,7 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { // Fetch the user's profile. - UserProfile userProfile = uberRidesService.getUserProfile().getBody(); + UserProfile userProfile = uberRidesService.getUserProfile().execute().body(); response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); diff --git a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/Server.java b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/Server.java index ea6d216..3c8dfb1 100644 --- a/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/Server.java +++ b/samples/servlet-sample/src/main/java/com/uber/sdk/rides/samples/servlet/Server.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,9 @@ package com.uber.sdk.rides.samples.servlet; import com.google.api.client.util.store.MemoryDataStoreFactory; +import com.uber.sdk.core.auth.Scope; import com.uber.sdk.rides.auth.OAuth2Credentials; +import com.uber.sdk.rides.client.SessionConfiguration; import org.eclipse.jetty.servlet.ServletContextHandler; @@ -31,6 +33,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.Properties; /** @@ -70,7 +73,18 @@ public static void main(String[] args) throws Exception { * * Throws an {@throws IOException} when no client ID or secret found in secrets.properties */ - static OAuth2Credentials createOAuth2Credentials() throws IOException { + static OAuth2Credentials createOAuth2Credentials(SessionConfiguration config) throws IOException { + + + return new OAuth2Credentials.Builder() + .setCredentialDataStoreFactory(MemoryDataStoreFactory.getDefaultInstance()) + .setRedirectUri(config.getRedirectUri()) + .setScopes(config.getScopes()) + .setClientSecrets(config.getClientId(), config.getClientSecret()) + .build(); + } + + static SessionConfiguration createSessionConfiguration() throws IOException { // Load the client ID and secret from a secrets properties file. Properties secrets = loadSecretProperties(); @@ -81,11 +95,11 @@ static OAuth2Credentials createOAuth2Credentials() throws IOException { throw new IllegalArgumentException( "Please enter your client ID and secret in the resoures/secrets.properties file."); } - - return new OAuth2Credentials.Builder() - .setCredentialDataStoreFactory(MemoryDataStoreFactory.getDefaultInstance()) + return new SessionConfiguration.Builder() + .setClientId(clientId) + .setClientSecret(clientSecret) .setRedirectUri(REDIRECT_URI) - .setClientSecrets(clientId, clientSecret) + .setScopes(Collections.singletonList(Scope.PROFILE)) .build(); } diff --git a/sdk/build.gradle b/sdk/build.gradle index d90787d..05a1ae0 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' @@ -24,17 +46,36 @@ signing { sign configurations.archives } +def getReleaseRepositoryUrl() { + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL + : "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + return hasProperty('ossrhUsername') ? ossrhUsername : "" +} + +def getRepositoryPassword() { + return hasProperty('ossrhPassword') ? ossrhPassword : "" +} + + uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } - repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') { - authentication(userName: ossrhUsername, password: ossrhPassword) + repository(url: getReleaseRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } - snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') { - authentication(userName: ossrhUsername, password: ossrhPassword) + snapshotRepository(url: getSnapshotRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) } pom.project { @@ -77,15 +118,19 @@ uploadArchives { } dependencies { - compile 'com.google.guava:guava:18.0' compile 'com.google.http-client:google-http-client-jackson2:1.19.0' compile 'com.google.oauth-client:google-oauth-client:1.19.0' - compile 'com.squareup.retrofit:retrofit:1.9.0' - compile 'com.squareup.okhttp:okhttp:2.5.0' + + compile 'com.squareup.retrofit2:retrofit:2.0.2' + compile 'com.squareup.retrofit2:converter-moshi:2.0.2' + compile 'com.squareup.okhttp3:okhttp:3.2.0' + compile 'com.squareup.okhttp3:logging-interceptor:3.2.0' testCompile 'junit:junit:4.12' testCompile 'org.assertj:assertj-core:1.7.1' testCompile 'org.hamcrest:hamcrest-library:1.3' testCompile 'org.mockito:mockito-core:1.10.8' testCompile 'com.squareup.okhttp:mockwebserver:2.5.0' + + testCompile 'com.github.tomakehurst:wiremock:1.57' } diff --git a/sdk/config/checkstyle/checkstyle-main.xml b/sdk/config/checkstyle/checkstyle-main.xml index 6aa44c0..41aaa7d 100644 --- a/sdk/config/checkstyle/checkstyle-main.xml +++ b/sdk/config/checkstyle/checkstyle-main.xml @@ -1,4 +1,26 @@ + + diff --git a/sdk/config/checkstyle/checkstyle-test.xml b/sdk/config/checkstyle/checkstyle-test.xml index 3d4142c..e34a2f5 100644 --- a/sdk/config/checkstyle/checkstyle-test.xml +++ b/sdk/config/checkstyle/checkstyle-test.xml @@ -1,4 +1,26 @@ + + diff --git a/sdk/src/main/java/com/uber/sdk/core/auth/AccessToken.java b/sdk/src/main/java/com/uber/sdk/core/auth/AccessToken.java new file mode 100644 index 0000000..3c1ec51 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/core/auth/AccessToken.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth; + +import com.uber.sdk.core.auth.internal.OAuthScopes; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * An access token for making requests to the Uber API. + */ +public class AccessToken { + private final long expires_in; + @OAuthScopes + private final Set scope; + private final String access_token; + private final String refresh_token; + private final String token_type; + + /** + * @param expiresIn the time that the access token expires. + * @param scopes the {@link Scope}s this access token works for. + * @param token the Uber API access token. + * @param refreshToken the Uber API refresh token. + * @param tokenType the Uber API token type. + */ + public AccessToken( + long expiresIn, + Collection scopes, + String token, + String refreshToken, + String tokenType) { + expires_in = expiresIn; + this.scope = new HashSet<>(scopes); + access_token = token; + refresh_token = refreshToken; + token_type = tokenType; + } + + /** + * @param expiresIn the time that the access token expires. + * @param scope space delimited list of {@link Scope}s. + * @param token the Uber API access token. + * @param refreshToken the Uber API refresh token. + * @param tokenType the Uber API token type. + */ + public AccessToken( + long expiresIn, + String scope, + String token, + String refreshToken, + String tokenType) { + expires_in = expiresIn; + this.scope = Scope.parseScopes(scope); + access_token = token; + refresh_token = refreshToken; + token_type = tokenType; + } + + /** + * Gets the time the {@link AccessToken} expires at. + * + * @return the expiration time. + */ + public long getExpiresIn() { + return expires_in; + } + + /** + * Gets the {@link Scope}s the access token works for. + * + * @return the scopes. + */ + public Collection getScopes() { + return Collections.unmodifiableCollection(scope); + } + + /** + * Gets the raw token used to make API requests + * + * @return the raw token. + */ + public String getToken() { + return access_token; + } + + /** + * Gets the refresh token used to update the {@link AccessToken#access_token}. + * + * @return the raw refresh token. + */ + public String getRefreshToken() { + return refresh_token; + } + + /** + * Gets the type associated with {@link AccessToken#access_token}. + * + * @return the raw token type + */ + public String getTokenType() { + return token_type; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AccessToken that = (AccessToken) o; + + if (expires_in != that.expires_in) return false; + if (scope != null ? !scope.equals(that.scope) : that.scope != null) return false; + if (access_token != null ? !access_token.equals(that.access_token) : that.access_token != null) + return false; + if (refresh_token != null ? !refresh_token.equals(that.refresh_token) : that.refresh_token != null) + return false; + return token_type != null ? token_type.equals(that.token_type) : that.token_type == null; + + } + + @Override + public int hashCode() { + int result = (int) (expires_in ^ (expires_in >>> 32)); + result = 31 * result + (scope != null ? scope.hashCode() : 0); + result = 31 * result + (access_token != null ? access_token.hashCode() : 0); + result = 31 * result + (refresh_token != null ? refresh_token.hashCode() : 0); + result = 31 * result + (token_type != null ? token_type.hashCode() : 0); + return result; + } +} diff --git a/sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenAuthenticator.java b/sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenAuthenticator.java new file mode 100644 index 0000000..2d1def6 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenAuthenticator.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth; + +import com.squareup.moshi.Moshi; +import com.uber.sdk.core.auth.internal.OAuth2Service; +import com.uber.sdk.core.auth.internal.OAuthScopesAdapter; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.internal.ApiInterceptor; + +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.Response; +import retrofit2.Retrofit; +import retrofit2.converter.moshi.MoshiConverterFactory; + +public class AccessTokenAuthenticator implements Authenticator { + + private static final String HEADER_BEARER_ACCESS_VALUE = "Bearer %s"; + private static final String TOKEN_URL = "https://login.%s/oauth/v2/mobile/"; + + private final SessionConfiguration sessionConfiguration; + private final AccessTokenStorage tokenStorage; + private final OAuth2Service auth2Service; + + public AccessTokenAuthenticator(SessionConfiguration sessionConfiguration, + AccessTokenStorage tokenStorage) { + this(sessionConfiguration, + tokenStorage, + createOAuthService(String.format(TOKEN_URL, + sessionConfiguration.getEndpointRegion().domain))); + } + + AccessTokenAuthenticator(SessionConfiguration sessionConfiguration, + AccessTokenStorage tokenStorage, + OAuth2Service auth2Service) { + this.sessionConfiguration = sessionConfiguration; + this.tokenStorage = tokenStorage; + this.auth2Service = auth2Service; + } + + @Override + public void signRequest(Request.Builder builder) { + setBearerToken(builder, tokenStorage.getAccessToken()); + } + + @Override + public boolean isRefreshable() { + return tokenStorage.getAccessToken() != null && tokenStorage.getAccessToken().getRefreshToken() != null; + } + + @Override + public Request refresh(Response response) throws IOException { + return doRefresh(response); + } + + /** + * Get SessionConfiguration used for authentication + */ + @Override + public SessionConfiguration getSessionConfiguration() { + return sessionConfiguration; + } + + /** + * Get AccessTokenStorage used for authentication + */ + public AccessTokenStorage getTokenStorage() { + return tokenStorage; + } + + synchronized Request doRefresh(Response response) throws IOException { + if (signedByOldToken(response, tokenStorage.getAccessToken())) { + return resign(response, tokenStorage.getAccessToken()); + } else { + return refreshAndSign(response, tokenStorage.getAccessToken()); + } + } + + Request resign(Response response, AccessToken auth2Token) { + Request.Builder builder = response.request().newBuilder(); + setBearerToken(builder, auth2Token); + + return builder.build(); + } + + Request refreshAndSign(Response response, AccessToken auth2Token) throws IOException { + AccessToken token = refreshToken(auth2Token); + return resign(response, token); + } + + AccessToken refreshToken(AccessToken auth2Token) throws IOException { + AccessToken newToken = auth2Service.refresh(auth2Token.getRefreshToken(), + sessionConfiguration.getClientId()) + .execute().body(); + tokenStorage.setAccessToken(newToken); + return newToken; + } + + boolean signedByOldToken(Response response, AccessToken oAuth2Token) { + String value = ApiInterceptor.getAuthorizationHeader(response.request()); + + String accessToken = createBearerToken(oAuth2Token); + + return value != null && !value.equals(accessToken); + } + + void setBearerToken(Request.Builder builder, AccessToken OAuth2Token) { + ApiInterceptor.setAuthorizationHeader(builder, createBearerToken(OAuth2Token)); + } + + String createBearerToken(AccessToken oAuth2Token) { + return String.format(HEADER_BEARER_ACCESS_VALUE, oAuth2Token.getToken()); + } + + static OAuth2Service createOAuthService(String baseUrl) { + final Moshi moshi = new Moshi.Builder().add(new OAuthScopesAdapter()).build(); + + return new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + .create(OAuth2Service.class); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/NetworkException.java b/sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenStorage.java similarity index 68% rename from sdk/src/main/java/com/uber/sdk/rides/client/error/NetworkException.java rename to sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenStorage.java index 5294ef7..e289a7b 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/error/NetworkException.java +++ b/sdk/src/main/java/com/uber/sdk/core/auth/AccessTokenStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,29 +20,32 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client.error; - -import java.io.IOException; +package com.uber.sdk.core.auth; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * An error caused by some network issue, the server was not able to be connected to. + * Common interface for storing and getting AccessToken */ -public class NetworkException extends IOException { - - private final String url; +public interface AccessTokenStorage { + /** + * Returned currently stored token. + * + * @return + */ + @Nullable + AccessToken getAccessToken(); - public NetworkException(String message, Throwable exception, @Nullable String url) { - super(message, exception); - this.url = url; - } + /** + * Replace token with new one. + * + * @param token + */ + void setAccessToken(@Nonnull AccessToken token); /** - * The request URL which created this error. + * Remove current token. */ - @Nullable - public String getUrl() { - return url; - } + void removeAccessToken(); } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/Callback.java b/sdk/src/main/java/com/uber/sdk/core/auth/Authenticator.java similarity index 57% rename from sdk/src/main/java/com/uber/sdk/rides/client/Callback.java rename to sdk/src/main/java/com/uber/sdk/core/auth/Authenticator.java index 768b9eb..2df4ef0 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/Callback.java +++ b/sdk/src/main/java/com/uber/sdk/core/auth/Authenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,36 +20,41 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client; +package com.uber.sdk.core.auth; -import com.uber.sdk.rides.client.error.ApiException; -import com.uber.sdk.rides.client.error.NetworkException; +import com.uber.sdk.rides.client.SessionConfiguration; -/** - * Communicates responses from a server. Only one method will be called in response - * to a given request. - */ -public interface Callback { +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.Response; + +public interface Authenticator { /** - * Successful HTTP response. - * @param t The model returned by the request. - * @param response The HTTP response to the request. + * Indicates whether this authenticator can be refreshed. + * + * @return */ - void success(T t, Response response); + boolean isRefreshable(); /** - * Unsuccessful HTTP response due to network failure. + * Add authentication header required to the request. + * + * @param builder */ - void failure(NetworkException exception); + void signRequest(Request.Builder builder); /** - * Unsuccessful HTTP response due to a non-2XX status code. + * Refresh authentication token that is used to {@link #signRequest(Request.Builder)} + * + * @param response + * @throws IOException */ - void failure(ApiException exception); + Request refresh(Response response) throws IOException; /** - * An unexpected exception due that should be rethrown in your application. + * Get {@link SessionConfiguration} used for providing signining information for requests */ - void failure(Throwable exception); + SessionConfiguration getSessionConfiguration(); } diff --git a/sdk/src/main/java/com/uber/sdk/core/auth/Scope.java b/sdk/src/main/java/com/uber/sdk/core/auth/Scope.java new file mode 100644 index 0000000..cbba5ab --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/core/auth/Scope.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth; + + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.annotation.Nonnull; + +import static com.uber.sdk.core.auth.Scope.ScopeType.GENERAL; +import static com.uber.sdk.core.auth.Scope.ScopeType.PRIVILEGED; + +/** + * An Uber API scope. See + * Scopes for more + * information. + */ +public enum Scope { + + /** + * Pull trip data of a user's historical pickups and drop-offs. + */ + HISTORY(GENERAL, 1), + + /** + * Same as History without city information. + */ + HISTORY_LITE(GENERAL, 2), + + /** + * Retrieve user's available registered payment methods. + */ + PAYMENT_METHODS(GENERAL, 4), + + /** + * Save and retrieve user's favorite places. + */ + PLACES(GENERAL, 8), + + /** + * Access basic profile information on a user's Uber account. + */ + PROFILE(GENERAL, 16), + + /** + * Access the Ride Request Widget. + */ + RIDE_WIDGETS(GENERAL, 32), + + /** + * Request ride on the behalf of an Uber account. + */ + REQUEST(PRIVILEGED, 64), + + /** + * Request ride for a ride on the behalf of an Uber account. + */ + REQUEST_RECEIPT(PRIVILEGED, 128), + + /** + * Request list of all trips belong to a user. + */ + ALL_TRIPS(PRIVILEGED, 256); + + + private ScopeType mScopeType; + + /** + * Use powers of two to allow bit masking operation. + */ + private int mBitValue; + + Scope(ScopeType scopeType, int bitValue) { + this.mScopeType = scopeType; + this.mBitValue = bitValue; + } + + /** + * Gets the {@link ScopeType} associated with this {@link Scope}. + * + * @return the type of scope. + */ + public ScopeType getScopeType() { + return mScopeType; + } + + /** + * Gets the bit value that represents this. + * + * @return the int value that represents this’. + */ + public int getBitValue() { + return mBitValue; + } + + /** + * Category of {@link Scope} that describes its level of access. + */ + public enum ScopeType { + + /** + * {@link Scope}s that can be used without review. + */ + GENERAL, + + /** + * {@link Scope}s that require approval before opened to your users in production. + */ + PRIVILEGED + } + + public static Set parseScopes(String concatenatedScopes) { + Set scopes = new LinkedHashSet<>(); + for (String scopeString : concatenatedScopes.split(" ")) { + try { + Scope scope = Scope.valueOf(scopeString.toUpperCase()); + scopes.add(scope); + } catch (IllegalArgumentException ex) { + } + } + return scopes; + } + + public static Set parseScopes(int bitValues) { + Set scopes = new LinkedHashSet<>(); + if (bitValues <= 0) { + return scopes; + } + + for (Scope scope : Scope.values()) { + if ((bitValues & scope.mBitValue) == scope.mBitValue) { + scopes.add(scope); + } + } + + return scopes; + } + + public static String toStandardString(@Nonnull Collection scopes) { + StringBuilder stringBuilder = new StringBuilder(); + int i = 0; + for (Scope scope : scopes) { + stringBuilder.append(scope.toString().toLowerCase()); + if (i < scopes.size() - 1) { + stringBuilder.append(' '); + } + i++; + } + return stringBuilder.toString(); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuth2Service.java b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuth2Service.java new file mode 100644 index 0000000..766fd51 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuth2Service.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth.internal; + +import com.uber.sdk.core.auth.AccessToken; + +import retrofit2.Call; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.POST; + +public interface OAuth2Service { + @FormUrlEncoded + @POST("token") + Call refresh(@Field("refresh_token") String refreshToken, + @Field("client_id") String clientId); +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesService.java b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopes.java similarity index 78% rename from sdk/src/main/java/com/uber/sdk/rides/client/UberRidesService.java rename to sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopes.java index 623b3a2..41e5ef2 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesService.java +++ b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,10 +20,15 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client; +package com.uber.sdk.core.auth.internal; -/** - * A marker interface for an Uber API service. - */ -public interface UberRidesService { +import com.squareup.moshi.JsonQualifier; + +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Retention(RUNTIME) +@JsonQualifier +public @interface OAuthScopes { } diff --git a/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapter.java b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapter.java new file mode 100644 index 0000000..96eea18 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapter.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth.internal; + +import com.squareup.moshi.FromJson; +import com.squareup.moshi.ToJson; +import com.uber.sdk.core.auth.Scope; + +import java.util.Set; + +public class OAuthScopesAdapter { + @FromJson + @OAuthScopes + Set fromJson(String scopes) { + return Scope.parseScopes(scopes); + } + + @ToJson + String toJson(@OAuthScopes Set scopes) { + return Scope.toStandardString(scopes); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/auth/AuthException.java b/sdk/src/main/java/com/uber/sdk/rides/auth/AuthException.java index c805f21..850a54f 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/auth/AuthException.java +++ b/sdk/src/main/java/com/uber/sdk/rides/auth/AuthException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/auth/CredentialsAuthenticator.java b/sdk/src/main/java/com/uber/sdk/rides/auth/CredentialsAuthenticator.java new file mode 100644 index 0000000..5108160 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/auth/CredentialsAuthenticator.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.auth; + +import com.google.api.client.auth.oauth2.Credential; +import com.uber.sdk.core.auth.Authenticator; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.internal.ApiInterceptor; + +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.Response; + +public class CredentialsAuthenticator implements Authenticator { + static final String HEADER_BEARER_ACCESS_VALUE = "Bearer %s"; + + private final Credential credential; + private final SessionConfiguration sessionConfiguration; + + public CredentialsAuthenticator(SessionConfiguration sessionConfiguration, Credential credential) { + this.credential = credential; + this.sessionConfiguration = sessionConfiguration; + } + + @Override + public void signRequest(Request.Builder builder) { + setBearerToken(builder, credential); + } + + @Override + public boolean isRefreshable() { + return true; + } + + @Override + public Request refresh(Response response) throws IOException { + return reauth(response); + } + + @Override + public SessionConfiguration getSessionConfiguration() { + return sessionConfiguration; + } + + /** + * Get {@link Credential} used for authentication + */ + public Credential getCredential() { + return credential; + } + + private synchronized Request reauth(Response response) throws IOException { + if (signedByOldToken(response, credential)) { + return resign(response, credential); + } else { + return refreshAndSign(response, credential); + } + } + + private static void setBearerToken(Request.Builder builder, Credential credential) { + ApiInterceptor.setAuthorizationHeader(builder, createBearerToken(credential)); + } + + private static String createBearerToken(Credential credential) { + return String.format(HEADER_BEARER_ACCESS_VALUE, credential.getAccessToken()); + } + + private Request resign(Response response, Credential credential) { + Request.Builder builder = response.request().newBuilder(); + setBearerToken(builder, credential); + + return builder.build(); + } + + private Request refreshAndSign(Response response, Credential credential) throws IOException { + credential.refreshToken(); + return resign(response, credential); + } + + private boolean signedByOldToken(Response response, Credential credential) { + String value = ApiInterceptor.getAuthorizationHeader(response.request()); + + String accessToken = createBearerToken(credential); + + return value != null && !value.equals(accessToken); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Credentials.java b/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Credentials.java index 788b895..9b6dbe8 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Credentials.java +++ b/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Credentials.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -35,13 +35,13 @@ import com.google.api.client.util.store.AbstractDataStoreFactory; import com.google.api.client.util.store.DataStore; import com.google.api.client.util.store.MemoryDataStoreFactory; -import com.google.common.base.Function; -import com.google.common.base.Preconditions; -import com.google.common.base.Strings; -import com.google.common.collect.Lists; -import com.google.common.net.UrlEscapers; +import com.uber.sdk.core.auth.Scope; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.utils.Preconditions; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -49,7 +49,7 @@ import javax.annotation.Nullable; -import static com.uber.sdk.rides.auth.OAuth2Credentials.LoginRegion.WORLD; +import static com.uber.sdk.rides.client.SessionConfiguration.EndpointRegion.WORLD; /** * Utility for creating and managing OAuth 2.0 Credentials. @@ -59,33 +59,6 @@ public class OAuth2Credentials { public static final String AUTHORIZATION_PATH = "/oauth/v2/authorize"; public static final String TOKEN_PATH = "/oauth/v2/token"; - /** - * An Uber API scope. See - * Scopes for more - * information. - */ - public enum Scope { - PROFILE, - REQUEST, - HISTORY, - PLACES, - REQUEST_RECEIPT, - ALL_TRIPS; - } - - /** - * LoginRegion to be used for authorization. - */ - public enum LoginRegion { - WORLD("https://login.uber.com"), - CHINA("https://login.uber.com.cn"); - - public String domain; - - LoginRegion(String domain) { - this.domain = domain; - } - } private AuthorizationCodeFlow authorizationCodeFlow; private Collection scopes; @@ -96,7 +69,7 @@ public enum LoginRegion { */ public static class Builder { - private LoginRegion loginRegion; + private SessionConfiguration.EndpointRegion loginRegion; private Set scopes; private Set customScopes; private String clientId; @@ -106,10 +79,29 @@ public static class Builder { private AuthorizationCodeFlow authorizationCodeFlow; private AbstractDataStoreFactory credentialDataStoreFactory; + /** + * Set the {@link SessionConfiguration} information + */ + public Builder setSessionConfiguration(SessionConfiguration configuration) { + this.loginRegion = configuration.getEndpointRegion(); + if (scopes != null) { + this.scopes = new HashSet<>(configuration.getScopes()); + } + + if (customScopes != null) { + this.customScopes = new HashSet<>(configuration.getCustomScopes()); + } + + this.clientId = configuration.getClientId(); + this.clientSecret = configuration.getClientSecret(); + this.redirectUri = configuration.getRedirectUri(); + return this; + } + /** * Sets the authorization server domain. */ - public Builder setLoginRegion(LoginRegion loginRegion) { + public Builder setLoginRegion(SessionConfiguration.EndpointRegion loginRegion) { this.loginRegion = loginRegion; return this; } @@ -175,8 +167,10 @@ public Builder setAuthorizationCodeFlow(AuthorizationCodeFlow authorizationCodeF } private void validate() { - Preconditions.checkState( - !Strings.isNullOrEmpty(clientId) && !Strings.isNullOrEmpty(clientSecret), + Preconditions.checkState(clientId != null + && !clientId.isEmpty() + && clientSecret != null + && !clientSecret.isEmpty(), "Client ID and secret must be set."); } @@ -189,14 +183,11 @@ public OAuth2Credentials build() { oAuth2Credentials.redirectUri = redirectUri; Set allScopes = new TreeSet<>(); - if (scopes != null && !scopes.isEmpty()) { - allScopes.addAll(Lists.transform(Lists.newArrayList(scopes), new Function() { - @Nullable - @Override - public String apply(@Nullable Scope input) { - return input != null ? input.name().toLowerCase() : null; - } - })); + + if (scopes != null) { + for (Scope scope : scopes) { + allScopes.add(scope.name().toLowerCase()); + } } if (customScopes != null) { @@ -225,10 +216,10 @@ public String apply(@Nullable Scope input) { BearerToken.authorizationHeaderAccessMethod(), httpTransport, new JacksonFactory(), - new GenericUrl(loginRegion.domain + TOKEN_PATH), + new GenericUrl(getLoginDomain(loginRegion) + TOKEN_PATH), new ClientParametersAuthentication(clientId, clientSecret), clientId, - loginRegion.domain + AUTHORIZATION_PATH); + getLoginDomain(loginRegion) + AUTHORIZATION_PATH); if (oAuth2Credentials.scopes != null && !oAuth2Credentials.scopes.isEmpty()) { builder.setScopes(oAuth2Credentials.scopes); } @@ -241,6 +232,10 @@ public String apply(@Nullable Scope input) { oAuth2Credentials.authorizationCodeFlow = authorizationCodeFlow; return oAuth2Credentials; } + + private String getLoginDomain(SessionConfiguration.EndpointRegion endpointRegion) { + return "https://login." + endpointRegion.domain; + } } private OAuth2Credentials() {} @@ -249,11 +244,11 @@ private OAuth2Credentials() {} * Gets the authorization URL to retrieve the authorization code. */ @Nullable - public String getAuthorizationUrl() { + public String getAuthorizationUrl() throws UnsupportedEncodingException { String authorizationCodeRequestUrl = authorizationCodeFlow.newAuthorizationUrl().setScopes(scopes).build(); if (redirectUri != null) { - authorizationCodeRequestUrl += "&redirect_uri=" + UrlEscapers.urlFormParameterEscaper().escape(redirectUri); + authorizationCodeRequestUrl += "&redirect_uri=" + URLEncoder.encode(redirectUri, "UTF-8"); } return authorizationCodeRequestUrl; } diff --git a/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Helper.java b/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Helper.java deleted file mode 100644 index 8473200..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/auth/OAuth2Helper.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.auth; - -import com.google.api.client.auth.oauth2.Credential; - -import java.io.IOException; - -/** - * Helper class for {@link Credential} objects. - */ -public class OAuth2Helper { - - public static final long DEFAULT_REFRESH_WINDOW = 300L; - - private final long refreshWindowSeconds; - - /** - * Constructor. - * @param refreshWindowSeconds The window in which the credential will be refreshed. - */ - public OAuth2Helper(long refreshWindowSeconds) { - this.refreshWindowSeconds = refreshWindowSeconds; - } - - /** - * Constructor. - */ - public OAuth2Helper() { - this(DEFAULT_REFRESH_WINDOW); - } - - /** - * Attempts to refresh the Credential. Returns true if and only if the token was refreshed. - * Otherwise, false. - */ - public boolean refreshCredentialIfNeeded(Credential credential) throws AuthException { - if (shouldRefreshCredential(credential)) { - try { - return credential.refreshToken(); - } catch (IOException e) { - throw new AuthException("Unable to refresh credential.", e); - } - } - return false; - } - - /** - * Returns true if and only if the credential can and should be refreshed. - */ - public boolean shouldRefreshCredential(Credential credential) { - return credential.getRefreshToken() != null - && (credential.getExpiresInSeconds() != null - && credential.getExpiresInSeconds() <= refreshWindowSeconds); - } -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/auth/ServerTokenAuthenticator.java b/sdk/src/main/java/com/uber/sdk/rides/auth/ServerTokenAuthenticator.java new file mode 100644 index 0000000..13676e6 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/auth/ServerTokenAuthenticator.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.auth; + +import com.uber.sdk.core.auth.Authenticator; +import com.uber.sdk.rides.client.SessionConfiguration; +import com.uber.sdk.rides.client.internal.ApiInterceptor; + +import okhttp3.Request; +import okhttp3.Response; + +public class ServerTokenAuthenticator implements Authenticator { + static final String HEADER_TOKEN_ACCESS_VALUE = "Token %s"; + + private final SessionConfiguration sessionConfiguration; + + public ServerTokenAuthenticator(SessionConfiguration sessionConfiguration) { + this.sessionConfiguration = sessionConfiguration; + } + + @Override + public void signRequest(Request.Builder builder) { + ApiInterceptor.setAuthorizationHeader(builder, + String.format(HEADER_TOKEN_ACCESS_VALUE, sessionConfiguration.getServerToken())); + } + + @Override + public Request refresh(Response response) { + return null; + //Do nothing, server token is not refreshable + } + + @Override + public boolean isRefreshable() { + return false; + } + + /** + * Get {@link SessionConfiguration} used for authentication + */ + @Override + public SessionConfiguration getSessionConfiguration() { + return sessionConfiguration; + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/AccessTokenSession.java b/sdk/src/main/java/com/uber/sdk/rides/client/AccessTokenSession.java new file mode 100644 index 0000000..07d9e5c --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/AccessTokenSession.java @@ -0,0 +1,21 @@ +package com.uber.sdk.rides.client; + +import com.uber.sdk.core.auth.AccessTokenAuthenticator; +import com.uber.sdk.core.auth.AccessTokenStorage; + +import javax.annotation.Nonnull; + +/** + * A session containing the details of how an {@link UberRidesApi} will interact with the API. + * Does authentication through either a server token or OAuth 2.0 credential, exactly one of which must exist. + * Uses {@link AccessTokenStorage} for connection + */ +public class AccessTokenSession extends Session { + /** + * @param config config to define connection parameters + * @param accessTokenStorage to access and refresh tokens + */ + public AccessTokenSession(@Nonnull SessionConfiguration config, @Nonnull AccessTokenStorage accessTokenStorage) { + super(new AccessTokenAuthenticator(config, accessTokenStorage)); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/CredentialsSession.java b/sdk/src/main/java/com/uber/sdk/rides/client/CredentialsSession.java new file mode 100644 index 0000000..a2792ab --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/CredentialsSession.java @@ -0,0 +1,21 @@ +package com.uber.sdk.rides.client; + +import com.google.api.client.auth.oauth2.Credential; +import com.uber.sdk.rides.auth.CredentialsAuthenticator; + +import javax.annotation.Nonnull; + +/** + * A session containing the details of how an {@link UberRidesApi} will interact with the API. + * Does authentication through either a server token or OAuth 2.0 credential, exactly one of which must exist. + * Uses {@link Credential} for connection + */ +public class CredentialsSession extends Session { + /** + * @param config config to define connection parameters + * @param credential to access and refresh token + */ + public CredentialsSession(@Nonnull SessionConfiguration config, @Nonnull Credential credential) { + super(new CredentialsAuthenticator(config, credential)); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/Response.java b/sdk/src/main/java/com/uber/sdk/rides/client/Response.java deleted file mode 100644 index cf7f50e..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/Response.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client; - -import com.google.common.collect.ImmutableList; - -import java.util.List; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * An HTTP Response. - */ -public final class Response { - - private final String url; - private final int status; - private final String reason; - private final ImmutableList
headers; - private final T responseObject; - - public Response(@Nonnull String url, - int status, - @Nonnull String reason, - @Nonnull List
headers, - @Nullable T responseObject) { - this.url = url; - this.status = status; - this.reason = reason; - this.headers = ImmutableList.copyOf(headers); - this.responseObject = responseObject; - } - - /** - * Gets the Request URL that lead to this response. - */ - @Nonnull - public String getUrl() { - return url; - } - - /** - * Gets the status code. - */ - public int getStatus() { - return status; - } - - /** - * Gets the status code reason phrase. - */ - @Nonnull - public String getReason() { - return reason; - } - - /** - * Immutable collection of headers. - */ - @Nonnull - public List
getHeaders() { - return headers; - } - - /** - * The response object. May be null if the response has no body or there was an error. - */ - @Nullable - public T getBody() { - return responseObject; - } -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/ServerTokenSession.java b/sdk/src/main/java/com/uber/sdk/rides/client/ServerTokenSession.java new file mode 100644 index 0000000..ace9d9e --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/ServerTokenSession.java @@ -0,0 +1,19 @@ +package com.uber.sdk.rides.client; + +import com.uber.sdk.rides.auth.ServerTokenAuthenticator; + +import javax.annotation.Nonnull; + +/** + * A session containing the details of how an {@link UberRidesApi} will interact with the API. + * Does authentication through either a server token or OAuth 2.0 credential, exactly one of which must exist. + * Uses server token for connection + */ +public class ServerTokenSession extends Session { + /** + * @param config to define connection parameters + */ + public ServerTokenSession(@Nonnull SessionConfiguration config) { + super(new ServerTokenAuthenticator(config)); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/Session.java b/sdk/src/main/java/com/uber/sdk/rides/client/Session.java index e3f59a2..844fe40 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/Session.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/Session.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,190 +22,30 @@ package com.uber.sdk.rides.client; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.repackaged.com.google.common.base.Preconditions; -import com.uber.sdk.rides.auth.OAuth2Credentials; - -import java.util.Locale; +import com.uber.sdk.core.auth.Authenticator; import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static com.uber.sdk.rides.client.Session.EndpointRegion.WORLD; /** - * A session containing the details of how an {@link UberRidesService} will interact with the API. + * A session containing the details of how an {@link UberRidesApi} will interact with the API. * Does authentication through either a server token or OAuth 2.0 credential, exactly one of which must exist. */ -public class Session { - - private final Credential credential; - private final EndpointRegion endpointRegion; - private final Environment environment; - private final Locale locale; - private final String serverToken; - - /** - * An Uber API Environment. See - * Sandbox for more - * information. - */ - public enum Environment { - PRODUCTION("api"), - SANDBOX("sandbox-api"); - - public String subDomain; - - Environment(String subDomain) { - this.subDomain = subDomain; - } - } - - public enum EndpointRegion { - WORLD("uber.com"), - CHINA("uber.com.cn"); - - public String domain; - - EndpointRegion(String domain) { - this.domain = domain; - } - } - - private Session(@Nullable Credential credential, - @Nonnull EndpointRegion endpointRegion, - @Nonnull Environment environment, - @Nullable Locale locale, - @Nullable String serverToken) { - this.credential = credential; - this.endpointRegion = endpointRegion; - this.environment = environment; - this.locale = locale; - this.serverToken = serverToken; - } - - /** - * Builder for {@link Session} objects. - */ - public static class Builder { - - private EndpointRegion endpointRegion; - private Credential credential; - private Environment environment; - private Locale locale; - private String serverToken; - - /** - * Sets the region to be used for requests. - */ - public Builder setEndpointRegion(EndpointRegion endpointRegion) { - this.endpointRegion = endpointRegion; - return this; - } - - /** - * Sets the requested Locale through the Accept-Language HTTP header. See - * Localization - * for possible locales. - */ - public Builder setAcceptLanguage(Locale locale) { - this.locale = locale; - return this; - } - - /** - * Sets the OAuth 2.0 Credential. See {@link OAuth2Credentials} for - * assistance with creating them. Exactly one of OAuth 2.0 credential or the server token must be present. - */ - public Builder setCredential(Credential credential) { - this.credential = credential; - return this; - } +public abstract class Session { - /** - * Sets the environment for all API requests. Optional and defaults to - * {@link Environment#PRODUCTION}. - */ - public Builder setEnvironment(Environment environment) { - this.environment = environment; - return this; - } - - /** - * Sets the Server Token to be used with requests. Exactly one of the server token or the OAuth 2.0 credential - * must be present. - */ - public Builder setServerToken(String serverToken) { - this.serverToken = serverToken; - return this; - } - - private void validate() { - Preconditions.checkState(credential != null || serverToken != null, - "An OAuth 2.0 credential or a server token is required to create a session."); - Preconditions.checkState((credential == null && serverToken != null) || - (credential != null && serverToken == null), "Session must have either an OAuth 2.0 credential or a server token, not both."); - Preconditions.checkState(environment != null, "Must supply an Environment"); - } - - /** - * Builds a {@code Session} object; - */ - public Session build() { - validate(); - - if (endpointRegion == null) { - endpointRegion = WORLD; - } - - return new Session(credential, endpointRegion, environment, locale, serverToken); - } - } - - /** - * Gets the endpoint host used to hit the Uber API. - */ - public String getEndpointHost() { - return String.format("https://%s.%s", environment.subDomain, endpointRegion.domain); - } - - /** - * Gets the {@link EndpointRegion} to be used for requests. - */ - @Nonnull - public EndpointRegion getEndpointRegion() { - return endpointRegion; - } - - /** - * Gets the credential requests are backed by if there is no server token. - */ - @Nullable - public Credential getCredential() { - return credential; - } - - /** - * Gets the environment all requests are made against. - */ - @Nonnull - public Environment getEnvironment() { - return environment; - } + private final T authenticator; /** - * Get the requested language Locale for requests. + * @param authenticator used to sign outgoing requests */ - @Nullable - public Locale getLocale() { - return locale; + public Session(@Nonnull T authenticator) { + this.authenticator = authenticator; } /** - * Gets the server token requests are backed by if there is no OAuth 2.0 Credential. + * Gets the {@link Authenticator} provided after authentication is completed. + * This is used to sign outgoing requests. */ - @Nullable - public String getServerToken() { - return serverToken; + public T getAuthenticator() { + return authenticator; } } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/SessionConfiguration.java b/sdk/src/main/java/com/uber/sdk/rides/client/SessionConfiguration.java new file mode 100644 index 0000000..1682783 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/SessionConfiguration.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client; + +import com.uber.sdk.core.auth.Scope; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.Locale; + +import javax.annotation.Nonnull; + +import static com.uber.sdk.rides.client.SessionConfiguration.EndpointRegion.WORLD; +import static com.uber.sdk.rides.client.utils.Preconditions.checkNotNull; + +/** + * LoginConfiguration is used to setup primitives needed for the Uber SDK to authenticate. + */ +public class SessionConfiguration implements Serializable { + /** + * An Uber API Environment. See + * Sandbox for more + * information. + */ + public enum Environment { + PRODUCTION("api"), + SANDBOX("sandbox-api"); + + public String subDomain; + + Environment(String subDomain) { + this.subDomain = subDomain; + } + } + + public enum EndpointRegion { + WORLD("uber.com"), + CHINA("uber.com.cn"); + + public String domain; + + EndpointRegion(String domain) { + this.domain = domain; + } + } + + /** + * Builder for {@link SessionConfiguration} + */ + public static class Builder { + private String clientId; + private String clientSecret; + private String serverToken; + private String redirectUri; + private EndpointRegion region = EndpointRegion.WORLD; + private Environment environment; + private Collection scopes; + private Collection customScopes; + private Locale locale; + + /** + * The Uber API requires a registered clientId to be sent along with API requests and Deeplinks. + * This can be registered and retrieved on the developer dashboard at https://developer.uber.com/ + * + * @param clientId to be used for identification + * @return + */ + public Builder setClientId(@Nonnull String clientId) { + this.clientId = clientId; + return this; + } + + /** + * The Uber API requires a registered clientSecret to be used for Authentication. + * This can be registered and retrieved on the developer dashboard at https://developer.uber.com/ + * + * Do not set client secret for Android or client side applications. + * + * @param clientSecret to be used for identification + * @return + */ + public Builder setClientSecret(@Nonnull String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + /** + * The Uber API can use a server token for some endpoints. + * + * @param serverToken to be used for identification + * @return + */ + public Builder setServerToken(@Nonnull String serverToken) { + this.serverToken = serverToken; + return this; + } + + /** + * Sets the redirect URI that is registered for this application. + * + * @param redirectUri the redirect URI {@link String} for this application. + */ + public Builder setRedirectUri(@Nonnull String redirectUri) { + this.redirectUri = redirectUri; + return this; + } + + /** + * Set the {@link EndpointRegion} your app is registered in. + * Used to determine what endpoints to send requests to. + * + * @param region The {@link EndpointRegion} the SDK should use + */ + public Builder setEndpointRegion(@Nonnull EndpointRegion region) { + this.region = region; + return this; + } + + /** + * Sets the {@link Environment} to be used for API requests + * + * @param environment to be set + * @return + */ + public Builder setEnvironment(@Nonnull Environment environment) { + this.environment = environment; + return this; + } + + /** + * Sets the Scope Collection to be used when requesting authentication + * + * @param scopes to be set + * @return + */ + public Builder setScopes(@Nonnull Collection scopes) { + this.scopes = scopes; + return this; + } + + /** + * Sets a list of custom scopes that your application must be explicitly whitelisted + * for. For any documented scopes, please use {@link #setScopes(Collection)} instead. + */ + public Builder setCustomScopes(@Nonnull Collection scopes) { + this.customScopes = scopes; + return this; + } + + /** + * Sets the requested Locale through the Accept-Language HTTP header. See + * Localization + * for possible locales. + */ + public Builder setLocale(@Nonnull Locale locale) { + this.locale = locale; + return this; + } + + /** + * Constructs {@link SessionConfiguration} from set Builder parameters. + * + * @return {@link SessionConfiguration} + * @throws NullPointerException when clientId has not been set + */ + public SessionConfiguration build() { + checkNotNull(clientId, "Client must be set"); + + if (region == null) { + region = WORLD; + } + + if (environment == null) { + environment = Environment.PRODUCTION; + } + + if (locale == null) { + locale = Locale.US; + } + + if (scopes == null) { + scopes = new HashSet<>(); + } else { + scopes = new HashSet<>(scopes); + } + + if (customScopes == null) { + customScopes = new HashSet<>(); + } else { + customScopes = new HashSet<>(customScopes); + } + + return new SessionConfiguration( + clientId, + clientSecret, + serverToken, + redirectUri, + region, + environment, + scopes, + customScopes, + locale); + } + } + + private final String clientId; + private final String clientSecret; + private final String serverToken; + private final String redirectUri; + private final EndpointRegion region; + private final Environment environment; + private final Collection scopes; + private final Collection customScopes; + private final Locale locale; + + protected SessionConfiguration(@Nonnull String clientId, + @Nonnull String clientSecret, + @Nonnull String serverToken, + @Nonnull String redirectUri, + @Nonnull EndpointRegion region, + @Nonnull Environment environment, + @Nonnull Collection scopes, + @Nonnull Collection customScopes, + @Nonnull Locale locale) { + this.clientId = clientId; + this.clientSecret = clientSecret; + this.serverToken = serverToken; + this.redirectUri = redirectUri; + this.region = region; + this.environment = environment; + this.scopes = scopes; + this.customScopes = customScopes; + this.locale = locale; + } + + /** + * Gets the Client ID to be used by the SDK for requests. + * + * @return The Client ID. + */ + public String getClientId() { + return clientId; + } + + /** + * Gets the Client Secret to be used by the SDK for requests. + * + * @return The Client Secret. + */ + public String getClientSecret() { + return clientSecret; + } + + /** + * Gets the server Token to be used by the SDK for requests + * + * @return The Server Token. + */ + public String getServerToken() { + return serverToken; + } + + /** + * Gets the Redirect URI to be used for implicit grant. + * + * @return The Redirect URI. + */ + public String getRedirectUri() { + return redirectUri; + } + + /** + * Gets the current {@link EndpointRegion} the SDK is using. + * Defaults to {@link EndpointRegion#WORLD}. + * + * @return The {@link EndpointRegion} the SDK is using. + */ + public EndpointRegion getEndpointRegion() { + return region; + } + + /** + * Gets the environment configured, either {@link Environment#PRODUCTION} or {@link Environment#SANDBOX} + * + * @return {@link Environment} that is configured + */ + public Environment getEnvironment() { + return environment; + } + + /** + * Gets the endpoint host used to hit the Uber API. + */ + @Nonnull + public String getEndpointHost() { + return String.format("https://%s.%s", environment.subDomain, region.domain); + } + + /** + * Gets the {@link Scope}'s set for authentication + * + * @return The Scope Collection + */ + public Collection getScopes() { + return scopes; + } + + /** + * Gets a list of custom scopes that your application must be explicitly whitelisted + * for. For any documented scopes, please use {@link #getScopes()} instead. + * + * @return The Scope Collection + */ + public Collection getCustomScopes() { + return customScopes; + } + + /** + * Get the requested language Locale for requests + */ + public Locale getLocale() { + return locale; + } + + public Builder newBuilder() { + return new Builder() + .setClientId(clientId) + .setRedirectUri(redirectUri) + .setEndpointRegion(region) + .setEnvironment(environment) + .setScopes(scopes); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesApi.java b/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesApi.java new file mode 100644 index 0000000..a45a646 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesApi.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client; + +import com.squareup.moshi.Moshi; +import com.uber.sdk.rides.client.internal.ApiInterceptor; +import com.uber.sdk.rides.client.internal.PrimitiveAdapter; +import com.uber.sdk.rides.client.internal.RefreshAuthenticator; +import com.uber.sdk.rides.client.services.RidesService; + +import javax.annotation.Nonnull; + +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.converter.moshi.MoshiConverterFactory; + +public class UberRidesApi { + + private final Retrofit retrofit; + + /** + * Builder for {@link UberRidesApi} + */ + public static class Builder { + Session session; + HttpLoggingInterceptor.Level logLevel; + HttpLoggingInterceptor.Logger logger; + OkHttpClient client; + + + Builder(@Nonnull Session session) { + this.session = session; + } + + /** + * Sets the Log level for requests. + * Optional and defaults to {@link HttpLoggingInterceptor.Level#NONE}. + */ + @Nonnull + public Builder setLogLevel(@Nonnull HttpLoggingInterceptor.Level logLevel) { + this.logLevel = logLevel; + return this; + } + + /** + * Sets the {@link okhttp3.logging.HttpLoggingInterceptor.Logger} to use. + * Optional and defaults to {@link okhttp3.logging.HttpLoggingInterceptor.Logger#DEFAULT} + */ + @Nonnull + public Builder setLogger(@Nonnull HttpLoggingInterceptor.Logger logger) { + this.logger = logger; + return this; + } + + /** + * Sets an existing {@link OkHttpClient } to use for Uber Rides API requests + * + * @param client {@link OkHttpClient} + * @return {@link Builder} for {@link UberRidesApi} + */ + @Nonnull + public Builder setOkHttpClient(@Nonnull OkHttpClient client) { + this.client = client; + return this; + } + + /** + * Create the {@link UberRidesApi} to be used. + * @return {@link UberRidesApi} + */ + public UberRidesApi build() { + if (logLevel == null) { + logLevel = HttpLoggingInterceptor.Level.NONE; + } + + if (logger == null) { + logger = HttpLoggingInterceptor.Logger.DEFAULT; + } + + if (client == null) { + client = new OkHttpClient(); + } + + HttpLoggingInterceptor loggingInterceptor = createLoggingInterceptor(logger, logLevel); + OkHttpClient newClient = createClient(client, session, loggingInterceptor); + Retrofit retrofit = createRetrofit(newClient, session); + + return new UberRidesApi(retrofit); + } + + HttpLoggingInterceptor createLoggingInterceptor(HttpLoggingInterceptor.Logger logger, + HttpLoggingInterceptor.Level level) { + final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(logger); + loggingInterceptor.setLevel(level); + return loggingInterceptor; + } + + OkHttpClient createClient(OkHttpClient client, + Session session, + HttpLoggingInterceptor loggingInterceptor) { + + return client.newBuilder() + .authenticator(new RefreshAuthenticator(session.getAuthenticator())) + .addInterceptor(new ApiInterceptor(session.getAuthenticator())) + .addInterceptor(loggingInterceptor) + .build(); + } + + Retrofit createRetrofit(OkHttpClient client, Session session) { + Moshi moshi = new Moshi.Builder().add(new PrimitiveAdapter()).build(); + + return new Retrofit.Builder() + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .baseUrl(session.getAuthenticator().getSessionConfiguration().getEndpointHost()) + .client(client) + .build(); + } + } + + /** + * Starts a {@link Builder} with a {@link Session} to create Uber Services. + * + * @param session required {@link Session} + */ + @Nonnull + public static Builder with(@Nonnull Session session) { + return new Builder(session); + } + + private UberRidesApi(@Nonnull Retrofit retrofit) { + this.retrofit = retrofit; + } + + /** + * Get the {@link RidesService} to use with the Uber API. + * Consumers should cache and reuse this object. + * + * @return {@link RidesService} + */ + public RidesService createService() { + return retrofit.create(RidesService.class); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesAsyncService.java b/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesAsyncService.java deleted file mode 100644 index e95e957..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesAsyncService.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client; - -import com.uber.sdk.rides.client.model.PaymentMethod; -import com.uber.sdk.rides.client.model.PaymentMethodsResponse; -import com.uber.sdk.rides.client.model.Place; -import com.uber.sdk.rides.client.model.Place.Places; -import com.uber.sdk.rides.client.model.PriceEstimatesResponse; -import com.uber.sdk.rides.client.model.Product; -import com.uber.sdk.rides.client.model.ProductsResponse; -import com.uber.sdk.rides.client.model.Promotion; -import com.uber.sdk.rides.client.model.Ride; -import com.uber.sdk.rides.client.model.RideEstimate; -import com.uber.sdk.rides.client.model.RideMap; -import com.uber.sdk.rides.client.model.RideReceipt; -import com.uber.sdk.rides.client.model.RideRequestParameters; -import com.uber.sdk.rides.client.model.RideUpdateParameters; -import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; -import com.uber.sdk.rides.client.model.SandboxRideRequestParameters; -import com.uber.sdk.rides.client.model.TimeEstimatesResponse; -import com.uber.sdk.rides.client.model.UserActivityPage; -import com.uber.sdk.rides.client.model.UserProfile; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static com.uber.sdk.rides.client.Session.Environment; - -/** - * Represents the asynchronous RPC methods of the Uber API. Can be built using - * - *

- *
- * UberRidesSyncService uberApiService = UberRidesServices.createSync(session);
- *
- * // Or
- *
- * uberApiService = UberRidesServices.sync().setSession(session).build();
- * 
- * @see UberRidesServices.Builder#async() - */ -public interface UberRidesAsyncService extends UberRidesService { - - /** - * Gets information about the promotion that will be available to a new user based on their - * activity's location. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param endLatitude Latitude component of end location. - * @param endLongitude Longitude component of end location. - * @param callback The request callback. - */ - void getPromotions(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude, - Callback callback); - - /** - * Gets a limited amount of data about a user's lifetime activity. - * - * @param offset Offset the list of returned results by this amount. Default is zero. - * @param limit Number of items to retrieve. Default is 5, maximum is 50. - * @param callback The request callback. - */ - void getUserActivity(@Nullable Integer offset, - @Nullable Integer limit, - Callback callback); - - /** - * Gets information about the user that has authorized with the application. - * - * @param callback The request callback. - */ - void getUserProfile(Callback callback); - - /** - * Gets an estimated price range for each product offered at a given location. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param endLatitude Latitude component of end location. - * @param endLongitude Longitude component of end location. - * @param callback The request callback. - */ - void getPriceEstimates(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude, - Callback callback); - - /** - * Gets ETAs for all products offered at a given location, with the responses expressed as - * integers in seconds. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param productId Unique identifier representing a specific product for a given latitude & - * longitude. - * @param callback The request callback. - */ - void getPickupTimeEstimates(float startLatitude, - float startLongitude, - @Nullable String productId, - Callback callback); - - /** - * Gets information about the products offered at a given location. - * - * @param latitude Latitude component of location. - * @param longitude Longitude component of location. - * @param callback The request callback. - */ - void getProducts(float latitude, float longitude, Callback callback); - - /** - * Gets information about a specific product. - * - * @param productId The unique product ID to fetch information about. - * @param callback The request callback. - */ - void getProduct(@Nonnull String productId, Callback callback); - - /** - * Cancel an ongoing ride request on behalf of a rider. - * - * @param rideId The unique identifier of a ride. - * @param callback The request callback. - */ - void cancelRide(@Nonnull String rideId, Callback callback); - - /** - * Requests a ride on behalf of an user given their desired product, start, and end locations. - * - * @param rideRequestParameters The ride request parameters. - * @param callback The request callback. - */ - void requestRide(RideRequestParameters rideRequestParameters, Callback callback); - - /** - * Update an ongoing request's destination. - * - * @param rideId The unique identifier of a ride. - * @param rideUpdateParameters The ride update parameters. - * @param callback The request callback. - */ - void updateRide(@Nonnull String rideId, - @Nonnull RideUpdateParameters rideUpdateParameters, - Callback callback); - - /** - * Gets the current ride an user is on. - * - * @param callback The request callback. - */ - void getCurrentRide(Callback callback); - - /** - * Cancels the current ride of a user. - * - * @param callback The request callback. - */ - void cancelCurrentRide(Callback callback); - - /** - * Gets information about a user's {@link Place}. - * - * @param placeId The identifier of a Place. - * @param callback The request callback. - */ - void getPlace(@Nonnull String placeId, Callback callback); - - /** - * Gets information about a user's {@link Place}. - * - * @param place One of the defined user {@link Places}. - * @param callback The request callback. - */ - void getPlace(@Nonnull Places place, Callback callback); - - /** - * Sets information about a user's {@link Place}. - * - * @param placeId The identifier of a Place. - * @param callback The request callback. - */ - void setPlace(@Nonnull String placeId, @Nonnull String address, Callback callback); - - /** - * Sets information about a user's {@link Place}. - * - * @param place One of the defined user {@link Places}. - * @param callback The request callback. - */ - void setPlace(@Nonnull Places place, @Nonnull String address, Callback callback); - - /** - * Gets details about a specific ride. - * - * @param rideId The unique identifier for a ride. - * @param callback The request callback. - */ - void getRideDetails(@Nonnull String rideId, Callback callback); - - /** - * Get receipt information for a completed request. - * - * @param rideId The unique identifier of a ride. - * @param callback The request callback. - */ - void getRideReceipt(@Nonnull String rideId, Callback callback); - - /** - *

- * The request estimate endpoint allows a ride to be estimated given the desired product, start, - * and end locations. If the end location is not provided, only the pickup ETA and details of - * surge pricing information are provided. If the pickup ETA is null, there are no cars - * available, but an estimate may still be given to the user. - *

- *

- * You can use this endpoint to determine if surge pricing is in effect. Do this before - * attempting to make a request so that you can preemptively have a user confirm surge by - * sending them to the surge_confirmation_href provided in the response. - *

- * - * @param rideRequestParameters The ride request parameters. - * @param callback The request callback. - */ - void estimateRide(RideRequestParameters rideRequestParameters, - Callback callback); - - /** - * Get a map with a visual representation of a ride for tracking purposes. - * - * @param rideId Unique identifier representing a ride. - * @param callback The request callback. - */ - void getRideMap(@Nonnull String rideId, Callback callback); - - /** - * Gets the {@link PaymentMethod PaymentMethods} of user and their last used method ID. - * - * @param callback The request callback. - */ - void getPaymentMethods(Callback callback); - - /** - * Updates the product in the {@link Environment#SANDBOX sandbox environement} to - * simulate the possible responses the Request endpoint will return when requesting a particular - * product, such as surge pricing and driver availability. - * - * @param productId The unique product ID to update. - * @param sandboxProductRequestParameters The sandbox product request parameters. - * @param callback The request callback. - */ - void updateSandboxProduct(String productId, - SandboxProductRequestParameters sandboxProductRequestParameters, - Callback callback); - - /** - * Updates the ride in the {@link Environment#SANDBOX - * sandbox environement} to simulate the possible states of a ride. - * - * @param rideId Unique identifier representing a ride. - * @param sandboxRideRequestParameters The sandbox ride request parameters. - * @param callback The request callback. - */ - void updateSandboxRide(String rideId, - SandboxRideRequestParameters sandboxRideRequestParameters, - Callback callback); -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesServices.java b/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesServices.java deleted file mode 100644 index 875b3dc..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesServices.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.uber.sdk.rides.auth.OAuth2Helper; -import com.uber.sdk.rides.client.internal.RetrofitUberRidesClient; - -import javax.annotation.Nonnull; - -/** - *

A factory for creating {@link UberRidesSyncService synchronous} and - * {@link UberRidesAsyncService asynchronous} services. One service should be used per Session to make - * calls to any number of generated services as demonstrated:


- *

- *     // Build an OAuth2Credentials object with your secrets.
- *     final OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder()
- *          // Set the appropriate properties.
- *          .build();
- *
- *     // Send user to authorize your application.
- *     String authorizationUrl = oAuth2Credentials.getAuthorizationUrl();
- *     String authorizationCode = redirectUserToAndCaptureCallback(authorizationUrl);
- *
- *     // Authenticate the user with the authorization code.
- *     final Credential credential = oAuth2Credentials.authenticate(authorizationCode);
- *
- *     // Build a Session object with your credentials and environment
- *     final Session session = new Session.Builder()
- *          .setCredential(credential)
- *          .setEnvironment(Session.Environment.SANDBOX)
- *          .build();
- *
- *     // Create the Uber API client once you are authenticated (either by loading an existing
- *     // Credential with oAuth2Credentials.loadCredential(...) or by running through the above
- *     // flow the first time).
- *     final UberRidesSyncService uberApiService = UberRidesServices.createSync(session);
- *
- *     // ...
- *
- *     // Call a service method.
- *     Response<ResponseType> uberApiService.serviceMethod("parameter1", "parameter2");
- * 
- */ -public class UberRidesServices { - - private final Session session; - private final LogLevel logLevel; - - /** - * Determines the level of logging. - */ - public enum LogLevel { - - /** No logging. */ - NONE, - - /** - * Log the headers, body, and metadata for both requests and responses. - */ - FULL; - } - - private UberRidesServices(@Nonnull Session session, @Nonnull LogLevel logLevel) { - this.session = session; - this.logLevel = logLevel; - } - - /** - * Builder for {@link UberRidesAsyncService} or {@link UberRidesSyncService} objects. Instantiated - * using either {@link Builder#sync()} or {@link Builder#async()}. - */ - public static class Builder { - - private Session session; - private LogLevel logLevel; - - /** - * Sets the Session for the service. See {@link Session} for assistance with creating one. - */ - public Builder setSession(Session session) { - this.session = session; - return this; - } - - /** - * Sets the Log level for requests. Optional and defaults to {@link LogLevel#NONE}. - */ - public Builder setLogLevel(LogLevel logLevel) { - this.logLevel = logLevel; - return this; - } - - @VisibleForTesting - UberRidesServices buildUberApiServices() { - LogLevel logLevel = this.logLevel != null ? this.logLevel : LogLevel.NONE; - - return new UberRidesServices<>(session, logLevel); - } - - private void validate() { - Preconditions.checkNotNull(session, "A session is required to create a service."); - } - - /** - * Builds a synchronous or asynchronous {@code UberRidesService} object. - */ - public U build() { - validate(); - return buildUberApiServices().create(); - } - - /** - * Creates a {@code Builder} for asynchronous service clients. - */ - public static Builder async() { - return new Builder<>(); - } - - /** - * Creates a {@code Builder} for synchronous service clients. - */ - public static Builder sync() { - return new Builder<>(); - } - } - - /** - * Gets a new synchronous Uber API Service with default logging and a provided session. - */ - public static UberRidesSyncService createSync(Session session) { - return UberRidesServices.Builder.sync().setSession(session).build(); - } - - /** - * Gets a new asynchronous Uber API Service with default logging and a provided session. - */ - public static UberRidesAsyncService createAsync(Session session) { - return UberRidesServices.Builder.async().setSession(session).build(); - } - - /** - * Gets the session that all requests are backed by. - */ - @Nonnull - @VisibleForTesting - Session getSession() { - return session; - } - - /** - * Gets the level of logging that all requests output. - */ - @Nonnull - @VisibleForTesting - LogLevel getLogLevel() { - return logLevel; - } - - private T create() { - return RetrofitUberRidesClient.getUberApiService(session, new OAuth2Helper(), logLevel); - } -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesSyncService.java b/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesSyncService.java deleted file mode 100644 index e33630b..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/UberRidesSyncService.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client; - -import com.uber.sdk.rides.client.error.ApiException; -import com.uber.sdk.rides.client.error.NetworkException; -import com.uber.sdk.rides.client.model.PaymentMethod; -import com.uber.sdk.rides.client.model.PaymentMethodsResponse; -import com.uber.sdk.rides.client.model.Place; -import com.uber.sdk.rides.client.model.Place.Places; -import com.uber.sdk.rides.client.model.PriceEstimatesResponse; -import com.uber.sdk.rides.client.model.Product; -import com.uber.sdk.rides.client.model.ProductsResponse; -import com.uber.sdk.rides.client.model.Promotion; -import com.uber.sdk.rides.client.model.Ride; -import com.uber.sdk.rides.client.model.RideEstimate; -import com.uber.sdk.rides.client.model.RideMap; -import com.uber.sdk.rides.client.model.RideReceipt; -import com.uber.sdk.rides.client.model.RideRequestParameters; -import com.uber.sdk.rides.client.model.RideUpdateParameters; -import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; -import com.uber.sdk.rides.client.model.SandboxRideRequestParameters; -import com.uber.sdk.rides.client.model.TimeEstimatesResponse; -import com.uber.sdk.rides.client.model.UserActivityPage; -import com.uber.sdk.rides.client.model.UserProfile; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static com.uber.sdk.rides.client.Session.Environment; - -/** - * Represents the synchronous RPC methods of the Uber API. Can be built using - *

- *
- * UberRidesSyncService uberApiService = UberRidesServices.createSync(session);
- *
- * // Or
- *
- * uberApiService = UberRidesServices.sync().setSession(session).build();
- * 
- * @see UberRidesServices.Builder#sync() - */ -public interface UberRidesSyncService extends UberRidesService { - - /** - * Gets information about the promotion that will be available to a new user based on their - * activity's location. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param endLatitude Latitude component of end location. - * @param endLongitude Longitude component of end location. - */ - Response getPromotions(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude) throws ApiException, NetworkException; - - /** - * Gets a limited amount of data about a user's lifetime activity. - * - * @param offset Offset the list of returned results by this amount. Default is zero. - * @param limit Number of items to retrieve. Default is 5, maximum is 50. - */ - Response getUserActivity(@Nullable Integer offset, - @Nullable Integer limit) throws ApiException, NetworkException; - - /** - * Gets information about the user that has authorized with the application. - */ - Response getUserProfile() throws ApiException, NetworkException; - - /** - * Gets an estimated price range for each product offered at a given location. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param endLatitude Latitude component of end location. - * @param endLongitude Longitude component of end location. - */ - Response getPriceEstimates(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude) throws ApiException, NetworkException; - - /** - * Gets ETAs for all products offered at a given location, with the responses expressed as - * integers in seconds. - * - * @param startLatitude Latitude component of start location. - * @param startLongitude Longitude component of start location. - * @param productId Unique identifier representing a specific product for a given latitude & - * longitude. - */ - Response getPickupTimeEstimates(float startLatitude, - float startLongitude, - @Nullable String productId) throws ApiException, NetworkException; - - - /** - * Gets information about the products offered at a given location. - * - * @param latitude Latitude component of location. - * @param longitude Longitude component of location. - */ - Response getProducts(float latitude, float longitude) throws ApiException, NetworkException; - - /** - * Gets information about a specific product. - * - * @param productId The unique product ID to fetch information about. - */ - Response getProduct(@Nonnull String productId) throws ApiException, NetworkException; - - - /** - * Cancel an ongoing ride request on behalf of a rider. - * - * @param rideId The unique identifier of a ride. - */ - Response cancelRide(@Nonnull String rideId) throws ApiException, NetworkException; - - /** - * Requests a ride on behalf of a user given their desired product, start, and end locations. - * - * @param rideRequestParameters The ride request parameters. - */ - Response requestRide(RideRequestParameters rideRequestParameters) throws ApiException, NetworkException; - - /** - * Update an ongoing request's destination. - * - * @param rideId The unique identifier of a ride. - * @param rideUpdateParameters The ride update parameters. - */ - Response updateRide(@Nonnull String rideId, @Nonnull RideUpdateParameters rideUpdateParameters) - throws ApiException, NetworkException; - - /** - * Gets the current ride a user is on. - */ - Response getCurrentRide() throws ApiException, NetworkException; - - /** - * Cancels the current ride of a user. - */ - Response cancelCurrentRide() throws ApiException, NetworkException; - - /** - * Gets information about a user's Place. - * - * @param placeId The identifier of a Place. - */ - Response getPlace(@Nonnull String placeId) throws ApiException, NetworkException; - - /** - * Gets information about a user's Place. - * - * @param place One of the defined user Places. - */ - Response getPlace(@Nonnull Places place) throws ApiException, NetworkException; - - /** - * Sets information about a user's {@link Place}. - * - * @param placeId The identifier of a Place. - */ - Response setPlace(@Nonnull String placeId, @Nonnull String address) throws ApiException, NetworkException; - - /** - * Sets information about a user's {@link Place}. - * - * @param place One of the defined user {@link Places}. - */ - Response setPlace(@Nonnull Places place, @Nonnull String address) throws ApiException, NetworkException; - - /** - * Gets details about a specific ride. - * - * @param rideId The unique identifier of a ride. - */ - Response getRideDetails(@Nonnull String rideId) throws ApiException, NetworkException; - - /** - * Get receipt information for a completed request. - * - * @param rideId The unique identifier of a ride. - */ - Response getRideReceipt(@Nonnull String rideId) throws ApiException, NetworkException; - - /** - *

- * The request estimate endpoint allows a ride to be estimated given the desired product, start, - * and end locations. If the end location is not provided, only the pickup ETA and details of - * surge pricing information are provided. If the pickup ETA is null, there are no cars - * available, but an estimate may still be given to the user. - *

- *

- * You can use this endpoint to determine if surge pricing is in effect. Do this before - * attempting to make a request so that you can preemptively have a user confirm surge by - * sending them to the surge_confirmation_href provided in the response. - *

- * - * @param rideRequestParameters The ride request parameters. - */ - Response estimateRide(RideRequestParameters rideRequestParameters) throws ApiException, - NetworkException; - - /** - * Get a map with a visual representation of a ride for tracking purposes. - * - * @param rideId Unique identifier representing a ride. - */ - Response getRideMap(@Nonnull String rideId) throws ApiException, NetworkException; - - /** - * Gets the {@link PaymentMethod PaymentMethods} of user and their last used method ID. - */ - Response getPaymentMethods() throws ApiException, NetworkException; - - /** - * Updates the product in the {@link Environment#SANDBOX sandbox environement} - * to simulate the possible responses the Request endpoint will return when requesting a particular product, - * such as surge pricing and driver availability. - * - * @param productId The unique product ID to update. - * @param sandboxProductRequestParameters The sandbox product request parameters. - */ - Response updateSandboxProduct(String productId, - SandboxProductRequestParameters sandboxProductRequestParameters) throws ApiException, NetworkException; - - - /** - * Updates the ride in the {@link Environment#SANDBOX sandbox environement} - * to simulate the possible states of a ride. - * - * @param rideId Unique identifier representing a ride request. - * @param sandboxRideRequestParameters The sandbox ride request parameters. - */ - Response updateSandboxRide(String rideId, - SandboxRideRequestParameters sandboxRideRequestParameters) throws ApiException, NetworkException; - -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/ApiException.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/ApiError.java similarity index 58% rename from sdk/src/main/java/com/uber/sdk/rides/client/error/ApiException.java rename to sdk/src/main/java/com/uber/sdk/rides/client/error/ApiError.java index 774c4f0..73cff2e 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/error/ApiException.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/ApiError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,42 +22,48 @@ package com.uber.sdk.rides.client.error; -import com.google.common.collect.ImmutableList; -import com.uber.sdk.rides.client.Response; - +import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * Represents an error returned by the API. + * Represents an error response from the Uber API. */ -public class ApiException extends RuntimeException { +public final class ApiError { + + @Nullable + private final Meta meta; + @Nonnull + private final List errors; - private final Response response; - private final List errors; + public ApiError(@Nullable Meta meta, @Nonnull List clientErrors) { + this.meta = meta; + this.errors = clientErrors; + } - public ApiException(String message, @Nullable Throwable exception, - @Nonnull Response response, @Nonnull List errors) { - super(message, exception); - this.response = response; - this.errors = ImmutableList.copyOf(errors); + ApiError(@Nonnull CompatibilityApiError oldApiError, int statusCode) { + this(oldApiError.code, statusCode, oldApiError.message); + } + + ApiError(@Nullable String code, int statusCode, @Nullable String message) { + this(null, Collections.singletonList(new ClientError(code, statusCode, message))); } /** - * Gets the response from the server + * @return the {@link Meta} information about the error. */ - @Nonnull - public Response getResponse() { - return response; + @Nullable + public Meta getMeta() { + return meta; } /** - * A list of errors detailing what caused this ApiException. + * @return a list of {@link ClientError}s that occurred. */ @Nonnull - public List getErrors() { + public List getClientErrors() { return errors; } } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/ClientError.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/ClientError.java index 2555e9e..77101ec 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/error/ClientError.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/ClientError.java @@ -1,46 +1,68 @@ /* - * Copyright (C) 2012 Square, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * http://www.apache.org/licenses/LICENSE-2.0 + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ package com.uber.sdk.rides.client.error; +import javax.annotation.Nullable; + /** - * An error due to some form of client error. For example bad input or attempting unauthorized access. + * A specific error describing what went wrong. */ -public class ClientError implements UberError { +public final class ClientError { - private String code; - private String message; + @Nullable + private final String code; + private final int status; + @Nullable + private final String title; - public ClientError(String code, String message) { + public ClientError(@Nullable String code, int status, @Nullable String title) { this.code = code; - this.message = message; + this.status = status; + this.title = title; } /** - * A short code referring to the error - * @see https://developer.uber.com/v1/endpoints/ + * @return the code for a specific endpoint error. + * See endpoint documentation + * for possible values and possible resolutions. */ + @Nullable public String getCode() { return code; } /** - * A message describing the error and possibly how to resolve it. + * @return the HTTP status code. + */ + public int getStatus() { + return status; + } + + /** + * @return the description of the error. */ - public String getMessage() { - return message; + @Nullable + public String getTitle() { + return title; } } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/Header.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/CompatibilityApiError.java similarity index 69% rename from sdk/src/main/java/com/uber/sdk/rides/client/Header.java rename to sdk/src/main/java/com/uber/sdk/rides/client/error/CompatibilityApiError.java index c135d9a..a1bb7ff 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/Header.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/CompatibilityApiError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,36 +20,30 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client; +package com.uber.sdk.rides.client.error; import javax.annotation.Nonnull; /** - * An HTTP Header + * An error type no longer supported by the API. Used to convert to an {@link ApiError}. */ -public class Header { +final class CompatibilityApiError { - private final String name; - private final String value; + @Nonnull + final String message; + @Nonnull + final String code; - public Header(@Nonnull String name, @Nonnull String value) { - this.name = name; - this.value = value; + public CompatibilityApiError(@Nonnull String message, @Nonnull String code) { + this.message = message; + this.code = code; } - /** - * Gets the name of the Header - */ - @Nonnull - public String getName() { - return name; + public String getMessage() { + return message; } - /** - * Gets the value of the Header - */ - @Nonnull - public String getValue() { - return value; + public String getCode() { + return code; } } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/ErrorParser.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/ErrorParser.java new file mode 100644 index 0000000..ca3dabd --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/ErrorParser.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.error; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.JsonDataException; +import com.squareup.moshi.Moshi; + +import java.io.IOException; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import retrofit2.Response; + +/** + * Used to parse a {@link Response} to an {@link ApiError}. + */ +public final class ErrorParser { + + /** + * Parses a {@link Response} into an {@link ApiError}. + * + * @param response the {@link Response} to parse. + * @return an {@link ApiError} if parsable, or {@code null} if the response is not in error. + */ + @Nullable + public static ApiError parseError(@Nonnull Response response) { + if (response.isSuccessful()) { + return null; + } + + try { + return parseError(response.errorBody().string(), response.code(), response.message()); + } catch (IOException e) { + return new ApiError(null, response.code(), "Unknown Error"); + } + } + + /** + * Parses an error body and code into an {@link ApiError}. + * + * @param errorBody the error body from the response. + * @param statusCode the status code from the response. + * @param message the message from the response. + * @return the parsed {@link ApiError}. + */ + @Nonnull + public static ApiError parseError(@Nullable String errorBody, int statusCode, @Nullable String message) { + if (errorBody == null) { + return new ApiError(null, statusCode, message); + } + + Moshi moshi = new Moshi.Builder().build(); + JsonAdapter oldApiErrorJsonAdapter = moshi.adapter(CompatibilityApiError.class).failOnUnknown(); + try { + return new ApiError(oldApiErrorJsonAdapter.fromJson(errorBody), statusCode); + } catch (IOException | JsonDataException exception) { + // Not old type of error, move on + } + + JsonAdapter apiErrorJsonAdapter = moshi.adapter(ApiError.class).failOnUnknown(); + try { + return apiErrorJsonAdapter.fromJson(errorBody); + } catch (IOException | JsonDataException exception) { + return new ApiError(null, statusCode, "Unknown Error"); + } + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/Meta.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/Meta.java new file mode 100644 index 0000000..0914a36 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/Meta.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.error; + +import javax.annotation.Nullable; + +/** + * Meta information about an {@link ApiError}. See specific endpoint + * documentation for what can be contained here. + */ +public class Meta { + + @Nullable + private final SurgeConfirmation surge_confirmation; + + public Meta(@Nullable SurgeConfirmation surgeConfirmation) { + this.surge_confirmation = surgeConfirmation; + } + + /** + * @return The {@link SurgeConfirmation} from the meta data if it was present. + */ + @Nullable + public SurgeConfirmation getSurgeConfirmation() { + return surge_confirmation; + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeConfirmation.java b/sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeConfirmation.java new file mode 100644 index 0000000..b00d794 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeConfirmation.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.error; + +import com.uber.sdk.rides.client.model.RideRequestParameters; +import com.uber.sdk.rides.client.services.RidesService; + +import javax.annotation.Nonnull; + +/** + * Used to confirm surge pricing when {@link RidesService#requestRide(RideRequestParameters)} has failed. See ride + * request documentation for more + * info. + */ +public final class SurgeConfirmation { + + @Nonnull + public final String href; + @Nonnull + public final String surge_confirmation_id; + public final float multiplier; + public final long expires_at; + + public SurgeConfirmation( + @Nonnull String href, + @Nonnull String surgeConfirmationId, + float multiplier, + long expiresAt) { + this.href = href; + this.surge_confirmation_id = surgeConfirmationId; + this.multiplier = multiplier; + this.expires_at = expiresAt; + } + + /** + * @return the href to be presented to the user for surge confirmation. + */ + @Nonnull + public String getHref() { + return href; + } + + /** + * @return the unique identifier of this surge confirmation. + */ + @Nonnull + public String getSurgeConfirmationId() { + return surge_confirmation_id; + } + + /** + * @return the surge multiplier. + */ + public float getMultiplier() { + return multiplier; + } + + /** + * @return the UTC expiration time for this surge confirmation. + */ + public long getExpiresAt() { + return expires_at; + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/internal/ApiInterceptor.java b/sdk/src/main/java/com/uber/sdk/rides/client/internal/ApiInterceptor.java new file mode 100644 index 0000000..787d21c --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/internal/ApiInterceptor.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.internal; + +import com.uber.sdk.core.auth.Authenticator; + +import java.io.IOException; + +import okhttp3.Interceptor; +import okhttp3.Request; +import okhttp3.Response; + +public class ApiInterceptor implements Interceptor { + static final String HEADER_ACCESS_TOKEN = "Authorization"; + + + static final String LIB_VERSION = "0.5.0"; + static final String HEADER_ACCEPT_LANGUAGE = "Accept-Language"; + static final String HEADER_USER_AGENT = "X-Uber-User-Agent"; + + public final Authenticator authenticator; + + public ApiInterceptor(Authenticator authenticator) { + this.authenticator = authenticator; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request.Builder requestBuilder = chain.request().newBuilder(); + + requestBuilder.addHeader(HEADER_ACCEPT_LANGUAGE, + authenticator.getSessionConfiguration().getLocale().getLanguage()); + + requestBuilder.addHeader(HEADER_USER_AGENT, "Java Rides SDK v" + LIB_VERSION); + + authenticator.signRequest(requestBuilder); + return chain.proceed(requestBuilder.build()); + } + + public static void setAuthorizationHeader(Request.Builder builder, String authorizationHeader) { + builder.removeHeader(HEADER_ACCESS_TOKEN); + builder.addHeader(HEADER_ACCESS_TOKEN, authorizationHeader); + } + + public static String getAuthorizationHeader(Request request) { + return request.header(HEADER_ACCESS_TOKEN); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/internal/PrimitiveAdapter.java b/sdk/src/main/java/com/uber/sdk/rides/client/internal/PrimitiveAdapter.java new file mode 100644 index 0000000..293f735 --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/internal/PrimitiveAdapter.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.internal; + +import com.squareup.moshi.FromJson; + +import javax.annotation.Nullable; + +/** + * Adapter used to adapt primitives coming back explicitly as null to 0; + */ +public class PrimitiveAdapter { + + @FromJson + public int intFromJson(@Nullable Integer value) { + if (value == null) { + return 0; + } + + return value; + } + + @FromJson + public float floatFromJson(@Nullable Float value) { + if (value == null) { + return 0; + } + + return value; + } + + @FromJson + public long longFromJson(@Nullable Long value) { + if (value == null) { + return 0; + } + + return value; + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeError.java b/sdk/src/main/java/com/uber/sdk/rides/client/internal/RefreshAuthenticator.java similarity index 53% rename from sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeError.java rename to sdk/src/main/java/com/uber/sdk/rides/client/internal/RefreshAuthenticator.java index 5409172..d44bc51 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/error/SurgeError.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/internal/RefreshAuthenticator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,34 +20,41 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client.error; +package com.uber.sdk.rides.client.internal; -/** - * An error caused by attempting to make a request without having - * confirmed relevant surge pricing - */ -public class SurgeError extends ClientError { +import com.uber.sdk.core.auth.Authenticator; + +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.Route; + +public class RefreshAuthenticator implements okhttp3.Authenticator { - private String href; - private String surgeConfirmationId; + static final int MAX_RETRIES = 3; + public final Authenticator authenticator; - public SurgeError(String code, String message, String href, String surgeConfirmationId) { - super(code, message); - this.href = href; - this.surgeConfirmationId = surgeConfirmationId; + public RefreshAuthenticator(Authenticator authenticator) { + this.authenticator = authenticator; } - /** - * A link to send the user to for accepting surge pricing. - */ - public String getHref() { - return href; + @Override + public Request authenticate(Route route, Response response) throws IOException { + if (authenticator.isRefreshable() && canRetry(response)) { + return authenticator.refresh(response); + } + + return null; } - /** - * The confirmation ID to be added to ride requests once the user has confirmed the pricing. - */ - public String getSurgeConfirmationId() { - return surgeConfirmationId; + + boolean canRetry(Response response) { + int responseCount = 1; + while ((response = response.priorResponse()) != null) { + responseCount++; + } + + return responseCount < MAX_RETRIES; } } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitAdapter.java b/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitAdapter.java deleted file mode 100644 index a54a15b..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitAdapter.java +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client.internal; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Throwables; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.SettableFuture; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.uber.sdk.rides.client.Callback; -import com.uber.sdk.rides.client.Response; -import com.uber.sdk.rides.client.UberRidesAsyncService; -import com.uber.sdk.rides.client.UberRidesService; -import com.uber.sdk.rides.client.UberRidesSyncService; -import com.uber.sdk.rides.client.error.ApiException; -import com.uber.sdk.rides.client.error.ClientError; -import com.uber.sdk.rides.client.error.NetworkException; -import com.uber.sdk.rides.client.error.SurgeError; -import com.uber.sdk.rides.client.error.UberError; -import com.uber.sdk.rides.client.model.PaymentMethodsResponse; -import com.uber.sdk.rides.client.model.Place; -import com.uber.sdk.rides.client.model.Place.Places; -import com.uber.sdk.rides.client.model.PlaceParameters; -import com.uber.sdk.rides.client.model.PriceEstimatesResponse; -import com.uber.sdk.rides.client.model.Product; -import com.uber.sdk.rides.client.model.ProductsResponse; -import com.uber.sdk.rides.client.model.Promotion; -import com.uber.sdk.rides.client.model.Ride; -import com.uber.sdk.rides.client.model.RideEstimate; -import com.uber.sdk.rides.client.model.RideMap; -import com.uber.sdk.rides.client.model.RideReceipt; -import com.uber.sdk.rides.client.model.RideRequestParameters; -import com.uber.sdk.rides.client.model.RideUpdateParameters; -import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; -import com.uber.sdk.rides.client.model.SandboxRideRequestParameters; -import com.uber.sdk.rides.client.model.TimeEstimatesResponse; -import com.uber.sdk.rides.client.model.UserActivityPage; -import com.uber.sdk.rides.client.model.UserProfile; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import retrofit.RetrofitError; -import retrofit.client.Header; -import retrofit.mime.TypedByteArray; - -/** - * An adapter uses Retrofit to back our {@link RetrofitUberRidesService} calls. - */ -public class RetrofitAdapter implements UberRidesAsyncService, UberRidesSyncService, - UberRidesService { - - private final T service; - - /** - * Constructor. - * @param retrofitService The Retrofit service. - */ - public RetrofitAdapter(T retrofitService) { - this.service = retrofitService; - } - - @Override - public void getPromotions(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude, - Callback callback) { - service.getPromotions(startLatitude, - startLongitude, endLatitude, - endLongitude, new InternalCallback<>(callback)); - } - - @Override - public Response getPromotions(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPromotions(startLatitude, startLongitude, endLatitude, endLongitude, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getUserActivity(@Nullable Integer offset, - @Nullable Integer limit, - Callback callback) { - service.getUserActivity(offset, limit, new InternalCallback<>(callback)); - } - - @Override - public Response getUserActivity(@Nullable Integer offset, @Nullable Integer limit) throws - ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getUserActivity(offset, limit, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getUserProfile(final Callback callback) { - service.getUserProfile(new InternalCallback<>(callback)); - } - - @Override - public Response getUserProfile() throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getUserProfile(new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getPriceEstimates(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude, - Callback callback) { - service.getPriceEstimates(startLatitude, startLongitude, endLatitude, endLongitude, - new InternalCallback<>(callback)); - } - - @Override - public Response getPriceEstimates(float startLatitude, - float startLongitude, - float endLatitude, - float endLongitude) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPriceEstimates(startLatitude, startLongitude, endLatitude, endLongitude, - new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getPickupTimeEstimates(float startLatitude, - float startLongitude, - @Nullable String productId, - Callback callback) { - service.getPickupTimeEstimate(startLatitude, - startLongitude, - productId, - new InternalCallback<>(callback)); - } - - @Override - public Response getPickupTimeEstimates(float startLatitude, - float startLongitude, - @Nullable String productId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPickupTimeEstimates(startLatitude, startLongitude, productId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getProducts(float latitude, float longitude, final Callback callback) { - service.getProducts(latitude, longitude, new InternalCallback<>(callback)); - } - - @Override - public Response getProducts(float latitude, float longitude) throws NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getProducts(latitude, longitude, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getProduct(@Nonnull String productId, Callback callback) { - service.getProduct(productId, new InternalCallback<>(callback)); - } - - @Override - public Response getProduct(@Nonnull String productId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getProduct(productId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void cancelRide(@Nonnull String rideId, Callback callback) { - service.cancelRide(rideId, new InternalCallback<>(callback)); - } - - @Override - public Response cancelRide(@Nonnull String rideId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - cancelRide(rideId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void requestRide(RideRequestParameters rideRequestParameters, Callback callback) { - service.requestRide(rideRequestParameters, new InternalCallback<>(callback)); - } - - @Override - public Response requestRide(RideRequestParameters rideRequestParameters) throws ApiException, - NetworkException { - final SettableFuture> future = SettableFuture.create(); - - requestRide(rideRequestParameters, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void updateRide(@Nonnull String rideId, - @Nonnull RideUpdateParameters rideUpdateParameters, - Callback callback) { - service.updateRide(rideId, rideUpdateParameters, new InternalCallback<>(callback)); - } - - @Override - public Response updateRide(@Nonnull String rideId, - @Nonnull RideUpdateParameters rideUpdateParameters) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - updateRide(rideId, rideUpdateParameters, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getCurrentRide(Callback callback) { - service.getCurrentRide(new InternalCallback<>(callback)); - } - - @Override - public Response getCurrentRide() throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getCurrentRide(new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void cancelCurrentRide(Callback callback) { - service.cancelCurrentRide(new InternalCallback<>(callback)); - } - - @Override - public Response cancelCurrentRide() throws ApiException, NetworkException{ - final SettableFuture> future = SettableFuture.create(); - - cancelCurrentRide(new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getPlace(@Nonnull String placeId, Callback callback) { - service.getPlace(placeId, new InternalCallback<>(callback)); - } - - @Override - public Response getPlace(@Nonnull String placeId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPlace(placeId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getPlace(@Nonnull Places place, Callback callback) { - service.getPlace(place.toString(), new InternalCallback<>(callback)); - } - - @Override - public Response getPlace(@Nonnull Places place) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPlace(place, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void setPlace(@Nonnull String placeId, @Nonnull String address, Callback callback) { - PlaceParameters placeParameters = new PlaceParameters.Builder().setAddress(address).build(); - - service.setPlace(placeId, placeParameters, new InternalCallback<>(callback)); - } - - @Override - public Response setPlace(@Nonnull String placeId, @Nonnull String address) throws ApiException, - NetworkException { - final SettableFuture> future = SettableFuture.create(); - - setPlace(placeId, address, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void setPlace(@Nonnull Places place, @Nonnull String address, Callback callback) { - PlaceParameters placeParameters = new PlaceParameters.Builder().setAddress(address).build(); - - service.setPlace(place.toString(), placeParameters, new InternalCallback<>(callback)); - } - - @Override - public Response setPlace(@Nonnull Places place, @Nonnull String address) throws ApiException, - NetworkException { - final SettableFuture> future = SettableFuture.create(); - - setPlace(place, address, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getRideDetails(@Nonnull String rideId, Callback callback) { - service.getRideDetails(rideId, new InternalCallback<>(callback)); - } - - @Override - public Response getRideDetails(@Nonnull String rideId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getRideDetails(rideId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getRideReceipt(@Nonnull String rideId, Callback callback) { - service.getRideReceipt(rideId, new InternalCallback(callback)); - } - - @Override - public Response getRideReceipt(@Nonnull String rideId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getRideReceipt(rideId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void estimateRide(RideRequestParameters rideRequestParameters, Callback callback) { - service.estimateRide(rideRequestParameters, new InternalCallback<>(callback)); - } - - @Override - public Response estimateRide(RideRequestParameters rideRequestParameters) throws - ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - estimateRide(rideRequestParameters, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getRideMap(@Nonnull String rideId, Callback callback) { - service.getRideMap(rideId, new InternalCallback<>(callback)); - } - - @Override - public Response getRideMap(@Nonnull String rideId) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getRideMap(rideId, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void getPaymentMethods(Callback callback) { - service.getPaymentMethods(new InternalCallback<>(callback)); - } - - @Override - public Response getPaymentMethods() throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - getPaymentMethods(new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void updateSandboxProduct(String productId, - SandboxProductRequestParameters sandboxProductRequestParameters, - final Callback callback) { - service.updateSandboxProduct(productId, sandboxProductRequestParameters, new InternalCallback<>(callback)); - } - - @Override - public Response updateSandboxProduct(String productId, - SandboxProductRequestParameters sandboxProductRequestParameters) - throws NetworkException { - final SettableFuture> future = SettableFuture.create(); - - updateSandboxProduct(productId, sandboxProductRequestParameters, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - @Override - public void updateSandboxRide(String rideId, - SandboxRideRequestParameters sandboxRideRequestParameters, - Callback callback) { - service.updateSandboxRide(rideId, sandboxRideRequestParameters, new InternalCallback<>(callback)); - } - - @Override - public Response updateSandboxRide(String rideId, - SandboxRideRequestParameters sandboxRideRequestParameters) throws ApiException, NetworkException { - final SettableFuture> future = SettableFuture.create(); - - updateSandboxRide(rideId, sandboxRideRequestParameters, new SettableFutureCallback<>(future)); - - return transformFuture(future); - } - - /** - * Callback that sets a {@code SettableFuture}. - * @param The response object type. - */ - static class SettableFutureCallback implements Callback { - - private SettableFuture> settableFuture; - - public SettableFutureCallback(SettableFuture> settableFuture) { - this.settableFuture = settableFuture; - } - - @Override - public void success(T obj, Response response) { - settableFuture.set(new ResponseOrException(response)); - } - - @Override - public void failure(NetworkException exception) { - settableFuture.set(new ResponseOrException(exception)); - } - - @Override - public void failure(ApiException exception) { - settableFuture.set(new ResponseOrException(exception)); - } - - @Override - public void failure(Throwable exception) { - settableFuture.set(new ResponseOrException(exception)); - } - } - - /** - * Retrofit callback that proxies to a library callback. - * @param The response object type. - */ - @VisibleForTesting - static class InternalCallback implements retrofit.Callback { - - private Callback callback; - - private InternalCallback(Callback callback) { - this.callback = callback; - } - - @Override - public void success(T t, retrofit.client.Response response) { - callback.success(t, transformResponse(response, t)); - } - - @Override - public void failure(RetrofitError error) { - Throwable throwable = transformError(error); - if (throwable instanceof ApiException) { - callback.failure((ApiException) throwable); - } else if (throwable instanceof NetworkException) { - callback.failure((NetworkException) throwable); - } else { - callback.failure(throwable); - } - - } - - private static Response transformResponse(retrofit.client.Response response, T responseObject) { - return new Response(response.getUrl(), response.getStatus(), response.getReason(), - Lists.transform(response.getHeaders(), transformHeader), responseObject); - }; - - private static Function transformHeader = new Function() { - @Override - public com.uber.sdk.rides.client.Header apply(Header header) { - return new com.uber.sdk.rides.client.Header(header.getName(), header.getValue()); - } - }; - - private static Throwable transformError(RetrofitError error) { - if (error.getKind().equals(RetrofitError.Kind.NETWORK)) { - return new NetworkException("Network error: " + error.getCause().getClass(), - error.getCause(), error.getUrl()); - } else if (error.getKind().equals(RetrofitError.Kind.HTTP)) { - retrofit.client.Response response = error.getResponse(); - List errors = getErrors(new String(((TypedByteArray) error.getResponse().getBody()).getBytes())); - return new ApiException(error.getMessage(), error, transformResponse(response, null), errors); - } - - return error.getCause(); - } - - @VisibleForTesting - static List getErrors(String body) { - JsonParser jsonParser = new JsonParser(); - JsonObject bodyObject = jsonParser.parse(body).getAsJsonObject(); - - List errors = new ArrayList<>(); - - if (bodyObject.has("errors")) { - JsonObject meta = bodyObject.getAsJsonObject("meta"); - JsonArray errorsArray = bodyObject.getAsJsonArray("errors"); - for (int i = 0; i < errorsArray.size(); i++) { - JsonObject error = errorsArray.get(i).getAsJsonObject(); - errors.add(createError(meta, error)); - } - } else if (bodyObject.has("code")) { - errors.add(new ClientError(bodyObject.get("code").getAsString(), bodyObject.get("message").getAsString())); - } else if (bodyObject.has("error")) { - errors.add(new ClientError("error", bodyObject.get("error").getAsString())); - } else { - errors.add(new ClientError("unknown", "unknown error, inspect response body for more information")); - } - return errors; - } - - @VisibleForTesting - static UberError createError(JsonObject meta, JsonObject error) { - String code = error.get("code").getAsString(); - String message = error.get("title").getAsString(); - if ("surge".equals(code)) { - JsonObject surgeConfirmationObject = meta.getAsJsonObject("surge_confirmation"); - return new SurgeError(code, message, surgeConfirmationObject.get("href").getAsString(), - surgeConfirmationObject.get("surge_confirmation_id").getAsString()); - } else { - return new ClientError(code, message); - } - } - } - - private static Function transformHeader = - new Function() { - @Override - public com.uber.sdk.rides.client.Header apply(Header header) { - return new com.uber.sdk.rides.client.Header(header.getName(), header.getValue()); - } - }; - - private static Response transformResponse(retrofit.client.Response response, T responseObject) { - return new Response(response.getUrl(), response.getStatus(), response.getReason(), - Lists.transform(response.getHeaders(), transformHeader), responseObject); - }; - - private static Response transformFuture(SettableFuture> future) - throws NetworkException { - final Response response; - try { - ResponseOrException responseOrException = future.get(); - - if (responseOrException.exception != null) { - if (responseOrException.exception instanceof NetworkException) { - throw (NetworkException) responseOrException.exception; - } else if (responseOrException.exception instanceof ApiException) { - throw (ApiException) responseOrException.exception; - } else { - Throwables.propagate(responseOrException.exception); - } - } - - response = responseOrException.response; - } catch (InterruptedException e) { - throw new NetworkException("Executor thread interrupted.", e, null); - } catch (ExecutionException e) { - throw new NetworkException("Executor thread interrupted.", e, null); - } - - if (response != null) { - return response; - } else { - throw new IllegalStateException("Response cannot be null."); - } - } - - private static class ResponseOrException { - - @Nullable private Response response; - @Nullable private Throwable exception; - - public ResponseOrException(@Nullable Response response) { - this.response = response; - } - - public ResponseOrException(@Nullable Throwable exception) { - this.exception = exception; - } - } -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClient.java b/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClient.java deleted file mode 100644 index 115301f..0000000 --- a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClient.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client.internal; - -import com.google.api.client.auth.oauth2.Credential; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; -import com.google.common.collect.Sets; -import com.google.common.net.HttpHeaders; -import com.google.common.reflect.Reflection; -import com.google.gson.GsonBuilder; -import com.squareup.okhttp.Interceptor; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Request; -import com.squareup.okhttp.Response; -import com.uber.sdk.rides.auth.OAuth2Helper; -import com.uber.sdk.rides.client.Session; -import com.uber.sdk.rides.client.Session.Environment; -import com.uber.sdk.rides.client.UberRidesService; -import com.uber.sdk.rides.client.UberRidesServices; - -import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.Method; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import retrofit.RequestInterceptor; -import retrofit.RestAdapter; -import retrofit.client.OkClient; -import retrofit.converter.GsonConverter; - -/** - * Internal Client for creating {@link RetrofitUberRidesService services}. - */ -public class RetrofitUberRidesClient { - - @VisibleForTesting static final String LIB_VERSION = "0.3.0"; - - /** - * Gets a new Uber API service client. - * - * @param session The Uber API session - * @param oAuth2Helper The OAuth 2.0 Helper - * @param logLevel The log level. - * @return A Uber API service client. - */ - @SuppressWarnings("unchecked") // Class casting is ensured. - public static T getUberApiService(Session session, - OAuth2Helper oAuth2Helper, UberRidesServices.LogLevel logLevel) { - return (T) getUberApiService(session, oAuth2Helper, logLevel, - session.getEndpointHost(), null, RetrofitUberRidesService.class); - } - - /** - * Gets an Uber API service client with a specified endpoint. - * - * @param session The Uber API session - * @param oAuth2Helper The OAuth 2.0 Helper - * @param logLevel The log level. - * @param endpointHost The endpoint host for the API client. - * @param httpClient The HTTP client - * @return An Uber API service client. - */ - @VisibleForTesting - @SuppressWarnings("unchecked") // Class casting is ensured. - static U getUberApiService(Session session, - OAuth2Helper oAuth2Helper, UberRidesServices.LogLevel logLevel, String endpointHost, - @Nullable OkHttpClient httpClient, Class internalApiServiceClass) { - - RestAdapter.LogLevel retrofitLogLevel = UberRidesServices.LogLevel.FULL.equals(logLevel) ? - RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE; - - RestAdapter restAdapter; - try { - restAdapter = buildRestAdapter(session, endpointHost, oAuth2Helper, retrofitLogLevel, httpClient); - } catch (IOException e) { - throw new IllegalStateException("Could not build REST adapter.", e); - } - - T internalService = Reflection.newProxy(internalApiServiceClass, - new InvocationHandler<>(session.getEnvironment(), internalApiServiceClass, - restAdapter.create(internalApiServiceClass))); - - return (U) new RetrofitAdapter(internalService); - } - - /** - * Builds a RestAdapter. - */ - private static RestAdapter buildRestAdapter(final Session session, - String endpointHost, - final OAuth2Helper oAuth2Helper, - RestAdapter.LogLevel logLevel, - OkHttpClient httpClient) throws IOException { - - RequestInterceptor requestInterceptor = new RequestInterceptor() { - - @Override - public void intercept(RequestFacade requestFacade) { - Credential credential = session.getCredential(); - if (credential != null) { - oAuth2Helper.refreshCredentialIfNeeded(credential); - requestFacade.addHeader("Authorization", "Bearer " + credential.getAccessToken()); - } else { - requestFacade.addHeader("Authorization", "Token " + session.getServerToken()); - } - - if (session.getLocale() != null) { - requestFacade.addHeader("Accept-Language", session.getLocale().getLanguage()); - } - - requestFacade.addHeader("X-Uber-User-Agent", "Java Rides SDK v" + LIB_VERSION); - } - }; - - if (httpClient == null) { - httpClient = new OkHttpClient(); - httpClient.setConnectTimeout(1, TimeUnit.MINUTES); - httpClient.setReadTimeout(1, TimeUnit.MINUTES); - httpClient.setFollowRedirects(false); - httpClient.interceptors().add(new Interceptor() { - @Override - public Response intercept(Chain chain) throws IOException { - Request oldRequest = chain.request(); - Response response = chain.proceed(oldRequest); - if (response.isRedirect()) { - String redirectUrl = response.header(HttpHeaders.LOCATION); - Request newRequest = oldRequest.newBuilder() - .url(redirectUrl) - .build(); - return chain.proceed(newRequest); - } - return response; - } - }); - } - - return new RestAdapter.Builder() - .setEndpoint(endpointHost) - .setConverter(new GsonConverter(new GsonBuilder().create())) - .setRequestInterceptor(requestInterceptor) - .setClient(new OkClient(httpClient)) - .setLogLevel(logLevel) - .build(); - } - - /** - * Invocation handler for API service calls. - * @param The API service type. - */ - @VisibleForTesting - static class InvocationHandler implements java.lang.reflect.InvocationHandler { - - private final Environment environment; - private final Class uberApiServiceClass; - private final T uberApiService; - - /** - * Invocation handler for API service class. - * - * @param environment The API environment. - * @param uberApiServiceClass The API service class. - * @param uberApiService The API service client. - */ - @VisibleForTesting - InvocationHandler(Environment environment, - Class uberApiServiceClass, - T uberApiService) { - this.environment = environment; - this.uberApiServiceClass = uberApiServiceClass; - this.uberApiService = uberApiService; - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Method uberApiServiceMethod = getMethodWithName(method.getName()); - if (environment.equals(Environment.PRODUCTION) - && uberApiServiceMethod.isAnnotationPresent(SandboxOnly.class)) { - throw new IllegalStateException("Sandbox only methods can't be called in production."); - } - - return uberApiServiceMethod.invoke(uberApiService, args); - } - - /** - * Gets the method with name from the underlying API service class. - */ - private Method getMethodWithName(final String name) { - try { - return Iterables.getOnlyElement( - Sets.filter(Sets.newHashSet(uberApiServiceClass.getMethods()), - new Predicate() { - @Override - public boolean apply(@Nullable Method input) { - return input != null && input.getName().equals(name); - } - })); - } catch (IllegalArgumentException e) { - throw new IllegalStateException("Services may not contain duplicate names.", e); - } - } - } - - /** - * Indicates that methods can only be called on the - * {@link Environment#SANDBOX Sandbox environment}. - */ - @Target(ElementType.METHOD) - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @interface SandboxOnly {} -} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Driver.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Driver.java index 6f6ee23..af537b6 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Driver.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Location.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Location.java index 1d9ce0e..ad79d32 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Location.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Location.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethod.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethod.java index fc11f8d..e04b6e0 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethod.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethod.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; /** diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethodsResponse.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethodsResponse.java index ac6653e..0a3f61a 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethodsResponse.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/PaymentMethodsResponse.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import java.util.List; diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Place.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Place.java index 4fcf76c..a1e4979 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Place.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Place.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; /** diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/PlaceParameters.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/PlaceParameters.java index d0cb2fe..e5f0ede 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/PlaceParameters.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/PlaceParameters.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import javax.annotation.Nonnull; diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimate.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimate.java index aa897de..4b2a56f 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimate.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimatesResponse.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimatesResponse.java index 6b1feea..ed7d485 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimatesResponse.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/PriceEstimatesResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Product.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Product.java index 9a3a59b..7a24f0d 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Product.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Product.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/ProductsResponse.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/ProductsResponse.java index 0fa01fc..2656de5 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/ProductsResponse.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/ProductsResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Promotion.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Promotion.java index 45d91bc..8c98093 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Promotion.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Promotion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Ride.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Ride.java index 25c0ba1..e63ef67 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Ride.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Ride.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideEstimate.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideEstimate.java index d30aed0..d4dc644 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideEstimate.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideEstimate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideMap.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideMap.java index 5cc1686..50791aa 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideMap.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideReceipt.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideReceipt.java index d798513..48a69f2 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideReceipt.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideReceipt.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import java.util.List; diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideRequestParameters.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideRequestParameters.java index cc90282..0fd5e7a 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideRequestParameters.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideRequestParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideUpdateParameters.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideUpdateParameters.java index 89d59bc..ac5c2aa 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/RideUpdateParameters.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/RideUpdateParameters.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import com.uber.sdk.rides.client.model.Place.Places; diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxProductRequestParameters.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxProductRequestParameters.java index 08b00ec..f7b37c5 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxProductRequestParameters.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxProductRequestParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxRideRequestParameters.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxRideRequestParameters.java index 15dfd75..c2c37bf 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxRideRequestParameters.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/SandboxRideRequestParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimate.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimate.java index e4a01a4..dcf222a 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimate.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimatesResponse.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimatesResponse.java index d556465..d58a59a 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimatesResponse.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/TimeEstimatesResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivity.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivity.java index 7ce7924..a638564 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivity.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivityPage.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivityPage.java index 0bdc247..13f18c2 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivityPage.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserActivityPage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserProfile.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserProfile.java index 15f21e5..496cbff 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/UserProfile.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/UserProfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/model/Vehicle.java b/sdk/src/main/java/com/uber/sdk/rides/client/model/Vehicle.java index 61bb9fb..0232dce 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/model/Vehicle.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/model/Vehicle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesService.java b/sdk/src/main/java/com/uber/sdk/rides/client/services/RidesService.java similarity index 60% rename from sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesService.java rename to sdk/src/main/java/com/uber/sdk/rides/client/services/RidesService.java index 852246b..c37941f 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesService.java +++ b/sdk/src/main/java/com/uber/sdk/rides/client/services/RidesService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,8 +20,9 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client.internal; +package com.uber.sdk.rides.client.services; +import com.uber.sdk.rides.client.SessionConfiguration; import com.uber.sdk.rides.client.model.PaymentMethod; import com.uber.sdk.rides.client.model.PaymentMethodsResponse; import com.uber.sdk.rides.client.model.Place; @@ -33,7 +34,6 @@ import com.uber.sdk.rides.client.model.Ride; import com.uber.sdk.rides.client.model.RideEstimate; import com.uber.sdk.rides.client.model.RideMap; -import com.uber.sdk.rides.client.model.RideReceipt; import com.uber.sdk.rides.client.model.RideRequestParameters; import com.uber.sdk.rides.client.model.RideUpdateParameters; import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; @@ -45,22 +45,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -import retrofit.Callback; -import retrofit.http.Body; -import retrofit.http.DELETE; -import retrofit.http.GET; -import retrofit.http.PATCH; -import retrofit.http.POST; -import retrofit.http.PUT; -import retrofit.http.Path; -import retrofit.http.Query; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.DELETE; +import retrofit2.http.GET; +import retrofit2.http.PATCH; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Path; +import retrofit2.http.Query; -import static com.uber.sdk.rides.client.Session.Environment; +public interface RidesService { -/** - * Represents the RPC methods of the Uber API. - */ -public interface RetrofitUberRidesService { /** * Gets information about the promotion that will be available to a new user based on their @@ -70,34 +66,34 @@ public interface RetrofitUberRidesService { * @param startLongitude Longitude component of start location. * @param endLatitude Latitude component of end location. * @param endLongitude Longitude component of end location. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/promotions") - void getPromotions(@Query("start_latitude") float startLatitude, - @Query("start_longitude") float startLongitude, - @Query("end_latitude") float endLatitude, - @Query("end_longitude") float endLongitude, - Callback callback); + Call getPromotions(@Query("start_latitude") float startLatitude, + @Query("start_longitude") float startLongitude, + @Query("end_latitude") float endLatitude, + @Query("end_longitude") float endLongitude); /** * Gets a limited amount of data about a user's lifetime activity. * * @param offset Offset the list of returned results by this amount. Default is zero. * @param limit Number of items to retrieve. Default is 5, maximum is 50. - * @param callback The request callback. - */ + * + * @return the request {@link Call} + * */ @GET("/v1.2/history") - void getUserActivity(@Nullable @Query("offset") Integer offset, - @Nullable @Query("limit") Integer limit, - Callback callback); + Call getUserActivity(@Nullable @Query("offset") Integer offset, + @Nullable @Query("limit") Integer limit); /** * Gets information about the user that has authorized with the application. * - * @param callback The request callback. + * @return the request {@link Call} */ @GET("/v1/me") - void getUserProfile(Callback callback); + Call getUserProfile(); /** * Gets an estimated price range for each product offered at a given location. @@ -106,14 +102,14 @@ void getUserActivity(@Nullable @Query("offset") Integer offset, * @param startLongitude Longitude component of start location. * @param endLatitude Latitude component of end location. * @param endLongitude Longitude component of end location. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/estimates/price") - void getPriceEstimates(@Query("start_latitude") float startLatitude, - @Query("start_longitude") float startLongitude, - @Query("end_latitude") float endLatitude, - @Query("end_longitude") float endLongitude, - Callback callback); + Call getPriceEstimates(@Query("start_latitude") float startLatitude, + @Query("start_longitude") float startLongitude, + @Query("end_latitude") float endLatitude, + @Query("end_longitude") float endLongitude); /** * Gets ETAs for all products offered at a given location, with the responses expressed as @@ -123,119 +119,114 @@ void getPriceEstimates(@Query("start_latitude") float startLatitude, * @param startLongitude Longitude component of start location. * @param productId Unique identifier representing a specific product for a given latitude & * longitude. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/estimates/time") - void getPickupTimeEstimate(@Query("start_latitude") float startLatitude, - @Query("start_longitude") float startLongitude, - @Nullable @Query("product_id") String productId, - Callback callback); + Call getPickupTimeEstimate(@Query("start_latitude") float startLatitude, + @Query("start_longitude") float startLongitude, + @Nullable @Query("product_id") String productId); /** * Gets information about the products offered at a given location. * * @param latitude Latitude component of location. * @param longitude Longitude component of location. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/products") - void getProducts(@Query("latitude") float latitude, - @Query("longitude") float longitude, - Callback callback); + Call getProducts(@Query("latitude") float latitude, + @Query("longitude") float longitude); /** * Gets information about a specific product. * * @param productId The unique product ID to fetch information about. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/products/{product_id}") - void getProduct(@Path("product_id") String productId, Callback callback); + Call getProduct(@Path("product_id") String productId); /** * Cancels an ongoing Ride for a user. * * @param rideId Unique identifier representing a Request. - * @param callback The request callback. + * + * @return the request {@link Call} */ @DELETE("/v1/requests/{request_id}") - void cancelRide(@Path("request_id") String rideId, Callback callback); + Call cancelRide(@Path("request_id") String rideId); /** * Requests a ride on behalf of a user given their desired product, start, and end locations. * * @param rideRequestParameters The ride request parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ @POST("/v1/requests") - void requestRide(@Body RideRequestParameters rideRequestParameters, Callback callback); + Call requestRide(@Body RideRequestParameters rideRequestParameters); /** * Gets the current ride a user is on. * - * @param callback The request callback. + * @return the request {@link Call} */ @GET("/v1/requests/current") - void getCurrentRide(Callback callback); + Call getCurrentRide(); /** * Cancels the current ride of a user. * - * @param callback The request callback. + * @return the request {@link Call} */ @DELETE("/v1/requests/current") - void cancelCurrentRide(Callback callback); + Call cancelCurrentRide(); /** * Update an ongoing request's destination. * * @param rideUpdateParameters The ride request parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ @PATCH("/v1/requests/{request_id}") - void updateRide(@Nonnull @Path("request_id") String rideId, - @Body RideUpdateParameters rideUpdateParameters, - Callback callback); + Call updateRide(@Nonnull @Path("request_id") String rideId, + @Body RideUpdateParameters rideUpdateParameters); /** * Gets information about a user's Place. * * @param placeId The identifier of a Place. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/places/{place_id}") - void getPlace(@Nonnull @Path("place_id") String placeId, Callback callback); + Call getPlace(@Nonnull @Path("place_id") String placeId); /** * Sets information about a user's Place. * * @param placeId The identifier of a Place. * @param placeParameters The place parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ @PUT("/v1/places/{place_id}") - void setPlace(@Nonnull @Path("place_id") String placeId, - @Nonnull @Body PlaceParameters placeParameters, - Callback callback); + Call setPlace(@Nonnull @Path("place_id") String placeId, + @Nonnull @Body PlaceParameters placeParameters); /** * Gets details about a specific ride. * * @param rideId The unique identifier for a ride. - * @param callback The request callback. - */ - @GET("/v1/requests/{request_id}") - void getRideDetails(@Nonnull @Path("request_id") String rideId, Callback callback); - - /** - * Get receipt information for a completed request. - * Access to this endpoint is restricted and requires whitelisting. * - * @param rideId The unique identifier for a ride. - * @param callback The request callback. + * @return the request {@link Call} */ - @GET("/v1/requests/{request_id}/receipt") - void getRideReceipt(@Nonnull @Path("request_id") String rideId, Callback callback); + @GET("/v1/requests/{request_id}") + Call getRideDetails(@Nonnull @Path("request_id") String rideId); /** *

@@ -251,11 +242,11 @@ void setPlace(@Nonnull @Path("place_id") String placeId, *

* * @param rideRequestParameters The ride request parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ @POST("/v1/requests/estimate") - void estimateRide(@Body RideRequestParameters rideRequestParameters, - Callback callback); + Call estimateRide(@Body RideRequestParameters rideRequestParameters); /** * Get a map with a visual representation of a ride for tracking purposes. @@ -264,45 +255,48 @@ void estimateRide(@Body RideRequestParameters rideRequestParameters, * to get a map before that will result in a 404 error. * * @param rideId Unique identifier representing a ride. - * @param callback The request callback. + * + * @return the request {@link Call} */ @GET("/v1/requests/{request_id}/map") - void getRideMap(@Nonnull @Path("request_id") String rideId , Callback callback); + Call getRideMap(@Nonnull @Path("request_id") String rideId); /** * Gets the {@link PaymentMethod PaymentMethods} of user and their last used method ID. * - * @param callback The request callback. + * @return the request {@link Call} */ @GET("/v1/payment-methods") - void getPaymentMethods(Callback callback); + Call getPaymentMethods(); /** - * Updates the product in the {@link Environment#SANDBOX sandbox environement} to simulate the + * Updates the product in the {@link SessionConfiguration.Environment#SANDBOX sandbox environement} to simulate the * possible responses the Request endpoint will return when requesting a particular product, * such as surge pricing and driver availability. * + * Will fail when called in {@link SessionConfiguration.Environment#PRODUCTION}. + * * @param productId The unique product ID to update. * @param sandboxProductRequestParameters The sandbox product request parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ - @RetrofitUberRidesClient.SandboxOnly @PUT("/v1/sandbox/products/{product_id}") - void updateSandboxProduct(@Path("product_id") String productId, - @Body SandboxProductRequestParameters sandboxProductRequestParameters, - Callback callback); + Call updateSandboxProduct(@Path("product_id") String productId, + @Body SandboxProductRequestParameters sandboxProductRequestParameters); /** - * Updates the ride in the {@link Environment#SANDBOX sandbox environement} to simulate the + * Updates the ride in the {@link SessionConfiguration.Environment#SANDBOX sandbox environement} to simulate the * possible states of a the Request. * + * Will fail when called in {@link SessionConfiguration.Environment#PRODUCTION}. + * * @param rideId Unique identifier representing a Request. * @param sandboxRideRequestParameters The sandbox ride request parameters. - * @param callback The request callback. + * + * @return the request {@link Call} */ - @RetrofitUberRidesClient.SandboxOnly @PUT("/v1/sandbox/requests/{request_id}") - void updateSandboxRide(@Path("request_id") String rideId, - @Body SandboxRideRequestParameters sandboxRideRequestParameters, - Callback callback); + Call updateSandboxRide(@Path("request_id") String rideId, + @Body SandboxRideRequestParameters sandboxRideRequestParameters); } diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/utils/Preconditions.java b/sdk/src/main/java/com/uber/sdk/rides/client/utils/Preconditions.java new file mode 100644 index 0000000..722084b --- /dev/null +++ b/sdk/src/main/java/com/uber/sdk/rides/client/utils/Preconditions.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.utils;/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +import java.util.Collection; + +import javax.annotation.Nonnull; + +/** + * Simple static methods to be called at the start of your own methods to verify + * correct arguments and state. + */ +public class Preconditions { + + /** + * Ensures the truth of an expression involving the state of the calling + * instance, but not involving any parameters to the calling method. + * + * @param expression a boolean expression + * @param errorMessage error message thrown if expression is false. + * @throws IllegalStateException if {@code expression} is false + */ + public static void checkState(final boolean expression, @Nonnull String errorMessage) { + if (!expression) { + throw new IllegalStateException(errorMessage); + } + } + + + /** + * Ensures the value is not null. + * + * @param value value to be validated. + * @param errorMessage error message thrown if value is null. + * @param type of value. + * @return value passed in if not null. + */ + @Nonnull + public static T checkNotNull(T value, @Nonnull String errorMessage) { + if (value == null) { + throw new NullPointerException(errorMessage); + } + return value; + } + + /** + * Ensures a collection is neither null nor empty. + * + * @param collection collection to be validated. + * @param errorMessage error message to be thrown if collection is null or empty. + * @param type of the collection item. + * @return collection passed in. + */ + @Nonnull + public static Collection checkNotEmpty(Collection collection, @Nonnull String errorMessage) { + checkState(collection != null && !collection.isEmpty(), errorMessage); + return collection; + } +} diff --git a/sdk/src/test/java/com/uber/sdk/core/auth/AccessTokenAuthenticatorTest.java b/sdk/src/test/java/com/uber/sdk/core/auth/AccessTokenAuthenticatorTest.java new file mode 100644 index 0000000..cbeaa15 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/core/auth/AccessTokenAuthenticatorTest.java @@ -0,0 +1,193 @@ +package com.uber.sdk.core.auth; + +import com.uber.sdk.core.auth.internal.OAuth2Service; +import com.uber.sdk.rides.client.SessionConfiguration; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import retrofit2.Call; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doCallRealMethod; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class AccessTokenAuthenticatorTest { + + @Mock + AccessTokenStorage accessTokenStorage; + + @Mock + AccessToken accessToken; + + @Mock + OAuth2Service service; + + @Mock + SessionConfiguration config; + + @Mock + Call serviceResult; + + AccessTokenAuthenticator authenticator; + + Request dummyRequest; + Response dummyResponse; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + authenticator = spy(new AccessTokenAuthenticator(config, accessTokenStorage, service)); + dummyRequest = new Request.Builder() + .url("http://test") + .build(); + + dummyResponse = new Response.Builder() + .request(dummyRequest) + .protocol(Protocol.HTTP_1_1) + .code(200) + .build(); + } + + @Test + public void testSignRequest_callsSetBearerToken() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(accessToken); + Request.Builder builder = dummyRequest.newBuilder(); + + authenticator.signRequest(builder); + verify(authenticator).setBearerToken(eq(builder), eq(accessToken)); + } + + @Test + public void testIsRefreshable_noToken_returnsFalse() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(null); + assertFalse(authenticator.isRefreshable()); + } + + @Test + public void testIsRefreshable_noRefreshToken_returnsFalse() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(accessToken); + when(accessToken.getRefreshToken()).thenReturn(null); + assertFalse(authenticator.isRefreshable()); + } + + @Test + public void testIsRefreshable_validToken_returnsTrue() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(accessToken); + when(accessToken.getRefreshToken()).thenReturn("refreshToken"); + assertTrue(authenticator.isRefreshable()); + } + + @Test + public void testRefresh_callsRefreshToken() throws Exception { + doReturn(dummyRequest).when(authenticator).doRefresh(eq(dummyResponse)); + authenticator.refresh(dummyResponse); + verify(authenticator).doRefresh(eq(dummyResponse)); + } + + @Test + public void testDoRefreshToken_ifSignedByOldToken_resign() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(accessToken); + doReturn(true).when(authenticator).signedByOldToken(eq(dummyResponse), eq(accessToken)); + doReturn(dummyRequest).when(authenticator).resign(eq(dummyResponse), eq(accessToken)); + Request result = authenticator.doRefresh(dummyResponse); + verify(authenticator).resign(eq(dummyResponse), eq(accessToken)); + assertEquals(dummyRequest, result); + } + + @Test + public void testDoRefreshToken_ifNotSignedByOldToken_refreshAndResign() throws Exception { + when(accessTokenStorage.getAccessToken()).thenReturn(accessToken); + doReturn(false).when(authenticator).signedByOldToken(eq(dummyResponse), eq(accessToken)); + doReturn(dummyRequest).when(authenticator).refreshAndSign(eq(dummyResponse), eq(accessToken)); + Request result = authenticator.doRefresh(dummyResponse); + verify(authenticator).refreshAndSign(eq(dummyResponse), eq(accessToken)); + assertEquals(dummyRequest, result); + } + + @Test + public void testResign_callsSetBearerToken() throws Exception { + authenticator.resign(dummyResponse, accessToken); + verify(authenticator).setBearerToken(any(Request.Builder.class), eq(accessToken)); + } + + @Test + public void testRefreshAndSign_callsRefreshAndCallsResign() throws Exception { + + AccessToken newToken = mock(AccessToken.class); + doReturn(newToken).when(authenticator).refreshToken(eq(accessToken)); + + authenticator.refreshAndSign(dummyResponse, accessToken); + + verify(authenticator).refreshToken(eq(accessToken)); + verify(authenticator).resign(eq(dummyResponse), eq(newToken)); + } + + @Test + public void testRefreshToken() throws Exception { + when(accessToken.getRefreshToken()).thenReturn("refresh"); + when(config.getClientId()).thenReturn("clientId"); + when(service.refresh(eq("refresh"), eq("clientId"))).thenReturn(serviceResult); + when(serviceResult.execute()).thenReturn(retrofit2.Response.success(accessToken)); + assertEquals(accessToken, authenticator.refreshToken(accessToken)); + verify(accessTokenStorage).setAccessToken(accessToken); + } + + @Test + public void testSignedByOldToken_whenEqual_returnFalse() throws Exception { + when(accessToken.getToken()).thenReturn("token1234"); + doCallRealMethod().when(authenticator).createBearerToken(eq(accessToken)); + + Request request = dummyRequest.newBuilder().header("Authorization", "Bearer token1234").build(); + Response response = dummyResponse.newBuilder().request(request).build(); + + assertFalse(authenticator.signedByOldToken(response, accessToken)); + } + + @Test + public void testSignedByOldToken_whenNotEqual_returnTrue() throws Exception { + when(accessToken.getToken()).thenReturn("token1234"); + doCallRealMethod().when(authenticator).createBearerToken(eq(accessToken)); + + Request request = dummyRequest.newBuilder().header("Authorization", "Bearer token123").build(); + Response response = dummyResponse.newBuilder().request(request).build(); + + assertTrue(authenticator.signedByOldToken(response, accessToken)); + } + + @Test + public void testSetBearerToken_formatsCorrectly() throws Exception { + Request.Builder builder = dummyRequest.newBuilder(); + when(accessToken.getToken()).thenReturn("token1234"); + authenticator.setBearerToken(builder, accessToken); + assertEquals("Bearer token1234", builder.build().header("Authorization")); + } + + @Test + public void testCreateBearerToken_formatsCorrectly() throws Exception { + when(accessToken.getToken()).thenReturn("token1234"); + assertEquals("Bearer token1234", authenticator.createBearerToken(accessToken)); + } + + @Test + public void testCreateOAuthService_notNull() throws Exception { + OAuth2Service service = AccessTokenAuthenticator.createOAuthService("http://test"); + assertNotNull(service); + } + +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/core/auth/ScopeTest.java b/sdk/src/test/java/com/uber/sdk/core/auth/ScopeTest.java new file mode 100644 index 0000000..546ca24 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/core/auth/ScopeTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScopeTest { + + @Test + public void testParseScopesWithZero_shouldReturnNothing() throws Exception { + Set scopes = Scope.parseScopes(0); + + assertThat(scopes).isEmpty(); + } + + @Test + public void testParseScopesWithNegativeValue_shouldReturnNothing() throws Exception { + Set scopes = Scope.parseScopes(-32); + + assertThat(scopes).isEmpty(); + } + + @Test + public void testParseScopesWithOneScope_shouldReturn() throws Exception { + Set scopes = Scope.parseScopes(Scope.HISTORY.getBitValue()); + + assertThat(scopes).contains(Scope.HISTORY); + } + + @Test + public void testParseScopesWithMultipleGeneralScopes_shouldReturn() throws Exception { + Set scopes = Scope.parseScopes(Scope.HISTORY.getBitValue() | Scope.PROFILE.getBitValue()); + + assertThat(scopes).contains(Scope.HISTORY, Scope.PROFILE); + } + + @Test + public void testParseScopesWithMixLevelScopes_shouldReturn() throws Exception { + Set scopes = Scope.parseScopes( + Scope.HISTORY.getBitValue() | Scope.REQUEST.getBitValue() | Scope.PROFILE.getBitValue()); + + assertThat(scopes).contains(Scope.HISTORY, Scope.REQUEST, Scope.PROFILE); + } + + @Test + public void testCustomScopes_shouldIgnore() throws Exception { + String scopeString = "history profile test"; + Set scopes = Scope.parseScopes(scopeString); + assertThat(scopes).contains(Scope.HISTORY, Scope.PROFILE); + assertThat(scopes.size()).isEqualTo(2); + } + + @Test + public void testToStandardStringOneScope_noSpace() { + Collection scopes = Arrays.asList(Scope.HISTORY); + + assertThat(Scope.toStandardString(scopes)).isEqualTo("history"); + } + + @Test + public void testToStandardStringMultiScopes_spaceDelimited() { + Collection scopes = Arrays.asList(Scope.HISTORY, Scope.ALL_TRIPS); + + assertThat(Scope.toStandardString(scopes)).isEqualTo("history all_trips"); + } + + @Test + public void testParseOneScope_shouldCreateCollection() { + assertThat(Scope.parseScopes("all_trips")).contains(Scope.ALL_TRIPS); + } + + @Test + public void testParseMultiScopes_shouldCreateCollection() { + assertThat(Scope.parseScopes("history all_trips")).contains(Scope.HISTORY, Scope.ALL_TRIPS); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuth2ServiceTest.java b/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuth2ServiceTest.java new file mode 100644 index 0000000..391e70d --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuth2ServiceTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth.internal; + +import com.github.tomakehurst.wiremock.common.ConsoleNotifier; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.squareup.moshi.Moshi; +import com.uber.sdk.core.auth.AccessToken; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.converter.moshi.MoshiConverterFactory; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.assertj.core.api.Assertions.assertThat; + + +public class OAuth2ServiceTest { + private static final String REFRESH_TOKEN = "RANDOM1234REFRESHTOKEN"; + private static final String CLIENT_ID = "MYCLIENTID123"; + private static final String REQUEST_BODY = "refresh_token=" + REFRESH_TOKEN + "&client_id=" + CLIENT_ID; + + private static WireMockConfiguration WIRE_MOCK_CONFIG = wireMockConfig() + .notifier(new ConsoleNotifier(true)) + .dynamicPort(); + + @Rule + public WireMockRule wireMockRule = new WireMockRule(WIRE_MOCK_CONFIG); + + private OAuth2Service oAuth2Service; + + @Before + public void setUp() throws Exception { + final HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS); + + final OkHttpClient okHttpClient = new OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .build(); + + final Moshi moshi = new Moshi.Builder().add(new OAuthScopesAdapter()).build(); + + oAuth2Service = new Retrofit.Builder().baseUrl("http://localhost:" + wireMockRule.port()) + .client(okHttpClient) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + .create(OAuth2Service.class); + } + + @Test + public void testRefresh_whenSuccessful() throws Exception { + stubFor(post(urlEqualTo("/token")) + .withRequestBody(equalTo(REQUEST_BODY)) + .willReturn(aResponse() + .withBodyFile("token_token.json"))); + + AccessToken accessToken = oAuth2Service.refresh(REFRESH_TOKEN, CLIENT_ID).execute().body(); + + assertThat(accessToken.getExpiresIn()).isEqualTo(2592000); + assertThat(accessToken.getToken()).isEqualTo("Access999Token"); + assertThat(accessToken.getRefreshToken()).isEqualTo("888RefreshToken"); + } +} diff --git a/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapterTest.java b/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapterTest.java new file mode 100644 index 0000000..3570c7f --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/core/auth/internal/OAuthScopesAdapterTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.core.auth.internal; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.uber.sdk.core.auth.AccessToken; +import com.uber.sdk.core.auth.Scope; + +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collection; + +import static org.assertj.core.api.Assertions.assertThat; + +public class OAuthScopesAdapterTest { + private static final String ACCESS_TOKEN = "{" + + "\"last_authenticated\":1464137596," + + "\"access_token\":\"Access999Token\"," + + "\"expires_in\":2592000," + + "\"token_type\":\"Bearer\"," + + "\"scope\":\"request all_trips profile\"," + + "\"refresh_token\":\"888RefreshToken\"" + + "}"; + + private JsonAdapter jsonAdapter; + + @Before + public void setUp() { + Moshi moshi = new Moshi.Builder().add(new OAuthScopesAdapter()).build(); + + jsonAdapter = moshi.adapter(AccessToken.class); + } + + @Test + public void fromJson() throws Exception { + AccessToken accessToken = jsonAdapter.fromJson(ACCESS_TOKEN); + assertThat(accessToken.getToken()).isEqualTo("Access999Token"); + assertThat(accessToken.getExpiresIn()).isEqualTo(2592000); + assertThat(accessToken.getRefreshToken()).isEqualTo("888RefreshToken"); + assertThat(accessToken.getScopes()).contains(Scope.REQUEST, Scope.ALL_TRIPS, Scope.PROFILE); + } + + @Test + public void toJson() throws Exception { + AccessToken accessToken = new AccessToken(2592000, + Arrays.asList(Scope.REQUEST, Scope.ALL_TRIPS, Scope.PROFILE), + "Access999Token", "888RefreshToken", "Bearer"); + + Collection scopes = accessToken.getScopes(); + String json = jsonAdapter.toJson(accessToken); + assertThat(json).containsOnlyOnce("\"scope\":\"" + Scope.toStandardString(scopes) + "\""); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2CredentialsTest.java b/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2CredentialsTest.java index c5b04f6..984836e 100644 --- a/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2CredentialsTest.java +++ b/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2CredentialsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,6 +34,7 @@ import com.google.api.client.testing.json.MockJsonFactory; import com.google.api.client.util.store.AbstractDataStoreFactory; import com.google.api.client.util.store.DataStore; +import com.uber.sdk.core.auth.Scope; import org.junit.Before; import org.junit.Rule; @@ -46,13 +47,12 @@ import java.util.ArrayList; import java.util.Arrays; -import static com.uber.sdk.rides.auth.OAuth2Credentials.LoginRegion.CHINA; +import static com.uber.sdk.rides.client.SessionConfiguration.EndpointRegion.CHINA; import static org.hamcrest.Matchers.any; import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; @@ -78,8 +78,8 @@ public void setUp() { public void getAuthorizationUrl() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST, - OAuth2Credentials.Scope.HISTORY)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST, + Scope.HISTORY)) .build(); assertEquals("https://login.uber.com/oauth/v2/authorize?client_id=CLIENT_ID" @@ -101,7 +101,7 @@ public void getAuthorizationUrl_whenThereAreNoScopes() throws Exception { public void getAuthorizationUrl_whenThereIsAnEmptyScopeList() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") - .setScopes(new ArrayList()) + .setScopes(new ArrayList()) .build(); assertEquals("https://login.uber.com/oauth/v2/authorize?client_id=CLIENT_ID&response_type=code", @@ -112,7 +112,7 @@ public void getAuthorizationUrl_whenThereIsAnEmptyScopeList() throws Exception { public void getAuthorizationUrl_whenThereAreCustomScopes() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE)) + .setScopes(Arrays.asList(Scope.PROFILE)) .setCustomScopes(Arrays.asList("custom")) .build(); @@ -127,7 +127,7 @@ public void getAuthorizationUrl_whenThereAreCustomScopes() throws Exception { public void getAuthorizationUrl_whenThereAreDuplicateCustomScopes() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE)) + .setScopes(Arrays.asList(Scope.PROFILE)) .setCustomScopes(Arrays.asList("profile")) .build(); @@ -140,7 +140,7 @@ public void getAuthorizationUrl_whenThereIsARedirectUri() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") .setRedirectUri("https://localhost:8181/OAuth2Callback") - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE)) + .setScopes(Arrays.asList(Scope.PROFILE)) .setCustomScopes(Arrays.asList("profile")) .build(); @@ -153,8 +153,8 @@ public void getAuthorizationUrl_whenThereIsARedirectUri() throws Exception { public void getAuthorizationUrl_whenUsingServerForChina() throws Exception { OAuth2Credentials oAuth2Credentials = new OAuth2Credentials.Builder() .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST, - OAuth2Credentials.Scope.HISTORY)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST, + Scope.HISTORY)) .setLoginRegion(CHINA) .build(); @@ -217,7 +217,7 @@ public void authenticate() throws Exception { .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") .setRedirectUri("http://redirect") .setHttpTransport(mockHttpTransport) - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST)) .build(); Credential credential = oAuth2Credentials.authenticate(authorizationCode, "userId"); @@ -285,7 +285,7 @@ public void loadCredential() throws Exception { .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") .setRedirectUri("http://redirect") .setHttpTransport(mockHttpTransport) - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST)) .build(); oAuth2Credentials.authenticate("authorizationCode", "userId"); @@ -306,7 +306,7 @@ public void clearCredential() throws Exception { .setClientSecrets("CLIENT_ID", "CLIENT_SECRET") .setRedirectUri("http://redirect") .setHttpTransport(mockHttpTransport) - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST)) .build(); oAuth2Credentials.authenticate("authorizationCode", "userId"); @@ -343,7 +343,7 @@ public void useCustomDataStore() throws Exception { .setRedirectUri("http://redirect") .setHttpTransport(mockHttpTransport) .setCredentialDataStoreFactory(mockDataStoreFactory) - .setScopes(Arrays.asList(OAuth2Credentials.Scope.PROFILE, OAuth2Credentials.Scope.REQUEST)) + .setScopes(Arrays.asList(Scope.PROFILE, Scope.REQUEST)) .build(); Credential storedCredential = oAuth2Credentials.authenticate("authorizationCode", "userId"); @@ -396,7 +396,7 @@ private static class MockHttpTransport extends com.google.api.client.testing.htt private String httpResponseContent = "{\n" + " \"access_token\" : \"accessToken\",\n" + " \"token_type\" : \"Bearer\",\n" + - " \"expires_in\" : " + OAuth2Helper.DEFAULT_REFRESH_WINDOW + ",\n" + + " \"expires_in\" : " + 300L + ",\n" + " \"refresh_token\" : \"refreshToken\"\n" + "}"; diff --git a/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2HelperTest.java b/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2HelperTest.java deleted file mode 100644 index c667ec6..0000000 --- a/sdk/src/test/java/com/uber/sdk/rides/auth/OAuth2HelperTest.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.auth; - -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.ClientParametersAuthentication; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.LowLevelHttpRequest; -import com.google.api.client.http.LowLevelHttpResponse; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.api.client.testing.http.MockLowLevelHttpRequest; -import com.google.api.client.testing.http.MockLowLevelHttpResponse; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.IOException; - -import static junit.framework.TestCase.assertFalse; -import static org.hamcrest.Matchers.isA; -import static org.junit.Assert.assertTrue; - -/** - * Tests for {@link com.uber.sdk.rides.auth.OAuth2Helper}. - */ -public class OAuth2HelperTest { - - private static final String ACCESS_TOKEN = "accessToken"; - private static final String REFRESH_TOKEN = "refreshToken"; - private static final GenericUrl TOKEN_SERVER_URL = new GenericUrl("https://login.uber.com/oauth/v2/token"); - - @Rule public ExpectedException exception = ExpectedException.none(); - - private OAuth2Helper oAuth2Helper; - private Credential credential; - private MockHttpTransport mockHttpTransport; - - @Before - public void setUp() { - mockHttpTransport = new MockHttpTransport(); - credential = - new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()) - .setTransport(mockHttpTransport) - .setJsonFactory(new JacksonFactory()) - .setClientAuthentication(new ClientParametersAuthentication("CLIENT_ID", "CLIENT_SECRET")) - .setTokenServerUrl(TOKEN_SERVER_URL).build(); - oAuth2Helper = new OAuth2Helper(); - } - - @Test - public void refreshCredential_whenNeeded_shouldRefresh() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - assertTrue(oAuth2Helper.refreshCredentialIfNeeded(credential)); - } - - @Test - public void refreshCredential_whenNotNeeded_shouldNotRefresh() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW + 60L); - - assertFalse(oAuth2Helper.refreshCredentialIfNeeded(credential)); - } - - @Test - public void refreshCredential_whenUnknownExpires_shouldNotRefresh() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(null); - - assertFalse(oAuth2Helper.refreshCredentialIfNeeded(credential)); - } - - @Test - public void refreshCredential_whenNeeded_shouldThrowException() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - mockHttpTransport.setHttpStatusCode(404); - mockHttpTransport.setHttpResponseContent("failed"); - - exception.expect(AuthException.class); - exception.expectCause(isA(IOException.class)); - - oAuth2Helper.refreshCredentialIfNeeded(credential); - } - - @Test - public void refreshCredential_whenNeeded_shouldReturnFalse() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - mockHttpTransport.setHttpStatusCode(500); - - assertFalse(oAuth2Helper.refreshCredentialIfNeeded(credential)); - } - - @Test - public void shouldRefreshCredential_whenNeeded() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - assertTrue(oAuth2Helper.shouldRefreshCredential(credential)); - } - - @Test - public void shouldRefreshCredential_whenNoRefreshToken_shouldReturnFalse() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(null); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - assertFalse(oAuth2Helper.shouldRefreshCredential(credential)); - } - - @Test - public void shouldRefreshCredential_whenNotNeeded_shouldReturnFalse() throws Exception { - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(null); - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW + 60L); - - assertFalse(oAuth2Helper.shouldRefreshCredential(credential)); - } - - private static class MockHttpTransport extends com.google.api.client.testing.http.MockHttpTransport { - - private int httpStatusCode = 200; - private String httpResponseContent = "{\n" + - " \"access_token\" : \"accessToken2\",\n" + - " \"token_type\" : \"Bearer\",\n" + - " \"expires_in\" : " + OAuth2Helper.DEFAULT_REFRESH_WINDOW + ",\n" + - " \"refresh_token\" : \"refreshToken2\"\n" + - "}"; - - public void setHttpStatusCode(int httpStatusCode) { - this.httpStatusCode = httpStatusCode; - } - - public void setHttpResponseContent(String httpResponseContent) { - this.httpResponseContent = httpResponseContent; - } - - @Override - public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException { - return new MockLowLevelHttpRequest() { - - @Override - public String getUrl() { - return url; - } - - @Override - public LowLevelHttpResponse execute() throws IOException { - MockLowLevelHttpResponse mock = new MockLowLevelHttpResponse(); - mock.setStatusCode(httpStatusCode); - mock.setContent(httpResponseContent); - return mock; - } - }; - } - } -} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/SessionConfigurationTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/SessionConfigurationTest.java new file mode 100644 index 0000000..394f3f1 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/SessionConfigurationTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client; + +import com.uber.sdk.core.auth.Scope; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import static com.uber.sdk.rides.client.SessionConfiguration.EndpointRegion.CHINA; +import static com.uber.sdk.rides.client.SessionConfiguration.Environment.PRODUCTION; +import static com.uber.sdk.rides.client.SessionConfiguration.Environment.SANDBOX; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +public class SessionConfigurationTest { + @Test + public void getClientId_whenSetOnBuilder_setsOnConfiguration() throws Exception { + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .build(); + + assertEquals("clientId", config.getClientId()); + } + + @Test + public void getRedirectUri_whenSetOnBuilder_setsOnConfiguration() throws Exception { + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .setRedirectUri("redirectUri") + .build(); + assertEquals("redirectUri", config.getRedirectUri()); + } + + @Test + public void getEndpointRegion_whenSetOnBuilder_setsOnConfiguration() throws Exception { + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .setEndpointRegion(CHINA) + .build(); + assertEquals(CHINA, config.getEndpointRegion()); + } + + @Test + public void getEnvironment_whenSetOnBuilder_setsOnConfiguration() throws Exception { + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .setEnvironment(SANDBOX) + .build(); + assertEquals(SANDBOX, config.getEnvironment()); + } + + @Test + public void getScopes_whenSetOnBuilder_setsOnConfiguration() throws Exception { + List scopes = Arrays.asList(Scope.ALL_TRIPS, Scope.HISTORY); + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .setScopes(scopes) + .build(); + assertTrue(scopes.containsAll(config.getScopes())); + } + + @Test + public void newBuilder_copiesConfiguration() throws Exception { + SessionConfiguration config = new SessionConfiguration.Builder() + .setClientId("clientId") + .setRedirectUri("test") + .build(); + + SessionConfiguration config2 = config.newBuilder().setClientId("clientId2").build(); + + assertEquals("clientId", config.getClientId()); + assertEquals("clientId2", config2.getClientId()); + assertEquals("test", config2.getRedirectUri()); + } + + @Test(expected = NullPointerException.class) + public void testBuilder_noClientId_throwsException() { + new SessionConfiguration.Builder().build(); + } + + @Test + public void testBuilder_withClientId_doesNotThrowError() { + new SessionConfiguration.Builder().setClientId("clientId").build(); + } + + @Test + public void buildSession_whenLocalizationProvided_shouldSucceed() throws Exception { + new SessionConfiguration.Builder().setEnvironment(PRODUCTION) + .setClientId("clientId") + .setLocale(new Locale("sv", "SE")) + .build(); + } + + @Test + public void buildSession_whenNoEnvironmentSupplied_shouldUseProduction() throws Exception { + SessionConfiguration sessionConfig = new SessionConfiguration.Builder() + .setClientId("clientId") + .build(); + assertEquals(SessionConfiguration.Environment.PRODUCTION, sessionConfig.getEnvironment()); + } + + @Test + public void buildSession_whenProductionEnvAndNotChina_shouldGiveNonCnProductionEndpointHost() throws Exception { + SessionConfiguration sessionConfig = new SessionConfiguration.Builder() + .setClientId("clientId") + .setEnvironment(PRODUCTION).build(); + assertEquals("https://api.uber.com", sessionConfig.getEndpointHost()); + } + + @Test + public void buildSession_whenSandboxEnvAndNotChina_shouldGiveNonCnSandboxEndpointHost() throws Exception { + SessionConfiguration sessionConfig = new SessionConfiguration.Builder() + .setClientId("clientId") + .setEnvironment(SANDBOX).build(); + assertEquals("https://sandbox-api.uber.com", sessionConfig.getEndpointHost()); + } + + @Test + public void buildSession_whenProductionEnvAndInChina_shouldGiveChinaProductionEndpointHost() throws Exception { + SessionConfiguration sessionConfig = new SessionConfiguration.Builder() + .setClientId("clientId") + .setEnvironment(PRODUCTION) + .setEndpointRegion(CHINA) + .build(); + assertEquals("https://api.uber.com.cn", sessionConfig.getEndpointHost()); + } + + @Test + public void buildSession_whenSandboxEnvAndInChina_shouldGiveChinaSandboxEndpointHost() throws Exception { + SessionConfiguration sessionConfig = new SessionConfiguration.Builder().setEnvironment(SANDBOX) + .setClientId("clientId") + .setEndpointRegion(CHINA) + .build(); + assertEquals("https://sandbox-api.uber.com.cn", sessionConfig.getEndpointHost()); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/SessionTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/SessionTest.java index ae1aa76..e838872 100644 --- a/sdk/src/test/java/com/uber/sdk/rides/client/SessionTest.java +++ b/sdk/src/test/java/com/uber/sdk/rides/client/SessionTest.java @@ -1,112 +1,41 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client; -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.ClientParametersAuthentication; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.json.jackson2.JacksonFactory; +import com.uber.sdk.core.auth.Authenticator; -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; -import static com.uber.sdk.rides.client.Session.EndpointRegion.CHINA; -import static com.uber.sdk.rides.client.Session.Environment.PRODUCTION; -import static com.uber.sdk.rides.client.Session.Environment.SANDBOX; import static org.junit.Assert.assertEquals; - -import java.util.Locale; +import static org.mockito.Mockito.mock; public class SessionTest { - private static final GenericUrl TOKEN_SERVER_URL = new GenericUrl("https://login.uber.com/oauth/v2/token"); - - @Rule public ExpectedException exception = ExpectedException.none(); - - private Credential credential; - - @Before - public void setUp() throws Exception { - credential = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()) - .setJsonFactory(new JacksonFactory()) - .setClientAuthentication(new ClientParametersAuthentication("CLIENT_ID", "CLIENT_SECRET")) - .setTokenServerUrl(TOKEN_SERVER_URL) - .build(); - credential.setAccessToken("accessToken"); - } - - @Test - public void buildSession_whenCredentialIsSuppliedAndNoServerToken_shouldSucceed() throws Exception { - new Session.Builder().setEnvironment(PRODUCTION).setCredential(credential).build(); - } - - @Test - public void buildSession_whenServerTokenIsSuppliedAndNoCredential_shouldSucceed() throws Exception { - new Session.Builder().setEnvironment(PRODUCTION).setServerToken("serverToken").build(); - } - - @Test - public void buildSession_whenLocalizationProvided_shouldSucceed() throws Exception { - new Session.Builder().setEnvironment(PRODUCTION) - .setServerToken("serverToken") - .setAcceptLanguage(new Locale("sv", "SE")) - .build(); - } - - @Test - public void buildSession_whenNoCredentialOrServerToken_shouldFail() throws Exception { - exception.expect(IllegalStateException.class); - exception.expectMessage("An OAuth 2.0 credential or a server token is required to create a session."); - - new Session.Builder().setEnvironment(PRODUCTION).build(); - } - - @Test - public void buildSession_whenBothCredentialAndServerToken_shouldFail() throws Exception { - exception.expect(IllegalStateException.class); - exception.expectMessage("Session must have either an OAuth 2.0 credential or a server token, not both."); - - new Session.Builder().setEnvironment(PRODUCTION) - .setCredential(credential) - .setServerToken("serverToken").build(); - } - - @Test - public void buildSession_whenNoEnvironmentSupplied_shouldFail() throws Exception { - exception.expect(IllegalStateException.class); - exception.expectMessage("Must supply an Environment"); - - new Session.Builder().setCredential(credential).build(); - } - - @Test - public void buildSession_whenProductionEnvAndNotChina_shouldGiveNonCnProductionEndpointHost() throws Exception { - Session session = new Session.Builder().setEnvironment(PRODUCTION).setCredential(credential).build(); - assertEquals("https://api.uber.com", session.getEndpointHost()); - } - - @Test - public void buildSession_whenSandboxEnvAndNotChina_shouldGiveNonCnSandboxEndpointHost() throws Exception { - Session session = new Session.Builder().setEnvironment(SANDBOX).setCredential(credential).build(); - assertEquals("https://sandbox-api.uber.com", session.getEndpointHost()); - } - - @Test - public void buildSession_whenProductionEnvAndInChina_shouldGiveChinaProductionEndpointHost() throws Exception { - Session session = new Session.Builder().setEnvironment(PRODUCTION) - .setCredential(credential) - .setEndpointRegion(CHINA) - .build(); - assertEquals("https://api.uber.com.cn", session.getEndpointHost()); - } - @Test - public void buildSession_whenSandboxEnvAndInChina_shouldGiveChinaSandboxEndpointHost() throws Exception { - Session session = new Session.Builder().setEnvironment(SANDBOX) - .setCredential(credential) - .setEndpointRegion(CHINA) - .build(); - assertEquals("https://sandbox-api.uber.com.cn", session.getEndpointHost()); + public void buildSession_containsMembersFromConstructor() throws Exception { + Authenticator authenticator = mock(Authenticator.class); + SessionConfiguration configuration = mock(SessionConfiguration.class); + Session session = new Session(authenticator) { }; + assertEquals(authenticator, session.getAuthenticator()); } } diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesApiTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesApiTest.java new file mode 100644 index 0000000..185ff9a --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesApiTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client; + +import com.uber.sdk.core.auth.Authenticator; +import com.uber.sdk.rides.client.internal.ApiInterceptor; +import com.uber.sdk.rides.client.internal.RefreshAuthenticator; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Locale; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class UberRidesApiTest { + + @Mock + Session session; + + @Mock + Authenticator authenticator; + + @Mock + SessionConfiguration config; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + when(session.getAuthenticator()).thenReturn(authenticator); + when(authenticator.getSessionConfiguration()).thenReturn(config); + when(config.getLocale()).thenReturn(Locale.US); + when(config.getEndpointHost()).thenReturn("http://api.uber.com"); + } + + @Test + public void createLoggingInterceptor_containsLogLevel() { + HttpLoggingInterceptor loggingInterceptor = UberRidesApi.with(session) + .createLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT, + HttpLoggingInterceptor.Level.BASIC); + assertEquals(HttpLoggingInterceptor.Level.BASIC, loggingInterceptor.getLevel()); + assertEquals(HttpLoggingInterceptor.Level.BASIC, loggingInterceptor.getLevel()); + } + + @Test + public void createClient_setsSessionAndLoggingInterceptor() { + HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); + OkHttpClient client = UberRidesApi.with(session) + .createClient(new OkHttpClient(), session, loggingInterceptor); + + assertEquals(authenticator, + ((RefreshAuthenticator) client.authenticator()).authenticator); + + for (Interceptor interceptor : client.interceptors()) { + if (interceptor instanceof ApiInterceptor) { + assertEquals(authenticator, ((ApiInterceptor)interceptor).authenticator); + } else if (interceptor instanceof HttpLoggingInterceptor){ + assertEquals(loggingInterceptor, interceptor); + } else { + fail("Interceptors did not match expected ones"); + } + } + } + + @Test + public void setOkHttpClient_isSetAndCallsNewBuilderDuringConstruction() throws Exception { + OkHttpClient client = mock(OkHttpClient.class); + when(client.newBuilder()).thenReturn(new OkHttpClient.Builder()); + + UberRidesApi.Builder builder = UberRidesApi.with(session).setOkHttpClient(client); + builder.build(); + verify(client).newBuilder(); + assertEquals(client, builder.client); + } + + @Test + public void setOkHttpClient_whenNull_returnsNewClient() { + UberRidesApi.Builder builder = UberRidesApi.with(session); + builder.build(); + assertNotNull(builder.client); + } + + @Test + public void setLogger_isSetAfterBuild() { + HttpLoggingInterceptor.Logger logger = HttpLoggingInterceptor.Logger.DEFAULT; + UberRidesApi.Builder builder = UberRidesApi.with(session).setLogger(logger); + builder.build(); + assertEquals(logger, builder.logger); + } + + @Test + public void setLogger_whenNull_returnsDefaultLogger() { + UberRidesApi.Builder builder = UberRidesApi.with(session); + builder.build(); + assertEquals(HttpLoggingInterceptor.Logger.DEFAULT, builder.logger); + } + + @Test + public void setLogLevel_isSetAfterBuild() { + HttpLoggingInterceptor.Level level= HttpLoggingInterceptor.Level.BASIC; + UberRidesApi.Builder builder = UberRidesApi.with(session).setLogLevel(level); + builder.build(); + assertEquals(level, builder.logLevel); + } + + @Test + public void setLogLevel_whenNull_returnsNoLogging() { + UberRidesApi.Builder builder = UberRidesApi.with(session); + builder.build(); + assertEquals(HttpLoggingInterceptor.Level.NONE, builder.logLevel); + } + + @Test + public void build_withOnlySession_completesSuccesfully() throws Exception { + assertNotNull(UberRidesApi.with(session).build()); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesServicesTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesServicesTest.java deleted file mode 100644 index 32d8d98..0000000 --- a/sdk/src/test/java/com/uber/sdk/rides/client/UberRidesServicesTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client; - -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.ClientParametersAuthentication; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.common.base.Function; -import com.google.common.collect.Lists; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; - -import javax.annotation.Nullable; - -import static com.uber.sdk.rides.client.Session.Environment.PRODUCTION; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; - -/** - * Tests {@link UberRidesServices}. - */ -public class UberRidesServicesTest { - - private static final GenericUrl TOKEN_SERVER_URL = new GenericUrl("https://login.uber.com/oauth/token"); - - @Rule public ExpectedException exception = ExpectedException.none(); - - private Credential credential; - private Session session; - - @Before - public void setUp() throws Exception { - credential = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()) - .setTransport(new NetHttpTransport()) - .setJsonFactory(new JacksonFactory()) - .setClientAuthentication(new ClientParametersAuthentication("CLIENT_ID", "CLIENT_SECRET")) - .setTokenServerUrl(TOKEN_SERVER_URL) - .build(); - - credential.setAccessToken("accessToken"); - credential.setRefreshToken("refreshToken"); - credential.setExpiresInSeconds(3600L); - - session = new Session.Builder().setEnvironment(PRODUCTION).setCredential(credential).build(); - } - - @Test - public void buildUberApiSyncService_whenSessionIsSupplied_shouldSucceed() throws Exception { - UberRidesServices.Builder.sync().setSession(session).build(); - } - - @Test - public void buildUberApiAsyncService_whenSessionIsSupplied_shouldSucceed() throws Exception { - UberRidesServices.Builder.async().setSession(session).build(); - } - - @Test - public void buildUberApiSyncServiceWithStatic_whenSessionIsSupplied_shouldSucceed() throws Exception { - UberRidesSyncService uberApiSyncService = UberRidesServices.createSync(session); - } - - @Test - public void buildUberApiAsyncServiceWithStatic_whenSessionIsSupplied_shouldSucceed() throws Exception { - UberRidesAsyncService uberApiAsyncService = UberRidesServices.createAsync(session); - } - - @Test - public void buildUberApiSyncService_whenNoSessionSupplied_shouldFail() throws Exception { - exception.expect(NullPointerException.class); - exception.expectMessage("A session is required to create a service."); - - UberRidesServices.Builder.sync().build(); - } - - @Test - public void buildUberApiAsyncService_whenNoSessionSupplied_shouldFail() throws Exception { - exception.expect(NullPointerException.class); - exception.expectMessage("A session is required to create a service."); - - UberRidesServices.Builder.async().build(); - } - - @Test - public void buildUberApiSyncService_whenSessionIsNull_shouldFail() throws Exception { - exception.expect(NullPointerException.class); - exception.expectMessage("A session is required to create a service."); - - UberRidesServices.Builder.sync().setSession(null).build(); - } - - @Test - public void buildUberApiAsyncService_whenSessionIsNull_shouldFail() throws Exception { - exception.expect(NullPointerException.class); - exception.expectMessage("A session is required to create a service."); - - UberRidesServices.Builder.async().setSession(null).build(); - } - - @Test - public void buildUberApiSyncService_whenNoLogLevel_shouldDefaultToNone() { - UberRidesServices uberRidesServices = UberRidesServices.Builder.sync().setSession(session).buildUberApiServices(); - - assertEquals(UberRidesServices.LogLevel.NONE, uberRidesServices.getLogLevel()); - } - - @Test - public void buildUberApiAsyncService_whenNoLogLevel_shouldDefaultToNone() { - UberRidesServices uberRidesServices = UberRidesServices.Builder.async().setSession(session).buildUberApiServices(); - - assertEquals(UberRidesServices.LogLevel.NONE, uberRidesServices.getLogLevel()); - } - - @Test - public void buildUberApiSyncService_whenNullLogLevel_shouldDefaultToNone() { - UberRidesServices uberRidesServices = UberRidesServices.Builder.sync() - .setSession(session) - .setLogLevel(null) - .buildUberApiServices(); - - assertEquals(UberRidesServices.LogLevel.NONE, uberRidesServices.getLogLevel()); - } - - @Test - public void buildUberApiAsyncService_whenNullLogLevel_shouldDefaultToNone() { - UberRidesServices uberRidesServices = UberRidesServices.Builder.async() - .setSession(session) - .setLogLevel(null) - .buildUberApiServices(); - - assertEquals(UberRidesServices.LogLevel.NONE, uberRidesServices.getLogLevel()); - } - - @Test - public void serviceMethodParity() { - List syncMethods = Lists.transform( - Arrays.asList(UberRidesSyncService.class.getMethods()), - new Function() { - @Nullable - @Override - public String apply(Method input) { - return input.getName(); - } - }); - - List asyncMethods = Lists.transform( - Arrays.asList(UberRidesAsyncService.class.getMethods()), - new Function() { - @Nullable - @Override - public String apply(Method input) { - return input.getName(); - } - }); - - assertThat(syncMethods, is(asyncMethods)); - } -} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/error/ErrorParserTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/error/ErrorParserTest.java new file mode 100644 index 0000000..91a9526 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/error/ErrorParserTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.error; + +import org.junit.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +public class ErrorParserTest { + + @Test + public void parseError_whenSuccessfulResponse_shouldReturnNull() { + ApiError apiError = ErrorParser.parseError(null, 404, "Not Found"); + assertThat(apiError.getMeta()).isNull(); + + assertError(apiError.getClientErrors(), null, 404, "Not Found"); + } + + @Test + public void parseError_whenOldError_shouldReturnProperApiError() { + String body = "{\"message\":\"Unable to find product thisIsNotAProductId\",\"code\":\"not_found\"}"; + ApiError apiError = ErrorParser.parseError(body, 404, "Not Found"); + assertThat(apiError.getMeta()).isNull(); + assertError(apiError.getClientErrors(), "not_found", 404, "Unable to find product thisIsNotAProductId"); + } + + @Test + public void parseError_whenErrorWithEmptyMeta_shouldReturnErrorWithMetaButNoCofirmation() { + String body = "{\"meta\":{},\"errors\":[{\"status\":404,\"code\":\"unknown_place_id\",\"title\":\"Only " + + "\\\"home\\\" and \\\"work\\\" are allowed.\"}]}"; + ApiError apiError = ErrorParser.parseError(body, 404, "Not Found"); + assertThat(apiError.getMeta().getSurgeConfirmation()).isNull(); + assertError(apiError.getClientErrors(), "unknown_place_id", 404, "Only \"home\" and \"work\" are allowed."); + } + + @Test + public void parseError_whenErrorWithSurge_shouldReturnFullError() { + String body = "{\"meta\":{\"surge_confirmation\":{\"href\":\"https:\\/\\/api.uber.com\\/v1\\/surge-confirmations\\/a9ca7bf4-315c-4a8d-86a4-1697b7b94de4\",\"expires_at\":1464118311,\"multiplier\":2.1,\"surge_confirmation_id\":\"a9ca7bf4-315c-4a8d-86a4-1697b7b94de4\"}},\"errors\":[{\"status\":409,\"code\":\"surge\",\"title\":\"Surge pricing is currently in effect for this product.\"}]}"; + ApiError apiError = ErrorParser.parseError(body, 409, "Unavailable"); + + SurgeConfirmation surgeConfirmation = apiError.getMeta().getSurgeConfirmation(); + assertThat(surgeConfirmation.getHref()).isEqualTo("https://api.uber.com/v1/surge-confirmations/a9ca7bf4-315c-4a8d-86a4-1697b7b94de4"); + assertThat(surgeConfirmation.getMultiplier()).isEqualTo(2.1f); + assertThat(surgeConfirmation.getExpiresAt()).isEqualTo(1464118311); + assertThat(surgeConfirmation.getSurgeConfirmationId()).isEqualTo("a9ca7bf4-315c-4a8d-86a4-1697b7b94de4"); + + assertError(apiError.getClientErrors(), "surge", 409, "Surge pricing is currently in effect for this product."); + } + + @Test + public void parseError_whenUnknownError_shouldReturnKnownError() { + String body = "{\"error\":\"This is not a supported Error\",\"random\":\"random field\"}"; + ApiError apiError = ErrorParser.parseError(body, 416, "ThisWasTheHttpMessage"); + + assertError(apiError.getClientErrors(), null, 416, "Unknown Error"); + } + + private void assertError(List clientErrors, String code, int status, String title) { + assertThat(clientErrors).hasSize(1); + ClientError clientError = clientErrors.get(0); + assertThat(clientError.getCode()).isEqualTo(code); + assertThat(clientError.getStatus()).isEqualTo(status); + assertThat(clientError.getTitle()).isEqualTo(title); + } +} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/ApiInterceptorTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/ApiInterceptorTest.java new file mode 100644 index 0000000..906df39 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/internal/ApiInterceptorTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.internal; + +import com.uber.sdk.core.auth.Authenticator; +import com.uber.sdk.rides.client.SessionConfiguration; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Locale; + +import okhttp3.Interceptor; +import okhttp3.Request; + +import static com.uber.sdk.rides.client.internal.ApiInterceptor.HEADER_ACCESS_TOKEN; +import static com.uber.sdk.rides.client.internal.ApiInterceptor.LIB_VERSION; +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class ApiInterceptorTest { + + @Mock + Authenticator authenticator; + + @Mock + Interceptor.Chain chain; + + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + } + + @Test + public void testIntercept() throws Exception { + ArgumentCaptor captor = ArgumentCaptor.forClass(Request.class); + ApiInterceptor interceptor = new ApiInterceptor(authenticator); + when(chain.request()).thenReturn(new Request.Builder().url("http://test").build()); + when(chain.proceed(captor.capture())).thenReturn(null); + SessionConfiguration config = mock(SessionConfiguration.class); + when(config.getLocale()).thenReturn(Locale.US); + when(authenticator.getSessionConfiguration()).thenReturn(config); + + interceptor.intercept(chain); + + verify(authenticator).signRequest(any(Request.Builder.class)); + Request request = captor.getValue(); + assertEquals(Locale.US.getLanguage(), request.headers().get(ApiInterceptor.HEADER_ACCEPT_LANGUAGE)); + assertEquals("Java Rides SDK v" + LIB_VERSION, request.headers().get(ApiInterceptor.HEADER_USER_AGENT)); + } + + @Test + public void testSetAuthorizationHeader_withExistingToken() { + Request.Builder builder = new Request.Builder().url("http://test"); + builder.header(HEADER_ACCESS_TOKEN, "accessToken"); + ApiInterceptor.setAuthorizationHeader(builder, "accessToken2"); + Request request = builder.build(); + assertEquals("accessToken2", request.header(HEADER_ACCESS_TOKEN)); + } + + @Test + public void testSetAuthorizationHeader_withoutExistingToken() { + Request.Builder builder = new Request.Builder().url("http://test"); + ApiInterceptor.setAuthorizationHeader(builder, "accessToken"); + Request request = builder.build(); + assertEquals("accessToken", request.header(HEADER_ACCESS_TOKEN)); + } + + @Test + public void testGetAuthorizationHeader() { + Request request = new Request.Builder() + .url("http://test") + .header(HEADER_ACCESS_TOKEN, "accessToken") + .build(); + + assertEquals("accessToken", ApiInterceptor.getAuthorizationHeader(request)); + } + +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveAdapterTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveAdapterTest.java new file mode 100644 index 0000000..6a93921 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveAdapterTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.uber.sdk.rides.client.internal; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; + +import org.junit.Test; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PrimitiveAdapterTest { + + @Test + public void fromJson_whenNull_shouldGoToZero() throws IOException { + Moshi moshi = new Moshi.Builder().add(new PrimitiveAdapter()).build(); + + JsonAdapter adapter = moshi.adapter(PrimitiveModel.class); + PrimitiveModel model = adapter.fromJson("{\"someint\":null,\"somefloat\":null,\"somelong\":null}"); + assertThat(model.getSomeint()).isZero(); + assertThat(model.getSomefloat()).isZero(); + assertThat(model.getSomelong()).isZero(); + } + + @Test + public void fromJson_whenValueProvided_shouldReturnValue() throws IOException { + Moshi moshi = new Moshi.Builder().add(new PrimitiveAdapter()).build(); + + JsonAdapter adapter = moshi.adapter(PrimitiveModel.class); + PrimitiveModel model = adapter.fromJson("{\"someint\":1,\"somefloat\":1.0,\"somelong\":11}"); + assertThat(model.getSomeint()).isEqualTo(1); + assertThat(model.getSomefloat()).isEqualTo(1.0f); + assertThat(model.getSomelong()).isEqualTo(11l); + } +} diff --git a/sdk/src/main/java/com/uber/sdk/rides/client/error/UberError.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveModel.java similarity index 73% rename from sdk/src/main/java/com/uber/sdk/rides/client/error/UberError.java rename to sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveModel.java index 0b9685a..75ad750 100644 --- a/sdk/src/main/java/com/uber/sdk/rides/client/error/UberError.java +++ b/sdk/src/test/java/com/uber/sdk/rides/client/internal/PrimitiveModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Uber Technologies, Inc. + * Copyright (c) 2016 Uber Technologies, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -20,10 +20,23 @@ * THE SOFTWARE. */ -package com.uber.sdk.rides.client.error; +package com.uber.sdk.rides.client.internal; -/** - * Represents an error returned in the response. - */ -public interface UberError { +public class PrimitiveModel { + + private int someint; + private float somefloat; + private long somelong; + + public int getSomeint() { + return someint; + } + + public float getSomefloat() { + return somefloat; + } + + public long getSomelong() { + return somelong; + } } diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RefreshAuthenticatorTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/RefreshAuthenticatorTest.java new file mode 100644 index 0000000..b081536 --- /dev/null +++ b/sdk/src/test/java/com/uber/sdk/rides/client/internal/RefreshAuthenticatorTest.java @@ -0,0 +1,92 @@ +package com.uber.sdk.rides.client.internal; + +import com.uber.sdk.core.auth.Authenticator; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +public class RefreshAuthenticatorTest { + + @Mock + Authenticator authenticator; + + Request request; + + Response response; + + RefreshAuthenticator refreshAuthenticator; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + + request = new Request.Builder().url("http://test").build(); + response = new Response.Builder() + .request(request) + .code(200) + .protocol(Protocol.HTTP_1_1) + .build(); + + refreshAuthenticator = spy(new RefreshAuthenticator(authenticator)); + } + + @Test + public void testAuthenticate_canReAuthAndRetry_callsRefresh() throws Exception { + doReturn(new Request.Builder().url("http://test").build()).when(authenticator).refresh(eq(response)); + doReturn(true).when(authenticator).isRefreshable(); + doReturn(true).when(refreshAuthenticator).canRetry(eq(response)); + + assertNotNull(refreshAuthenticator.authenticate(null, response)); + verify(authenticator).refresh(eq(response)); + } + + @Test + public void testAuthenticate_canReAuthButCannotRetry_callsRefresh() throws Exception { + doReturn(true).when(authenticator).isRefreshable(); + doReturn(false).when(refreshAuthenticator).canRetry(eq(response)); + + assertNull(refreshAuthenticator.authenticate(null, response)); + verify(authenticator, never()).refresh(eq(response)); + } + + @Test + public void testAuthenticate_cannotReAuthButCanRetry_callsRefresh() throws Exception { + doReturn(false).when(authenticator).isRefreshable(); + doReturn(true).when(refreshAuthenticator).canRetry(eq(response)); + + assertNull(refreshAuthenticator.authenticate(null, response)); + verify(authenticator, never()).refresh(eq(response)); + } + + @Test + public void testCanRetry_whenUnderMax_returnsTrue() throws Exception { + Response underMax = response.newBuilder().priorResponse(response).build(); + assertTrue(refreshAuthenticator.canRetry(underMax)); + } + + @Test + public void testCanRetry_whenOverMax_returnsFalse() throws Exception { + Response wrapper1 = response.newBuilder().priorResponse(response).build(); + Response wrapper2 = wrapper1.newBuilder().priorResponse(wrapper1).build(); + Response wrapper3 = wrapper2.newBuilder().priorResponse(wrapper2).build(); + Response wrapper4 = wrapper3.newBuilder().priorResponse(wrapper3).build(); + + assertFalse(refreshAuthenticator.canRetry(wrapper4)); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitAdapterTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitAdapterTest.java deleted file mode 100644 index ba587c8..0000000 --- a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitAdapterTest.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client.internal; - -import com.google.common.io.Files; -import com.uber.sdk.rides.client.error.ClientError; -import com.uber.sdk.rides.client.error.SurgeError; -import com.uber.sdk.rides.client.error.UberError; - -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; - -import static com.uber.sdk.rides.client.internal.RetrofitAdapter.InternalCallback.getErrors; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class RetrofitAdapterTest { - - @Test - public void onGetErrors_whenSimpleError_parseSingleClientError() throws Exception { - String errorBody = readFile("src/test/resources/mockresponses/simple_error_body"); - - List errors = getErrors(errorBody); - assertEquals("Parsed more than one error", 1, errors.size()); - UberError uberError = errors.get(0); - assertTrue("Error is not a ClientError", uberError instanceof ClientError); - ClientError clientError = (ClientError) uberError; - assertEquals("Error code did not match body", "not_found", clientError.getCode()); - assertEquals("Error message did not match body", "Unable to find product notAProductId", clientError.getMessage()); - } - - @Test - public void onGetErrors_whenSurgeError_parseSurgeError() throws IOException { - String errorBody = readFile("src/test/resources/mockresponses/surge_error_body"); - - List errors = getErrors(errorBody); - assertEquals("Parsed more than one error", 1, errors.size()); - UberError uberError = errors.get(0); - assertTrue(uberError instanceof SurgeError); - SurgeError surgeError = (SurgeError) uberError; - assertEquals("Error code did not match body", "surge", surgeError.getCode()); - assertEquals("Error message did not match body", "Surge pricing is currently in effect for this product.", - surgeError.getMessage()); - assertEquals("SurgeConfirmation href did not match", "https://api.uber.com/v1/surge-confirmations/e100a670", - surgeError.getHref()); - assertEquals("SurgeConfirmatoin id did not match", "e100a670", - surgeError.getSurgeConfirmationId()); - } - - private String readFile(String path) throws IOException { - File file = new File(path); - if (!file.exists()) { - file = new File("sdk/" + path); - } - return Files.toString(file, StandardCharsets.UTF_8); - } -} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientIntegrationTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientIntegrationTest.java deleted file mode 100644 index 38f5d2b..0000000 --- a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientIntegrationTest.java +++ /dev/null @@ -1,970 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client.internal; - -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.ClientParametersAuthentication; -import com.google.api.client.auth.oauth2.Credential; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.http.javanet.NetHttpTransport; -import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.common.io.Files; -import com.google.common.util.concurrent.SettableFuture; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.mockwebserver.MockResponse; -import com.squareup.okhttp.mockwebserver.MockWebServer; -import com.squareup.okhttp.mockwebserver.RecordedRequest; -import com.squareup.okhttp.mockwebserver.SocketPolicy; -import com.uber.sdk.rides.auth.OAuth2Helper; -import com.uber.sdk.rides.client.Callback; -import com.uber.sdk.rides.client.Response; -import com.uber.sdk.rides.client.Session; -import com.uber.sdk.rides.client.UberRidesAsyncService; -import com.uber.sdk.rides.client.UberRidesServices; -import com.uber.sdk.rides.client.UberRidesSyncService; -import com.uber.sdk.rides.client.error.ApiException; -import com.uber.sdk.rides.client.error.ClientError; -import com.uber.sdk.rides.client.error.NetworkException; -import com.uber.sdk.rides.client.error.UberError; -import com.uber.sdk.rides.client.model.Product; -import com.uber.sdk.rides.client.model.ProductsResponse; -import com.uber.sdk.rides.client.model.Ride; -import com.uber.sdk.rides.client.model.RideEstimate; -import com.uber.sdk.rides.client.model.RideRequestParameters; -import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; -import com.uber.sdk.rides.client.model.UserProfile; - -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import java.io.File; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -import static com.uber.sdk.rides.client.Session.Environment.PRODUCTION; -import static com.uber.sdk.rides.client.Session.Environment.SANDBOX; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * Integration test for the Uber API client. - */ -public class RetrofitUberRidesClientIntegrationTest { - - private static final String ACCESS_TOKEN = "accessToken"; - private static final String REFRESH_TOKEN = "refreshToken"; - private static final float START_LAT = 37.613f; - private static final float START_LONG = -122.477f; - private static final float END_LAT = 37.808f; - private static final float END_LONG = -122.416f; - - @Rule public ExpectedException exception = ExpectedException.none(); - - private Credential credential; - private Session sandboxSession; - private MockWebServer server; - private OkHttpClient okHttpClient; - private String endpointHost; - private UberRidesAsyncService uberApiAsyncService; - private UberRidesSyncService uberApiSyncService; - - @Before - public void setUp() throws Exception { - server = new MockWebServer(); - - server.start(); - - endpointHost = server.url("").toString(); - - credential = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()) - .setTransport(new NetHttpTransport()) - .setJsonFactory(new JacksonFactory()) - .setClientAuthentication(new ClientParametersAuthentication("CLIENT_ID", "CLIENT_SECRET")) - .setTokenServerUrl(new GenericUrl(endpointHost)) - .build(); - - credential.setAccessToken(ACCESS_TOKEN); - credential.setRefreshToken(REFRESH_TOKEN); - credential.setExpiresInSeconds(3600L); - - sandboxSession = new Session.Builder() - .setCredential(credential) - .setEnvironment(SANDBOX) - .build(); - - okHttpClient = new OkHttpClient(); - - uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - okHttpClient, RetrofitUberRidesService.class); - - uberApiSyncService = (UberRidesSyncService) uberApiAsyncService; - } - - @After - public void tearDown() throws IOException { - server.shutdown(); - } - - @Test - public void onGet_whenAsyncHappyPath_shouldSucceed() throws Exception { - String body = readFile("src/test/resources/mockresponses/get_products_response"); - - server.enqueue(new MockResponse().setBody(body)); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getProducts(37.613f, -122.477f, new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertProductsWithCredential(server.takeRequest(), response.response, - response.apiException, response.networkException); - } - - @Test - public void onGet_whenSyncHappyPath_shouldSucceed() throws Exception { - String body = readFile("src/test/resources/mockresponses/get_products_response"); - - server.enqueue(new MockResponse().setBody(body)); - - Response response = uberApiSyncService.getProducts(37.613f, -122.477f); - - assertProductsWithCredential(server.takeRequest(), response, null, null); - } - - private static void assertProductsWithCredential(RecordedRequest request, Response response, - ApiException apiException, - NetworkException networkException) { - assertNotNull(response); - assertNull(apiException); - assertNull(networkException); - - ProductsResponse productsResponse = response.getBody(); - assertNotNull(productsResponse); - - assertEquals("Request Path does not match", "/v1/products?latitude=37.613&longitude=-122.477", - request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "GET", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); - assertEquals("Response reason does not match", "OK", response.getReason()); - - List products = productsResponse.getProducts(); - - assertThat("Request body does not match", products, - Matchers.hasItems( - allOf(hasProperty("productId", is("04a497f5-380d-47f2-bf1b-ad4cfdcb51f2")), - hasProperty("displayName", is("uberX")), - hasProperty("description", is("uberX")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("b5e6755e-05dd-44cc-903d-94bdaa7ffc78")), - hasProperty("displayName", is("uberXL")), - hasProperty("description", is("Low-cost rides for large groups")), - hasProperty("capacity", is(6))), - allOf(hasProperty("productId", is("d4abaae7-f4d6-4152-91cc-77523e8165a4")), - hasProperty("displayName", is("UberBLACK")), - hasProperty("description", is("The original Uber")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0")), - hasProperty("displayName", is("UberSUV")), - hasProperty("description", is("Room for everyone")), - hasProperty("capacity", is(6))), - allOf(hasProperty("productId", is("4057d8cc-f0f5-43fa-b448-1cd891b0fc66")), - hasProperty("displayName", is("ASSIST")), - hasProperty("description", is("ASSIST")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7")), - hasProperty("displayName", is("uberWAV")), - hasProperty("description", is("Wheelchair Accessible Vehicles")), - hasProperty("capacity", is(4))))); - } - - @Test - public void onGet_whenAsyncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/get_product_error"); - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - final SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getProduct("thisIsNotAProductId", new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertProductError(server.takeRequest(), response.response, response.apiException, response.networkException); - } - - @Test - public void onGet_whenSyncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/get_product_error"); - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - ApiException exception = null; - Response response = null; - - try { - response = uberApiSyncService.getProduct("thisIsNotAProductId"); - } catch (ApiException e) { - exception = e; - } - - assertProductError(server.takeRequest(), response, exception, null); - } - - private static void assertProductError(RecordedRequest request, Response response, - ApiException apiException, NetworkException networkException) { - assertNull(response); - assertNull(networkException); - - assertEquals("Request path does not match", "/v1/products/thisIsNotAProductId", request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "GET", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, - apiException.getResponse().getStatus()); - assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); - - List errors = apiException.getErrors(); - assertEquals("More than one error", 1, errors.size()); - UberError uberError = errors.get(0); - assertTrue("Error is not a ClientError", uberError instanceof ClientError); - ClientError clientError = (ClientError) uberError; - assertEquals("Error code did not match body", "not_found", clientError.getCode()); - assertEquals("Error message did not match body", "Unable to find product thisIsNotAProductId", - clientError.getMessage()); - } - - @Test - public void onGet_withLanguage() throws Exception { - Session localizedSandboxSession = new Session.Builder() - .setAcceptLanguage(new Locale("sv", "SE")) - .setCredential(credential) - .setEnvironment(Session.Environment.SANDBOX) - .build(); - - UberRidesSyncService localizedUberApiSyncService = RetrofitUberRidesClient.getUberApiService( - localizedSandboxSession, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - okHttpClient, RetrofitUberRidesService.class); - - String body = readFile("src/test/resources/mockresponses/get_localized_products_response"); - - server.enqueue(new MockResponse().setBody(body)); - Response < ProductsResponse > response = localizedUberApiSyncService.getProducts(37.613f, -122.477f); - - assertLocalizedProducts(server.takeRequest(), response, null, null); - } - - private static void assertLocalizedProducts(RecordedRequest request, Response response, - ApiException apiException, - NetworkException networkException) { - assertNotNull(response); - assertNull(apiException); - assertNull(networkException); - - ProductsResponse productsResponse = response.getBody(); - assertNotNull(productsResponse); - - assertEquals("Accept-Language Header not found", "sv", request.getHeader("Accept-Language")); - assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); - assertEquals("Response reason does not match", "OK", response.getReason()); - - List products = productsResponse.getProducts(); - - assertThat("Request body does not match", products, - Matchers.hasItems( - allOf(hasProperty("productId", is("a1111c8c-c720-46c3-8534-2fcdd730040d")), - hasProperty("displayName", is("uberX")), - hasProperty("description", is("Den billigare Ubern"))))); - } - - @Test - public void onPut_whenAsyncHappyPath_shouldSucceed() throws Exception { - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); - - SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() - .setDriversAvailable(true) - .setSurgeMultiplier(2.4f) - .build(); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.updateSandboxProduct("d4abaae7-f4d6-4152-91cc-77523e8165a4", - sandboxProductRequestParameters, - new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertSandboxProduct(server.takeRequest(), response.response, response.apiException, - response.networkException); - } - - @Test - public void onPut_whenSyncHappyPath_shouldSucceed() throws Exception { - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); - - SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() - .setDriversAvailable(true) - .setSurgeMultiplier(2.4f) - .build(); - - Response response = uberApiSyncService.updateSandboxProduct("d4abaae7-f4d6-4152-91cc-77523e8165a4", - sandboxProductRequestParameters); - - assertSandboxProduct(server.takeRequest(), response, null, null); - } - - private static void assertSandboxProduct( - RecordedRequest request, Response response, - ApiException apiException, - NetworkException networkException) { - assertNotNull(response); - assertNull(response.getBody()); - assertNull(apiException); - assertNull(networkException); - - assertEquals("Request Path does not match", "/v1/sandbox/products/d4abaae7-f4d6-4152-91cc-77523e8165a4", - request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "PUT", request.getMethod()); - assertEquals("Request body does not match", "{\"surge_multiplier\":2.4,\"drivers_available\":true}", - request.getBody().readUtf8()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_NO_CONTENT, response.getStatus()); - assertEquals("Response reason does not match", "NO CONTENT", response.getReason()); - } - - @Test - public void onPut_whenAsyncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/put_sandbox_params_no_product_id_response"); - - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() - .setDriversAvailable(true) - .setSurgeMultiplier(2.4f) - .build(); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.updateSandboxProduct("thisIsNotAProductId", sandboxProductRequestParameters, - new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertSandboxProductError(server.takeRequest(), response.response, response.apiException, - response.networkException); - - } - - @Test - public void onPut_whenSyncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/put_sandbox_params_no_product_id_response"); - - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - SandboxProductRequestParameters sandboxProductRequestParameters = new SandboxProductRequestParameters.Builder() - .setDriversAvailable(true) - .setSurgeMultiplier(2.4f) - .build(); - - ApiException exception = null; - Response response = null; - - try { - response = uberApiSyncService.updateSandboxProduct("thisIsNotAProductId", sandboxProductRequestParameters); - } catch (ApiException e) { - exception = e; - } - - assertSandboxProductError(server.takeRequest(), response, exception, null); - } - - private static void assertSandboxProductError(RecordedRequest request, Response response, - ApiException apiException, - NetworkException networkException) { - assertNull(response); - assertNull(networkException); - - assertEquals("Request path does not match", "/v1/sandbox/products/thisIsNotAProductId", request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "PUT", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, - apiException.getResponse().getStatus()); - assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); - } - - @Test - public void onPost_whenAsyncHappyPath_shouldSucceed() throws Exception { - String body = readFile("src/test/resources/mockresponses/post_ride_request"); - server.enqueue(new MockResponse() - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_ACCEPTED + " Accepted") - .setBody(body)); - - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setDropoffCoordinates(END_LAT, END_LONG) - .setProductId("d4abaae7-f4d6-4152-91cc-77523e8165a4") - .build(); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.requestRide(rideRequestParameters, new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertRideRequest(server.takeRequest(), response.response, null, null); - } - - @Test - public void onPost_whenSyncHappyPath_shouldSucceed() throws Exception { - String body = readFile("src/test/resources/mockresponses/post_ride_request"); - server.enqueue(new MockResponse() - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_ACCEPTED + " Accepted") - .setBody(body)); - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setDropoffCoordinates(END_LAT, END_LONG) - .setProductId("d4abaae7-f4d6-4152-91cc-77523e8165a4") - .build(); - - Response response = uberApiSyncService.requestRide(rideRequestParameters); - - assertRideRequest(server.takeRequest(), response, null, null); - } - - private static void assertRideRequest(RecordedRequest request, Response response, ApiException apiException, - NetworkException networkException) { - assertNotNull(response); - assertNotNull(response.getBody()); - assertNull(apiException); - assertNull(networkException); - - assertEquals("Request Path does not match", "/v1/requests", - request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "POST", request.getMethod()); - assertEquals("Request body does not match", - "{\"product_id\":\"d4abaae7-f4d6-4152-91cc-77523e8165a4\",\"start_latitude\":37.613,\"start_longitude\":-122.477,\"end_latitude\":37.808,\"end_longitude\":-122.416}", - request.getBody().readUtf8()); - - assertNotNull(response); - assertEquals("Response code does not match", HttpURLConnection.HTTP_ACCEPTED, response.getStatus()); - assertEquals("Response reason does not match", "Accepted", response.getReason()); - - assertThat("Request body does not match", response.getBody(), - allOf(hasProperty("rideId", is("1033c525-746e-48ab-8eee-ab983e039e78")), - hasProperty("status", is("processing")), - hasProperty("driver", nullValue()), - hasProperty("eta", is(13)), - hasProperty("surgeMultiplier", is(1.0f)), - hasProperty("location", nullValue()), - hasProperty("vehicle", nullValue()))); - - } - - @Test - public void onPost_whenAysncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/post_ride_error"); - server.enqueue(new MockResponse() - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setDropoffCoordinates(END_LAT, END_LONG) - .setProductId("thisIsNotAProductId") - .build(); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.requestRide(rideRequestParameters, new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertRideRequestError(server.takeRequest(), response.response, response.apiException, - response.networkException); - } - - @Test - public void onPost_whenSyncInvalidProductId_shouldFail() throws Exception { - String body = readFile("src/test/resources/mockresponses/post_ride_error"); - server.enqueue(new MockResponse() - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NOT_FOUND + " Not Found") - .setBody(body)); - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setDropoffCoordinates(END_LAT, END_LONG) - .setProductId("thisIsNotAProductId") - .build(); - - ApiException exception = null; - Response response = null; - - try { - response = uberApiSyncService.requestRide(rideRequestParameters); - } catch (ApiException e) { - exception = e; - } - - assertRideRequestError(server.takeRequest(), response, exception, null); - } - - private static void assertRideRequestError(RecordedRequest request, Response response, - ApiException apiException, NetworkException networkException) { - assertNull(response); - assertNull(networkException); - - assertEquals("Request path does not match", "/v1/requests", request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "POST", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_NOT_FOUND, - apiException.getResponse().getStatus()); - assertEquals("Response reason does not match", "Not Found", apiException.getResponse().getReason()); - - List errors = apiException.getErrors(); - assertEquals("More than one error", 1, errors.size()); - UberError uberError = errors.get(0); - assertTrue("Error is not a ClientError", uberError instanceof ClientError); - ClientError clientError = (ClientError) uberError; - assertEquals("Error code did not match body", "not_found", clientError.getCode()); - assertEquals("Error message did not match body", - "Invalid product \"thisIsNotAProductId\". " - + "Available: d4abaae7-f4d6-4152-91cc-77523e8165a4, 8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0, " - + "04a497f5-380d-47f2-bf1b-ad4cfdcb51f2, 2832a1f5-cfc0-48bb-ab76-7ea7a62060e7, " - + "4057d8cc-f0f5-43fa-b448-1cd891b0fc66, b5e6755e-05dd-44cc-903d-94bdaa7ffc78", - clientError.getMessage()); - } - - @Test - public void onDelete_whenAsyncHappyPath_shouldSucceed() throws Exception { - server.enqueue(new MockResponse().setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_NO_CONTENT + " NO CONTENT")); - - String rideId = "542498f1-5096-418e-96c0-0cba096cb70c"; - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.cancelRide(rideId, new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertDeleteRide(server.takeRequest(), response.response); - } - - private static void assertDeleteRide(RecordedRequest request, Response response) { - assertNotNull(request); - assertNotNull(response); - - assertEquals("Request Path does not match", - "/v1/requests/542498f1-5096-418e-96c0-0cba096cb70c", - request.getPath()); - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "DELETE", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_NO_CONTENT, response.getStatus()); - assertEquals("Response reason does not match", "NO CONTENT", response.getReason()); - } - - @Test - public void onCall_whenAsyncCredentialNeedsRefresh_shouldRefreshCredential() throws Exception { - String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); - server.enqueue(new MockResponse().setBody(refreshResponseBody)); - - String getProfileResponseBody = readFile("src/test/resources/mockresponses/get_user_profile_response"); - server.enqueue(new MockResponse().setBody(getProfileResponseBody)); - - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertCredentialRefresh(response.response, response.responseObject, response.apiException, - response.networkException); - } - - @Test - public void onCall_whenSyncCredentialNeedsRefresh_shouldRefreshCredential() throws Exception { - String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); - server.enqueue(new MockResponse().setBody(refreshResponseBody)); - - String getProfileResponseBody = readFile("src/test/resources/mockresponses/get_user_profile_response"); - server.enqueue(new MockResponse().setBody(getProfileResponseBody)); - - credential.setExpiresInSeconds(OAuth2Helper.DEFAULT_REFRESH_WINDOW - 60L); - - Response response = uberApiSyncService.getUserProfile(); - - assertCredentialRefresh(response, response.getBody(), null, null); - } - - private void assertCredentialRefresh(Response response, UserProfile userProfile, - ApiException apiException, NetworkException networkException) - throws InterruptedException { - assertNotNull(response); - assertNotNull(userProfile); - assertNull(apiException); - assertNull(networkException); - - RecordedRequest refreshRequest = server.takeRequest(); - - assertEquals("Refresh request body does not match", - "grant_type=refresh_token&refresh_token=refreshToken&client_id=CLIENT_ID&client_secret=CLIENT_SECRET", - refreshRequest.getBody().readUtf8()); - assertEquals("Refresh request method does not match", "POST", refreshRequest.getMethod()); - - RecordedRequest getProfileRequest = server.takeRequest(); - - assertEquals("Get Profile Request path does not match", "/v1/me", getProfileRequest.getPath()); - assertEquals("Authorization Header does not match", "Bearer accessToken2", - getProfileRequest.getHeader("Authorization")); - assertEquals("Get Profile Request method does not match", "GET", getProfileRequest.getMethod()); - - assertEquals("accessToken2", credential.getAccessToken()); - assertEquals("refreshToken2", credential.getRefreshToken()); - } - - @Test - public void onCall_whenAsyncServerToken_shouldSendServerToken() throws Exception { - Session session = new Session.Builder().setEnvironment(PRODUCTION).setServerToken("serverToken").build(); - - uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(session, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - okHttpClient, RetrofitUberRidesService.class); - - String body = readFile("src/test/resources/mockresponses/get_products_response"); - server.enqueue(new MockResponse().setBody(body)); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getProducts(37.613f, -122.477f, new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(1, TimeUnit.SECONDS); - - assertProductsWithServerToken(server.takeRequest(), response.response, response.responseObject, - response.apiException, response.networkException); - } - - @Test - public void onCall_whenSyncServerToken_shouldSendServerToken() throws Exception { - Session session = new Session.Builder().setEnvironment(PRODUCTION).setServerToken("serverToken").build(); - - uberApiSyncService = RetrofitUberRidesClient.getUberApiService(session, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - okHttpClient, RetrofitUberRidesService.class); - - String body = readFile("src/test/resources/mockresponses/get_products_response"); - server.enqueue(new MockResponse().setBody(body)); - - Response response = uberApiSyncService.getProducts(37.613f, -122.477f); - - assertProductsWithServerToken(server.takeRequest(), response, response.getBody(), null, null); - } - - private void assertProductsWithServerToken( - RecordedRequest request, Response response, - ProductsResponse productsResponse, ApiException apiException, - NetworkException networkException) { - assertNotNull(productsResponse); - assertNotNull(response); - assertNull(apiException); - assertNull(networkException); - - assertEquals("Request Path does not match", "/v1/products?latitude=37.613&longitude=-122.477", - request.getPath()); - assertEquals("Authorization Header not found", "Token serverToken", request.getHeader("Authorization")); - assertEquals("Request method does not match", "GET", request.getMethod()); - - assertEquals("Response code does not match", HttpURLConnection.HTTP_OK, response.getStatus()); - assertEquals("Response reason does not match", "OK", response.getReason()); - - List products = productsResponse.getProducts(); - - assertThat("Request body does not match", products, - Matchers.hasItems( - allOf(hasProperty("productId", is("04a497f5-380d-47f2-bf1b-ad4cfdcb51f2")), - hasProperty("displayName", is("uberX")), - hasProperty("description", is("uberX")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("b5e6755e-05dd-44cc-903d-94bdaa7ffc78")), - hasProperty("displayName", is("uberXL")), - hasProperty("description", is("Low-cost rides for large groups")), - hasProperty("capacity", is(6))), - allOf(hasProperty("productId", is("d4abaae7-f4d6-4152-91cc-77523e8165a4")), - hasProperty("displayName", is("UberBLACK")), - hasProperty("description", is("The original Uber")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("8920cb5e-51a4-4fa4-acdf-dd86c5e18ae0")), - hasProperty("displayName", is("UberSUV")), - hasProperty("description", is("Room for everyone")), - hasProperty("capacity", is(6))), - allOf(hasProperty("productId", is("4057d8cc-f0f5-43fa-b448-1cd891b0fc66")), - hasProperty("displayName", is("ASSIST")), - hasProperty("description", is("ASSIST")), - hasProperty("capacity", is(4))), - allOf(hasProperty("productId", is("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7")), - hasProperty("displayName", is("uberWAV")), - hasProperty("description", is("Wheelchair Accessible Vehicles")), - hasProperty("capacity", is(4))))); - } - - @Test - public void onCall_whenSyncTimeout_shouldThrowException() throws Exception { - okHttpClient.setConnectTimeout(1, TimeUnit.MILLISECONDS); - okHttpClient.setReadTimeout(1, TimeUnit.MILLISECONDS); - - exception.expect(NetworkException.class); - - server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE)); - - uberApiSyncService.getUserProfile(); - } - - @Test - public void onCall_whenAsyncTimeout_shouldThrowException() throws Exception{ - okHttpClient.setConnectTimeout(1, TimeUnit.MILLISECONDS); - okHttpClient.setReadTimeout(1, TimeUnit.MILLISECONDS); - - server.enqueue(new MockResponse().setSocketPolicy(SocketPolicy.NO_RESPONSE)); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(); - - assertNotNull(response.networkException); - } - - @Test - public void onCall_whenSyncUnexpectedException_shouldThrowException() throws Exception { - exception.expect(RuntimeException.class); - - server.enqueue(new MockResponse().setBody("Not JSON")); - - uberApiSyncService.getUserProfile(); - } - - @Test - public void onCall_whenAsyncUnexpectedException_shouldThrowException() throws Exception { - server.enqueue(new MockResponse().setBody("Not JSON")); - - SettableFuture> future = SettableFuture.create(); - - uberApiAsyncService.getUserProfile(new SettableFutureCallback<>(future)); - - SettableResponse response = future.get(); - - assertNotNull(response.unknownException); - } - - @Test - public void onCall_whenAsyncHappyPath_shouldHaveHeaders() throws Exception { - String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); - server.enqueue(new MockResponse().setBody(refreshResponseBody)); - - uberApiAsyncService.getUserProfile( - new SettableFutureCallback<>(SettableFuture.>create())); - - assertHeaders(server.takeRequest(1, TimeUnit.SECONDS)); - } - - @Test - public void onCall_whenSyncHappyPath_shouldHaveHeaders() throws Exception { - String refreshResponseBody = readFile("src/test/resources/mockresponses/post_refresh_token_response"); - server.enqueue(new MockResponse().setBody(refreshResponseBody)); - - uberApiSyncService.getUserProfile(); - - assertHeaders(server.takeRequest()); - } - - @Test - public void onCall_whenAsyncRedirect_shouldAutomaticallyRedirectAndPreserveHeaders() throws Exception { - String redirectedResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirected"); - MockWebServer redirectServer = new MockWebServer(); - redirectServer.enqueue(new MockResponse().setBody(redirectedResponseBody)); - - String redirectResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirect"); - server.enqueue(new MockResponse() - .setBody(redirectResponseBody) - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_MOVED_TEMP + " Found") - .setHeader("Location", redirectServer.getUrl("/v1/requests/estimate"))); - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setProductId("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7") - .setDropoffCoordinates(END_LAT, END_LONG).build(); - - uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - null, - RetrofitUberRidesService.class); - - uberApiAsyncService.estimateRide(rideRequestParameters, - new SettableFutureCallback<>(SettableFuture.>create())); - - RecordedRequest firstRequest = server.takeRequest(1, TimeUnit.SECONDS); - assertHeaders(firstRequest); - RecordedRequest redirectedRequest = redirectServer.takeRequest(1, TimeUnit.SECONDS); - assertHeaders(redirectedRequest); - assertEquals("Redirected Request Line does not match", - "POST /v1/requests/estimate HTTP/1.1", - redirectedRequest.getRequestLine()); - } - - @Test - public void onCall_whenSyncRedirect_shouldAutomaticallyRedirectAndPreserveHeaders() throws Exception { - String redirectedResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirected"); - MockWebServer redirectServer = new MockWebServer(); - redirectServer.enqueue(new MockResponse().setBody(redirectedResponseBody)); - - String redirectResponseBody = readFile("src/test/resources/mockresponses/estimate_ride_redirect"); - server.enqueue(new MockResponse() - .setBody(redirectResponseBody) - .setStatus("HTTP/1.1 " + HttpURLConnection.HTTP_MOVED_TEMP + " Found") - .setHeader("Location", redirectServer.getUrl("/v1/requests/estimate"))); - - RideRequestParameters rideRequestParameters = new RideRequestParameters.Builder() - .setPickupCoordinates(START_LAT, START_LONG) - .setProductId("2832a1f5-cfc0-48bb-ab76-7ea7a62060e7") - .setDropoffCoordinates(END_LAT, END_LONG).build(); - - uberApiSyncService = RetrofitUberRidesClient.getUberApiService(sandboxSession, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL, - endpointHost, - null, RetrofitUberRidesService.class); - - uberApiSyncService.estimateRide(rideRequestParameters); - - RecordedRequest firstRequest = server.takeRequest(); - assertHeaders(firstRequest); - RecordedRequest redirectedRequest = redirectServer.takeRequest(); - assertHeaders(redirectedRequest); - assertEquals("Redirected Request Line does not match", - "POST /v1/requests/estimate HTTP/1.1", - redirectedRequest.getRequestLine()); - } - - private static void assertHeaders(RecordedRequest request) { - assertEquals("Authorization Header not found", "Bearer accessToken", request.getHeader("Authorization")); - assertEquals("User Agent Header not found", "Java Rides SDK v" + RetrofitUberRidesClient.LIB_VERSION, - request.getHeader("X-Uber-User-Agent")); - } - - private String readFile(String path) throws IOException { - File file = new File(path); - if (!file.exists()) { - file = new File("sdk/" + path); - } - return Files.toString(file, StandardCharsets.UTF_8); - } - - private static class SettableFutureCallback implements Callback { - - private SettableFuture> settableFuture; - - public SettableFutureCallback(SettableFuture> settableFuture) { - this.settableFuture = settableFuture; - } - - @Override - public void success(T obj, Response response) { - settableFuture.set(new SettableResponse<>(obj, response, null, null, null)); - } - - @Override - public void failure(NetworkException exception) { - settableFuture.set(new SettableResponse(null, null, exception, null, null)); - } - - @Override - public void failure(ApiException exception) { - settableFuture.set(new SettableResponse(null, null, null, exception, null)); - } - - @Override - public void failure(Throwable exception) { - settableFuture.set(new SettableResponse(null, null, null, null, exception)); - } - } - - private static class SettableResponse { - - T responseObject; - Response response; - NetworkException networkException; - ApiException apiException; - Throwable unknownException; - - public SettableResponse(T responseObject, - Response response, - NetworkException networkException, - ApiException apiException, - Throwable unknownException) { - this.responseObject = responseObject; - this.response = response; - this.networkException = networkException; - this.apiException = apiException; - this.unknownException = unknownException; - } - } -} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientTest.java deleted file mode 100644 index 6bbc71c..0000000 --- a/sdk/src/test/java/com/uber/sdk/rides/client/internal/RetrofitUberRidesClientTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2015 Uber Technologies, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package com.uber.sdk.rides.client.internal; - -import com.google.api.client.auth.oauth2.BearerToken; -import com.google.api.client.auth.oauth2.Credential; -import com.google.common.reflect.Reflection; -import com.uber.sdk.rides.auth.OAuth2Helper; -import com.uber.sdk.rides.client.Callback; -import com.uber.sdk.rides.client.Session; -import com.uber.sdk.rides.client.UberRidesAsyncService; -import com.uber.sdk.rides.client.UberRidesServices; -import com.uber.sdk.rides.client.UberRidesSyncService; -import com.uber.sdk.rides.client.model.SandboxProductRequestParameters; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import retrofit.RestAdapter; -import retrofit.http.PUT; -import retrofit.http.Path; - -import static com.uber.sdk.rides.client.Session.Environment.PRODUCTION; -import static org.mockito.Mockito.mock; - -public class RetrofitUberRidesClientTest { - - @Rule public ExpectedException exception = ExpectedException.none(); - - private Credential credential; - - @Before - public void setUp() throws Exception { - credential = new Credential.Builder(BearerToken.authorizationHeaderAccessMethod()).build(); - } - - @Test - public void onSandboxCall_whenAsyncInProductionEnvironment_shouldThrowException() throws Exception { - Session session = new Session.Builder() - .setCredential(credential) - .setEnvironment(PRODUCTION) - .build(); - - UberRidesAsyncService uberApiAsyncService = RetrofitUberRidesClient.getUberApiService(session, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL); - - exception.expect(IllegalStateException.class); - exception.expectMessage("Sandbox only methods can't be called in production."); - - Callback callback = mock(Callback.class); - - uberApiAsyncService.updateSandboxProduct("thisIsNotAProductId", - new SandboxProductRequestParameters.Builder().build(),callback); - } - - @Test - public void onSandboxCall_whenSyncInProductionEnvironment_shouldThrowException() throws Exception { - Session session = new Session.Builder() - .setCredential(credential) - .setEnvironment(PRODUCTION) - .build(); - - UberRidesSyncService uberApiSyncService = RetrofitUberRidesClient.getUberApiService(session, - new OAuth2Helper(), - UberRidesServices.LogLevel.FULL); - - exception.expect(IllegalStateException.class); - exception.expectMessage("Sandbox only methods can't be called in production."); - - uberApiSyncService.updateSandboxProduct("thisIsNotAProductId", - new SandboxProductRequestParameters.Builder().build()); - } - - @Test - public void onCreateService_whenDuplicateMethodNames_shouldThrowException() throws Exception { - Session session = new Session.Builder().setEnvironment(PRODUCTION).setCredential(credential).build(); - - RestAdapter restAdapter = mock(RestAdapter.class); - - DuplicateNameUberApiService service = Reflection.newProxy(DuplicateNameUberApiService.class, - new RetrofitUberRidesClient.InvocationHandler<>(session.getEnvironment(), - DuplicateNameUberApiService.class, restAdapter)); - - exception.expect(IllegalStateException.class); - exception.expectMessage("Services may not contain duplicate names."); - - Callback callback = mock(Callback.class); - - service.duplicateMethod("thisIsNotAProductId", callback); - } - - private interface DuplicateNameUberApiService { - - @PUT("/not/a/real/path/{product_id}") - void duplicateMethod(@Path("product_id") String productId, Callback callback); - - @PUT("/not/a/real/path/{product_id}") - void duplicateMethod(@Path("product_id") double productId, Callback callback); - } -} diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/model/RideRequestParametersTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/model/RideRequestParametersTest.java index 5adb8a1..6e40a92 100644 --- a/sdk/src/test/java/com/uber/sdk/rides/client/model/RideRequestParametersTest.java +++ b/sdk/src/test/java/com/uber/sdk/rides/client/model/RideRequestParametersTest.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import com.uber.sdk.rides.client.model.Place.Places; diff --git a/sdk/src/test/java/com/uber/sdk/rides/client/model/RideUpdateParametersTest.java b/sdk/src/test/java/com/uber/sdk/rides/client/model/RideUpdateParametersTest.java index 152c6fe..be90fa2 100644 --- a/sdk/src/test/java/com/uber/sdk/rides/client/model/RideUpdateParametersTest.java +++ b/sdk/src/test/java/com/uber/sdk/rides/client/model/RideUpdateParametersTest.java @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.uber.sdk.rides.client.model; import org.junit.Rule; diff --git a/sdk/src/test/resources/__files/token_token.json b/sdk/src/test/resources/__files/token_token.json new file mode 100644 index 0000000..a181872 --- /dev/null +++ b/sdk/src/test/resources/__files/token_token.json @@ -0,0 +1,8 @@ +{ + "last_authenticated": 1464137596, + "access_token": "Access999Token", + "expires_in": 2592000, + "token_type": "Bearer", + "scope": "request all_trips profile ride_widgets history places history_lite", + "refresh_token": "888RefreshToken" +} diff --git a/settings.gradle b/settings.gradle index 015cce5..d5adc03 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,25 @@ +/* + * Copyright (c) 2016 Uber Technologies, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + include ':sdk' include ':samples' include ':samples:cmdline-sample'