1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "google_apis/gaia/oauth2_token_service_request.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "google_apis/gaia/google_service_auth_error.h"
13 #include "google_apis/gaia/oauth2_access_token_consumer.h"
15 OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
18 OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() {
21 // Core serves as the base class for OAuth2TokenService operations. Each
22 // operation should be modeled as a derived type.
24 // Core is used like this:
26 // 1. Constructed on owner thread.
28 // 2. Start() is called on owner thread, which calls StartOnTokenServiceThread()
29 // on token service thread.
31 // 3. Request is executed.
33 // 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread()
34 // on token service thread.
36 // 5. Core is destroyed on owner thread.
37 class OAuth2TokenServiceRequest::Core
38 : public base::NonThreadSafe
,
39 public base::RefCountedThreadSafe
<OAuth2TokenServiceRequest::Core
> {
41 // Note the thread where an instance of Core is constructed is referred to as
42 // the "owner thread" here.
43 Core(OAuth2TokenServiceRequest
* owner
,
44 const scoped_refptr
<TokenServiceProvider
>& provider
);
46 // Starts the core. Must be called on the owner thread.
49 // Stops the core. Must be called on the owner thread.
52 // Returns true if this object has been stopped. Must be called on the owner
54 bool IsStopped() const;
57 // Core must be destroyed on the owner thread. If data members must be
58 // cleaned up or destroyed on the token service thread, do so in the
59 // StopOnTokenServiceThread method.
62 // Called on the token service thread.
63 virtual void StartOnTokenServiceThread() = 0;
65 // Called on the token service thread.
66 virtual void StopOnTokenServiceThread() = 0;
68 base::SingleThreadTaskRunner
* token_service_task_runner();
69 OAuth2TokenService
* token_service();
70 OAuth2TokenServiceRequest
* owner();
73 friend class base::RefCountedThreadSafe
<OAuth2TokenServiceRequest::Core
>;
77 scoped_refptr
<base::SingleThreadTaskRunner
> token_service_task_runner_
;
78 OAuth2TokenServiceRequest
* owner_
;
80 // Clear on owner thread. OAuth2TokenServiceRequest promises to clear its
81 // last reference to TokenServiceProvider on the owner thread so the caller
82 // can ensure it is destroyed on the owner thread if desired.
83 scoped_refptr
<TokenServiceProvider
> provider_
;
85 DISALLOW_COPY_AND_ASSIGN(Core
);
88 OAuth2TokenServiceRequest::Core::Core(
89 OAuth2TokenServiceRequest
* owner
,
90 const scoped_refptr
<TokenServiceProvider
>& provider
)
91 : owner_(owner
), provider_(provider
) {
94 token_service_task_runner_
= provider_
->GetTokenServiceTaskRunner();
95 DCHECK(token_service_task_runner_
);
98 OAuth2TokenServiceRequest::Core::~Core() {
101 void OAuth2TokenServiceRequest::Core::Start() {
102 DCHECK(CalledOnValidThread());
103 token_service_task_runner_
->PostTask(
105 base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread
,
109 void OAuth2TokenServiceRequest::Core::Stop() {
110 DCHECK(CalledOnValidThread());
111 DCHECK(!IsStopped());
113 // Detaches |owner_| from this instance so |owner_| will be called back only
114 // if |Stop()| has never been called.
117 // We are stopping and will likely be destroyed soon. Use a reply closure
118 // (DoNothing) to retain "this" and ensure we are destroyed in the owner
119 // thread, not the task runner thread. PostTaskAndReply guarantees that the
120 // reply closure will execute after StopOnTokenServiceThread has completed.
121 token_service_task_runner_
->PostTaskAndReply(
123 base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread
,
125 base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing
, this));
128 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
129 DCHECK(CalledOnValidThread());
130 return owner_
== NULL
;
133 base::SingleThreadTaskRunner
*
134 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
135 return token_service_task_runner_
;
138 OAuth2TokenService
* OAuth2TokenServiceRequest::Core::token_service() {
139 DCHECK(token_service_task_runner_
->BelongsToCurrentThread());
140 return provider_
->GetTokenService();
143 OAuth2TokenServiceRequest
* OAuth2TokenServiceRequest::Core::owner() {
144 DCHECK(CalledOnValidThread());
148 void OAuth2TokenServiceRequest::Core::DoNothing() {
149 DCHECK(CalledOnValidThread());
154 // An implementation of Core for getting an access token.
155 class RequestCore
: public OAuth2TokenServiceRequest::Core
,
156 public OAuth2TokenService::Consumer
{
158 RequestCore(OAuth2TokenServiceRequest
* owner
,
160 OAuth2TokenServiceRequest::TokenServiceProvider
>& provider
,
161 OAuth2TokenService::Consumer
* consumer
,
162 const std::string
& account_id
,
163 const OAuth2TokenService::ScopeSet
& scopes
);
165 // OAuth2TokenService::Consumer. Must be called on the token service thread.
166 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
167 const std::string
& access_token
,
168 const base::Time
& expiration_time
) OVERRIDE
;
169 virtual void OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
170 const GoogleServiceAuthError
& error
) OVERRIDE
;
173 friend class base::RefCountedThreadSafe
<RequestCore
>;
175 // Must be destroyed on the owner thread.
176 virtual ~RequestCore();
178 // Core implementation.
179 virtual void StartOnTokenServiceThread() OVERRIDE
;
180 virtual void StopOnTokenServiceThread() OVERRIDE
;
182 void InformOwnerOnGetTokenSuccess(std::string access_token
,
183 base::Time expiration_time
);
184 void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error
);
186 scoped_refptr
<base::SingleThreadTaskRunner
> owner_task_runner_
;
187 OAuth2TokenService::Consumer
* const consumer_
;
188 std::string account_id_
;
189 OAuth2TokenService::ScopeSet scopes_
;
191 // OAuth2TokenService request for fetching OAuth2 access token; it should be
192 // created, reset and accessed only on the token service thread.
193 scoped_ptr
<OAuth2TokenService::Request
> request_
;
195 DISALLOW_COPY_AND_ASSIGN(RequestCore
);
198 RequestCore::RequestCore(
199 OAuth2TokenServiceRequest
* owner
,
200 const scoped_refptr
<OAuth2TokenServiceRequest::TokenServiceProvider
>&
202 OAuth2TokenService::Consumer
* consumer
,
203 const std::string
& account_id
,
204 const OAuth2TokenService::ScopeSet
& scopes
)
205 : OAuth2TokenServiceRequest::Core(owner
, provider
),
206 OAuth2TokenService::Consumer("oauth2_token_service"),
207 owner_task_runner_(base::ThreadTaskRunnerHandle::Get()),
209 account_id_(account_id
),
212 DCHECK(!account_id_
.empty());
213 DCHECK(!scopes_
.empty());
216 RequestCore::~RequestCore() {
219 void RequestCore::StartOnTokenServiceThread() {
220 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
221 request_
= token_service()->StartRequest(account_id_
, scopes_
, this).Pass();
224 void RequestCore::StopOnTokenServiceThread() {
225 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
229 void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request
* request
,
230 const std::string
& access_token
,
231 const base::Time
& expiration_time
) {
232 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
233 DCHECK_EQ(request_
.get(), request
);
234 owner_task_runner_
->PostTask(
236 base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess
,
243 void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request
* request
,
244 const GoogleServiceAuthError
& error
) {
245 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
246 DCHECK_EQ(request_
.get(), request
);
247 owner_task_runner_
->PostTask(
249 base::Bind(&RequestCore::InformOwnerOnGetTokenFailure
, this, error
));
253 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token
,
254 base::Time expiration_time
) {
255 DCHECK(CalledOnValidThread());
257 consumer_
->OnGetTokenSuccess(owner(), access_token
, expiration_time
);
261 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error
) {
262 DCHECK(CalledOnValidThread());
264 consumer_
->OnGetTokenFailure(owner(), error
);
268 // An implementation of Core for invalidating an access token.
269 class InvalidateCore
: public OAuth2TokenServiceRequest::Core
{
271 InvalidateCore(OAuth2TokenServiceRequest
* owner
,
273 OAuth2TokenServiceRequest::TokenServiceProvider
>& provider
,
274 const std::string
& access_token
,
275 const std::string
& account_id
,
276 const OAuth2TokenService::ScopeSet
& scopes
);
279 friend class base::RefCountedThreadSafe
<InvalidateCore
>;
281 // Must be destroyed on the owner thread.
282 virtual ~InvalidateCore();
284 // Core implementation.
285 virtual void StartOnTokenServiceThread() OVERRIDE
;
286 virtual void StopOnTokenServiceThread() OVERRIDE
;
288 std::string access_token_
;
289 std::string account_id_
;
290 OAuth2TokenService::ScopeSet scopes_
;
292 DISALLOW_COPY_AND_ASSIGN(InvalidateCore
);
295 InvalidateCore::InvalidateCore(
296 OAuth2TokenServiceRequest
* owner
,
297 const scoped_refptr
<OAuth2TokenServiceRequest::TokenServiceProvider
>&
299 const std::string
& access_token
,
300 const std::string
& account_id
,
301 const OAuth2TokenService::ScopeSet
& scopes
)
302 : OAuth2TokenServiceRequest::Core(owner
, provider
),
303 access_token_(access_token
),
304 account_id_(account_id
),
306 DCHECK(!access_token_
.empty());
307 DCHECK(!account_id_
.empty());
308 DCHECK(!scopes
.empty());
311 InvalidateCore::~InvalidateCore() {
314 void InvalidateCore::StartOnTokenServiceThread() {
315 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
316 token_service()->InvalidateToken(account_id_
, scopes_
, access_token_
);
319 void InvalidateCore::StopOnTokenServiceThread() {
320 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
327 scoped_ptr
<OAuth2TokenServiceRequest
> OAuth2TokenServiceRequest::CreateAndStart(
328 const scoped_refptr
<TokenServiceProvider
>& provider
,
329 const std::string
& account_id
,
330 const OAuth2TokenService::ScopeSet
& scopes
,
331 OAuth2TokenService::Consumer
* consumer
) {
332 scoped_ptr
<OAuth2TokenServiceRequest
> request(
333 new OAuth2TokenServiceRequest(account_id
));
334 scoped_refptr
<Core
> core(
335 new RequestCore(request
.get(), provider
, consumer
, account_id
, scopes
));
336 request
->StartWithCore(core
);
337 return request
.Pass();
341 void OAuth2TokenServiceRequest::InvalidateToken(
342 const scoped_refptr
<TokenServiceProvider
>& provider
,
343 const std::string
& account_id
,
344 const OAuth2TokenService::ScopeSet
& scopes
,
345 const std::string
& access_token
) {
346 scoped_ptr
<OAuth2TokenServiceRequest
> request(
347 new OAuth2TokenServiceRequest(account_id
));
348 scoped_refptr
<Core
> core(new InvalidateCore(
349 request
.get(), provider
, access_token
, account_id
, scopes
));
350 request
->StartWithCore(core
);
353 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
357 std::string
OAuth2TokenServiceRequest::GetAccountId() const {
361 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
362 const std::string
& account_id
)
363 : account_id_(account_id
) {
364 DCHECK(!account_id_
.empty());
367 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr
<Core
>& core
) {