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 "content/browser/service_worker/service_worker_registration_handle.h"
6
7#include "content/browser/service_worker/service_worker_context_core.h"
8#include "content/browser/service_worker/service_worker_dispatcher_host.h"
9#include "content/browser/service_worker/service_worker_handle.h"
10#include "content/common/service_worker/service_worker_messages.h"
11
12namespace content {
13
14static const int kDocumentMainThreadId = 0;
15
16ServiceWorkerRegistrationHandle::ServiceWorkerRegistrationHandle(
17    base::WeakPtr<ServiceWorkerContextCore> context,
18    ServiceWorkerDispatcherHost* dispatcher_host,
19    int provider_id,
20    ServiceWorkerRegistration* registration)
21    : context_(context),
22      dispatcher_host_(dispatcher_host),
23      provider_id_(provider_id),
24      handle_id_(context ? context->GetNewRegistrationHandleId()
25                         : kInvalidServiceWorkerRegistrationHandleId),
26      ref_count_(1),
27      registration_(registration) {
28  DCHECK(registration_.get());
29  SetVersionAttributes(registration->installing_version(),
30                       registration->waiting_version(),
31                       registration->active_version());
32  registration_->AddListener(this);
33}
34
35ServiceWorkerRegistrationHandle::~ServiceWorkerRegistrationHandle() {
36  DCHECK(registration_.get());
37  registration_->RemoveListener(this);
38}
39
40ServiceWorkerRegistrationObjectInfo
41ServiceWorkerRegistrationHandle::GetObjectInfo() {
42  ServiceWorkerRegistrationObjectInfo info;
43  info.handle_id = handle_id_;
44  info.scope = registration_->pattern();
45  return info;
46}
47
48ServiceWorkerObjectInfo
49ServiceWorkerRegistrationHandle::CreateServiceWorkerHandleAndPass(
50    ServiceWorkerVersion* version) {
51  ServiceWorkerObjectInfo info;
52  if (context_ && version) {
53    scoped_ptr<ServiceWorkerHandle> handle =
54        ServiceWorkerHandle::Create(context_,
55                                    dispatcher_host_,
56                                    kDocumentMainThreadId,
57                                    provider_id_,
58                                    version);
59    info = handle->GetObjectInfo();
60    dispatcher_host_->RegisterServiceWorkerHandle(handle.Pass());
61  }
62  return info;
63}
64
65void ServiceWorkerRegistrationHandle::IncrementRefCount() {
66  DCHECK_GT(ref_count_, 0);
67  ++ref_count_;
68}
69
70void ServiceWorkerRegistrationHandle::DecrementRefCount() {
71  DCHECK_GT(ref_count_, 0);
72  --ref_count_;
73}
74
75void ServiceWorkerRegistrationHandle::OnVersionAttributesChanged(
76    ServiceWorkerRegistration* registration,
77    ChangedVersionAttributesMask changed_mask,
78    const ServiceWorkerRegistrationInfo& info) {
79  DCHECK_EQ(registration->id(), registration_->id());
80  SetVersionAttributes(registration->installing_version(),
81                       registration->waiting_version(),
82                       registration->active_version());
83}
84
85void ServiceWorkerRegistrationHandle::OnRegistrationFailed(
86    ServiceWorkerRegistration* registration) {
87  DCHECK_EQ(registration->id(), registration_->id());
88  ClearVersionAttributes();
89}
90
91void ServiceWorkerRegistrationHandle::OnUpdateFound(
92    ServiceWorkerRegistration* registration) {
93  if (!dispatcher_host_)
94    return;  // Could be NULL in some tests.
95  dispatcher_host_->Send(new ServiceWorkerMsg_UpdateFound(
96      kDocumentMainThreadId, GetObjectInfo()));
97}
98
99void ServiceWorkerRegistrationHandle::SetVersionAttributes(
100    ServiceWorkerVersion* installing_version,
101    ServiceWorkerVersion* waiting_version,
102    ServiceWorkerVersion* active_version) {
103  ChangedVersionAttributesMask mask;
104
105  if (installing_version != installing_version_.get()) {
106    installing_version_ = installing_version;
107    mask.add(ChangedVersionAttributesMask::INSTALLING_VERSION);
108  }
109  if (waiting_version != waiting_version_.get()) {
110    waiting_version_ = waiting_version;
111    mask.add(ChangedVersionAttributesMask::WAITING_VERSION);
112  }
113  if (active_version != active_version_.get()) {
114    active_version_ = active_version;
115    mask.add(ChangedVersionAttributesMask::ACTIVE_VERSION);
116  }
117
118  if (!dispatcher_host_)
119    return;  // Could be NULL in some tests.
120  if (!mask.changed())
121    return;
122
123  ServiceWorkerVersionAttributes attributes;
124  if (mask.installing_changed()) {
125    attributes.installing =
126        CreateServiceWorkerHandleAndPass(installing_version);
127  }
128  if (mask.waiting_changed()) {
129    attributes.waiting =
130        CreateServiceWorkerHandleAndPass(waiting_version);
131  }
132  if (mask.active_changed()) {
133    attributes.active =
134        CreateServiceWorkerHandleAndPass(active_version);
135  }
136
137  dispatcher_host_->Send(new ServiceWorkerMsg_SetVersionAttributes(
138      kDocumentMainThreadId, provider_id_, handle_id_,
139      mask.changed(), attributes));
140}
141
142void ServiceWorkerRegistrationHandle::ClearVersionAttributes() {
143  SetVersionAttributes(NULL, NULL, NULL);
144}
145
146}  // namespace content
147