Merge from Chromium at DEPS revision 290040
This commit was generated by merge_to_master.py.
Change-Id: I694ec52d1e0b553f163c2faf4373d63270ab1aac
diff --git a/mojo/application_manager/application_manager.cc b/mojo/application_manager/application_manager.cc
new file mode 100644
index 0000000..1a75cae
--- /dev/null
+++ b/mojo/application_manager/application_manager.cc
@@ -0,0 +1,302 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/application_manager/application_manager.h"
+
+#include <stdio.h>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "mojo/application_manager/application_loader.h"
+#include "mojo/common/common_type_converters.h"
+#include "mojo/public/cpp/application/connect.h"
+#include "mojo/public/interfaces/application/application.mojom.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "mojo/services/public/interfaces/content_handler/content_handler.mojom.h"
+
+namespace mojo {
+
+namespace {
+// Used by TestAPI.
+bool has_created_instance = false;
+
+class StubServiceProvider : public InterfaceImpl<ServiceProvider> {
+ public:
+ ServiceProvider* GetRemoteServiceProvider() { return client(); }
+
+ private:
+ virtual void ConnectToService(const String& service_name,
+ ScopedMessagePipeHandle client_handle)
+ MOJO_OVERRIDE {}
+};
+
+} // namespace
+
+class ApplicationManager::LoadCallbacksImpl
+ : public ApplicationLoader::LoadCallbacks {
+ public:
+ LoadCallbacksImpl(base::WeakPtr<ApplicationManager> manager,
+ const GURL& requested_url,
+ const GURL& requestor_url,
+ ServiceProviderPtr service_provider)
+ : manager_(manager),
+ requested_url_(requested_url),
+ requestor_url_(requestor_url),
+ service_provider_(service_provider.Pass()) {}
+
+ private:
+ virtual ~LoadCallbacksImpl() {}
+
+ // LoadCallbacks implementation
+ virtual ScopedMessagePipeHandle RegisterApplication() OVERRIDE {
+ ScopedMessagePipeHandle shell_handle;
+ if (manager_) {
+ manager_->RegisterLoadedApplication(requested_url_,
+ requestor_url_,
+ service_provider_.Pass(),
+ &shell_handle);
+ }
+ return shell_handle.Pass();
+ }
+
+ virtual void LoadWithContentHandler(const GURL& content_handler_url,
+ URLResponsePtr content) OVERRIDE {
+ if (manager_) {
+ manager_->LoadWithContentHandler(requested_url_,
+ requestor_url_,
+ content_handler_url,
+ content.Pass(),
+ service_provider_.Pass());
+ }
+ }
+
+ base::WeakPtr<ApplicationManager> manager_;
+ GURL requested_url_;
+ GURL requestor_url_;
+ ServiceProviderPtr service_provider_;
+};
+
+class ApplicationManager::ShellImpl : public InterfaceImpl<Shell> {
+ public:
+ ShellImpl(ApplicationManager* manager, const GURL& url)
+ : manager_(manager), url_(url) {}
+
+ virtual ~ShellImpl() {}
+
+ void ConnectToClient(const GURL& requestor_url,
+ ServiceProviderPtr service_provider) {
+ client()->AcceptConnection(String::From(requestor_url),
+ service_provider.Pass());
+ }
+
+ // ServiceProvider implementation:
+ virtual void ConnectToApplication(
+ const String& app_url,
+ InterfaceRequest<ServiceProvider> in_service_provider) OVERRIDE {
+ ServiceProviderPtr out_service_provider;
+ out_service_provider.Bind(in_service_provider.PassMessagePipe());
+ manager_->ConnectToApplication(
+ app_url.To<GURL>(), url_, out_service_provider.Pass());
+ }
+
+ const GURL& url() const { return url_; }
+
+ private:
+ virtual void OnConnectionError() OVERRIDE {
+ manager_->OnShellImplError(this);
+ }
+
+ ApplicationManager* const manager_;
+ const GURL url_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellImpl);
+};
+
+struct ApplicationManager::ContentHandlerConnection {
+ ContentHandlerConnection(ApplicationManager* manager,
+ const GURL& content_handler_url) {
+ ServiceProviderPtr service_provider;
+ BindToProxy(&service_provider_impl, &service_provider);
+ manager->ConnectToApplication(
+ content_handler_url, GURL(), service_provider.Pass());
+ mojo::ConnectToService(service_provider_impl.client(), &content_handler);
+ }
+
+ StubServiceProvider service_provider_impl;
+ ContentHandlerPtr content_handler;
+};
+
+// static
+ApplicationManager::TestAPI::TestAPI(ApplicationManager* manager)
+ : manager_(manager) {
+}
+
+ApplicationManager::TestAPI::~TestAPI() {
+}
+
+bool ApplicationManager::TestAPI::HasCreatedInstance() {
+ return has_created_instance;
+}
+
+bool ApplicationManager::TestAPI::HasFactoryForURL(const GURL& url) const {
+ return manager_->url_to_shell_impl_.find(url) !=
+ manager_->url_to_shell_impl_.end();
+}
+
+ApplicationManager::ApplicationManager()
+ : interceptor_(NULL), weak_ptr_factory_(this) {
+}
+
+ApplicationManager::~ApplicationManager() {
+ STLDeleteValues(&url_to_content_handler_);
+ TerminateShellConnections();
+ STLDeleteValues(&url_to_loader_);
+ STLDeleteValues(&scheme_to_loader_);
+}
+
+void ApplicationManager::TerminateShellConnections() {
+ STLDeleteValues(&url_to_shell_impl_);
+}
+
+// static
+ApplicationManager* ApplicationManager::GetInstance() {
+ static base::LazyInstance<ApplicationManager> instance =
+ LAZY_INSTANCE_INITIALIZER;
+ has_created_instance = true;
+ return &instance.Get();
+}
+
+void ApplicationManager::ConnectToApplication(
+ const GURL& url,
+ const GURL& requestor_url,
+ ServiceProviderPtr service_provider) {
+ URLToShellImplMap::const_iterator shell_it = url_to_shell_impl_.find(url);
+ if (shell_it != url_to_shell_impl_.end()) {
+ ConnectToClient(
+ shell_it->second, url, requestor_url, service_provider.Pass());
+ return;
+ }
+
+ scoped_refptr<LoadCallbacksImpl> callbacks(
+ new LoadCallbacksImpl(weak_ptr_factory_.GetWeakPtr(),
+ url,
+ requestor_url,
+ service_provider.Pass()));
+ GetLoaderForURL(url)->Load(this, url, callbacks);
+}
+
+void ApplicationManager::ConnectToClient(ShellImpl* shell_impl,
+ const GURL& url,
+ const GURL& requestor_url,
+ ServiceProviderPtr service_provider) {
+ if (interceptor_) {
+ shell_impl->ConnectToClient(
+ requestor_url,
+ interceptor_->OnConnectToClient(url, service_provider.Pass()));
+ } else {
+ shell_impl->ConnectToClient(requestor_url, service_provider.Pass());
+ }
+}
+
+void ApplicationManager::RegisterLoadedApplication(
+ const GURL& url,
+ const GURL& requestor_url,
+ ServiceProviderPtr service_provider,
+ ScopedMessagePipeHandle* shell_handle) {
+ ShellImpl* shell_impl = NULL;
+ URLToShellImplMap::iterator iter = url_to_shell_impl_.find(url);
+ if (iter != url_to_shell_impl_.end()) {
+ // This can happen because services are loaded asynchronously. So if we get
+ // two requests for the same service close to each other, we might get here
+ // and find that we already have it.
+ shell_impl = iter->second;
+ } else {
+ MessagePipe pipe;
+ shell_impl = WeakBindToPipe(new ShellImpl(this, url), pipe.handle1.Pass());
+ url_to_shell_impl_[url] = shell_impl;
+ *shell_handle = pipe.handle0.Pass();
+ }
+
+ ConnectToClient(shell_impl, url, requestor_url, service_provider.Pass());
+}
+
+void ApplicationManager::LoadWithContentHandler(
+ const GURL& content_url,
+ const GURL& requestor_url,
+ const GURL& content_handler_url,
+ URLResponsePtr content,
+ ServiceProviderPtr service_provider) {
+ ContentHandlerConnection* connection = NULL;
+ URLToContentHandlerMap::iterator iter =
+ url_to_content_handler_.find(content_handler_url);
+ if (iter != url_to_content_handler_.end()) {
+ connection = iter->second;
+ } else {
+ connection = new ContentHandlerConnection(this, content_handler_url);
+ url_to_content_handler_[content_handler_url] = connection;
+ }
+ connection->content_handler->OnConnect(
+ content_url.spec(), content.Pass(), service_provider.Pass());
+}
+
+void ApplicationManager::SetLoaderForURL(scoped_ptr<ApplicationLoader> loader,
+ const GURL& url) {
+ URLToLoaderMap::iterator it = url_to_loader_.find(url);
+ if (it != url_to_loader_.end())
+ delete it->second;
+ url_to_loader_[url] = loader.release();
+}
+
+void ApplicationManager::SetLoaderForScheme(
+ scoped_ptr<ApplicationLoader> loader,
+ const std::string& scheme) {
+ SchemeToLoaderMap::iterator it = scheme_to_loader_.find(scheme);
+ if (it != scheme_to_loader_.end())
+ delete it->second;
+ scheme_to_loader_[scheme] = loader.release();
+}
+
+void ApplicationManager::SetInterceptor(Interceptor* interceptor) {
+ interceptor_ = interceptor;
+}
+
+ApplicationLoader* ApplicationManager::GetLoaderForURL(const GURL& url) {
+ URLToLoaderMap::const_iterator url_it = url_to_loader_.find(url);
+ if (url_it != url_to_loader_.end())
+ return url_it->second;
+ SchemeToLoaderMap::const_iterator scheme_it =
+ scheme_to_loader_.find(url.scheme());
+ if (scheme_it != scheme_to_loader_.end())
+ return scheme_it->second;
+ return default_loader_.get();
+}
+
+void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
+ // Called from ~ShellImpl, so we do not need to call Destroy here.
+ const GURL url = shell_impl->url();
+ URLToShellImplMap::iterator it = url_to_shell_impl_.find(url);
+ DCHECK(it != url_to_shell_impl_.end());
+ delete it->second;
+ url_to_shell_impl_.erase(it);
+ ApplicationLoader* loader = GetLoaderForURL(url);
+ if (loader)
+ loader->OnServiceError(this, url);
+}
+
+ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName(
+ const GURL& application_url,
+ const std::string& interface_name) {
+ StubServiceProvider* stub_sp = new StubServiceProvider;
+ ServiceProviderPtr spp;
+ BindToProxy(stub_sp, &spp);
+ ConnectToApplication(application_url, GURL(), spp.Pass());
+ MessagePipe pipe;
+ stub_sp->GetRemoteServiceProvider()->ConnectToService(interface_name,
+ pipe.handle1.Pass());
+ return pipe.handle0.Pass();
+}
+} // namespace mojo