summaryrefslogtreecommitdiffstats
path: root/mojo/service_manager
diff options
context:
space:
mode:
authordavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 23:41:34 +0000
committerdavemoore@chromium.org <davemoore@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-27 23:41:34 +0000
commitfadab2ebbefc8dfcec3b25dc6324612a3b9ff565 (patch)
treed9d4aa7ca0b84bef47c22c7c7aacc1af340a7984 /mojo/service_manager
parent33fdddfddcca933851c1a3044d0d881cd5455dfd (diff)
downloadchromium_src-fadab2ebbefc8dfcec3b25dc6324612a3b9ff565.zip
chromium_src-fadab2ebbefc8dfcec3b25dc6324612a3b9ff565.tar.gz
chromium_src-fadab2ebbefc8dfcec3b25dc6324612a3b9ff565.tar.bz2
Move service_manager to top level dir
BUG=None TEST=Existing TBR=darin Review URL: https://codereview.chromium.org/180243020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@253973 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/service_manager')
-rw-r--r--mojo/service_manager/service_manager.cc106
-rw-r--r--mojo/service_manager/service_manager.h73
-rw-r--r--mojo/service_manager/service_manager_unittest.cc138
-rw-r--r--mojo/service_manager/test.mojom17
4 files changed, 334 insertions, 0 deletions
diff --git a/mojo/service_manager/service_manager.cc b/mojo/service_manager/service_manager.cc
new file mode 100644
index 0000000..bfc2bd7
--- /dev/null
+++ b/mojo/service_manager/service_manager.cc
@@ -0,0 +1,106 @@
+// Copyright 2013 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/service_manager/service_manager.h"
+
+#include "base/logging.h"
+#include "mojo/public/bindings/allocation_scope.h"
+#include "mojo/public/bindings/error_handler.h"
+#include "mojo/public/bindings/remote_ptr.h"
+
+namespace mojo {
+namespace shell {
+
+class ServiceManager::ServiceFactory : public Shell, public ErrorHandler {
+ public:
+ ServiceFactory(ServiceManager* manager, const GURL& url)
+ : manager_(manager),
+ url_(url) {
+ InterfacePipe<Shell> pipe;
+ shell_client_.reset(pipe.handle_to_peer.Pass(), this, this);
+ manager_->GetLoaderForURL(url)->Load(url, pipe.handle_to_self.Pass());
+ }
+ virtual ~ServiceFactory() {}
+
+ void ConnectToClient(ScopedMessagePipeHandle handle) {
+ if (handle.is_valid()) {
+ AllocationScope scope;
+ shell_client_->AcceptConnection(url_.spec(), handle.Pass());
+ }
+ }
+
+ virtual void Connect(const String& url,
+ ScopedMessagePipeHandle client_pipe) MOJO_OVERRIDE {
+ manager_->Connect(GURL(url.To<std::string>()), client_pipe.Pass());
+ }
+
+ virtual void OnError() MOJO_OVERRIDE {
+ manager_->RemoveServiceFactory(this);
+ }
+
+ const GURL& url() const { return url_; }
+
+ private:
+ ServiceManager* const manager_;
+ const GURL url_;
+ RemotePtr<ShellClient> shell_client_;
+ DISALLOW_COPY_AND_ASSIGN(ServiceFactory);
+};
+
+ServiceManager::Loader::Loader() {}
+ServiceManager::Loader::~Loader() {}
+
+bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const {
+ return manager_->url_to_service_factory_.find(url) !=
+ manager_->url_to_service_factory_.end();
+}
+
+ServiceManager::ServiceManager() : default_loader_(NULL) {
+}
+
+ServiceManager::~ServiceManager() {
+ for (ServiceFactoryMap::iterator it = url_to_service_factory_.begin();
+ it != url_to_service_factory_.end(); ++it) {
+ delete it->second;
+ }
+ url_to_service_factory_.clear();
+}
+
+void ServiceManager::SetLoaderForURL(Loader* loader, const GURL& gurl) {
+ DCHECK(url_to_loader_.find(gurl) == url_to_loader_.end());
+ url_to_loader_[gurl] = loader;
+}
+
+ServiceManager::Loader* ServiceManager::GetLoaderForURL(const GURL& gurl) {
+ LoaderMap::const_iterator it = url_to_loader_.find(gurl);
+ if (it != url_to_loader_.end())
+ return it->second;
+ DCHECK(default_loader_);
+ return default_loader_;
+}
+
+void ServiceManager::Connect(const GURL& url,
+ ScopedMessagePipeHandle client_handle) {
+ ServiceFactoryMap::const_iterator service_it =
+ url_to_service_factory_.find(url);
+ ServiceFactory* service_factory;
+ if (service_it != url_to_service_factory_.end()) {
+ service_factory = service_it->second;
+ } else {
+ service_factory = new ServiceFactory(this, url);
+ url_to_service_factory_[url] = service_factory;
+ }
+ service_factory->ConnectToClient(client_handle.Pass());
+}
+
+void ServiceManager::RemoveServiceFactory(ServiceFactory* service_factory) {
+ ServiceFactoryMap::iterator it =
+ url_to_service_factory_.find(service_factory->url());
+ DCHECK(it != url_to_service_factory_.end());
+ delete it->second;
+ url_to_service_factory_.erase(it);
+}
+
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/service_manager/service_manager.h b/mojo/service_manager/service_manager.h
new file mode 100644
index 0000000..4c7cfd58
--- /dev/null
+++ b/mojo/service_manager/service_manager.h
@@ -0,0 +1,73 @@
+// Copyright 2013 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.
+
+#ifndef MOJO_SERVICE_MANAGER_SERVICE_MANAGER_H_
+#define MOJO_SERVICE_MANAGER_SERVICE_MANAGER_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "mojo/public/shell/shell.mojom.h"
+#include "mojo/public/system/core_cpp.h"
+#include "url/gurl.h"
+
+namespace mojo {
+namespace shell {
+
+class ServiceManager {
+ public:
+ // Interface to allowing default loading behavior to be overridden for a
+ // specific url.
+ class Loader {
+ public:
+ virtual ~Loader();
+ virtual void Load(const GURL& url, ScopedShellHandle service_handle) = 0;
+ protected:
+ Loader();
+ };
+
+ // API for testing.
+ class TestAPI {
+ private:
+ friend class ServiceManagerTest;
+ explicit TestAPI(ServiceManager* manager) : manager_(manager) {}
+ // Returns true if there is a ServiceFactory for this URL.
+ bool HasFactoryForURL(const GURL& url) const;
+
+ ServiceManager* manager_;
+ };
+
+ ServiceManager();
+ ~ServiceManager();
+
+ // Sets the default Loader to be used if not overridden by SetLoaderForURL().
+ // Does not take ownership of |loader|.
+ void set_default_loader(Loader* loader) { default_loader_ = loader; }
+ // Sets a Loader to be used for a specific url.
+ // Does not take ownership of |loader|.
+ void SetLoaderForURL(Loader* loader, const GURL& gurl);
+ // Returns the Loader to use for a url (using default if not overridden.)
+ Loader* GetLoaderForURL(const GURL& gurl);
+ // Loads a service if necessary and establishes a new client connection.
+ void Connect(const GURL& url, ScopedMessagePipeHandle client_handle);
+
+ private:
+ class ServiceFactory;
+
+ // Removes a ServiceFactory when it no longer has any connections.
+ void RemoveServiceFactory(ServiceFactory* service_factory);
+
+ Loader* default_loader_;
+ typedef std::map<GURL, ServiceFactory*> ServiceFactoryMap;
+ ServiceFactoryMap url_to_service_factory_;
+ typedef std::map<GURL, Loader*> LoaderMap;
+ LoaderMap url_to_loader_;
+ DISALLOW_COPY_AND_ASSIGN(ServiceManager);
+};
+
+} // namespace shell
+} // namespace mojo
+
+#endif // MOJO_SERVICE_MANAGER_SERVICE_MANAGER_H_
diff --git a/mojo/service_manager/service_manager_unittest.cc b/mojo/service_manager/service_manager_unittest.cc
new file mode 100644
index 0000000..fba2044
--- /dev/null
+++ b/mojo/service_manager/service_manager_unittest.cc
@@ -0,0 +1,138 @@
+// 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/public/bindings/allocation_scope.h"
+#include "mojo/public/bindings/remote_ptr.h"
+#include "mojo/public/environment/environment.h"
+#include "mojo/public/shell/application.h"
+#include "mojo/public/shell/shell.mojom.h"
+#include "mojo/public/utility/run_loop.h"
+#include "mojo/service_manager/service_manager.h"
+#include "mojo/service_manager/test.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mojo {
+namespace shell {
+namespace {
+
+const char kTestURLString[] = "test:testService";
+
+struct TestContext {
+ TestContext() : num_impls(0) {}
+ std::string last_test_string;
+ int num_impls;
+};
+
+class TestServiceImpl :
+ public Service<TestService, TestServiceImpl, TestContext> {
+ public:
+ TestServiceImpl() {}
+
+ virtual ~TestServiceImpl() {
+ --context()->num_impls;
+ }
+
+ virtual void Test(const mojo::String& test_string) OVERRIDE {
+ context()->last_test_string = test_string.To<std::string>();
+ client()->AckTest();
+ }
+
+ void Initialize(ServiceFactory<TestServiceImpl, TestContext>* service_factory,
+ ScopedMessagePipeHandle client_handle) {
+ Service<TestService, TestServiceImpl, TestContext>::Initialize(
+ service_factory, client_handle.Pass());
+ ++context()->num_impls;
+ }
+};
+
+class TestClientImpl : public TestClient {
+ public:
+ explicit TestClientImpl(ScopedTestServiceHandle service_handle)
+ : service_(service_handle.Pass(), this),
+ quit_after_ack_(false) {
+ }
+
+ virtual ~TestClientImpl() {}
+
+ virtual void AckTest() OVERRIDE {
+ if (quit_after_ack_)
+ mojo::RunLoop::current()->Quit();
+ }
+
+ void Test(std::string test_string) {
+ AllocationScope scope;
+ quit_after_ack_ = true;
+ service_->Test(mojo::String(test_string));
+ }
+
+ private:
+ RemotePtr<TestService> service_;
+ bool quit_after_ack_;
+ DISALLOW_COPY_AND_ASSIGN(TestClientImpl);
+};
+} // namespace
+
+class ServiceManagerTest : public testing::Test,
+ public ServiceManager::Loader {
+ public:
+ ServiceManagerTest() {}
+
+ virtual ~ServiceManagerTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ GURL test_url(kTestURLString);
+ service_manager_.reset(new ServiceManager);
+ service_manager_->SetLoaderForURL(this, test_url);
+
+ InterfacePipe<TestService, AnyInterface> pipe;
+ test_client_.reset(new TestClientImpl(pipe.handle_to_self.Pass()));
+ service_manager_->Connect(test_url, pipe.handle_to_peer.Pass());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ test_client_.reset(NULL);
+ test_app_.reset(NULL);
+ service_manager_.reset(NULL);
+ }
+
+ virtual void Load(const GURL& url,
+ ScopedShellHandle shell_handle) OVERRIDE {
+ test_app_.reset(new Application(shell_handle.Pass()));
+ test_app_->AddServiceFactory(
+ new ServiceFactory<TestServiceImpl, TestContext>(&context_));
+ }
+
+ bool HasFactoryForTestURL() {
+ ServiceManager::TestAPI manager_test_api(service_manager_.get());
+ return manager_test_api.HasFactoryForURL(GURL(kTestURLString));
+ }
+
+ protected:
+ mojo::Environment env_;
+ mojo::RunLoop loop_;
+ TestContext context_;
+ scoped_ptr<Application> test_app_;
+ scoped_ptr<TestClientImpl> test_client_;
+ scoped_ptr<ServiceManager> service_manager_;
+ DISALLOW_COPY_AND_ASSIGN(ServiceManagerTest);
+};
+
+TEST_F(ServiceManagerTest, Basic) {
+ test_client_->Test("test");
+ loop_.Run();
+ EXPECT_EQ(std::string("test"), context_.last_test_string);
+}
+
+TEST_F(ServiceManagerTest, ClientError) {
+ test_client_->Test("test");
+ EXPECT_TRUE(HasFactoryForTestURL());
+ loop_.Run();
+ EXPECT_EQ(1, context_.num_impls);
+ test_client_.reset(NULL);
+ loop_.Run();
+ EXPECT_EQ(0, context_.num_impls);
+ EXPECT_FALSE(HasFactoryForTestURL());
+}
+} // namespace shell
+} // namespace mojo
diff --git a/mojo/service_manager/test.mojom b/mojo/service_manager/test.mojom
new file mode 100644
index 0000000..59ebfa9
--- /dev/null
+++ b/mojo/service_manager/test.mojom
@@ -0,0 +1,17 @@
+// Copyright 2013 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.
+
+module mojo {
+
+[Peer=TestClient]
+interface TestService {
+ Test(string test_string);
+};
+
+[Peer=TestService]
+interface TestClient {
+ AckTest();
+};
+
+}