Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / mojo / shell / dynamic_application_loader.cc
index b0d343e..ac0686e 100644 (file)
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/file_util.h"
 #include "base/files/file_path.h"
+#include "base/files/file_util.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "mojo/common/common_type_converters.h"
 #include "mojo/common/data_pipe_utils.h"
 #include "mojo/services/public/interfaces/network/url_loader.mojom.h"
 #include "mojo/shell/context.h"
-#include "mojo/shell/keep_alive.h"
 #include "mojo/shell/switches.h"
 #include "net/base/filename_util.h"
 
 namespace mojo {
 namespace shell {
 
-namespace {
+// Encapsulates loading and running one individual application.
+//
+// Loaders are owned by DynamicApplicationLoader. DynamicApplicationLoader must
+// ensure that all the parameters passed to Loader subclasses stay valid through
+// Loader's lifetime.
+//
+// Async operations are done with WeakPtr to protect against
+// DynamicApplicationLoader going away (and taking all the Loaders with it)
+// while the async operation is outstanding.
+class DynamicApplicationLoader::Loader {
+ public:
+  Loader(Context* context,
+         DynamicServiceRunnerFactory* runner_factory,
+         scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
+         const LoaderCompleteCallback& loader_complete_callback)
+      : load_callbacks_(load_callbacks),
+        loader_complete_callback_(loader_complete_callback),
+        context_(context),
+        runner_factory_(runner_factory),
+        weak_ptr_factory_(this) {}
+
+  virtual ~Loader() {}
+
+ protected:
+  void RunLibrary(const base::FilePath& path, bool path_exists) {
+    ScopedMessagePipeHandle shell_handle =
+        load_callbacks_->RegisterApplication();
+    if (!shell_handle.is_valid()) {
+      LoaderComplete();
+      return;
+    }
+
+    if (!path_exists) {
+      DVLOG(1) << "Library not started because library path '" << path.value()
+               << "' does not exist.";
+      LoaderComplete();
+      return;
+    }
+
+    runner_ = runner_factory_->Create(context_);
+    runner_->Start(
+        path,
+        shell_handle.Pass(),
+        base::Bind(&Loader::LoaderComplete, weak_ptr_factory_.GetWeakPtr()));
+  }
 
-void RunLibraryComplete(DynamicServiceRunner* runner,
-                        const base::FilePath& temp_file) {
-  delete runner;
-  if (!temp_file.empty())
-    base::DeleteFile(temp_file, false);
-}
+  void LoaderComplete() { loader_complete_callback_.Run(this); }
+
+  scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks_;
+  LoaderCompleteCallback loader_complete_callback_;
+  Context* context_;
+
+ private:
+  DynamicServiceRunnerFactory* runner_factory_;
+  scoped_ptr<DynamicServiceRunner> runner_;
+  base::WeakPtrFactory<Loader> weak_ptr_factory_;
+};
+
+// A loader for local files.
+class DynamicApplicationLoader::LocalLoader : public Loader {
+ public:
+  LocalLoader(const GURL& url,
+              Context* context,
+              DynamicServiceRunnerFactory* runner_factory,
+              scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
+              const LoaderCompleteCallback& loader_complete_callback)
+      : Loader(context,
+               runner_factory,
+               load_callbacks,
+               loader_complete_callback),
+        weak_ptr_factory_(this) {
+    base::FilePath path;
+    net::FileURLToFilePath(url, &path);
+
+    // Async for consistency with network case.
+    base::MessageLoop::current()->PostTask(
+        FROM_HERE,
+        base::Bind(&LocalLoader::RunLibrary,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   path,
+                   base::PathExists(path)));
+  }
+
+  virtual ~LocalLoader() {}
+
+ private:
+  base::WeakPtrFactory<LocalLoader> weak_ptr_factory_;
+};
+
+// A loader for network files.
+class DynamicApplicationLoader::NetworkLoader : public Loader {
+ public:
+  NetworkLoader(const GURL& url,
+                MimeTypeToURLMap* mime_type_to_url,
+                Context* context,
+                DynamicServiceRunnerFactory* runner_factory,
+                NetworkService* network_service,
+                scoped_refptr<ApplicationLoader::LoadCallbacks> load_callbacks,
+                const LoaderCompleteCallback& loader_complete_callback)
+      : Loader(context,
+               runner_factory,
+               load_callbacks,
+               loader_complete_callback),
+        mime_type_to_url_(mime_type_to_url),
+        weak_ptr_factory_(this) {
+    URLRequestPtr request(URLRequest::New());
+    request->url = String::From(url);
+    request->auto_follow_redirects = true;
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableCache)) {
+      request->bypass_cache = true;
+    }
+
+    network_service->CreateURLLoader(Get(&url_loader_));
+    url_loader_->Start(request.Pass(),
+                       base::Bind(&NetworkLoader::OnLoadComplete,
+                                  weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  virtual ~NetworkLoader() {
+    if (!file_.empty())
+      base::DeleteFile(file_, false);
+  }
+
+ private:
+  void OnLoadComplete(URLResponsePtr response) {
+    if (response->error) {
+      LOG(ERROR) << "Error (" << response->error->code << ": "
+                 << response->error->description << ") while fetching "
+                 << response->url;
+      LoaderComplete();
+      return;
+    }
+
+    MimeTypeToURLMap::iterator iter =
+        mime_type_to_url_->find(response->mime_type);
+    if (iter != mime_type_to_url_->end()) {
+      load_callbacks_->LoadWithContentHandler(iter->second, response.Pass());
+      return;
+    }
+
+    base::CreateTemporaryFile(&file_);
+    common::CopyToFile(
+        response->body.Pass(),
+        file_,
+        context_->task_runners()->blocking_pool(),
+        base::Bind(
+            &NetworkLoader::RunLibrary, weak_ptr_factory_.GetWeakPtr(), file_));
+  }
 
-}  // namespace
+  MimeTypeToURLMap* mime_type_to_url_;
+  URLLoaderPtr url_loader_;
+  base::FilePath file_;
+  base::WeakPtrFactory<NetworkLoader> weak_ptr_factory_;
+};
 
 DynamicApplicationLoader::DynamicApplicationLoader(
     Context* context,
     scoped_ptr<DynamicServiceRunnerFactory> runner_factory)
     : context_(context),
       runner_factory_(runner_factory.Pass()),
-      weak_ptr_factory_(this) {
+
+      // Unretained() is correct here because DynamicApplicationLoader owns the
+      // loaders that we pass this callback to.
+      loader_complete_callback_(
+          base::Bind(&DynamicApplicationLoader::LoaderComplete,
+                     base::Unretained(this))) {
 }
 
 DynamicApplicationLoader::~DynamicApplicationLoader() {
@@ -49,9 +200,10 @@ void DynamicApplicationLoader::RegisterContentHandler(
   mime_type_to_url_[mime_type] = content_handler_url;
 }
 
-void DynamicApplicationLoader::Load(ApplicationManager* manager,
-                                    const GURL& url,
-                                    scoped_refptr<LoadCallbacks> callbacks) {
+void DynamicApplicationLoader::Load(
+    ApplicationManager* manager,
+    const GURL& url,
+    scoped_refptr<LoadCallbacks> load_callbacks) {
   GURL resolved_url;
   if (url.SchemeIs("mojo")) {
     resolved_url = context_->mojo_url_resolver()->Resolve(url);
@@ -59,116 +211,38 @@ void DynamicApplicationLoader::Load(ApplicationManager* manager,
     resolved_url = url;
   }
 
-  if (resolved_url.SchemeIsFile())
-    LoadLocalService(resolved_url, callbacks);
-  else
-    LoadNetworkService(resolved_url, callbacks);
-}
-
-void DynamicApplicationLoader::LoadLocalService(
-    const GURL& resolved_url,
-    scoped_refptr<LoadCallbacks> callbacks) {
-  base::FilePath path;
-  net::FileURLToFilePath(resolved_url, &path);
-  const bool kDeleteFileAfter = false;
-
-  // Async for consistency with network case.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&DynamicApplicationLoader::RunLibrary,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 path,
-                 callbacks,
-                 kDeleteFileAfter,
-                 base::PathExists(path)));
-}
+  if (resolved_url.SchemeIsFile()) {
+    loaders_.push_back(new LocalLoader(resolved_url,
+                                       context_,
+                                       runner_factory_.get(),
+                                       load_callbacks,
+                                       loader_complete_callback_));
+    return;
+  }
 
-void DynamicApplicationLoader::LoadNetworkService(
-    const GURL& resolved_url,
-    scoped_refptr<LoadCallbacks> callbacks) {
   if (!network_service_) {
     context_->application_manager()->ConnectToService(
         GURL("mojo:mojo_network_service"), &network_service_);
   }
-  if (!url_loader_)
-    network_service_->CreateURLLoader(Get(&url_loader_));
 
-  URLRequestPtr request(URLRequest::New());
-  request->url = String::From(resolved_url);
-  request->auto_follow_redirects = true;
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableCache)) {
-    request->bypass_cache = true;
-  }
-
-  url_loader_->Start(
-      request.Pass(),
-      base::Bind(&DynamicApplicationLoader::OnLoadNetworkServiceComplete,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callbacks));
-}
-
-void DynamicApplicationLoader::OnLoadNetworkServiceComplete(
-    scoped_refptr<LoadCallbacks> callbacks,
-    URLResponsePtr response) {
-  if (response->error) {
-    LOG(ERROR) << "Error (" << response->error->code << ": "
-               << response->error->description << ") while fetching "
-               << response->url;
-  }
-
-  MimeTypeToURLMap::iterator iter = mime_type_to_url_.find(response->mime_type);
-  if (iter != mime_type_to_url_.end()) {
-    callbacks->LoadWithContentHandler(iter->second, response.Pass());
-    return;
-  }
-
-  base::FilePath file;
-  base::CreateTemporaryFile(&file);
-
-  const bool kDeleteFileAfter = true;
-  common::CopyToFile(response->body.Pass(),
-                     file,
-                     context_->task_runners()->blocking_pool(),
-                     base::Bind(&DynamicApplicationLoader::RunLibrary,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                file,
-                                callbacks,
-                                kDeleteFileAfter));
+  loaders_.push_back(new NetworkLoader(resolved_url,
+                                       &mime_type_to_url_,
+                                       context_,
+                                       runner_factory_.get(),
+                                       network_service_.get(),
+                                       load_callbacks,
+                                       loader_complete_callback_));
 }
 
-void DynamicApplicationLoader::RunLibrary(
-    const base::FilePath& path,
-    scoped_refptr<LoadCallbacks> callbacks,
-    bool delete_file_after,
-    bool path_exists) {
-  // TODO(aa): We need to create a runner, even if we're not going to use it,
-  // because it getting destroyed is what causes shell to shut down. If we don't
-  // create this, in the case where shell never successfully creates even one
-  // app, then shell will never shut down, because no runners are ever
-  // destroyed.
-  scoped_ptr<DynamicServiceRunner> runner(runner_factory_->Create(context_));
-  if (!path_exists)
-    return;
-
-  ScopedMessagePipeHandle shell_handle = callbacks->RegisterApplication();
-  if (!shell_handle.is_valid())
-    return;
-
-  DynamicServiceRunner* runner_raw = runner.release();
-  runner_raw->Start(path,
-                    shell_handle.Pass(),
-                    base::Bind(&RunLibraryComplete,
-                               base::Unretained(runner_raw),
-                               delete_file_after ? path : base::FilePath()));
-}
-
-void DynamicApplicationLoader::OnServiceError(ApplicationManager* manager,
-                                              const GURL& url) {
+void DynamicApplicationLoader::OnApplicationError(ApplicationManager* manager,
+                                                  const GURL& url) {
   // TODO(darin): What should we do about service errors? This implies that
   // the app closed its handle to the service manager. Maybe we don't care?
 }
 
+void DynamicApplicationLoader::LoaderComplete(Loader* loader) {
+  loaders_.erase(std::find(loaders_.begin(), loaders_.end(), loader));
+}
+
 }  // namespace shell
 }  // namespace mojo