Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / google_apis / gaia / oauth2_token_service_request.cc
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.
4
5 #include "google_apis/gaia/oauth2_token_service_request.h"
6
7 #include "base/bind.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"
14
15 OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
16 }
17
18 OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() {
19 }
20
21 // Core serves as the base class for OAuth2TokenService operations.  Each
22 // operation should be modeled as a derived type.
23 //
24 // Core is used like this:
25 //
26 // 1. Constructed on owner thread.
27 //
28 // 2. Start() is called on owner thread, which calls StartOnTokenServiceThread()
29 // on token service thread.
30 //
31 // 3. Request is executed.
32 //
33 // 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread()
34 // on token service thread.
35 //
36 // 5. Core is destroyed on owner thread.
37 class OAuth2TokenServiceRequest::Core
38     : public base::NonThreadSafe,
39       public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> {
40  public:
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);
45
46   // Starts the core.  Must be called on the owner thread.
47   void Start();
48
49   // Stops the core.  Must be called on the owner thread.
50   void Stop();
51
52   // Returns true if this object has been stopped.  Must be called on the owner
53   // thread.
54   bool IsStopped() const;
55
56  protected:
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.
60   virtual ~Core();
61
62   // Called on the token service thread.
63   virtual void StartOnTokenServiceThread() = 0;
64
65   // Called on the token service thread.
66   virtual void StopOnTokenServiceThread() = 0;
67
68   base::SingleThreadTaskRunner* token_service_task_runner();
69   OAuth2TokenService* token_service();
70   OAuth2TokenServiceRequest* owner();
71
72  private:
73   friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
74
75   void DoNothing();
76
77   scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_;
78   OAuth2TokenServiceRequest* owner_;
79
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_;
84
85   DISALLOW_COPY_AND_ASSIGN(Core);
86 };
87
88 OAuth2TokenServiceRequest::Core::Core(
89     OAuth2TokenServiceRequest* owner,
90     const scoped_refptr<TokenServiceProvider>& provider)
91     : owner_(owner), provider_(provider) {
92   DCHECK(owner_);
93   DCHECK(provider_);
94   token_service_task_runner_ = provider_->GetTokenServiceTaskRunner();
95   DCHECK(token_service_task_runner_);
96 }
97
98 OAuth2TokenServiceRequest::Core::~Core() {
99 }
100
101 void OAuth2TokenServiceRequest::Core::Start() {
102   DCHECK(CalledOnValidThread());
103   token_service_task_runner_->PostTask(
104       FROM_HERE,
105       base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
106                  this));
107 }
108
109 void OAuth2TokenServiceRequest::Core::Stop() {
110   DCHECK(CalledOnValidThread());
111   DCHECK(!IsStopped());
112
113   // Detaches |owner_| from this instance so |owner_| will be called back only
114   // if |Stop()| has never been called.
115   owner_ = NULL;
116
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(
122       FROM_HERE,
123       base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread,
124                  this),
125       base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing, this));
126 }
127
128 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
129   DCHECK(CalledOnValidThread());
130   return owner_ == NULL;
131 }
132
133 base::SingleThreadTaskRunner*
134 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
135   return token_service_task_runner_;
136 }
137
138 OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
139   DCHECK(token_service_task_runner_->BelongsToCurrentThread());
140   return provider_->GetTokenService();
141 }
142
143 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
144   DCHECK(CalledOnValidThread());
145   return owner_;
146 }
147
148 void OAuth2TokenServiceRequest::Core::DoNothing() {
149   DCHECK(CalledOnValidThread());
150 }
151
152 namespace {
153
154 // An implementation of Core for getting an access token.
155 class RequestCore : public OAuth2TokenServiceRequest::Core,
156                     public OAuth2TokenService::Consumer {
157  public:
158   RequestCore(OAuth2TokenServiceRequest* owner,
159               const scoped_refptr<
160                   OAuth2TokenServiceRequest::TokenServiceProvider>& provider,
161               OAuth2TokenService::Consumer* consumer,
162               const std::string& account_id,
163               const OAuth2TokenService::ScopeSet& scopes);
164
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;
171
172  private:
173   friend class base::RefCountedThreadSafe<RequestCore>;
174
175   // Must be destroyed on the owner thread.
176   virtual ~RequestCore();
177
178   // Core implementation.
179   virtual void StartOnTokenServiceThread() OVERRIDE;
180   virtual void StopOnTokenServiceThread() OVERRIDE;
181
182   void InformOwnerOnGetTokenSuccess(std::string access_token,
183                                     base::Time expiration_time);
184   void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error);
185
186   scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
187   OAuth2TokenService::Consumer* const consumer_;
188   std::string account_id_;
189   OAuth2TokenService::ScopeSet scopes_;
190
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_;
194
195   DISALLOW_COPY_AND_ASSIGN(RequestCore);
196 };
197
198 RequestCore::RequestCore(
199     OAuth2TokenServiceRequest* owner,
200     const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>&
201         provider,
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()),
208       consumer_(consumer),
209       account_id_(account_id),
210       scopes_(scopes) {
211   DCHECK(consumer_);
212   DCHECK(!account_id_.empty());
213   DCHECK(!scopes_.empty());
214 }
215
216 RequestCore::~RequestCore() {
217 }
218
219 void RequestCore::StartOnTokenServiceThread() {
220   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
221   request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
222 }
223
224 void RequestCore::StopOnTokenServiceThread() {
225   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
226   request_.reset();
227 }
228
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(
235       FROM_HERE,
236       base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess,
237                  this,
238                  access_token,
239                  expiration_time));
240   request_.reset();
241 }
242
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(
248       FROM_HERE,
249       base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error));
250   request_.reset();
251 }
252
253 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
254                                                base::Time expiration_time) {
255   DCHECK(CalledOnValidThread());
256   if (!IsStopped()) {
257     consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
258   }
259 }
260
261 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
262   DCHECK(CalledOnValidThread());
263   if (!IsStopped()) {
264     consumer_->OnGetTokenFailure(owner(), error);
265   }
266 }
267
268 // An implementation of Core for invalidating an access token.
269 class InvalidateCore : public OAuth2TokenServiceRequest::Core {
270  public:
271   InvalidateCore(OAuth2TokenServiceRequest* owner,
272                  const scoped_refptr<
273                      OAuth2TokenServiceRequest::TokenServiceProvider>& provider,
274                  const std::string& access_token,
275                  const std::string& account_id,
276                  const OAuth2TokenService::ScopeSet& scopes);
277
278  private:
279   friend class base::RefCountedThreadSafe<InvalidateCore>;
280
281   // Must be destroyed on the owner thread.
282   virtual ~InvalidateCore();
283
284   // Core implementation.
285   virtual void StartOnTokenServiceThread() OVERRIDE;
286   virtual void StopOnTokenServiceThread() OVERRIDE;
287
288   std::string access_token_;
289   std::string account_id_;
290   OAuth2TokenService::ScopeSet scopes_;
291
292   DISALLOW_COPY_AND_ASSIGN(InvalidateCore);
293 };
294
295 InvalidateCore::InvalidateCore(
296     OAuth2TokenServiceRequest* owner,
297     const scoped_refptr<OAuth2TokenServiceRequest::TokenServiceProvider>&
298         provider,
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),
305       scopes_(scopes) {
306   DCHECK(!access_token_.empty());
307   DCHECK(!account_id_.empty());
308   DCHECK(!scopes.empty());
309 }
310
311 InvalidateCore::~InvalidateCore() {
312 }
313
314 void InvalidateCore::StartOnTokenServiceThread() {
315   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
316   token_service()->InvalidateToken(account_id_, scopes_, access_token_);
317 }
318
319 void InvalidateCore::StopOnTokenServiceThread() {
320   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
321   // Nothing to do.
322 }
323
324 }  // namespace
325
326 // static
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();
338 }
339
340 // static
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);
351 }
352
353 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
354   core_->Stop();
355 }
356
357 std::string OAuth2TokenServiceRequest::GetAccountId() const {
358   return account_id_;
359 }
360
361 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
362     const std::string& account_id)
363     : account_id_(account_id) {
364   DCHECK(!account_id_.empty());
365 }
366
367 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {
368   DCHECK(core);
369   core_ = core;
370   core_->Start();
371 }