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, TokenServiceProvider* provider);
45 // Starts the core. Must be called on the owner thread.
48 // Stops the core. Must be called on the owner thread.
51 // Returns true if this object has been stopped. Must be called on the owner
53 bool IsStopped() const;
56 // Core must be destroyed on the owner thread. If data members must be
57 // cleaned up or destroyed on the token service thread, do so in the
58 // StopOnTokenServiceThread method.
61 // Called on the token service thread.
62 virtual void StartOnTokenServiceThread() = 0;
64 // Called on the token service thread.
65 virtual void StopOnTokenServiceThread() = 0;
67 base::SingleThreadTaskRunner* token_service_task_runner();
68 OAuth2TokenService* token_service();
69 OAuth2TokenServiceRequest* owner();
72 friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
76 scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_;
77 OAuth2TokenServiceRequest* owner_;
78 TokenServiceProvider* provider_;
79 DISALLOW_COPY_AND_ASSIGN(Core);
82 OAuth2TokenServiceRequest::Core::Core(OAuth2TokenServiceRequest* owner,
83 TokenServiceProvider* provider)
84 : owner_(owner), provider_(provider) {
87 token_service_task_runner_ = provider_->GetTokenServiceTaskRunner();
88 DCHECK(token_service_task_runner_);
91 OAuth2TokenServiceRequest::Core::~Core() {
94 void OAuth2TokenServiceRequest::Core::Start() {
95 DCHECK(CalledOnValidThread());
96 token_service_task_runner_->PostTask(
98 base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
102 void OAuth2TokenServiceRequest::Core::Stop() {
103 DCHECK(CalledOnValidThread());
104 DCHECK(!IsStopped());
106 // Detaches |owner_| from this instance so |owner_| will be called back only
107 // if |Stop()| has never been called.
110 // We are stopping and will likely be destroyed soon. Use a reply closure
111 // (DoNothing) to retain "this" and ensure we are destroyed in the owner
112 // thread, not the task runner thread. PostTaskAndReply guarantees that the
113 // reply closure will execute after StopOnTokenServiceThread has completed.
114 token_service_task_runner_->PostTaskAndReply(
116 base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread,
118 base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing, this));
121 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
122 DCHECK(CalledOnValidThread());
123 return owner_ == NULL;
126 base::SingleThreadTaskRunner*
127 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
128 return token_service_task_runner_;
131 OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
132 DCHECK(token_service_task_runner_->BelongsToCurrentThread());
133 return provider_->GetTokenService();
136 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
137 DCHECK(CalledOnValidThread());
141 void OAuth2TokenServiceRequest::Core::DoNothing() {
142 DCHECK(CalledOnValidThread());
147 // An implementation of Core for getting an access token.
148 class RequestCore : public OAuth2TokenServiceRequest::Core,
149 public OAuth2TokenService::Consumer {
151 RequestCore(OAuth2TokenServiceRequest* owner,
152 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
153 OAuth2TokenService::Consumer* consumer,
154 const std::string& account_id,
155 const OAuth2TokenService::ScopeSet& scopes);
157 // OAuth2TokenService::Consumer. Must be called on the token service thread.
158 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
159 const std::string& access_token,
160 const base::Time& expiration_time) OVERRIDE;
161 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
162 const GoogleServiceAuthError& error) OVERRIDE;
165 friend class base::RefCountedThreadSafe<RequestCore>;
167 // Must be destroyed on the owner thread.
168 virtual ~RequestCore();
170 // Core implementation.
171 virtual void StartOnTokenServiceThread() OVERRIDE;
172 virtual void StopOnTokenServiceThread() OVERRIDE;
174 void InformOwnerOnGetTokenSuccess(std::string access_token,
175 base::Time expiration_time);
176 void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error);
178 scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
179 OAuth2TokenService::Consumer* const consumer_;
180 std::string account_id_;
181 OAuth2TokenService::ScopeSet scopes_;
183 // OAuth2TokenService request for fetching OAuth2 access token; it should be
184 // created, reset and accessed only on the token service thread.
185 scoped_ptr<OAuth2TokenService::Request> request_;
187 DISALLOW_COPY_AND_ASSIGN(RequestCore);
190 RequestCore::RequestCore(
191 OAuth2TokenServiceRequest* owner,
192 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
193 OAuth2TokenService::Consumer* consumer,
194 const std::string& account_id,
195 const OAuth2TokenService::ScopeSet& scopes)
196 : OAuth2TokenServiceRequest::Core(owner, provider),
197 OAuth2TokenService::Consumer("oauth2_token_service"),
198 owner_task_runner_(base::ThreadTaskRunnerHandle::Get()),
200 account_id_(account_id),
203 DCHECK(!account_id_.empty());
204 DCHECK(!scopes_.empty());
207 RequestCore::~RequestCore() {
210 void RequestCore::StartOnTokenServiceThread() {
211 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
212 request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
215 void RequestCore::StopOnTokenServiceThread() {
216 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
220 void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
221 const std::string& access_token,
222 const base::Time& expiration_time) {
223 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
224 DCHECK_EQ(request_.get(), request);
225 owner_task_runner_->PostTask(
227 base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess,
234 void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request* request,
235 const GoogleServiceAuthError& error) {
236 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
237 DCHECK_EQ(request_.get(), request);
238 owner_task_runner_->PostTask(
240 base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error));
244 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
245 base::Time expiration_time) {
246 DCHECK(CalledOnValidThread());
248 consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
252 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
253 DCHECK(CalledOnValidThread());
255 consumer_->OnGetTokenFailure(owner(), error);
259 // An implementation of Core for invalidating an access token.
260 class InvalidateCore : public OAuth2TokenServiceRequest::Core {
262 InvalidateCore(OAuth2TokenServiceRequest* owner,
263 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
264 const std::string& access_token,
265 const std::string& account_id,
266 const OAuth2TokenService::ScopeSet& scopes);
269 friend class base::RefCountedThreadSafe<InvalidateCore>;
271 // Must be destroyed on the owner thread.
272 virtual ~InvalidateCore();
274 // Core implementation.
275 virtual void StartOnTokenServiceThread() OVERRIDE;
276 virtual void StopOnTokenServiceThread() OVERRIDE;
278 std::string access_token_;
279 std::string account_id_;
280 OAuth2TokenService::ScopeSet scopes_;
282 DISALLOW_COPY_AND_ASSIGN(InvalidateCore);
285 InvalidateCore::InvalidateCore(
286 OAuth2TokenServiceRequest* owner,
287 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
288 const std::string& access_token,
289 const std::string& account_id,
290 const OAuth2TokenService::ScopeSet& scopes)
291 : OAuth2TokenServiceRequest::Core(owner, provider),
292 access_token_(access_token),
293 account_id_(account_id),
295 DCHECK(!access_token_.empty());
296 DCHECK(!account_id_.empty());
297 DCHECK(!scopes.empty());
300 InvalidateCore::~InvalidateCore() {
303 void InvalidateCore::StartOnTokenServiceThread() {
304 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
305 token_service()->InvalidateToken(account_id_, scopes_, access_token_);
308 void InvalidateCore::StopOnTokenServiceThread() {
309 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
316 scoped_ptr<OAuth2TokenServiceRequest> OAuth2TokenServiceRequest::CreateAndStart(
317 TokenServiceProvider* provider,
318 const std::string& account_id,
319 const OAuth2TokenService::ScopeSet& scopes,
320 OAuth2TokenService::Consumer* consumer) {
321 scoped_ptr<OAuth2TokenServiceRequest> request(
322 new OAuth2TokenServiceRequest(account_id));
323 scoped_refptr<Core> core(
324 new RequestCore(request.get(), provider, consumer, account_id, scopes));
325 request->StartWithCore(core);
326 return request.Pass();
330 void OAuth2TokenServiceRequest::InvalidateToken(
331 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
332 const std::string& account_id,
333 const OAuth2TokenService::ScopeSet& scopes,
334 const std::string& access_token) {
335 scoped_ptr<OAuth2TokenServiceRequest> request(
336 new OAuth2TokenServiceRequest(account_id));
337 scoped_refptr<Core> core(new InvalidateCore(
338 request.get(), provider, access_token, account_id, scopes));
339 request->StartWithCore(core);
342 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
346 std::string OAuth2TokenServiceRequest::GetAccountId() const {
350 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
351 const std::string& account_id)
352 : account_id_(account_id) {
353 DCHECK(!account_id_.empty());
356 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {