1 // Copyright 2015 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 "extensions/browser/api/printer_provider/printer_provider_api.h"
10 #include "base/bind.h"
11 #include "base/lazy_instance.h"
12 #include "base/stl_util.h"
13 #include "base/values.h"
14 #include "extensions/browser/api/printer_provider_internal/printer_provider_internal_api.h"
15 #include "extensions/browser/event_router.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extension_registry_factory.h"
18 #include "extensions/common/api/printer_provider.h"
19 #include "extensions/common/api/printer_provider_internal.h"
20 #include "extensions/common/extension.h"
22 namespace extensions
{
26 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<PrinterProviderAPI
>>
27 g_api_factory
= LAZY_INSTANCE_INITIALIZER
;
29 // The separator between extension id and the extension's internal printer id
30 // used when generating a printer id unique across extensions.
31 const char kPrinterIdSeparator
= ':';
33 // Given an extension ID and an ID of a printer reported by the extension, it
34 // generates a ID for the printer unique across extensions (assuming that the
35 // printer id is unique in the extension's space).
36 std::string
GeneratePrinterId(const std::string
& extension_id
,
37 const std::string
& internal_printer_id
) {
38 std::string result
= extension_id
;
39 result
.append(1, kPrinterIdSeparator
);
40 result
.append(internal_printer_id
);
44 // Parses an ID created using |GeneratePrinterId| to it's components:
45 // the extension ID and the printer ID internal to the extension.
46 // Returns whenter the ID was succesfully parsed.
47 bool ParsePrinterId(const std::string
& printer_id
,
48 std::string
* extension_id
,
49 std::string
* internal_printer_id
) {
50 size_t separator
= printer_id
.find_first_of(kPrinterIdSeparator
);
51 if (separator
== std::string::npos
)
53 *extension_id
= printer_id
.substr(0, separator
);
54 *internal_printer_id
= printer_id
.substr(separator
+ 1);
58 PrinterProviderAPI::PrintError
APIPrintErrorToInternalType(
59 core_api::printer_provider_internal::PrintError error
) {
61 case core_api::printer_provider_internal::PRINT_ERROR_NONE
:
62 // The PrintError parameter is not set, which implies an error.
63 return PrinterProviderAPI::PRINT_ERROR_FAILED
;
64 case core_api::printer_provider_internal::PRINT_ERROR_OK
:
65 return PrinterProviderAPI::PRINT_ERROR_NONE
;
66 case core_api::printer_provider_internal::PRINT_ERROR_FAILED
:
67 return PrinterProviderAPI::PRINT_ERROR_FAILED
;
68 case core_api::printer_provider_internal::PRINT_ERROR_INVALID_TICKET
:
69 return PrinterProviderAPI::PRINT_ERROR_INVALID_TICKET
;
70 case core_api::printer_provider_internal::PRINT_ERROR_INVALID_DATA
:
71 return PrinterProviderAPI::PRINT_ERROR_INVALID_DATA
;
73 return PrinterProviderAPI::PRINT_ERROR_FAILED
;
78 PrinterProviderAPI::PrintJob::PrintJob() {
81 PrinterProviderAPI::PrintJob::~PrintJob() {
85 BrowserContextKeyedAPIFactory
<PrinterProviderAPI
>*
86 PrinterProviderAPI::GetFactoryInstance() {
87 return g_api_factory
.Pointer();
90 PrinterProviderAPI::PrinterProviderAPI(content::BrowserContext
* browser_context
)
91 : browser_context_(browser_context
),
92 internal_api_observer_(this),
93 extension_registry_observer_(this) {
94 internal_api_observer_
.Add(
95 PrinterProviderInternalAPI::GetFactoryInstance()->Get(browser_context
));
96 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context
));
99 PrinterProviderAPI::~PrinterProviderAPI() {
102 void PrinterProviderAPI::DispatchGetPrintersRequested(
103 const GetPrintersCallback
& callback
) {
104 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
105 if (!event_router
->HasEventListener(
106 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
107 callback
.Run(base::ListValue(), true /* done */);
111 scoped_ptr
<GetPrintersRequest
> request(new GetPrintersRequest(callback
));
112 // |pending_get_printers_requests_| take ownership of |request| which gets
113 // NULLed out. Save the pointer before passing it to the requests, as it will
114 // be needed later on.
115 GetPrintersRequest
* raw_request_ptr
= request
.get();
116 int request_id
= pending_get_printers_requests_
.Add(request
.Pass());
118 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
119 // Request id is not part of the public API, but it will be massaged out in
121 internal_args
->AppendInteger(request_id
);
123 scoped_ptr
<Event
> event(
124 new Event(core_api::printer_provider::OnGetPrintersRequested::kEventName
,
125 internal_args
.Pass()));
126 // This callback is called synchronously during |BroadcastEvent|, so
127 // Unretained is safe. Also, |raw_request_ptr| will stay valid at least until
128 // |BroadcastEvent| finishes.
129 event
->will_dispatch_callback
=
130 base::Bind(&PrinterProviderAPI::WillRequestPrinters
,
131 base::Unretained(this), raw_request_ptr
);
133 event_router
->BroadcastEvent(event
.Pass());
136 void PrinterProviderAPI::DispatchGetCapabilityRequested(
137 const std::string
& printer_id
,
138 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
139 std::string extension_id
;
140 std::string internal_printer_id
;
141 if (!ParsePrinterId(printer_id
, &extension_id
, &internal_printer_id
)) {
142 callback
.Run(base::DictionaryValue());
146 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
147 if (!event_router
->ExtensionHasEventListener(
149 core_api::printer_provider::OnGetCapabilityRequested::kEventName
)) {
150 callback
.Run(base::DictionaryValue());
154 int request_id
= pending_capability_requests_
[extension_id
].Add(callback
);
156 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
157 // Request id is not part of the public API, but it will be massaged out in
159 internal_args
->AppendInteger(request_id
);
160 internal_args
->AppendString(internal_printer_id
);
162 scoped_ptr
<Event
> event(new Event(
163 core_api::printer_provider::OnGetCapabilityRequested::kEventName
,
164 internal_args
.Pass()));
166 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
169 void PrinterProviderAPI::DispatchPrintRequested(
170 const PrinterProviderAPI::PrintJob
& job
,
171 const PrinterProviderAPI::PrintCallback
& callback
) {
172 std::string extension_id
;
173 std::string internal_printer_id
;
174 if (!ParsePrinterId(job
.printer_id
, &extension_id
, &internal_printer_id
)) {
175 callback
.Run(PRINT_ERROR_FAILED
);
179 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
180 if (!event_router
->ExtensionHasEventListener(
182 core_api::printer_provider::OnPrintRequested::kEventName
)) {
183 callback
.Run(PRINT_ERROR_FAILED
);
187 core_api::printer_provider::PrintJob print_job
;
188 print_job
.printer_id
= internal_printer_id
;
189 print_job
.content_type
= job
.content_type
;
191 std::vector
<char>(job
.document_bytes
.begin(), job
.document_bytes
.end());
193 int request_id
= pending_print_requests_
[extension_id
].Add(callback
);
195 scoped_ptr
<base::ListValue
> internal_args(new base::ListValue
);
196 // Request id is not part of the public API and it will be massaged out in
198 internal_args
->AppendInteger(request_id
);
199 internal_args
->Append(print_job
.ToValue().release());
200 scoped_ptr
<Event
> event(
201 new Event(core_api::printer_provider::OnPrintRequested::kEventName
,
202 internal_args
.Pass()));
204 event_router
->DispatchEventToExtension(extension_id
, event
.Pass());
207 PrinterProviderAPI::GetPrintersRequest::GetPrintersRequest(
208 const GetPrintersCallback
& callback
)
209 : callback_(callback
) {
212 PrinterProviderAPI::GetPrintersRequest::~GetPrintersRequest() {
215 void PrinterProviderAPI::GetPrintersRequest::AddSource(
216 const std::string
& extension_id
) {
217 extensions_
.insert(extension_id
);
220 bool PrinterProviderAPI::GetPrintersRequest::IsDone() const {
221 return extensions_
.empty();
224 void PrinterProviderAPI::GetPrintersRequest::ReportForExtension(
225 const std::string
& extension_id
,
226 const base::ListValue
& printers
) {
227 if (extensions_
.erase(extension_id
) > 0)
228 callback_
.Run(printers
, IsDone());
231 PrinterProviderAPI::PendingGetPrintersRequests::PendingGetPrintersRequests()
232 : last_request_id_(0) {
235 PrinterProviderAPI::PendingGetPrintersRequests::~PendingGetPrintersRequests() {
236 STLDeleteContainerPairSecondPointers(pending_requests_
.begin(),
237 pending_requests_
.end());
240 int PrinterProviderAPI::PendingGetPrintersRequests::Add(
241 scoped_ptr
<GetPrintersRequest
> request
) {
242 pending_requests_
[++last_request_id_
] = request
.release();
243 return last_request_id_
;
246 bool PrinterProviderAPI::PendingGetPrintersRequests::CompleteForExtension(
247 const std::string
& extension_id
,
249 const base::ListValue
& result
) {
250 auto it
= pending_requests_
.find(request_id
);
251 if (it
== pending_requests_
.end())
254 GetPrintersRequest
* request
= it
->second
;
255 request
->ReportForExtension(extension_id
, result
);
256 if (request
->IsDone()) {
257 pending_requests_
.erase(it
);
263 void PrinterProviderAPI::PendingGetPrintersRequests::FailAllForExtension(
264 const std::string
& extension_id
) {
265 auto it
= pending_requests_
.begin();
266 while (it
!= pending_requests_
.end()) {
267 int request_id
= it
->first
;
268 // |it| may get deleted during |CompleteForExtension|, so progress it to the
269 // next item before calling the method.
271 CompleteForExtension(extension_id
, request_id
, base::ListValue());
275 PrinterProviderAPI::PendingGetCapabilityRequests::PendingGetCapabilityRequests()
276 : last_request_id_(0) {
279 PrinterProviderAPI::PendingGetCapabilityRequests::
280 ~PendingGetCapabilityRequests() {
283 int PrinterProviderAPI::PendingGetCapabilityRequests::Add(
284 const PrinterProviderAPI::GetCapabilityCallback
& callback
) {
285 pending_requests_
[++last_request_id_
] = callback
;
286 return last_request_id_
;
289 bool PrinterProviderAPI::PendingGetCapabilityRequests::Complete(
291 const base::DictionaryValue
& response
) {
292 auto it
= pending_requests_
.find(request_id
);
293 if (it
== pending_requests_
.end())
296 GetCapabilityCallback callback
= it
->second
;
297 pending_requests_
.erase(it
);
299 callback
.Run(response
);
303 void PrinterProviderAPI::PendingGetCapabilityRequests::FailAll() {
304 for (auto& request
: pending_requests_
)
305 request
.second
.Run(base::DictionaryValue());
306 pending_requests_
.clear();
309 PrinterProviderAPI::PendingPrintRequests::PendingPrintRequests()
310 : last_request_id_(0) {
313 PrinterProviderAPI::PendingPrintRequests::~PendingPrintRequests() {
316 int PrinterProviderAPI::PendingPrintRequests::Add(
317 const PrinterProviderAPI::PrintCallback
& callback
) {
318 pending_requests_
[++last_request_id_
] = callback
;
319 return last_request_id_
;
322 bool PrinterProviderAPI::PendingPrintRequests::Complete(int request_id
,
323 PrintError response
) {
324 auto it
= pending_requests_
.find(request_id
);
325 if (it
== pending_requests_
.end())
328 PrintCallback callback
= it
->second
;
329 pending_requests_
.erase(it
);
331 callback
.Run(response
);
335 void PrinterProviderAPI::PendingPrintRequests::FailAll() {
336 for (auto& request
: pending_requests_
)
337 request
.second
.Run(PRINT_ERROR_FAILED
);
338 pending_requests_
.clear();
341 void PrinterProviderAPI::OnGetPrintersResult(
342 const Extension
* extension
,
344 const PrinterProviderInternalAPIObserver::PrinterInfoVector
& result
) {
345 base::ListValue printer_list
;
347 // Update some printer description properties to better identify the extension
348 // managing the printer.
349 for (size_t i
= 0; i
< result
.size(); ++i
) {
350 scoped_ptr
<base::DictionaryValue
> printer(result
[i
]->ToValue());
351 std::string internal_printer_id
;
352 CHECK(printer
->GetString("id", &internal_printer_id
));
353 printer
->SetString("id",
354 GeneratePrinterId(extension
->id(), internal_printer_id
));
355 printer
->SetString("extensionId", extension
->id());
356 printer_list
.Append(printer
.release());
359 pending_get_printers_requests_
.CompleteForExtension(extension
->id(),
360 request_id
, printer_list
);
363 void PrinterProviderAPI::OnGetCapabilityResult(
364 const Extension
* extension
,
366 const base::DictionaryValue
& result
) {
367 pending_capability_requests_
[extension
->id()].Complete(request_id
, result
);
370 void PrinterProviderAPI::OnPrintResult(
371 const Extension
* extension
,
373 core_api::printer_provider_internal::PrintError error
) {
374 pending_print_requests_
[extension
->id()].Complete(
375 request_id
, APIPrintErrorToInternalType(error
));
378 void PrinterProviderAPI::OnExtensionUnloaded(
379 content::BrowserContext
* browser_context
,
380 const Extension
* extension
,
381 UnloadedExtensionInfo::Reason reason
) {
382 pending_get_printers_requests_
.FailAllForExtension(extension
->id());
384 auto print_it
= pending_print_requests_
.find(extension
->id());
385 if (print_it
!= pending_print_requests_
.end()) {
386 print_it
->second
.FailAll();
387 pending_print_requests_
.erase(print_it
);
390 auto capability_it
= pending_capability_requests_
.find(extension
->id());
391 if (capability_it
!= pending_capability_requests_
.end()) {
392 capability_it
->second
.FailAll();
393 pending_capability_requests_
.erase(capability_it
);
397 bool PrinterProviderAPI::WillRequestPrinters(
398 PrinterProviderAPI::GetPrintersRequest
* request
,
399 content::BrowserContext
* browser_context
,
400 const Extension
* extension
,
401 base::ListValue
* args
) const {
404 EventRouter
* event_router
= EventRouter::Get(browser_context_
);
405 if (!event_router
->ExtensionHasEventListener(
407 core_api::printer_provider::OnGetPrintersRequested::kEventName
)) {
411 request
->AddSource(extension
->id());
416 void BrowserContextKeyedAPIFactory
<
417 PrinterProviderAPI
>::DeclareFactoryDependencies() {
418 DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
419 DependsOn(PrinterProviderInternalAPI::GetFactoryInstance());
420 DependsOn(ExtensionRegistryFactory::GetInstance());
423 } // namespace extensions