jenkins-bot has submitted this change and it was merged. Change subject: Upgrade to Retrofit 2 ......................................................................
Upgrade to Retrofit 2 Note that if you use Developer Settings for RetrofitLogLevel or any of the URI patterns the vlues may have to be updated. The base URIs now have to end with a slash. For RetrofitLogLevel see the discussion of HttpLoggingInterceptor below. A lot has changed in Retrofit land: * RestAdapter was renamed to Retrofit. * Interceptors have moved to OkHttp since the HTTP connection layer has been moved to OkHttp. * HttpLoggingInterceptor does not have the HEADERS_AND_ARGS logging level anymore. FULL got renamed to BODY. If you used one of those log level values before you will need to set a new level or you won't get logging since default is NONE. * Slashes have moved in URIs. Base URIs should always end with a slash. Relative URLs usually not have a slash at the beginning. * Using Call object to encapsulate request/response pairs. * Same service interface for synchronous and asynchronous requests. Use execute for synchronous, enqueue for asynchronous requests. * The callback methods for responses and failures have changed. E.g. 400 HTTP code is included in onResponse. Have to check isSuccessful() there. The callback method onFailure() only deals with exceptions, usually IOExceptions. * HTTP headers in OkHttp only get replaced if a headers() builder is and its set() method is used. (Executing addHeader() on an existing header, like User-Agent does nothing.) * MockWebServer is now part of OkHttp3 and in a different package. It also likes to use HttpUtl instead of URL. But fortunately, there is a convenient converter to URLs. Additional changes: * RestAdapterFactory was renamed to RetrofitFactory to match the rename of RestAdapter to Retrofit * Introduced a retrofit package since we also have a few more classes to support Retrofit (RetrofitException, ...) Further info: * https://github.com/square/okhttp/wiki/Recipes * https://futurestud.io/blog/retrofit-2-upgrade-guide-from-1-9 Change-Id: I0fd2fd9b9b800ac49dd28911591a85e7e01b57c9 --- M app/build.gradle M app/proguard-rules.pro M app/src/main/java/org/wikipedia/OkHttpConnectionFactory.java M app/src/main/java/org/wikipedia/WikipediaApp.java D app/src/main/java/org/wikipedia/dataclient/NullBodyAwareOkClient.java D app/src/main/java/org/wikipedia/dataclient/RestAdapterFactory.java A app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitException.java A app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitExceptionBuilder.java A app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitFactory.java M app/src/main/java/org/wikipedia/readinglist/api/ReadingListDataClient.java M app/src/main/java/org/wikipedia/server/PageService.java M app/src/main/java/org/wikipedia/server/mwapi/MwPageEndpointsCache.java M app/src/main/java/org/wikipedia/server/mwapi/MwPageService.java M app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java M app/src/main/java/org/wikipedia/server/restbase/RbPageService.java M app/src/main/java/org/wikipedia/settings/Prefs.java M app/src/main/java/org/wikipedia/settings/RbSwitch.java M app/src/main/java/org/wikipedia/useroption/dataclient/DefaultUserOptionDataClient.java M app/src/main/java/org/wikipedia/useroption/sync/UserOptionSyncAdapter.java M app/src/main/java/org/wikipedia/util/ThrowableUtil.java M app/src/main/java/org/wikipedia/zero/WikipediaZeroHandler.java M app/src/main/res/values/preference_values.xml M app/src/main/res/xml/developer_preferences.xml M app/src/test/java/org/wikipedia/dataclient/RetrofitClientBaseTest.java M app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListPageTitlesTest.java M app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListsTest.java M app/src/test/java/org/wikipedia/test/TestWebServer.java 27 files changed, 504 insertions(+), 337 deletions(-) Approvals: Mholloway: Looks good to me, approved Niedzielski: Looks good to me, but someone else must approve jenkins-bot: Verified diff --git a/app/build.gradle b/app/build.gradle index 1de5ada..4eebd43 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -155,7 +155,8 @@ // use http://gradleplease.appspot.com/ or http://search.maven.org/. // Debug with ./gradlew -q app:dependencies --configuration compile - String okHttpVersion = '2.7.0' + String retrofitVersion = '2.0.2' + String okHttpVersion = '3.2.0' String supportVersion = '23.3.0' String espressoVersion = '2.2.1' @@ -168,10 +169,11 @@ compile "com.android.support:preference-v14:$supportVersion" compile 'com.facebook.fresco:fresco:0.8.1' compile 'com.google.code.gson:gson:2.6.2' - compile "com.squareup.okhttp:okhttp-urlconnection:$okHttpVersion" - compile "com.squareup.okhttp:okhttp:$okHttpVersion" + compile "com.squareup.okhttp3:okhttp-urlconnection:$okHttpVersion" // for JavaNetCookieJar + compile "com.squareup.okhttp3:logging-interceptor:$okHttpVersion" compile 'com.squareup:otto:1.3.8' - compile 'com.squareup.retrofit:retrofit:1.9.0' + compile "com.squareup.retrofit2:retrofit:$retrofitVersion" + compile "com.squareup.retrofit2:converter-gson:$retrofitVersion" compile 'com.mobsandgeeks:android-saripaar:2.0.3' compile 'com.github.ryanjohn1:onboarding:1.0.3' compile 'com.jakewharton:butterknife:7.0.1' @@ -185,7 +187,7 @@ testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.9.5' testCompile 'org.robolectric:robolectric:3.0' - testCompile "com.squareup.okhttp:mockwebserver:$okHttpVersion" + testCompile "com.squareup.okhttp3:mockwebserver:$okHttpVersion" // Required by Android JUnit Runner. androidTestCompile "com.android.support:support-annotations:$supportVersion" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e51459d..6a07bcd 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -17,27 +17,25 @@ -dontwarn com.android.volley.toolbox.** # --- /Fresco --- -# https://github.com/square/okio/issues/60 --dontwarn okio.** - --dontwarn com.squareup.okhttp.** --dontnote com.squareup.okhttp.internal.Platform - - -keep class com.mobsandgeeks.saripaar.** {*;} -keep class uk.co.senab.photoview.** {*;} -keep class com.github.kevinsawicki.http.** {*;} -# --- Retrofit --- -# https://github.com/square/retrofit/issues/117 --dontwarn retrofit.** --keep class retrofit.** { *; } +# --- Retrofit2 --- +-dontwarn retrofit2.** +-keep class retrofit2.** { *; } -keepattributes Signature -keepattributes Exceptions # --- /Retrofit --- +# --- OkHttp + Okio --- +-dontwarn okhttp3.** +-keep class okhttp3.** { *; } +-dontwarn okio.* +# --- /OkHttp + Okio --- + # --- Butter Knife --- -keep class butterknife.** { *; } -dontwarn butterknife.internal.** diff --git a/app/src/main/java/org/wikipedia/OkHttpConnectionFactory.java b/app/src/main/java/org/wikipedia/OkHttpConnectionFactory.java index b602790..65428a4 100644 --- a/app/src/main/java/org/wikipedia/OkHttpConnectionFactory.java +++ b/app/src/main/java/org/wikipedia/OkHttpConnectionFactory.java @@ -2,10 +2,12 @@ import android.content.Context; import com.github.kevinsawicki.http.HttpRequest; -import com.squareup.okhttp.Cache; -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.OkUrlFactory; -import com.squareup.okhttp.Protocol; +import okhttp3.Cache; +import okhttp3.CookieJar; +import okhttp3.JavaNetCookieJar; +import okhttp3.OkHttpClient; +import okhttp3.OkUrlFactory; +import okhttp3.Protocol; import java.io.IOException; import java.net.HttpURLConnection; @@ -25,7 +27,7 @@ @Override public HttpURLConnection create(URL url) throws IOException { - return new OkUrlFactory(client).open(url); + return new OkUrlFactory(client).open(url); // TODO: update to newer API } @Override @@ -35,18 +37,22 @@ } public static OkHttpClient createClient(Context context) { - OkHttpClient client = new OkHttpClient(); - client.setCookieHandler(((WikipediaApp)context.getApplicationContext()).getCookieManager()); - client.setCache(new Cache(context.getCacheDir(), HTTP_CACHE_SIZE)); - // Create a custom set of protocols that excludes HTTP/2, since OkHttp doesn't play // nicely with nginx over HTTP/2. // TODO: Remove when https://github.com/square/okhttp/issues/2543 is fixed. List<Protocol> protocolList = new ArrayList<>(); protocolList.add(Protocol.SPDY_3); protocolList.add(Protocol.HTTP_1_1); - client.setProtocols(protocolList); - return client; + SharedPreferenceCookieManager cookieManager + = ((WikipediaApp) context.getApplicationContext()).getCookieManager(); + // TODO: consider using okhttp3.CookieJar implementation instead of JavaNetCookieJar wrapper + CookieJar cookieJar = new JavaNetCookieJar(cookieManager); + + return new OkHttpClient.Builder() + .cookieJar(cookieJar) + .cache(new Cache(context.getCacheDir(), HTTP_CACHE_SIZE)) + .protocols(protocolList) + .build(); } } diff --git a/app/src/main/java/org/wikipedia/WikipediaApp.java b/app/src/main/java/org/wikipedia/WikipediaApp.java index c81b082..bf5f87b 100644 --- a/app/src/main/java/org/wikipedia/WikipediaApp.java +++ b/app/src/main/java/org/wikipedia/WikipediaApp.java @@ -63,7 +63,8 @@ import java.util.Random; import java.util.UUID; -import retrofit.RequestInterceptor; +import okhttp3.Headers; +import okhttp3.Request; import static org.wikipedia.util.DimenUtil.getFontSizeFromSp; import static org.wikipedia.util.ReleaseUtil.getChannel; @@ -226,7 +227,7 @@ public Api getAPIForSite(Site site, boolean mobile) { String host = mobile ? site.mobileHost() : site.host(); String acceptLanguage = getAcceptLanguage(site); - Map<String, String> customHeaders = buildCustomHeaders(acceptLanguage); + Map<String, String> customHeaders = buildCustomHeadersMap(acceptLanguage); Api api; String cachedApiKey = host + "-" + acceptLanguage; @@ -530,16 +531,19 @@ return PrefsOnboardingStateMachine.getInstance(); } - /** For Retrofit requests. Keep in sync with #buildCustomHeaders */ - public void injectCustomHeaders(RequestInterceptor.RequestFacade request, Site site) { - Map<String, String> headers = buildCustomHeaders(getAcceptLanguage(site)); - for (String key : headers.keySet()) { - request.addHeader(key, headers.get(key)); + /** For Retrofit requests. Keep in sync with #buildCustomHeadersMap */ + public Headers buildCustomHeaders(Request request, Site site) { + Map<String, String> toSetHeaders = buildCustomHeadersMap(getAcceptLanguage(site)); + + Headers.Builder moreHeaders = request.headers().newBuilder(); + for (String key : toSetHeaders.keySet()) { + moreHeaders.set(key, toSetHeaders.get(key)); } + return moreHeaders.build(); } /** For java-mwapi API requests. */ - private Map<String, String> buildCustomHeaders(String acceptLanguage) { + private Map<String, String> buildCustomHeadersMap(String acceptLanguage) { Map<String, String> headers = new HashMap<>(); headers.put("User-Agent", getUserAgent()); diff --git a/app/src/main/java/org/wikipedia/dataclient/NullBodyAwareOkClient.java b/app/src/main/java/org/wikipedia/dataclient/NullBodyAwareOkClient.java deleted file mode 100644 index cc40c2d..0000000 --- a/app/src/main/java/org/wikipedia/dataclient/NullBodyAwareOkClient.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.wikipedia.dataclient; - -import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.internal.http.HttpMethod; - -import java.io.IOException; -import java.io.OutputStream; - -import retrofit.client.OkClient; -import retrofit.client.Request; -import retrofit.client.Response; -import retrofit.mime.TypedOutput; - -/** Workaround for https://github.com/square/retrofit/issues/854. */ -public class NullBodyAwareOkClient extends OkClient { - public NullBodyAwareOkClient(OkHttpClient okHttpClient) { - super(okHttpClient); - } - - @Override - public Response execute(Request request) throws IOException { - if (HttpMethod.requiresRequestBody(request.getMethod()) && request.getBody() == null) { - Request newRequest = new Request(request.getMethod(), request.getUrl(), - request.getHeaders(), EmptyOutput.INSTANCE); - return super.execute(newRequest); - } - - return super.execute(request); - } - - private static final class EmptyOutput implements TypedOutput { - static final TypedOutput INSTANCE = new EmptyOutput(); - - private EmptyOutput() { } - - @Override - public String fileName() { - return null; - } - - @Override - public String mimeType() { - return "application/json"; - } - - @Override - public long length() { - return 0; - } - - @Override public void writeTo(OutputStream out) throws IOException { } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/dataclient/RestAdapterFactory.java b/app/src/main/java/org/wikipedia/dataclient/RestAdapterFactory.java deleted file mode 100644 index b9d978c..0000000 --- a/app/src/main/java/org/wikipedia/dataclient/RestAdapterFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.wikipedia.dataclient; - -import android.support.annotation.NonNull; - -import com.google.gson.GsonBuilder; - -import org.wikipedia.OkHttpConnectionFactory; -import org.wikipedia.Site; -import org.wikipedia.WikipediaApp; -import org.wikipedia.server.Protection; -import org.wikipedia.settings.Prefs; - -import retrofit.RequestInterceptor; -import retrofit.RestAdapter; -import retrofit.converter.GsonConverter; - -public final class RestAdapterFactory { - public static RestAdapter newInstance(@NonNull Site site) { - return newInstance(site, site.scheme() + "://" + site.authority()); - } - - public static RestAdapter newInstance(@NonNull final Site site, @NonNull String endpoint) { - final WikipediaApp app = WikipediaApp.getInstance(); - return new RestAdapter.Builder() - .setLogLevel(Prefs.getRetrofitLogLevel()) - .setClient(new NullBodyAwareOkClient(OkHttpConnectionFactory.createClient(app))) - .setRequestInterceptor(new RequestInterceptor() { - @Override - public void intercept(RequestFacade request) { - app.injectCustomHeaders(request, site); - } - }) - .setEndpoint(endpoint) - - // following is only needed for the hacky PageLead.Protection deserialization - // remove once https://phabricator.wikimedia.org/T69054 is resolved (see T111131) - .setConverter(new GsonConverter(new GsonBuilder() - .registerTypeAdapter(Protection.class, new Protection.Deserializer()) - .create())) - - .build(); - } - - private RestAdapterFactory() { } -} \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitException.java b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitException.java new file mode 100644 index 0000000..dbf8649 --- /dev/null +++ b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitException.java @@ -0,0 +1,91 @@ +package org.wikipedia.dataclient.retrofit; + +import okhttp3.ResponseBody; +import retrofit2.Converter; +import retrofit2.Response; +import retrofit2.Retrofit; + +import java.io.IOException; +import java.lang.annotation.Annotation; + +/** + * This is RetrofitError converted to Retrofit 2 + */ +public class RetrofitException extends RuntimeException { + public static RetrofitException httpError(Response response, Retrofit retrofit) { + return httpError(response.raw().request().url().toString(), response, retrofit); + } + + public static RetrofitException httpError(String url, Response response, Retrofit retrofit) { + String message = response.code() + " " + response.message(); + return new RetrofitException(message, url, response, Kind.HTTP, null, retrofit); + } + + public static RetrofitException networkError(IOException exception) { + return new RetrofitException(exception.getMessage(), null, null, Kind.NETWORK, exception, null); + } + + public static RetrofitException unexpectedError(Throwable exception) { + return new RetrofitException(exception.getMessage(), null, null, Kind.UNEXPECTED, exception, null); + } + + /** Identifies the event kind which triggered a {@link RetrofitException}. */ + public enum Kind { + /** An {@link IOException} occurred while communicating to the server. */ + NETWORK, + /** A non-200 HTTP status code was received from the server. */ + HTTP, + /** + * An internal error occurred while attempting to execute a request. It is best practice to + * re-throw this exception so your application crashes. + */ + UNEXPECTED + } + + private final String url; + private final Response response; + private final Kind kind; + private final Retrofit retrofit; + + RetrofitException(String message, String url, Response response, Kind kind, Throwable exception, Retrofit retrofit) { + super(message, exception); + this.url = url; + this.response = response; + this.kind = kind; + this.retrofit = retrofit; + } + + /** The request URL which produced the error. */ + public String getUrl() { + return url; + } + + /** Response object containing status code, headers, body, etc. */ + public Response getResponse() { + return response; + } + + /** The event kind which triggered this error. */ + public Kind getKind() { + return kind; + } + + /** The Retrofit this request was executed on */ + public Retrofit getRetrofit() { + return retrofit; + } + + /** + * HTTP response body converted to specified {@code type}. {@code null} if there is no + * response. + * + * @throws IOException if unable to convert the body to the specified {@code type}. + */ + public <T> T getErrorBodyAs(Class<T> type) throws IOException { + if (response == null || response.errorBody() == null) { + return null; + } + Converter<ResponseBody, T> converter = retrofit.responseBodyConverter(type, new Annotation[0]); + return converter.convert(response.errorBody()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitExceptionBuilder.java b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitExceptionBuilder.java new file mode 100644 index 0000000..dc27470 --- /dev/null +++ b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitExceptionBuilder.java @@ -0,0 +1,13 @@ +package org.wikipedia.dataclient.retrofit; + +import retrofit2.Response; +import retrofit2.Retrofit; + +public final class RetrofitExceptionBuilder { + public static RetrofitException build(Response response, Retrofit retrofit) { + return RetrofitException.httpError(response.raw().request().url().toString(), response, retrofit); + } + + private RetrofitExceptionBuilder() { + } +} diff --git a/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitFactory.java b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitFactory.java new file mode 100644 index 0000000..d117079 --- /dev/null +++ b/app/src/main/java/org/wikipedia/dataclient/retrofit/RetrofitFactory.java @@ -0,0 +1,71 @@ +package org.wikipedia.dataclient.retrofit; + +import org.wikipedia.Site; +import org.wikipedia.WikipediaApp; +import org.wikipedia.server.Protection; +import org.wikipedia.settings.Prefs; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +import android.support.annotation.NonNull; + +import java.io.IOException; + +public final class RetrofitFactory { + public static Retrofit newInstance(@NonNull Site site) { + return newInstance(site, site.scheme() + "://" + site.authority() + "/"); + } + + public static Retrofit newInstance(@NonNull final Site site, @NonNull String endpoint) { + final WikipediaApp app = WikipediaApp.getInstance(); + + HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); + loggingInterceptor.setLevel(Prefs.getRetrofitLogLevel()); + + OkHttpClient.Builder httpClient = new OkHttpClient.Builder() + .addInterceptor(loggingInterceptor) + .addNetworkInterceptor( + new Interceptor() { + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + request = request.newBuilder() + .headers(app.buildCustomHeaders(request, site)) + .build(); + return chain.proceed(request); + } + } + ); + + OkHttpClient client = httpClient.build(); + return new Retrofit.Builder() + .client(client) + .baseUrl(endpoint) + .addConverterFactory(buildCustomGsonConverter()) + .build(); + } + + /** + * Add custom deserializer, which is only needed for the hacky PageLead.Protection + * deserialization. + * Replace this method with GsonConverterFactory.create() once + * https://phabricator.wikimedia.org/T69054 is resolved (see T111131). + */ + private static GsonConverterFactory buildCustomGsonConverter() { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Protection.class, new Protection.Deserializer()); + Gson myGson = gsonBuilder.create(); + return GsonConverterFactory.create(myGson); + } + + private RetrofitFactory() { } +} \ No newline at end of file diff --git a/app/src/main/java/org/wikipedia/readinglist/api/ReadingListDataClient.java b/app/src/main/java/org/wikipedia/readinglist/api/ReadingListDataClient.java index aef2853..71ad553 100644 --- a/app/src/main/java/org/wikipedia/readinglist/api/ReadingListDataClient.java +++ b/app/src/main/java/org/wikipedia/readinglist/api/ReadingListDataClient.java @@ -3,13 +3,16 @@ import org.wikipedia.Site; import org.wikipedia.readinglist.api.legacy.LegacyReadingListPageTitlesResponse; import org.wikipedia.readinglist.api.legacy.LegacyReadingListsResponse; -import org.wikipedia.dataclient.RestAdapterFactory; +import org.wikipedia.dataclient.retrofit.RetrofitFactory; -import retrofit.http.GET; -import retrofit.http.Query; +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; import android.support.annotation.NonNull; import android.support.annotation.VisibleForTesting; + +import java.io.IOException; /** * Gets and posts collection related data from and to the server. @@ -20,19 +23,19 @@ @NonNull private final Api client; public ReadingListDataClient() { - client = RestAdapterFactory.newInstance(SITE).create(Api.class); + client = RetrofitFactory.newInstance(SITE).create(Api.class); } @VisibleForTesting public ReadingListDataClient(String baseUrl) { - client = RestAdapterFactory.newInstance(SITE, baseUrl).create(Api.class); + client = RetrofitFactory.newInstance(SITE, baseUrl).create(Api.class); } /** * Gets the Collections of the current user. */ - public LegacyReadingListsResponse getReadingLists() { - return client.getReadingLists(); + public LegacyReadingListsResponse getReadingLists() throws IOException { + return client.getReadingLists().execute().body(); } /** @@ -40,18 +43,18 @@ * * @param listId ID of the reading list to be retrieved */ - public LegacyReadingListPageTitlesResponse getMemberPages(int listId) { - return client.getMemberPages(listId); + public LegacyReadingListPageTitlesResponse getMemberPages(int listId) throws IOException { + return client.getMemberPages(listId).execute().body(); } private interface Api { - String ACTION_QUERY_LIST = "/w/api.php?format=json&formatversion=2&action=query&list="; + String ACTION_QUERY_LIST = "w/api.php?format=json&formatversion=2&action=query&list="; @GET(ACTION_QUERY_LIST + "lists" + "&lstprop=label%7Cdescription%7Cpublic%7Creview%7Cimage%7Ccount%7Cupdated%7Cowner") - LegacyReadingListsResponse getReadingLists(); + Call<LegacyReadingListsResponse> getReadingLists(); @GET(ACTION_QUERY_LIST + "listpages") - LegacyReadingListPageTitlesResponse getMemberPages(@Query("lspid") int collectionId); + Call<LegacyReadingListPageTitlesResponse> getMemberPages(@Query("lspid") int collectionId); } } diff --git a/app/src/main/java/org/wikipedia/server/PageService.java b/app/src/main/java/org/wikipedia/server/PageService.java index 4514bc3..5ac52ef 100644 --- a/app/src/main/java/org/wikipedia/server/PageService.java +++ b/app/src/main/java/org/wikipedia/server/PageService.java @@ -1,5 +1,7 @@ package org.wikipedia.server; +import java.io.IOException; + /** * Generic interface for Page content service. * Usually we would use direct Retrofit Callbacks here but since we have two ways of @@ -44,9 +46,11 @@ /** * Gets all page content of a given title. Used in the saved page sync background service. + * Synchronous call. * * @param title the page title to be used including prefix * @param noImages add the noimages flag to the request if true + * @throws IOException when the request did not succeed */ - PageCombo pageCombo(String title, boolean noImages); + PageCombo pageCombo(String title, boolean noImages) throws IOException; } diff --git a/app/src/main/java/org/wikipedia/server/mwapi/MwPageEndpointsCache.java b/app/src/main/java/org/wikipedia/server/mwapi/MwPageEndpointsCache.java index dcf6e75..fbb8024 100644 --- a/app/src/main/java/org/wikipedia/server/mwapi/MwPageEndpointsCache.java +++ b/app/src/main/java/org/wikipedia/server/mwapi/MwPageEndpointsCache.java @@ -3,7 +3,7 @@ import android.support.annotation.Nullable; import org.wikipedia.Site; -import org.wikipedia.dataclient.RestAdapterFactory; +import org.wikipedia.dataclient.retrofit.RetrofitFactory; /** * It's good to cache the Retrofit web service since it's a memory intensive object. @@ -27,6 +27,6 @@ } private MwPageService.MwPageEndpoints createMwService(Site site) { - return RestAdapterFactory.newInstance(site).create(MwPageService.MwPageEndpoints.class); + return RetrofitFactory.newInstance(site).create(MwPageService.MwPageEndpoints.class); } } diff --git a/app/src/main/java/org/wikipedia/server/mwapi/MwPageService.java b/app/src/main/java/org/wikipedia/server/mwapi/MwPageService.java index a83a754..3c51020 100644 --- a/app/src/main/java/org/wikipedia/server/mwapi/MwPageService.java +++ b/app/src/main/java/org/wikipedia/server/mwapi/MwPageService.java @@ -2,45 +2,67 @@ import org.wikipedia.Site; import org.wikipedia.WikipediaApp; +import org.wikipedia.dataclient.retrofit.RetrofitException; import org.wikipedia.server.PageCombo; import org.wikipedia.server.PageLead; import org.wikipedia.server.PageRemaining; import org.wikipedia.server.PageService; import org.wikipedia.server.PageSummary; +import org.wikipedia.server.restbase.RbPageEndpointsCache; import org.wikipedia.settings.RbSwitch; import org.wikipedia.zero.WikipediaZeroHandler; -import retrofit.Callback; -import retrofit.RetrofitError; -import retrofit.client.Response; -import retrofit.http.GET; -import retrofit.http.Headers; -import retrofit.http.Query; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.http.GET; +import retrofit2.http.Headers; +import retrofit2.http.Query; + +import java.io.IOException; /** * Retrofit web service client for MediaWiki PHP API. */ public class MwPageService implements PageService { private final MwPageEndpoints webService; + private final Retrofit retrofit; private WikipediaZeroHandler responseHeaderHandler; public MwPageService(final Site site) { responseHeaderHandler = WikipediaApp.getInstance().getWikipediaZeroHandler(); webService = MwPageEndpointsCache.INSTANCE.getMwPageEndpoints(site); + retrofit = RbPageEndpointsCache.INSTANCE.getRetrofit(); } @Override public void pageSummary(String title, final PageSummary.Callback cb) { - webService.pageSummary(title, new Callback<MwPageSummary>() { + Call<MwPageSummary> call = webService.pageSummary(title); + call.enqueue(new Callback<MwPageSummary>() { + /** + * Invoked for a received HTTP response. + * <p/> + * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500. + * Call {@link Response#isSuccessful()} to determine if the response indicates success. + */ @Override - public void success(MwPageSummary pageSummary, Response response) { - responseHeaderHandler.onHeaderCheck(response); - cb.success(pageSummary); + public void onResponse(Call<MwPageSummary> call, Response<MwPageSummary> response) { + if (response.isSuccessful()) { + responseHeaderHandler.onHeaderCheck(response); + cb.success(response.body()); + } else { + cb.failure(RetrofitException.httpError(response, retrofit)); + } } + /** + * Invoked when a network exception occurred talking to the server or when an unexpected + * exception occurred creating the request or processing the response. + */ @Override - public void failure(RetrofitError error) { - cb.failure(error); + public void onFailure(Call<MwPageSummary> call, Throwable t) { + cb.failure(t); } }); } @@ -48,54 +70,69 @@ @Override public void pageLead(String title, int leadImageThumbWidth, boolean noImages, final PageLead.Callback cb) { - webService.pageLead(title, leadImageThumbWidth, optional(noImages), new Callback<MwPageLead>() { + Call<MwPageLead> call = webService.pageLead(title, leadImageThumbWidth, optional(noImages)); + call.enqueue(new Callback<MwPageLead>() { @Override - public void success(MwPageLead pageLead, Response response) { - responseHeaderHandler.onHeaderCheck(response); - cb.success(pageLead); + public void onResponse(Call<MwPageLead> call, Response<MwPageLead> response) { + if (response.isSuccessful()) { + responseHeaderHandler.onHeaderCheck(response); + cb.success(response.body()); + } else { + cb.failure(RetrofitException.httpError(response, retrofit)); + } } @Override - public void failure(RetrofitError error) { - cb.failure(error); + public void onFailure(Call<MwPageLead> call, Throwable t) { + cb.failure(t); } }); } @Override public void pageRemaining(String title, boolean noImages, final PageRemaining.Callback cb) { - webService.pageRemaining(title, optional(noImages), new Callback<MwPageRemaining>() { + Call<MwPageRemaining> call = webService.pageRemaining(title, optional(noImages)); + call.enqueue(new Callback<MwPageRemaining>() { @Override - public void success(MwPageRemaining pageRemaining, Response response) { - RbSwitch.INSTANCE.onMwSuccess(); - cb.success(pageRemaining); + public void onResponse(Call<MwPageRemaining> call, Response<MwPageRemaining> response) { + if (response.isSuccessful()) { + RbSwitch.INSTANCE.onMwSuccess(); + cb.success(response.body()); + } else { + cb.failure(RetrofitException.httpError(response, retrofit)); + } } @Override - public void failure(RetrofitError error) { - cb.failure(error); + public void onFailure(Call<MwPageRemaining> call, Throwable t) { + cb.failure(t); } }); } @Override public void pageCombo(String title, boolean noImages, final PageCombo.Callback cb) { - webService.pageCombo(title, optional(noImages), new Callback<MwPageCombo>() { + Call<MwPageCombo> call = webService.pageCombo(title, optional(noImages)); + call.enqueue(new Callback<MwPageCombo>() { @Override - public void success(MwPageCombo pageCombo, Response response) { - cb.success(pageCombo); + public void onResponse(Call<MwPageCombo> call, Response<MwPageCombo> response) { + if (response.isSuccessful()) { + cb.success(response.body()); + } else { + cb.failure(RetrofitException.httpError(response, retrofit)); + } } @Override - public void failure(RetrofitError error) { - cb.failure(error); + public void onFailure(Call<MwPageCombo> call, Throwable t) { + cb.failure(t); } }); } @Override - public MwPageCombo pageCombo(String title, boolean noImages) { - return webService.pageCombo(title, noImages); + public MwPageCombo pageCombo(String title, boolean noImages) throws IOException { + return webService.pageCombo(title, noImages).execute().body(); } /** @@ -118,7 +155,7 @@ * Gets the lead section and initial metadata of a given title. * * @param title the page title with prefix if necessary - * @param cb a Retrofit callback which provides the populated MwPageLead object in #success + * @return a Retrofit Call which provides the populated MwPageLead object in #success */ /* Here's the rationale for this API call: @@ -134,10 +171,10 @@ unparsed wikitext, which we certainly don't want. */ @Headers("x-analytics: preview=1") - @GET("/w/api.php?action=query&format=json&formatversion=2&prop=extracts%7Cpageimages" + @GET("w/api.php?action=query&format=json&formatversion=2&prop=extracts%7Cpageimages" + "&redirects=true&exsentences=5&explaintext=true&piprop=thumbnail%7Cname" + "&pithumbsize=" + WikipediaApp.PREFERRED_THUMB_SIZE) - void pageSummary(@Query("titles") String title, Callback<MwPageSummary> cb); + Call<MwPageSummary> pageSummary(@Query("titles") String title); /** * Gets the lead section and initial metadata of a given title. @@ -145,45 +182,28 @@ * @param title the page title with prefix if necessary * @param leadImageThumbWidth one of the bucket widths for the lead image * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated MwPageLead object in #success */ @Headers("x-analytics: pageview=1") - @GET("/w/api.php?action=mobileview&format=json&formatversion=2&prop=" + @GET("w/api.php?action=mobileview&format=json&formatversion=2&prop=" + "text%7Csections%7Clanguagecount%7Cthumb%7Cimage%7Cid%7Crevision%7Cdescription" + "%7Clastmodified%7Cnormalizedtitle%7Cdisplaytitle%7Cprotection%7Ceditable" + "&onlyrequestedsections=1§ions=0§ionprop=toclevel%7Cline%7Canchor" + "&noheadings=true") - void pageLead(@Query("page") String title, @Query("thumbsize") int leadImageThumbWidth, - @Query("noimages") Boolean noImages, Callback<MwPageLead> cb); + Call<MwPageLead> pageLead(@Query("page") String title, + @Query("thumbsize") int leadImageThumbWidth, + @Query("noimages") Boolean noImages); /** * Gets the remaining sections of a given title. * * @param title the page title to be used including prefix * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated MwPageRemaining object in #success */ - @GET("/w/api.php?action=mobileview&format=json&prop=" + @GET("w/api.php?action=mobileview&format=json&prop=" + "text%7Csections&onlyrequestedsections=1§ions=1-" + "§ionprop=toclevel%7Cline%7Canchor&noheadings=true") - void pageRemaining(@Query("page") String title, @Query("noimages") Boolean noImages, - Callback<MwPageRemaining> cb); - - /** - * Gets all page content of a given title -- for refreshing a saved page - * Note: the only difference in the URL from #pageLead is the sections=all instead of 0. - * - * @param title the page title to be used including prefix - * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated MwPageCombo object in #success - */ - @GET("/w/api.php?action=mobileview&format=json&formatversion=2&prop=" - + "text%7Csections%7Clanguagecount%7Cthumb%7Cimage%7Cid%7Crevision%7Cdescription" - + "%7Clastmodified%7Cnormalizedtitle%7Cdisplaytitle%7Cprotection%7Ceditable" - + "&onlyrequestedsections=1§ions=all§ionprop=toclevel%7Cline%7Canchor" - + "&noheadings=true") - void pageCombo(@Query("page") String title, @Query("noimages") Boolean noImages, - Callback<MwPageCombo> cb); + Call<MwPageRemaining> pageRemaining(@Query("page") String title, + @Query("noimages") Boolean noImages); /** * Gets all page content of a given title -- for refreshing a saved page @@ -192,11 +212,12 @@ * @param title the page title to be used including prefix * @param noImages add the noimages flag to the request if true */ - @GET("/w/api.php?action=mobileview&format=json&formatversion=2&prop=" + @GET("w/api.php?action=mobileview&format=json&formatversion=2&prop=" + "text%7Csections%7Clanguagecount%7Cthumb%7Cimage%7Cid%7Crevision%7Cdescription" + "%7Clastmodified%7Cnormalizedtitle%7Cdisplaytitle%7Cprotection%7Ceditable" + "&onlyrequestedsections=1§ions=all§ionprop=toclevel%7Cline%7Canchor" + "&noheadings=true") - MwPageCombo pageCombo(@Query("page") String title, @Query("noimages") Boolean noImages); + Call<MwPageCombo> pageCombo(@Query("page") String title, + @Query("noimages") Boolean noImages); } } diff --git a/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java b/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java index de3ed01..a0596f3 100644 --- a/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java +++ b/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java @@ -1,8 +1,10 @@ package org.wikipedia.server.restbase; import org.wikipedia.Site; -import org.wikipedia.dataclient.RestAdapterFactory; +import org.wikipedia.dataclient.retrofit.RetrofitFactory; import org.wikipedia.settings.Prefs; + +import retrofit2.Retrofit; import java.util.Locale; @@ -15,8 +17,13 @@ private Site site; private RbPageService.RbEndpoints cachedWebService; + private Retrofit retrofit; private RbPageEndpointsCache() { + } + + public Retrofit getRetrofit() { + return retrofit; } public RbPageService.RbEndpoints getRbEndpoints(Site newSite) { @@ -28,8 +35,8 @@ } private RbPageService.RbEndpoints createRbService(Site site) { - return RestAdapterFactory.newInstance(site, - String.format(Locale.ROOT, Prefs.getRestbaseUriFormat(), site.scheme(), site.authority())) - .create(RbPageService.RbEndpoints.class); + retrofit = RetrofitFactory.newInstance(site, + String.format(Locale.ROOT, Prefs.getRestbaseUriFormat(), site.scheme(), site.authority())); + return retrofit.create(RbPageService.RbEndpoints.class); } } diff --git a/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java b/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java index e5b6d10..0f2050a 100644 --- a/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java +++ b/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java @@ -2,6 +2,7 @@ import org.wikipedia.Site; import org.wikipedia.WikipediaApp; +import org.wikipedia.dataclient.retrofit.RetrofitException; import org.wikipedia.server.PageCombo; import org.wikipedia.server.PageLead; import org.wikipedia.server.PageRemaining; @@ -10,41 +11,62 @@ import org.wikipedia.settings.RbSwitch; import org.wikipedia.zero.WikipediaZeroHandler; +import java.io.IOException; import java.util.Map; -import retrofit.Callback; -import retrofit.RetrofitError; -import retrofit.client.Response; -import retrofit.http.GET; -import retrofit.http.Headers; -import retrofit.http.Path; -import retrofit.http.Query; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.http.GET; +import retrofit2.http.Headers; +import retrofit2.http.Path; +import retrofit2.http.Query; /** * Retrofit web service client for RESTBase Nodejs API. */ public class RbPageService implements PageService { private final RbEndpoints webService; + private Retrofit retrofit; private WikipediaZeroHandler responseHeaderHandler; public RbPageService(final Site site) { responseHeaderHandler = WikipediaApp.getInstance().getWikipediaZeroHandler(); webService = RbPageEndpointsCache.INSTANCE.getRbEndpoints(site); + retrofit = RbPageEndpointsCache.INSTANCE.getRetrofit(); } @Override - public void pageSummary(String title, final PageSummary.Callback cb) { - webService.pageSummary(title, new Callback<RbPageSummary>() { + public void pageSummary(final String title, final PageSummary.Callback cb) { + Call<RbPageSummary> call = webService.pageSummary(title); + call.enqueue(new Callback<RbPageSummary>() { + /** + * Invoked for a received HTTP response. + * <p/> + * Note: An HTTP response may still indicate an application-level failure such as a 404 or 500. + * Call {@link Response#isSuccessful()} to determine if the response indicates success. + */ @Override - public void success(RbPageSummary pageSummary, Response response) { - responseHeaderHandler.onHeaderCheck(response); - cb.success(pageSummary); + public void onResponse(Call<RbPageSummary> call, Response<RbPageSummary> response) { + if (response.isSuccessful()) { + responseHeaderHandler.onHeaderCheck(response); + cb.success(response.body()); + } else { + Throwable throwable = RetrofitException.httpError(response, retrofit); + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); + } } + /** + * Invoked when a network exception occurred talking to the server or when an unexpected + * exception occurred creating the request or processing the response. + */ @Override - public void failure(RetrofitError error) { - RbSwitch.INSTANCE.onRbRequestFailed(error); - cb.failure(error); + public void onFailure(Call<RbPageSummary> call, Throwable t) { + RbSwitch.INSTANCE.onRbRequestFailed(t); + cb.failure(t); } }); } @@ -52,57 +74,79 @@ @Override public void pageLead(String title, final int leadImageThumbWidth, boolean noImages, final PageLead.Callback cb) { - webService.pageLead(title, optional(noImages), new Callback<RbPageLead>() { + Call<RbPageLead> call = webService.pageLead(title, optional(noImages)); + call.enqueue(new Callback<RbPageLead>() { @Override - public void success(RbPageLead pageLead, Response response) { - responseHeaderHandler.onHeaderCheck(response); - pageLead.setLeadImageThumbWidth(leadImageThumbWidth); - cb.success(pageLead); + public void onResponse(Call<RbPageLead> call, Response<RbPageLead> response) { + if (response.isSuccessful()) { + responseHeaderHandler.onHeaderCheck(response); + RbPageLead pageLead = response.body(); + pageLead.setLeadImageThumbWidth(leadImageThumbWidth); + cb.success(pageLead); + } else { + Throwable throwable = RetrofitException.httpError(response, retrofit); + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); + } } @Override - public void failure(RetrofitError error) { - RbSwitch.INSTANCE.onRbRequestFailed(error); - cb.failure(error); + public void onFailure(Call<RbPageLead> call, Throwable t) { + RbSwitch.INSTANCE.onRbRequestFailed(t); + cb.failure(t); } }); } @Override public void pageRemaining(String title, boolean noImages, final PageRemaining.Callback cb) { - webService.pageRemaining(title, optional(noImages), new Callback<RbPageRemaining>() { + Call<RbPageRemaining> call = webService.pageRemaining(title, optional(noImages)); + call.enqueue(new Callback<RbPageRemaining>() { @Override - public void success(RbPageRemaining pageRemaining, Response response) { - cb.success(pageRemaining); + public void onResponse(Call<RbPageRemaining> call, Response<RbPageRemaining> response) { + if (response.isSuccessful()) { + cb.success(response.body()); + } else { + Throwable throwable = RetrofitException.httpError(response, retrofit); + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); + } } @Override - public void failure(RetrofitError error) { - RbSwitch.INSTANCE.onRbRequestFailed(error); - cb.failure(error); + public void onFailure(Call<RbPageRemaining> call, Throwable t) { + RbSwitch.INSTANCE.onRbRequestFailed(t); + cb.failure(t); } }); } @Override public void pageCombo(String title, boolean noImages, final PageCombo.Callback cb) { - webService.pageCombo(title, optional(noImages), new Callback<RbPageCombo>() { + Call<RbPageCombo> call = webService.pageCombo(title, optional(noImages)); + call.enqueue(new Callback<RbPageCombo>() { @Override - public void success(RbPageCombo pageCombo, Response response) { - cb.success(pageCombo); + public void onResponse(Call<RbPageCombo> call, Response<RbPageCombo> response) { + if (response.isSuccessful()) { + cb.success(response.body()); + } else { + Throwable throwable = RetrofitException.httpError(response, retrofit); + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); + } } @Override - public void failure(RetrofitError error) { - RbSwitch.INSTANCE.onRbRequestFailed(error); - cb.failure(error); + public void onFailure(Call<RbPageCombo> call, Throwable t) { + RbSwitch.INSTANCE.onRbRequestFailed(t); + cb.failure(t); } }); } @Override - public RbPageCombo pageCombo(String title, boolean noImages) { - return webService.pageCombo(title, noImages); + public RbPageCombo pageCombo(String title, boolean noImages) throws IOException { + return webService.pageCombo(title, noImages).execute().body(); } /* Not defined in the PageService interface since the Wiktionary definition endpoint exists only @@ -110,25 +154,33 @@ * of a wiki page. */ public void define(String title, final RbDefinition.Callback cb) { - webService.define(title, new Callback<Map<String, RbDefinition.Usage[]>>() { + Call<Map<String, RbDefinition.Usage[]>> call = webService.define(title); + call.enqueue(new Callback<Map<String, RbDefinition.Usage[]>>() { @Override - public void success(Map<String, RbDefinition.Usage[]> definition, Response response) { - responseHeaderHandler.onHeaderCheck(response); - cb.success(new RbDefinition(definition)); + public void onResponse(Call<Map<String, RbDefinition.Usage[]>> call, + Response<Map<String, RbDefinition.Usage[]>> response) { + if (response.isSuccessful()) { + responseHeaderHandler.onHeaderCheck(response); + cb.success(new RbDefinition(response.body())); + } else { + Throwable throwable = RetrofitException.httpError(response, retrofit); + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); + } } @Override - public void failure(RetrofitError error) { - RbSwitch.INSTANCE.onRbRequestFailed(error); - cb.failure(error); + public void onFailure(Call<Map<String, RbDefinition.Usage[]>> call, Throwable throwable) { + RbSwitch.INSTANCE.onRbRequestFailed(throwable); + cb.failure(throwable); } }); } /** * Optional boolean Retrofit parameter. - * We don't want to send the query parameter at all when it's false since the presence of the parameter - * alone is enough to trigger the truthy behavior. + * We don't want to send the query parameter at all when it's false since the presence of the + * parameter alone is enough to trigger the truthy behavior. */ private Boolean optional(boolean param) { if (param) { @@ -145,34 +197,30 @@ * Gets a page summary for a given title -- for link previews * * @param title the page title to be used including prefix - * @param cb a Retrofit callback which provides the populated RbPageCombo object in #success */ @Headers("x-analytics: preview=1") - @GET("/page/summary/{title}") - void pageSummary(@Path("title") String title, Callback<RbPageSummary> cb); + @GET("page/summary/{title}") + Call<RbPageSummary> pageSummary(@Path("title") String title); /** * Gets the lead section and initial metadata of a given title. * * @param title the page title with prefix if necessary * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated RbPageLead object in #success */ @Headers("x-analytics: pageview=1") - @GET("/page/mobile-sections-lead/{title}") - void pageLead(@Path("title") String title, @Query("noimages") Boolean noImages, - Callback<RbPageLead> cb); + @GET("page/mobile-sections-lead/{title}") + Call<RbPageLead> pageLead(@Path("title") String title, @Query("noimages") Boolean noImages); /** * Gets the remaining sections of a given title. * * @param title the page title to be used including prefix * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated RbPageRemaining object in #success */ - @GET("/page/mobile-sections-remaining/{title}") - void pageRemaining(@Path("title") String title, @Query("noimages") Boolean noImages, - Callback<RbPageRemaining> cb); + @GET("page/mobile-sections-remaining/{title}") + Call<RbPageRemaining> pageRemaining(@Path("title") String title, + @Query("noimages") Boolean noImages); /** * Gets all page content of a given title -- for refreshing a saved page @@ -180,27 +228,17 @@ * * @param title the page title to be used including prefix * @param noImages add the noimages flag to the request if true - * @param cb a Retrofit callback which provides the populated RbPageCombo object in #success */ - @GET("/page/mobile-sections/{title}") - void pageCombo(@Path("title") String title, @Query("noimages") Boolean noImages, - Callback<RbPageCombo> cb); - - /** - * Gets all page content of a given title. Used in the saved page sync background service. - * - * @param title the page title to be used including prefix - * @param noImages add the noimages flag to the request if true - */ - @GET("/page/mobile-sections/{title}") - RbPageCombo pageCombo(@Path("title") String title, @Query("noimages") Boolean noImages); + @GET("page/mobile-sections/{title}") + Call<RbPageCombo> pageCombo(@Path("title") String title, + @Query("noimages") Boolean noImages); /** * Gets selected Wiktionary content for a given title derived from user-selected text * * @param title the Wiktionary page title derived from user-selected Wikipedia article text */ - @GET("/page/definition/{title}") - void define(@Path("title") String title, Callback<Map<String, RbDefinition.Usage[]>> cb); + @GET("page/definition/{title}") + Call<Map<String, RbDefinition.Usage[]>> define(@Path("title") String title); } } diff --git a/app/src/main/java/org/wikipedia/settings/Prefs.java b/app/src/main/java/org/wikipedia/settings/Prefs.java index ab61d90..af74123 100644 --- a/app/src/main/java/org/wikipedia/settings/Prefs.java +++ b/app/src/main/java/org/wikipedia/settings/Prefs.java @@ -19,7 +19,7 @@ import java.util.Collections; import java.util.List; -import retrofit.RestAdapter; +import okhttp3.logging.HttpLoggingInterceptor.Level; import static org.wikipedia.settings.PrefsIoUtil.contains; import static org.wikipedia.settings.PrefsIoUtil.getBoolean; @@ -281,36 +281,34 @@ setInt(R.string.preference_key_request_successes, successes); } - public static RestAdapter.LogLevel getRetrofitLogLevel() { + public static Level getRetrofitLogLevel() { String prefValue = getString(R.string.preference_key_retrofit_log_level, null); if (prefValue == null) { - return RestAdapter.LogLevel.NONE; + return Level.NONE; } switch (prefValue) { case "BASIC": - return RestAdapter.LogLevel.BASIC; + return Level.BASIC; case "HEADERS": - return RestAdapter.LogLevel.HEADERS; - case "HEADERS_AND_ARGS": - return RestAdapter.LogLevel.HEADERS_AND_ARGS; - case "FULL": - return RestAdapter.LogLevel.FULL; + return Level.HEADERS; + case "BODY": + return Level.BODY; case "NONE": default: - return RestAdapter.LogLevel.NONE; + return Level.NONE; } } @NonNull public static String getRestbaseUriFormat() { return StringUtil.defaultIfBlank(getString(R.string.preference_key_restbase_uri_format, null), - "%1$s://%2$s/api/rest_v1"); + "%1$s://%2$s/api/rest_v1/"); } @NonNull public static Uri getMediaWikiBaseUri() { return Uri.parse(StringUtil.defaultIfBlank(getString(R.string.preference_key_mediawiki_base_uri, null), - "https://wikipedia.org")); + "https://wikipedia.org/")); } public static long getLastRunTime(@NonNull String task) { diff --git a/app/src/main/java/org/wikipedia/settings/RbSwitch.java b/app/src/main/java/org/wikipedia/settings/RbSwitch.java index da4d339..e84d4a7 100644 --- a/app/src/main/java/org/wikipedia/settings/RbSwitch.java +++ b/app/src/main/java/org/wikipedia/settings/RbSwitch.java @@ -2,8 +2,7 @@ import org.wikipedia.Site; import org.wikipedia.WikipediaApp; - -import retrofit.RetrofitError; +import org.wikipedia.dataclient.retrofit.RetrofitException; import java.util.Random; @@ -97,7 +96,7 @@ /** * Call this method when a RESTBase call fails. */ - public void onRbRequestFailed(RetrofitError error) { + public void onRbRequestFailed(Throwable error) { if (isSignificantFailure(error)) { markRbFailed(); if (!Prefs.useRestBaseSetManually()) { @@ -111,12 +110,17 @@ * We don't want to fallback just because of a user error (404) * or a network issue on the client side (RetrofitError.Kind.NETWORK). */ - private static boolean isSignificantFailure(RetrofitError error) { - if (error.getKind() == RetrofitError.Kind.HTTP) { - int status = error.getResponse().getStatus(); + private static boolean isSignificantFailure(Throwable throwable) { + if (!(throwable instanceof RetrofitException)) { + return false; + } + + RetrofitException error = (RetrofitException) throwable; + if (error.getKind() == RetrofitException.Kind.HTTP) { + int status = error.getResponse().code(); return status != HTTP_NOT_FOUND; } - return error.getKind() != RetrofitError.Kind.NETWORK; + return error.getKind() != RetrofitException.Kind.NETWORK; } private static void markRbFailed() { diff --git a/app/src/main/java/org/wikipedia/useroption/dataclient/DefaultUserOptionDataClient.java b/app/src/main/java/org/wikipedia/useroption/dataclient/DefaultUserOptionDataClient.java index 9693ef6..f2890aa 100644 --- a/app/src/main/java/org/wikipedia/useroption/dataclient/DefaultUserOptionDataClient.java +++ b/app/src/main/java/org/wikipedia/useroption/dataclient/DefaultUserOptionDataClient.java @@ -7,7 +7,8 @@ import org.wikipedia.Site; import org.wikipedia.WikipediaApp; -import org.wikipedia.dataclient.RestAdapterFactory; +import org.wikipedia.dataclient.retrofit.RetrofitException; +import org.wikipedia.dataclient.retrofit.RetrofitFactory; import org.wikipedia.dataclient.mwapi.MwPostResponse; import org.wikipedia.dataclient.mwapi.MwQueryResponse; import org.wikipedia.editing.FetchEditTokenTask; @@ -15,12 +16,11 @@ import java.util.concurrent.Executor; -import retrofit.RetrofitError; -import retrofit.http.Field; -import retrofit.http.FormUrlEncoded; -import retrofit.http.GET; -import retrofit.http.POST; -import retrofit.http.Query; +import retrofit2.http.Field; +import retrofit2.http.FormUrlEncoded; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Query; public class DefaultUserOptionDataClient implements UserOptionDataClient { @NonNull private final Site site; @@ -28,7 +28,7 @@ public DefaultUserOptionDataClient(@NonNull Site site) { this.site = site; - client = RestAdapterFactory.newInstance(site).create(Client.class); + client = RetrofitFactory.newInstance(site).create(Client.class); } @NonNull @@ -54,7 +54,8 @@ String token = app().getEditTokenStorage().token(site); if (token == null) { - throw RetrofitError.unexpectedError(site.authority(), new RuntimeException("No token")); + throw RetrofitException.unexpectedError( + new RuntimeException("No token for " + site.authority())); } return token; } @@ -85,7 +86,7 @@ } private interface Client { - String ACTION = "/w/api.php?format=json&formatversion=2&action="; + String ACTION = "w/api.php?format=json&formatversion=2&action="; @GET(ACTION + "query&meta=userinfo&uiprop=options") @NonNull MwQueryResponse<QueryUserInfo> get(); @@ -115,8 +116,9 @@ app().getEditTokenStorage().token(site, null); } - throw RetrofitError.unexpectedError(site.host(), - new RuntimeException("Bad response=" + result())); + throw RetrofitException.unexpectedError( + new RuntimeException("Bad response for site " + site.host() + + " = " + result())); } } } diff --git a/app/src/main/java/org/wikipedia/useroption/sync/UserOptionSyncAdapter.java b/app/src/main/java/org/wikipedia/useroption/sync/UserOptionSyncAdapter.java index 7c341e2..1f8e830 100644 --- a/app/src/main/java/org/wikipedia/useroption/sync/UserOptionSyncAdapter.java +++ b/app/src/main/java/org/wikipedia/useroption/sync/UserOptionSyncAdapter.java @@ -10,6 +10,7 @@ import org.wikipedia.auth.AccountUtil; import org.wikipedia.database.http.HttpStatus; +import org.wikipedia.dataclient.retrofit.RetrofitException; import org.wikipedia.useroption.UserOption; import org.wikipedia.useroption.database.UserOptionDao; import org.wikipedia.useroption.database.UserOptionRow; @@ -20,8 +21,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; - -import retrofit.RetrofitError; public class UserOptionSyncAdapter extends AbstractThreadedSyncAdapter { public UserOptionSyncAdapter(Context context, boolean autoInitialize) { @@ -44,7 +43,7 @@ if (!uploadOnly) { download(); } - } catch (RetrofitError e) { + } catch (RetrofitException e) { L.d(e); ++syncResult.stats.numIoExceptions; } @@ -70,7 +69,7 @@ //noinspection ConstantConditions UserOptionDataClientSingleton.instance().post(row.dat()); } - } catch (RetrofitError e) { + } catch (RetrofitException e) { UserOptionDao.instance().failTransaction(rows); throw e; } diff --git a/app/src/main/java/org/wikipedia/util/ThrowableUtil.java b/app/src/main/java/org/wikipedia/util/ThrowableUtil.java index ec28683..d3a410e 100644 --- a/app/src/main/java/org/wikipedia/util/ThrowableUtil.java +++ b/app/src/main/java/org/wikipedia/util/ThrowableUtil.java @@ -4,11 +4,13 @@ import org.mediawiki.api.json.ApiException; import com.github.kevinsawicki.http.HttpRequest; import org.json.JSONException; + import android.content.Context; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import javax.net.ssl.SSLException; + import java.net.UnknownHostException; import java.util.concurrent.TimeoutException; diff --git a/app/src/main/java/org/wikipedia/zero/WikipediaZeroHandler.java b/app/src/main/java/org/wikipedia/zero/WikipediaZeroHandler.java index 877f0df..798e90c 100644 --- a/app/src/main/java/org/wikipedia/zero/WikipediaZeroHandler.java +++ b/app/src/main/java/org/wikipedia/zero/WikipediaZeroHandler.java @@ -13,8 +13,8 @@ import org.wikipedia.util.UriUtil; import org.wikipedia.util.log.L; -import retrofit.client.Header; -import retrofit.client.Response; +import okhttp3.Headers; +import retrofit2.Response; import android.app.Activity; import android.content.BroadcastReceiver; @@ -38,7 +38,6 @@ import android.widget.TextView; import java.net.URL; -import java.util.List; import static org.wikipedia.util.UriUtil.visitInExternalBrowser; @@ -338,10 +337,10 @@ } private String getHeader(Response response, String key) { - List<Header> headers = response.getHeaders(); - for (Header header: headers) { - if (key.equalsIgnoreCase(header.getName())) { - return header.getValue(); + Headers headers = response.headers(); + for (String name: headers.names()) { + if (key.equalsIgnoreCase(name)) { + return headers.get(name); } } return null; diff --git a/app/src/main/res/values/preference_values.xml b/app/src/main/res/values/preference_values.xml index 20487fd..d52d2ec 100644 --- a/app/src/main/res/values/preference_values.xml +++ b/app/src/main/res/values/preference_values.xml @@ -4,7 +4,6 @@ <item>NONE</item> <item>BASIC</item> <item>HEADERS</item> - <item>HEADERS_AND_ARGS</item> - <item>FULL</item> + <item>BODY</item> </string-array> </resources> \ No newline at end of file diff --git a/app/src/main/res/xml/developer_preferences.xml b/app/src/main/res/xml/developer_preferences.xml index 1fdff7e..f214e3f 100644 --- a/app/src/main/res/xml/developer_preferences.xml +++ b/app/src/main/res/xml/developer_preferences.xml @@ -37,8 +37,8 @@ style="@style/DataStringPreference" android:key="@string/preference_key_restbase_uri_format" android:title="@string/preference_key_restbase_uri_format" - android:dialogMessage="Prod: %1$s://%2$s/api/rest_v1 - \nDev: http://host:6927/%2$s/v1 + android:dialogMessage="Prod: %1$s://%2$s/api/rest_v1/ + \nDev: http://host:6927/%2$s/v1/ \n%1$s ➛ protocol (https if omitted) \n%2$s ➛ WP host \nNote: change requires restart." /> diff --git a/app/src/test/java/org/wikipedia/dataclient/RetrofitClientBaseTest.java b/app/src/test/java/org/wikipedia/dataclient/RetrofitClientBaseTest.java index 6ee553f..2d6e201 100644 --- a/app/src/test/java/org/wikipedia/dataclient/RetrofitClientBaseTest.java +++ b/app/src/test/java/org/wikipedia/dataclient/RetrofitClientBaseTest.java @@ -8,6 +8,8 @@ import android.support.annotation.NonNull; +import java.io.IOException; + /** * A base class for test cases of Retrofit clients using the MockWebServer. */ @@ -25,7 +27,7 @@ } protected void runTest(String responseBody, BaseTestSubject subject) - throws InterruptedException { + throws InterruptedException, IOException { server.enqueue(responseBody); subject.execute(); @@ -41,7 +43,7 @@ return client; } - public abstract void execute(); + public abstract void execute() throws IOException; protected BaseTestSubject() { client = new ReadingListDataClient(server.getUrl("/").toString()); diff --git a/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListPageTitlesTest.java b/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListPageTitlesTest.java index bf716ac..a11b847 100644 --- a/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListPageTitlesTest.java +++ b/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListPageTitlesTest.java @@ -9,6 +9,7 @@ import android.support.annotation.Nullable; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -52,7 +53,7 @@ } @Override - public void execute() { + public void execute() throws IOException { LegacyReadingListPageTitlesResponse actual = getClient().getMemberPages(WATCHLIST_ID); if (expected != null) { List<LegacyReadingListPageTitle> act = actual.query().getMemberPages(); diff --git a/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListsTest.java b/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListsTest.java index 0a8b4f7..3e1e4e0 100644 --- a/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListsTest.java +++ b/app/src/test/java/org/wikipedia/readinglist/api/legacy/GetLegacyReadingListsTest.java @@ -9,6 +9,7 @@ import android.support.annotation.Nullable; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -59,7 +60,7 @@ } @Override - public void execute() { + public void execute() throws IOException { LegacyReadingListsResponse actual = getClient().getReadingLists(); if (expected != null) { List<LegacyReadingList> act = actual.query().getLists(); diff --git a/app/src/test/java/org/wikipedia/test/TestWebServer.java b/app/src/test/java/org/wikipedia/test/TestWebServer.java index 38c38b7..46d9833 100644 --- a/app/src/test/java/org/wikipedia/test/TestWebServer.java +++ b/app/src/test/java/org/wikipedia/test/TestWebServer.java @@ -1,7 +1,7 @@ package org.wikipedia.test; -import com.squareup.okhttp.mockwebserver.MockResponse; -import com.squareup.okhttp.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; import org.wikipedia.testlib.TestConstants; @@ -28,7 +28,7 @@ } public URL getUrl(String path) { - return server.getUrl(path); + return server.url(path).url(); } public int getRequestCount() { -- To view, visit https://gerrit.wikimedia.org/r/286900 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I0fd2fd9b9b800ac49dd28911591a85e7e01b57c9 Gerrit-PatchSet: 10 Gerrit-Project: apps/android/wikipedia Gerrit-Branch: master Gerrit-Owner: BearND <[email protected]> Gerrit-Reviewer: BearND <[email protected]> Gerrit-Reviewer: Brion VIBBER <[email protected]> Gerrit-Reviewer: Dbrant <[email protected]> Gerrit-Reviewer: Mholloway <[email protected]> Gerrit-Reviewer: Niedzielski <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
