Move application_manager from /mojo to /shell.

application_manager is an implementation detail of the shell.

BUG=430984
R=jamesr@chromium.org

Review URL: https://codereview.chromium.org/814273005
diff --git a/shell/application_manager/application_manager.cc b/shell/application_manager/application_manager.cc
new file mode 100644
index 0000000..2ead72e
--- /dev/null
+++ b/shell/application_manager/application_manager.cc
@@ -0,0 +1,275 @@
+// 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 "shell/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/public/cpp/application/connect.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/error_handler.h"
+#include "mojo/public/interfaces/application/shell.mojom.h"
+#include "mojo/services/content_handler/public/interfaces/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:
+  void ConnectToService(const String& service_name,
+                        ScopedMessagePipeHandle client_handle) override {}
+};
+
+}  // namespace
+
+
+ApplicationManager::Delegate::~Delegate() {
+}
+
+void ApplicationManager::Delegate::OnApplicationError(const GURL& url) {
+  LOG(ERROR) << "Communication error with application: " << url.spec();
+}
+
+GURL ApplicationManager::Delegate::ResolveURL(const GURL& url) {
+  return url;
+}
+
+class ApplicationManager::ContentHandlerConnection : public ErrorHandler {
+ public:
+  ContentHandlerConnection(ApplicationManager* manager,
+                           const GURL& content_handler_url)
+      : manager_(manager), content_handler_url_(content_handler_url) {
+    ServiceProviderPtr services;
+    manager->ConnectToApplication(content_handler_url, GURL(),
+                                  GetProxy(&services), nullptr);
+    mojo::ConnectToService(services.get(), &content_handler_);
+    content_handler_.set_error_handler(this);
+  }
+
+  ContentHandler* content_handler() { return content_handler_.get(); }
+
+  GURL content_handler_url() { return content_handler_url_; }
+
+ private:
+  // ErrorHandler implementation:
+  void OnConnectionError() override { manager_->OnContentHandlerError(this); }
+
+  ApplicationManager* manager_;
+  GURL content_handler_url_;
+  ContentHandlerPtr content_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentHandlerConnection);
+};
+
+// 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(Delegate* delegate)
+    : delegate_(delegate),
+      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_);
+}
+
+void ApplicationManager::ConnectToApplication(
+    const GURL& requested_url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services) {
+  DCHECK(requested_url.is_valid());
+  ApplicationLoader* loader = GetLoaderForURL(requested_url,
+                                              DONT_INCLUDE_DEFAULT_LOADER);
+  if (loader) {
+    ConnectToApplicationImpl(requested_url, requested_url, requestor_url,
+                             services.Pass(), exposed_services.Pass(), loader);
+    return;
+  }
+
+  GURL resolved_url = delegate_->ResolveURL(requested_url);
+  loader = GetLoaderForURL(resolved_url, INCLUDE_DEFAULT_LOADER);
+  if (loader) {
+    ConnectToApplicationImpl(requested_url, resolved_url, requestor_url,
+                             services.Pass(), exposed_services.Pass(), loader);
+    return;
+  }
+
+  LOG(WARNING) << "Could not find loader to load application: "
+               << requested_url.spec();
+}
+
+void ApplicationManager::ConnectToApplicationImpl(
+    const GURL& requested_url,
+    const GURL& resolved_url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services,
+    ApplicationLoader* loader) {
+  ShellImpl* shell = nullptr;
+  URLToShellImplMap::const_iterator shell_it =
+      url_to_shell_impl_.find(resolved_url);
+  if (shell_it != url_to_shell_impl_.end()) {
+    shell = shell_it->second;
+  } else {
+    MessagePipe pipe;
+    shell =
+        new ShellImpl(pipe.handle0.Pass(), this, requested_url, resolved_url);
+    url_to_shell_impl_[resolved_url] = shell;
+    shell->client()->Initialize(GetArgsForURL(requested_url));
+
+    loader->Load(this, resolved_url, pipe.handle1.Pass(),
+                 base::Bind(&ApplicationManager::LoadWithContentHandler,
+                            weak_ptr_factory_.GetWeakPtr()));
+  }
+  ConnectToClient(shell, resolved_url, requestor_url, services.Pass(),
+                  exposed_services.Pass());
+}
+
+void ApplicationManager::ConnectToClient(
+    ShellImpl* shell_impl,
+    const GURL& url,
+    const GURL& requestor_url,
+    InterfaceRequest<ServiceProvider> services,
+    ServiceProviderPtr exposed_services) {
+  shell_impl->ConnectToClient(requestor_url, services.Pass(),
+                              exposed_services.Pass());
+}
+
+void ApplicationManager::RegisterExternalApplication(
+    const GURL& url,
+    ScopedMessagePipeHandle shell_handle) {
+  ShellImpl* shell_impl = new ShellImpl(shell_handle.Pass(), this, url, url);
+  url_to_shell_impl_[url] = shell_impl;
+  shell_impl->client()->Initialize(GetArgsForURL(url));
+}
+
+void ApplicationManager::LoadWithContentHandler(
+    const GURL& content_handler_url,
+    ScopedMessagePipeHandle shell_handle,
+    URLResponsePtr url_response) {
+  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()->StartApplication(
+      MakeProxy<Shell>(shell_handle.Pass()), url_response.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::SetArgsForURL(const std::vector<std::string>& args,
+                                       const GURL& url) {
+  url_to_args_[url] = args;
+}
+
+ApplicationLoader* ApplicationManager::GetLoaderForURL(
+    const GURL& url, IncludeDefaultLoader include_default_loader) {
+  auto url_it = url_to_loader_.find(url);
+  if (url_it != url_to_loader_.end())
+    return url_it->second;
+  auto scheme_it = scheme_to_loader_.find(url.scheme());
+  if (scheme_it != scheme_to_loader_.end())
+    return scheme_it->second;
+  if (include_default_loader == INCLUDE_DEFAULT_LOADER)
+    return default_loader_.get();
+  return NULL;
+}
+
+void ApplicationManager::OnShellImplError(ShellImpl* shell_impl) {
+  // Called from ~ShellImpl, so we do not need to call Destroy here.
+  const GURL url = shell_impl->url();
+  const GURL requested_url = shell_impl->requested_url();
+  // Remove the shell.
+  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(requested_url,
+                                              INCLUDE_DEFAULT_LOADER);
+  if (loader)
+    loader->OnApplicationError(this, url);
+  delegate_->OnApplicationError(requested_url);
+}
+
+void ApplicationManager::OnContentHandlerError(
+    ContentHandlerConnection* content_handler) {
+  // Remove the mapping to the content handler.
+  auto it =
+      url_to_content_handler_.find(content_handler->content_handler_url());
+  DCHECK(it != url_to_content_handler_.end());
+  delete it->second;
+  url_to_content_handler_.erase(it);
+}
+
+ScopedMessagePipeHandle ApplicationManager::ConnectToServiceByName(
+    const GURL& application_url,
+    const std::string& interface_name) {
+  ServiceProviderPtr services;
+  ConnectToApplication(application_url, GURL(), GetProxy(&services), nullptr);
+  MessagePipe pipe;
+  services->ConnectToService(interface_name, pipe.handle1.Pass());
+  return pipe.handle0.Pass();
+}
+
+Array<String> ApplicationManager::GetArgsForURL(const GURL& url) {
+  URLToArgsMap::const_iterator args_it = url_to_args_.find(url);
+  if (args_it != url_to_args_.end())
+    return Array<String>::From(args_it->second);
+  return Array<String>();
+}
+}  // namespace mojo