• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.volley.toolbox;
18 
19 import androidx.annotation.Nullable;
20 import androidx.annotation.RestrictTo;
21 import com.android.volley.AuthFailureError;
22 import com.android.volley.Request;
23 import com.android.volley.VolleyLog;
24 import java.io.IOException;
25 import java.io.InterruptedIOException;
26 import java.util.Map;
27 import java.util.concurrent.CountDownLatch;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.atomic.AtomicReference;
30 
31 /**
32  * Asynchronous extension of the {@link BaseHttpStack} class.
33  *
34  * <p><b>WARNING</b>: This API is experimental and subject to breaking changes. Please see
35  * https://github.com/google/volley/wiki/Asynchronous-Volley for more details.
36  */
37 public abstract class AsyncHttpStack extends BaseHttpStack {
38     private ExecutorService mBlockingExecutor;
39     private ExecutorService mNonBlockingExecutor;
40 
41     public interface OnRequestComplete {
42         /** Invoked when the stack successfully completes a request. */
onSuccess(HttpResponse httpResponse)43         void onSuccess(HttpResponse httpResponse);
44 
45         /** Invoked when the stack throws an {@link AuthFailureError} during a request. */
onAuthError(AuthFailureError authFailureError)46         void onAuthError(AuthFailureError authFailureError);
47 
48         /** Invoked when the stack throws an {@link IOException} during a request. */
onError(IOException ioException)49         void onError(IOException ioException);
50     }
51 
52     /**
53      * Makes an HTTP request with the given parameters, and calls the {@link OnRequestComplete}
54      * callback, with either the {@link HttpResponse} or error that was thrown.
55      *
56      * @param request to perform
57      * @param additionalHeaders to be sent together with {@link Request#getHeaders()}
58      * @param callback to be called after retrieving the {@link HttpResponse} or throwing an error.
59      */
executeRequest( Request<?> request, Map<String, String> additionalHeaders, OnRequestComplete callback)60     public abstract void executeRequest(
61             Request<?> request, Map<String, String> additionalHeaders, OnRequestComplete callback);
62 
63     /**
64      * This method sets the non blocking executor to be used by the stack for non-blocking tasks.
65      * This method must be called before executing any requests.
66      */
67     @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
setNonBlockingExecutor(ExecutorService executor)68     public void setNonBlockingExecutor(ExecutorService executor) {
69         mNonBlockingExecutor = executor;
70     }
71 
72     /**
73      * This method sets the blocking executor to be used by the stack for potentially blocking
74      * tasks. This method must be called before executing any requests.
75      */
76     @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
setBlockingExecutor(ExecutorService executor)77     public void setBlockingExecutor(ExecutorService executor) {
78         mBlockingExecutor = executor;
79     }
80 
81     /** Gets blocking executor to perform any potentially blocking tasks. */
getBlockingExecutor()82     protected ExecutorService getBlockingExecutor() {
83         return mBlockingExecutor;
84     }
85 
86     /** Gets non-blocking executor to perform any non-blocking tasks. */
getNonBlockingExecutor()87     protected ExecutorService getNonBlockingExecutor() {
88         return mNonBlockingExecutor;
89     }
90 
91     /**
92      * Performs an HTTP request with the given parameters.
93      *
94      * @param request the request to perform
95      * @param additionalHeaders additional headers to be sent together with {@link
96      *     Request#getHeaders()}
97      * @return the {@link HttpResponse}
98      * @throws IOException if an I/O error occurs during the request
99      * @throws AuthFailureError if an authentication failure occurs during the request
100      */
101     @Override
executeRequest( Request<?> request, Map<String, String> additionalHeaders)102     public final HttpResponse executeRequest(
103             Request<?> request, Map<String, String> additionalHeaders)
104             throws IOException, AuthFailureError {
105         final CountDownLatch latch = new CountDownLatch(1);
106         final AtomicReference<Response> entry = new AtomicReference<>();
107         executeRequest(
108                 request,
109                 additionalHeaders,
110                 new OnRequestComplete() {
111                     @Override
112                     public void onSuccess(HttpResponse httpResponse) {
113                         Response response =
114                                 new Response(
115                                         httpResponse,
116                                         /* ioException= */ null,
117                                         /* authFailureError= */ null);
118                         entry.set(response);
119                         latch.countDown();
120                     }
121 
122                     @Override
123                     public void onAuthError(AuthFailureError authFailureError) {
124                         Response response =
125                                 new Response(
126                                         /* httpResponse= */ null,
127                                         /* ioException= */ null,
128                                         authFailureError);
129                         entry.set(response);
130                         latch.countDown();
131                     }
132 
133                     @Override
134                     public void onError(IOException ioException) {
135                         Response response =
136                                 new Response(
137                                         /* httpResponse= */ null,
138                                         ioException,
139                                         /* authFailureError= */ null);
140                         entry.set(response);
141                         latch.countDown();
142                     }
143                 });
144         try {
145             latch.await();
146         } catch (InterruptedException e) {
147             VolleyLog.e(e, "while waiting for CountDownLatch");
148             Thread.currentThread().interrupt();
149             throw new InterruptedIOException(e.toString());
150         }
151         Response response = entry.get();
152         if (response.httpResponse != null) {
153             return response.httpResponse;
154         } else if (response.ioException != null) {
155             throw response.ioException;
156         } else {
157             throw response.authFailureError;
158         }
159     }
160 
161     private static class Response {
162         HttpResponse httpResponse;
163         IOException ioException;
164         AuthFailureError authFailureError;
165 
Response( @ullable HttpResponse httpResponse, @Nullable IOException ioException, @Nullable AuthFailureError authFailureError)166         private Response(
167                 @Nullable HttpResponse httpResponse,
168                 @Nullable IOException ioException,
169                 @Nullable AuthFailureError authFailureError) {
170             this.httpResponse = httpResponse;
171             this.ioException = ioException;
172             this.authFailureError = authFailureError;
173         }
174     }
175 }
176