672015241779a45d4e8f1dea882947d0844c3011
[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, TokenServiceProvider* provider);
44
45   // Starts the core.  Must be called on the owner thread.
46   void Start();
47
48   // Stops the core.  Must be called on the owner thread.
49   void Stop();
50
51   // Returns true if this object has been stopped.  Must be called on the owner
52   // thread.
53   bool IsStopped() const;
54
55  protected:
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.
59   virtual ~Core();
60
61   // Called on the token service thread.
62   virtual void StartOnTokenServiceThread() = 0;
63
64   // Called on the token service thread.
65   virtual void StopOnTokenServiceThread() = 0;
66
67   base::SingleThreadTaskRunner* token_service_task_runner();
68   OAuth2TokenService* token_service();
69   OAuth2TokenServiceRequest* owner();
70
71  private:
72   friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
73
74   void DoNothing();
75
76   scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_;
77   OAuth2TokenServiceRequest* owner_;
78   TokenServiceProvider* provider_;
79   DISALLOW_COPY_AND_ASSIGN(Core);
80 };
81
82 OAuth2TokenServiceRequest::Core::Core(OAuth2TokenServiceRequest* owner,
83                                       TokenServiceProvider* provider)
84     : owner_(owner), provider_(provider) {
85   DCHECK(owner_);
86   DCHECK(provider_);
87   token_service_task_runner_ = provider_->GetTokenServiceTaskRunner();
88   DCHECK(token_service_task_runner_);
89 }
90
91 OAuth2TokenServiceRequest::Core::~Core() {
92 }
93
94 void OAuth2TokenServiceRequest::Core::Start() {
95   DCHECK(CalledOnValidThread());
96   token_service_task_runner_->PostTask(
97       FROM_HERE,
98       base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
99                  this));
100 }
101
102 void OAuth2TokenServiceRequest::Core::Stop() {
103   DCHECK(CalledOnValidThread());
104   DCHECK(!IsStopped());
105
106   // Detaches |owner_| from this instance so |owner_| will be called back only
107   // if |Stop()| has never been called.
108   owner_ = NULL;
109
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(
115       FROM_HERE,
116       base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread,
117                  this),
118       base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing, this));
119 }
120
121 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
122   DCHECK(CalledOnValidThread());
123   return owner_ == NULL;
124 }
125
126 base::SingleThreadTaskRunner*
127 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
128   return token_service_task_runner_;
129 }
130
131 OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
132   DCHECK(token_service_task_runner_->BelongsToCurrentThread());
133   return provider_->GetTokenService();
134 }
135
136 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
137   DCHECK(CalledOnValidThread());
138   return owner_;
139 }
140
141 void OAuth2TokenServiceRequest::Core::DoNothing() {
142   DCHECK(CalledOnValidThread());
143 }
144
145 namespace {
146
147 // An implementation of Core for getting an access token.
148 class RequestCore : public OAuth2TokenServiceRequest::Core,
149                     public OAuth2TokenService::Consumer {
150  public:
151   RequestCore(OAuth2TokenServiceRequest* owner,
152               OAuth2TokenServiceRequest::TokenServiceProvider* provider,
153               OAuth2TokenService::Consumer* consumer,
154               const std::string& account_id,
155               const OAuth2TokenService::ScopeSet& scopes);
156
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;
163
164  private:
165   friend class base::RefCountedThreadSafe<RequestCore>;
166
167   // Must be destroyed on the owner thread.
168   virtual ~RequestCore();
169
170   // Core implementation.
171   virtual void StartOnTokenServiceThread() OVERRIDE;
172   virtual void StopOnTokenServiceThread() OVERRIDE;
173
174   void InformOwnerOnGetTokenSuccess(std::string access_token,
175                                     base::Time expiration_time);
176   void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error);
177
178   scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
179   OAuth2TokenService::Consumer* const consumer_;
180   std::string account_id_;
181   OAuth2TokenService::ScopeSet scopes_;
182
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_;
186
187   DISALLOW_COPY_AND_ASSIGN(RequestCore);
188 };
189
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()),
199       consumer_(consumer),
200       account_id_(account_id),
201       scopes_(scopes) {
202   DCHECK(consumer_);
203   DCHECK(!account_id_.empty());
204   DCHECK(!scopes_.empty());
205 }
206
207 RequestCore::~RequestCore() {
208 }
209
210 void RequestCore::StartOnTokenServiceThread() {
211   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
212   request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
213 }
214
215 void RequestCore::StopOnTokenServiceThread() {
216   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
217   request_.reset();
218 }
219
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(
226       FROM_HERE,
227       base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess,
228                  this,
229                  access_token,
230                  expiration_time));
231   request_.reset();
232 }
233
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(
239       FROM_HERE,
240       base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error));
241   request_.reset();
242 }
243
244 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
245                                                base::Time expiration_time) {
246   DCHECK(CalledOnValidThread());
247   if (!IsStopped()) {
248     consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
249   }
250 }
251
252 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
253   DCHECK(CalledOnValidThread());
254   if (!IsStopped()) {
255     consumer_->OnGetTokenFailure(owner(), error);
256   }
257 }
258
259 // An implementation of Core for invalidating an access token.
260 class InvalidateCore : public OAuth2TokenServiceRequest::Core {
261  public:
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);
267
268  private:
269   friend class base::RefCountedThreadSafe<InvalidateCore>;
270
271   // Must be destroyed on the owner thread.
272   virtual ~InvalidateCore();
273
274   // Core implementation.
275   virtual void StartOnTokenServiceThread() OVERRIDE;
276   virtual void StopOnTokenServiceThread() OVERRIDE;
277
278   std::string access_token_;
279   std::string account_id_;
280   OAuth2TokenService::ScopeSet scopes_;
281
282   DISALLOW_COPY_AND_ASSIGN(InvalidateCore);
283 };
284
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),
294       scopes_(scopes) {
295   DCHECK(!access_token_.empty());
296   DCHECK(!account_id_.empty());
297   DCHECK(!scopes.empty());
298 }
299
300 InvalidateCore::~InvalidateCore() {
301 }
302
303 void InvalidateCore::StartOnTokenServiceThread() {
304   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
305   token_service()->InvalidateToken(account_id_, scopes_, access_token_);
306 }
307
308 void InvalidateCore::StopOnTokenServiceThread() {
309   DCHECK(token_service_task_runner()->BelongsToCurrentThread());
310   // Nothing to do.
311 }
312
313 }  // namespace
314
315 // static
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();
327 }
328
329 // static
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);
340 }
341
342 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
343   core_->Stop();
344 }
345
346 std::string OAuth2TokenServiceRequest::GetAccountId() const {
347   return account_id_;
348 }
349
350 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
351     const std::string& account_id)
352     : account_id_(account_id) {
353   DCHECK(!account_id_.empty());
354 }
355
356 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {
357   DCHECK(core);
358   core_ = core;
359   core_->Start();
360 }