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 "mojo/application_manager/application_manager.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/stl_util.h"
14 #include "mojo/application_manager/application_loader.h"
15 #include "mojo/common/common_type_converters.h"
16 #include "mojo/public/cpp/application/connect.h"
17 #include "mojo/public/interfaces/application/application.mojom.h"
18 #include "mojo/public/interfaces/application/shell.mojom.h"
19 #include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
25 bool has_created_instance
= false;
27 class StubServiceProvider
: public InterfaceImpl
<ServiceProvider
> {
29 ServiceProvider
* GetRemoteServiceProvider() { return client(); }
32 virtual void ConnectToService(const String
& service_name
,
33 ScopedMessagePipeHandle client_handle
)
39 class ApplicationManager::LoadCallbacksImpl
40 : public ApplicationLoader::LoadCallbacks
{
42 LoadCallbacksImpl(base::WeakPtr
<ApplicationManager
> manager
,
43 const GURL
& requested_url
,
44 const GURL
& requestor_url
,
45 ServiceProviderPtr service_provider
)
47 requested_url_(requested_url
),
48 requestor_url_(requestor_url
),
49 service_provider_(service_provider
.Pass()) {}
52 virtual ~LoadCallbacksImpl() {}
54 // LoadCallbacks implementation
55 virtual ScopedMessagePipeHandle
RegisterApplication() OVERRIDE
{
56 ScopedMessagePipeHandle shell_handle
;
58 manager_
->RegisterLoadedApplication(requested_url_
,
60 service_provider_
.Pass(),
63 return shell_handle
.Pass();
66 virtual void LoadWithContentHandler(const GURL
& content_handler_url
,
67 URLResponsePtr content
) OVERRIDE
{
69 manager_
->LoadWithContentHandler(requested_url_
,
73 service_provider_
.Pass());
77 base::WeakPtr
<ApplicationManager
> manager_
;
80 ServiceProviderPtr service_provider_
;
83 class ApplicationManager::ShellImpl
: public InterfaceImpl
<Shell
> {
85 ShellImpl(ApplicationManager
* manager
, const GURL
& url
)
86 : manager_(manager
), url_(url
) {}
88 virtual ~ShellImpl() {}
90 void ConnectToClient(const GURL
& requestor_url
,
91 ServiceProviderPtr service_provider
) {
92 client()->AcceptConnection(String::From(requestor_url
),
93 service_provider
.Pass());
96 // ServiceProvider implementation:
97 virtual void ConnectToApplication(
98 const String
& app_url
,
99 InterfaceRequest
<ServiceProvider
> in_service_provider
) OVERRIDE
{
100 ServiceProviderPtr out_service_provider
;
101 out_service_provider
.Bind(in_service_provider
.PassMessagePipe());
102 manager_
->ConnectToApplication(
103 app_url
.To
<GURL
>(), url_
, out_service_provider
.Pass());
106 const GURL
& url() const { return url_
; }
109 virtual void OnConnectionError() OVERRIDE
{
110 manager_
->OnShellImplError(this);
113 ApplicationManager
* const manager_
;
116 DISALLOW_COPY_AND_ASSIGN(ShellImpl
);
119 struct ApplicationManager::ContentHandlerConnection
{
120 ContentHandlerConnection(ApplicationManager
* manager
,
121 const GURL
& content_handler_url
) {
122 ServiceProviderPtr service_provider
;
123 BindToProxy(&service_provider_impl
, &service_provider
);
124 manager
->ConnectToApplication(
125 content_handler_url
, GURL(), service_provider
.Pass());
126 mojo::ConnectToService(service_provider_impl
.client(), &content_handler
);
129 StubServiceProvider service_provider_impl
;
130 ContentHandlerPtr content_handler
;
134 ApplicationManager::TestAPI::TestAPI(ApplicationManager
* manager
)
135 : manager_(manager
) {
138 ApplicationManager::TestAPI::~TestAPI() {
141 bool ApplicationManager::TestAPI::HasCreatedInstance() {
142 return has_created_instance
;
145 bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL
& url
) const {
146 return manager_
->url_to_shell_impl_
.find(url
) !=
147 manager_
->url_to_shell_impl_
.end();
150 ApplicationManager::ApplicationManager()
151 : interceptor_(NULL
), weak_ptr_factory_(this) {
154 ApplicationManager::~ApplicationManager() {
155 STLDeleteValues(&url_to_content_handler_
);
156 TerminateShellConnections();
157 STLDeleteValues(&url_to_loader_
);
158 STLDeleteValues(&scheme_to_loader_
);
161 void ApplicationManager::TerminateShellConnections() {
162 STLDeleteValues(&url_to_shell_impl_
);
166 ApplicationManager
* ApplicationManager::GetInstance() {
167 static base::LazyInstance
<ApplicationManager
> instance
=
168 LAZY_INSTANCE_INITIALIZER
;
169 has_created_instance
= true;
170 return &instance
.Get();
173 void ApplicationManager::ConnectToApplication(
175 const GURL
& requestor_url
,
176 ServiceProviderPtr service_provider
) {
177 URLToShellImplMap::const_iterator shell_it
= url_to_shell_impl_
.find(url
);
178 if (shell_it
!= url_to_shell_impl_
.end()) {
180 shell_it
->second
, url
, requestor_url
, service_provider
.Pass());
184 scoped_refptr
<LoadCallbacksImpl
> callbacks(
185 new LoadCallbacksImpl(weak_ptr_factory_
.GetWeakPtr(),
188 service_provider
.Pass()));
189 GetLoaderForURL(url
)->Load(this, url
, callbacks
);
192 void ApplicationManager::ConnectToClient(ShellImpl
* shell_impl
,
194 const GURL
& requestor_url
,
195 ServiceProviderPtr service_provider
) {
197 shell_impl
->ConnectToClient(
199 interceptor_
->OnConnectToClient(url
, service_provider
.Pass()));
201 shell_impl
->ConnectToClient(requestor_url
, service_provider
.Pass());
205 void ApplicationManager::RegisterLoadedApplication(
207 const GURL
& requestor_url
,
208 ServiceProviderPtr service_provider
,
209 ScopedMessagePipeHandle
* shell_handle
) {
210 ShellImpl
* shell_impl
= NULL
;
211 URLToShellImplMap::iterator iter
= url_to_shell_impl_
.find(url
);
212 if (iter
!= url_to_shell_impl_
.end()) {
213 // This can happen because services are loaded asynchronously. So if we get
214 // two requests for the same service close to each other, we might get here
215 // and find that we already have it.
216 shell_impl
= iter
->second
;
219 shell_impl
= WeakBindToPipe(new ShellImpl(this, url
), pipe
.handle1
.Pass());
220 url_to_shell_impl_
[url
] = shell_impl
;
221 *shell_handle
= pipe
.handle0
.Pass();
224 ConnectToClient(shell_impl
, url
, requestor_url
, service_provider
.Pass());
227 void ApplicationManager::LoadWithContentHandler(
228 const GURL
& content_url
,
229 const GURL
& requestor_url
,
230 const GURL
& content_handler_url
,
231 URLResponsePtr content
,
232 ServiceProviderPtr service_provider
) {
233 ContentHandlerConnection
* connection
= NULL
;
234 URLToContentHandlerMap::iterator iter
=
235 url_to_content_handler_
.find(content_handler_url
);
236 if (iter
!= url_to_content_handler_
.end()) {
237 connection
= iter
->second
;
239 connection
= new ContentHandlerConnection(this, content_handler_url
);
240 url_to_content_handler_
[content_handler_url
] = connection
;
242 connection
->content_handler
->OnConnect(
243 content_url
.spec(), content
.Pass(), service_provider
.Pass());
246 void ApplicationManager::SetLoaderForURL(scoped_ptr
<ApplicationLoader
> loader
,
248 URLToLoaderMap::iterator it
= url_to_loader_
.find(url
);
249 if (it
!= url_to_loader_
.end())
251 url_to_loader_
[url
] = loader
.release();
254 void ApplicationManager::SetLoaderForScheme(
255 scoped_ptr
<ApplicationLoader
> loader
,
256 const std::string
& scheme
) {
257 SchemeToLoaderMap::iterator it
= scheme_to_loader_
.find(scheme
);
258 if (it
!= scheme_to_loader_
.end())
260 scheme_to_loader_
[scheme
] = loader
.release();
263 void ApplicationManager::SetInterceptor(Interceptor
* interceptor
) {
264 interceptor_
= interceptor
;
267 ApplicationLoader
* ApplicationManager::GetLoaderForURL(const GURL
& url
) {
268 URLToLoaderMap::const_iterator url_it
= url_to_loader_
.find(url
);
269 if (url_it
!= url_to_loader_
.end())
270 return url_it
->second
;
271 SchemeToLoaderMap::const_iterator scheme_it
=
272 scheme_to_loader_
.find(url
.scheme());
273 if (scheme_it
!= scheme_to_loader_
.end())
274 return scheme_it
->second
;
275 return default_loader_
.get();
278 void ApplicationManager::OnShellImplError(ShellImpl
* shell_impl
) {
279 // Called from ~ShellImpl, so we do not need to call Destroy here.
280 const GURL url
= shell_impl
->url();
281 URLToShellImplMap::iterator it
= url_to_shell_impl_
.find(url
);
282 DCHECK(it
!= url_to_shell_impl_
.end());
284 url_to_shell_impl_
.erase(it
);
285 ApplicationLoader
* loader
= GetLoaderForURL(url
);
287 loader
->OnServiceError(this, url
);
290 ScopedMessagePipeHandle
ApplicationManager::ConnectToServiceByName(
291 const GURL
& application_url
,
292 const std::string
& interface_name
) {
293 StubServiceProvider
* stub_sp
= new StubServiceProvider
;
294 ServiceProviderPtr spp
;
295 BindToProxy(stub_sp
, &spp
);
296 ConnectToApplication(application_url
, GURL(), spp
.Pass());
298 stub_sp
->GetRemoteServiceProvider()->ConnectToService(interface_name
,
299 pipe
.handle1
.Pass());
300 return pipe
.handle0
.Pass();