diff options
author | jam <jam@chromium.org> | 2015-05-14 15:56:10 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-14 22:56:18 +0000 |
commit | 05a3de409c2653028aede6a467bb70c0addf57fc (patch) | |
tree | 77329d790a38ff6aed7d8f9ae1d17e169887057a /mojo/application | |
parent | 067d014b8f1918db09939aa765bdfa7576ab3d50 (diff) | |
download | chromium_src-05a3de409c2653028aede6a467bb70c0addf57fc.zip chromium_src-05a3de409c2653028aede6a467bb70c0addf57fc.tar.gz chromium_src-05a3de409c2653028aede6a467bb70c0addf57fc.tar.bz2 |
Fork the mojo shell interfaces used by Mandoline.
Per in-person discussions, as long as we have a fork of mojo shell we'll fork the interfaces.
I'll do third_party/mojo/src/mojo/public/java/application in a followup.
TBR=tsepez
Review URL: https://codereview.chromium.org/1139123006
Cr-Commit-Position: refs/heads/master@{#329965}
Diffstat (limited to 'mojo/application')
36 files changed, 1678 insertions, 15 deletions
diff --git a/mojo/application/BUILD.gn b/mojo/application/BUILD.gn index 958d87b..5800c0c 100644 --- a/mojo/application/BUILD.gn +++ b/mojo/application/BUILD.gn @@ -10,7 +10,7 @@ source_set("application") { ] public_deps = [ - "//third_party/mojo/src/mojo/public/cpp/application", + "//mojo/application/public/cpp:application", ] deps = [ "//base", @@ -27,9 +27,9 @@ source_set("content_handler") { deps = [ ":application", "//base", + "//mojo/application/public/interfaces", "//mojo/common", "//mojo/environment:chromium", - "//third_party/mojo/src/mojo/public/interfaces/application", "//third_party/mojo_services/src/content_handler/public/interfaces", "//mojo/services/network/public/interfaces", ] @@ -46,7 +46,7 @@ source_set("test_support") { deps = [ "//base", "//base/test:test_support", - "//third_party/mojo/src/mojo/public/cpp/application:application", + "//mojo/application/public/cpp:application", "//third_party/mojo/src/mojo/public/cpp/bindings", "//third_party/mojo/src/mojo/public/cpp/environment", "//third_party/mojo/src/mojo/public/cpp/system", diff --git a/mojo/application/application_runner_chromium.cc b/mojo/application/application_runner_chromium.cc index e5f21ca..35d945d 100644 --- a/mojo/application/application_runner_chromium.cc +++ b/mojo/application/application_runner_chromium.cc @@ -9,9 +9,9 @@ #include "base/debug/stack_trace.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/application_impl.h" #include "mojo/common/message_pump_mojo.h" -#include "mojo/public/cpp/application/application_delegate.h" -#include "mojo/public/cpp/application/application_impl.h" int g_argc; const char* const* g_argv; diff --git a/mojo/application/application_test_base_chromium.cc b/mojo/application/application_test_base_chromium.cc index 72bf189..bb9afa1 100644 --- a/mojo/application/application_test_base_chromium.cc +++ b/mojo/application/application_test_base_chromium.cc @@ -6,11 +6,11 @@ #include "base/command_line.h" #include "base/strings/utf_string_conversions.h" -#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/interfaces/application.mojom.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/system/message_pipe.h" -#include "mojo/public/interfaces/application/application.mojom.h" namespace mojo { namespace test { diff --git a/mojo/application/application_test_base_chromium.h b/mojo/application/application_test_base_chromium.h index c050848..ee17e42 100644 --- a/mojo/application/application_test_base_chromium.h +++ b/mojo/application/application_test_base_chromium.h @@ -5,11 +5,11 @@ #ifndef MOJO_APPLICATION_APPLICATION_TEST_BASE_CHROMIUM_H_ #define MOJO_APPLICATION_APPLICATION_TEST_BASE_CHROMIUM_H_ -#include "mojo/public/cpp/application/application_delegate.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/interfaces/application.mojom.h" #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/string.h" #include "mojo/public/cpp/system/macros.h" -#include "mojo/public/interfaces/application/application.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { diff --git a/mojo/application/content_handler_factory.cc b/mojo/application/content_handler_factory.cc index 8518f4c..9fac371 100644 --- a/mojo/application/content_handler_factory.cc +++ b/mojo/application/content_handler_factory.cc @@ -11,11 +11,11 @@ #include "base/memory/weak_ptr.h" #include "base/threading/platform_thread.h" #include "mojo/application/application_runner_chromium.h" +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/interface_factory_impl.h" #include "mojo/common/message_pump_mojo.h" -#include "mojo/public/cpp/application/application_connection.h" -#include "mojo/public/cpp/application/application_delegate.h" -#include "mojo/public/cpp/application/application_impl.h" -#include "mojo/public/cpp/application/interface_factory_impl.h" #include "mojo/public/cpp/bindings/strong_binding.h" namespace mojo { diff --git a/mojo/application/content_handler_factory.h b/mojo/application/content_handler_factory.h index aabba6f..25ee2be 100644 --- a/mojo/application/content_handler_factory.h +++ b/mojo/application/content_handler_factory.h @@ -6,8 +6,8 @@ #define MOJO_APPLICATION_CONTENT_HANDLER_FACTORY_H_ #include "base/memory/scoped_ptr.h" -#include "mojo/public/cpp/application/interface_factory.h" -#include "mojo/public/interfaces/application/shell.mojom.h" +#include "mojo/application/public/cpp/interface_factory.h" +#include "mojo/application/public/interfaces/shell.mojom.h" #include "mojo/services/network/public/interfaces/url_loader.mojom.h" #include "third_party/mojo_services/src/content_handler/public/interfaces/content_handler.mojom.h" diff --git a/mojo/application/public/cpp/BUILD.gn b/mojo/application/public/cpp/BUILD.gn new file mode 100644 index 0000000..796f615 --- /dev/null +++ b/mojo/application/public/cpp/BUILD.gn @@ -0,0 +1,99 @@ +# 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. + +import("//third_party/mojo/src/mojo/public/mojo_sdk.gni") + +# GYP version: mojo/mojo_base.gyp:mojo_application_base +mojo_sdk_source_set("application") { + restrict_external_deps = false + sources = [ + "application_connection.h", + "application_delegate.h", + "application_impl.h", + "connect.h", + "interface_factory.h", + "interface_factory_impl.h", + "lib/application_connection.cc", + "lib/application_delegate.cc", + "lib/application_impl.cc", + "lib/interface_factory_connector.h", + "lib/service_connector_registry.cc", + "lib/service_connector_registry.h", + "lib/service_provider_impl.cc", + "lib/service_registry.cc", + "lib/service_registry.h", + "service_connector.h", + "service_provider_impl.h", + ] + + deps = [ + "//mojo/application/public/interfaces", + ] + + mojo_sdk_deps = [ + "mojo/public/cpp/bindings", + "mojo/public/cpp/environment", + "mojo/public/cpp/system", + ] +} + +# GYP version: mojo/mojo_base.gyp:mojo_application_standalone +mojo_sdk_source_set("standalone") { + sources = [ + "lib/application_runner.cc", + ] + + public_deps = [ + ":application", + ] + + mojo_sdk_deps = [ + "mojo/public/cpp/environment:standalone", + "mojo/public/cpp/utility", + ] +} + +mojo_sdk_source_set("test_support") { + testonly = true + restrict_external_deps = false + sources = [ + "application_test_base.h", + "lib/application_test_base.cc", + ] + + deps = [ + ":application", + "//mojo/application/public/interfaces", + "//testing/gtest", + ] + + mojo_sdk_deps = [ + "mojo/public/cpp/bindings", + "mojo/public/cpp/environment", + "mojo/public/cpp/system", + ] +} + +mojo_sdk_source_set("test_support_standalone") { + testonly = true + restrict_external_deps = false + sources = [ + "lib/application_test_main.cc", + ] + + public_deps = [ + ":test_support", + ] + + deps = [ + ":application", + "//mojo/application/public/interfaces", + ] + + mojo_sdk_deps = [ + "mojo/public/cpp/environment:standalone", + "mojo/public/cpp/system", + "mojo/public/cpp/utility", + ] +} diff --git a/mojo/application/public/cpp/application_connection.h b/mojo/application/public/cpp/application_connection.h new file mode 100644 index 0000000..ff900d3 --- /dev/null +++ b/mojo/application/public/cpp/application_connection.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_CONNECTION_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_CONNECTION_H_ + +#include <string> + +#include "mojo/application/public/cpp/lib/interface_factory_connector.h" +#include "mojo/application/public/interfaces/service_provider.mojom.h" + +namespace mojo { + +class ServiceConnector; + +// Represents a connection to another application. An instance of this class is +// passed to ApplicationDelegate's ConfigureIncomingConnection() method each +// time a connection is made to this app, and to ApplicationDelegate's +// ConfigureOutgoingConnection() method when the app connects to another. +// +// To use, define a class that implements your specific service API (e.g., +// FooImpl to implement a service named Foo). Then implement an +// InterfaceFactory<Foo> that binds instances of FooImpl to +// InterfaceRequest<Foo>s and register that on the connection like this: +// +// connection->AddService(&factory); +// +// Or, if you have multiple factories implemented by the same type, explicitly +// specify the interface to register the factory for: +// +// connection->AddService<Foo>(&my_foo_and_bar_factory_); +// connection->AddService<Bar>(&my_foo_and_bar_factory_); +// +// The InterfaceFactory must outlive the ApplicationConnection. +// +// Additionally you specify a ServiceConnector. If a ServiceConnector has +// been set and an InterfaceFactory has not been registered for the interface +// request, than the interface request is sent to the ServiceConnector. +// +// Just as with InterfaceFactory, ServiceConnector must outlive +// ApplicationConnection. +class ApplicationConnection { + public: + virtual ~ApplicationConnection(); + + // See class description for details. + virtual void SetServiceConnector(ServiceConnector* connector) = 0; + + // Makes Interface available as a service to the remote application. + // |factory| will create implementations of Interface on demand. + template <typename Interface> + void AddService(InterfaceFactory<Interface>* factory) { + SetServiceConnectorForName( + new internal::InterfaceFactoryConnector<Interface>(factory), + Interface::Name_); + } + + // Binds |ptr| to an implemention of Interface in the remote application. + // |ptr| can immediately be used to start sending requests to the remote + // service. + template <typename Interface> + void ConnectToService(InterfacePtr<Interface>* ptr) { + if (ServiceProvider* sp = GetServiceProvider()) { + MessagePipe pipe; + ptr->Bind(InterfacePtrInfo<Interface>(pipe.handle0.Pass(), 0u)); + sp->ConnectToService(Interface::Name_, pipe.handle1.Pass()); + } + } + + // Returns the URL that was used by the source application to establish a + // connection to the destination application. + // + // When ApplicationConnection is representing an incoming connection this can + // be different than the URL the application was initially loaded from, if the + // application handles multiple URLs. Note that this is the URL after all + // URL rewriting and HTTP redirects have been performed. + // + // When ApplicationConnection is representing and outgoing connection, this + // will be the same as the value returned by GetRemoveApplicationURL(). + virtual const std::string& GetConnectionURL() = 0; + + // Returns the URL identifying the remote application on this connection. + virtual const std::string& GetRemoteApplicationURL() = 0; + + // Returns the raw proxy to the remote application's ServiceProvider + // interface. Most applications will just use ConnectToService() instead. + // Caller does not take ownership. + virtual ServiceProvider* GetServiceProvider() = 0; + + private: + virtual void SetServiceConnectorForName(ServiceConnector* service_connector, + const std::string& name) = 0; +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_CONNECTION_H_ diff --git a/mojo/application/public/cpp/application_delegate.h b/mojo/application/public/cpp/application_delegate.h new file mode 100644 index 0000000..2c3423f --- /dev/null +++ b/mojo/application/public/cpp/application_delegate.h @@ -0,0 +1,47 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_DELEGATE_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_DELEGATE_H_ + +#include <string> + +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +class ApplicationConnection; +class ApplicationImpl; + +// An abstract class that the application may subclass to control various +// behaviors of ApplicationImpl. +class ApplicationDelegate { + public: + ApplicationDelegate(); + virtual ~ApplicationDelegate(); + + // Called exactly once before any other method. + virtual void Initialize(ApplicationImpl* app); + + // Override this method to configure what services a connection supports when + // being connected to from an app. + // Return false to reject the connection entirely. + virtual bool ConfigureIncomingConnection(ApplicationConnection* connection); + + // Override this method to configure what services a connection supports when + // connecting to another app. + // Return false to reject the connection entirely. + virtual bool ConfigureOutgoingConnection(ApplicationConnection* connection); + + // Called before ApplicationImpl::Terminate(). After returning from this call + // the delegate can no longer rely on the main run loop still running. + virtual void Quit(); + + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationDelegate); +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_DELEGATE_H_ diff --git a/mojo/application/public/cpp/application_impl.h b/mojo/application/public/cpp/application_impl.h new file mode 100644 index 0000000..a5d58f50 --- /dev/null +++ b/mojo/application/public/cpp/application_impl.h @@ -0,0 +1,140 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_IMPL_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_IMPL_H_ + +#include <vector> + +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/lib/service_registry.h" +#include "mojo/application/public/interfaces/application.mojom.h" +#include "mojo/application/public/interfaces/shell.mojom.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// Utility class for communicating with the Shell, and providing Services +// to clients. +// +// To use define a class that implements your specific server api, e.g. FooImpl +// to implement a service named Foo. +// That class must subclass an InterfaceImpl specialization. +// +// If there is context that is to be shared amongst all instances, define a +// constructor with that class as its only argument, otherwise define an empty +// constructor. +// +// class FooImpl : public InterfaceImpl<Foo> { +// public: +// FooImpl(ApplicationContext* app_context) {} +// }; +// +// or +// +// class BarImpl : public InterfaceImpl<Bar> { +// public: +// // contexts will remain valid for the lifetime of BarImpl. +// BarImpl(ApplicationContext* app_context, BarContext* service_context) +// : app_context_(app_context), servicecontext_(context) {} +// +// Create an ApplicationImpl instance that collects any service implementations. +// +// ApplicationImpl app(service_provider_handle); +// app.AddService<FooImpl>(); +// +// BarContext context; +// app.AddService<BarImpl>(&context); +// +// +class ApplicationImpl : public Application { + public: + // Does not take ownership of |delegate|, which must remain valid for the + // lifetime of ApplicationImpl. + ApplicationImpl(ApplicationDelegate* delegate, + InterfaceRequest<Application> request); + ~ApplicationImpl() override; + + // The Mojo shell. This will return a valid pointer after Initialize() has + // been invoked. It will remain valid until UnbindConnections() is invoked or + // the ApplicationImpl is destroyed. + Shell* shell() const { return shell_.get(); } + + const std::string& url() const { return url_; } + + // Returns any initial configuration arguments, passed by the Shell. + const std::vector<std::string>& args() const { return args_; } + bool HasArg(const std::string& arg) const; + + // Requests a new connection to an application. Returns a pointer to the + // connection if the connection is permitted by this application's delegate, + // or nullptr otherwise. Caller does not take ownership. The pointer remains + // valid until an error occurs on the connection with the Shell, or until the + // ApplicationImpl is destroyed, whichever occurs first. + ApplicationConnection* ConnectToApplication(const String& application_url); + + // Connect to application identified by |application_url| and connect to the + // service implementation of the interface identified by |Interface|. + template <typename Interface> + void ConnectToService(const std::string& application_url, + InterfacePtr<Interface>* ptr) { + ConnectToApplication(application_url)->ConnectToService(ptr); + } + + // Application implementation. + void Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) override; + + // Block until the Application is initialized, if it is not already. + void WaitForInitialize(); + + // Unbinds the Shell and Application connections. Can be used to re-bind the + // handles to another implementation of ApplicationImpl, for instance when + // running apptests. + void UnbindConnections(InterfaceRequest<Application>* application_request, + ShellPtr* shell); + + // Quits the main run loop for this application. + static void Terminate(); + + protected: + // Application implementation. + void AcceptConnection(const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const String& url) override; + + private: + class ShellPtrWatcher; + + void ClearConnections(); + + void OnShellError() { + delegate_->Quit(); + ClearConnections(); + Terminate(); + } + + // Application implementation. + void RequestQuit() override; + + typedef std::vector<internal::ServiceRegistry*> ServiceRegistryList; + + ServiceRegistryList incoming_service_registries_; + ServiceRegistryList outgoing_service_registries_; + ApplicationDelegate* delegate_; + Binding<Application> binding_; + ShellPtr shell_; + ShellPtrWatcher* shell_watch_; + std::string url_; + std::vector<std::string> args_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationImpl); +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_IMPL_H_ diff --git a/mojo/application/public/cpp/application_runner.h b/mojo/application/public/cpp/application_runner.h new file mode 100644 index 0000000..e537c66 --- /dev/null +++ b/mojo/application/public/cpp/application_runner.h @@ -0,0 +1,44 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_RUNNER_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_RUNNER_H_ + +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +class ApplicationDelegate; + +// A utility for running an Application. The typical use case is to use +// when writing your MojoMain: +// +// MojoResult MojoMain(MojoHandle application_request) { +// mojo::ApplicationRunner runner(new MyApplicationDelegate()); +// return runner.Run(application_request); +// } +// +// ApplicationRunner takes care of mojo environment initialization and +// shutdown, and starting a RunLoop from which your application can run and +// ultimately Quit(). +class ApplicationRunner { + public: + // Takes ownership of |delegate|. + explicit ApplicationRunner(ApplicationDelegate* delegate); + ~ApplicationRunner(); + + // Once the various parameters have been set above, use Run to initialize an + // ApplicationImpl wired to the provided delegate, and run a RunLoop until + // the application exits. + MojoResult Run(MojoHandle application_request); + + private: + ApplicationDelegate* delegate_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner); +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_RUNNER_H_ diff --git a/mojo/application/public/cpp/application_test_base.h b/mojo/application/public/cpp/application_test_base.h new file mode 100644 index 0000000..9314bda --- /dev/null +++ b/mojo/application/public/cpp/application_test_base.h @@ -0,0 +1,62 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_TEST_BASE_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_TEST_BASE_H_ + +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/interfaces/application.mojom.h" +#include "mojo/public/cpp/bindings/array.h" +#include "mojo/public/cpp/bindings/string.h" +#include "mojo/public/cpp/system/macros.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { + +class ApplicationImpl; + +namespace test { + +// Access the command line arguments passed to the application test. +const Array<String>& Args(); + +// Run all application tests. This must be called after the environment is +// initialized, to support construction of a default run loop. +MojoResult RunAllTests(MojoHandle application_request_handle); + +// A GTEST base class for application testing executed in mojo_shell. +class ApplicationTestBase : public testing::Test { + public: + ApplicationTestBase(); + ~ApplicationTestBase() override; + + protected: + ApplicationImpl* application_impl() { return application_impl_; } + + // Get the ApplicationDelegate for the application to be tested. + virtual ApplicationDelegate* GetApplicationDelegate(); + + // testing::Test: + void SetUp() override; + void TearDown() override; + + // True by default, which indicates a MessageLoop will automatically be + // created for the application. Tests may override this function to prevent + // a default loop from being created. + virtual bool ShouldCreateDefaultRunLoop(); + + private: + // The application implementation instance, reconstructed for each test. + ApplicationImpl* application_impl_; + // The application delegate used if GetApplicationDelegate is not overridden. + ApplicationDelegate default_application_delegate_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ApplicationTestBase); +}; + +} // namespace test + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_APPLICATION_TEST_BASE_H_ diff --git a/mojo/application/public/cpp/connect.h b/mojo/application/public/cpp/connect.h new file mode 100644 index 0000000..ecf920e --- /dev/null +++ b/mojo/application/public/cpp/connect.h @@ -0,0 +1,23 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_CONNECT_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_CONNECT_H_ + +#include "mojo/application/public/interfaces/service_provider.mojom.h" + +namespace mojo { + +// Binds |ptr| to a remote implementation of Interface from |service_provider|. +template <typename Interface> +inline void ConnectToService(ServiceProvider* service_provider, + InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(InterfacePtrInfo<Interface>(pipe.handle0.Pass(), 0u)); + service_provider->ConnectToService(Interface::Name_, pipe.handle1.Pass()); +} + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_CONNECT_H_ diff --git a/mojo/application/public/cpp/interface_factory.h b/mojo/application/public/cpp/interface_factory.h new file mode 100644 index 0000000..cd7f6e1 --- /dev/null +++ b/mojo/application/public/cpp/interface_factory.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_H_ + +#include "mojo/public/cpp/bindings/interface_impl.h" +#include "mojo/public/cpp/bindings/interface_request.h" + +namespace mojo { + +class ApplicationConnection; +template <typename Interface> +class InterfaceRequest; + +// Implement this class to provide implementations of a given interface and +// bind them to incoming requests. The implementation of this class is +// responsible for managing the lifetime of the implementations of the +// interface. +template <typename Interface> +class InterfaceFactory { + public: + virtual ~InterfaceFactory() {} + virtual void Create(ApplicationConnection* connection, + InterfaceRequest<Interface> request) = 0; +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_H_ diff --git a/mojo/application/public/cpp/interface_factory_impl.h b/mojo/application/public/cpp/interface_factory_impl.h new file mode 100644 index 0000000..d4cf1c2 --- /dev/null +++ b/mojo/application/public/cpp/interface_factory_impl.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_ + +#include "mojo/application/public/cpp/interface_factory.h" + +namespace mojo { + +// Use this class to allocate and bind instances of Impl to interface requests. +// The lifetime of the constructed Impl is bound to the pipe. +template <typename Impl, + typename Interface = typename Impl::ImplementedInterface> +class InterfaceFactoryImpl : public InterfaceFactory<Interface> { + public: + virtual ~InterfaceFactoryImpl() {} + + virtual void Create(ApplicationConnection* connection, + InterfaceRequest<Interface> request) override { + BindToRequest(new Impl(), &request); + } +}; + +// Use this class to allocate and bind instances of Impl constructed with a +// context parameter to interface requests. The lifetime of the constructed +// Impl is bound to the pipe. +template <typename Impl, + typename Context, + typename Interface = typename Impl::ImplementedInterface> +class InterfaceFactoryImplWithContext : public InterfaceFactory<Interface> { + public: + explicit InterfaceFactoryImplWithContext(Context* context) + : context_(context) {} + virtual ~InterfaceFactoryImplWithContext() {} + + virtual void Create(ApplicationConnection* connection, + InterfaceRequest<Interface> request) override { + BindToRequest(new Impl(context_), &request); + } + + private: + Context* context_; +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_INTERFACE_FACTORY_IMPL_H_ diff --git a/mojo/application/public/cpp/lazy_interface_ptr.h b/mojo/application/public/cpp/lazy_interface_ptr.h new file mode 100644 index 0000000..090beb2 --- /dev/null +++ b/mojo/application/public/cpp/lazy_interface_ptr.h @@ -0,0 +1,46 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_ + +#include "mojo/application/public/cpp/connect.h" +#include "mojo/application/public/interfaces/service_provider.mojom.h" + +namespace mojo { + +// An InterfacePtr that will request an implementation from a specified +// ServiceProvider when it is first accessed with the get() method. +template <typename Interface> +class LazyInterfacePtr : public InterfacePtr<Interface> { + public: + LazyInterfacePtr() : service_provider_(nullptr) {} + + LazyInterfacePtr(ServiceProvider* service_provider) + : service_provider_(service_provider) {} + + void set_service_provider(ServiceProvider* service_provider) { + if (service_provider != service_provider_) { + InterfacePtr<Interface>::reset(); + } + service_provider_ = service_provider; + } + + Interface* get() const { + if (!InterfacePtr<Interface>::get() && service_provider_) { + mojo::ConnectToService<Interface>( + service_provider_, const_cast<LazyInterfacePtr<Interface>*>(this)); + } + return InterfacePtr<Interface>::get(); + } + Interface* operator->() const { return get(); } + Interface& operator*() const { return *get(); } + + private: + ServiceProvider* service_provider_; +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_LAZY_INTERFACE_PTR_H_ diff --git a/mojo/application/public/cpp/lib/application_connection.cc b/mojo/application/public/cpp/lib/application_connection.cc new file mode 100644 index 0000000..a76757f --- /dev/null +++ b/mojo/application/public/cpp/lib/application_connection.cc @@ -0,0 +1,12 @@ +// 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/public/cpp/application_connection.h" + +namespace mojo { + +ApplicationConnection::~ApplicationConnection() { +} + +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/application_delegate.cc b/mojo/application/public/cpp/lib/application_delegate.cc new file mode 100644 index 0000000..bbe75cc --- /dev/null +++ b/mojo/application/public/cpp/lib/application_delegate.cc @@ -0,0 +1,30 @@ +// 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/public/cpp/application_delegate.h" + +namespace mojo { + +ApplicationDelegate::ApplicationDelegate() { +} +ApplicationDelegate::~ApplicationDelegate() { +} + +void ApplicationDelegate::Initialize(ApplicationImpl* app) { +} + +bool ApplicationDelegate::ConfigureIncomingConnection( + ApplicationConnection* connection) { + return true; +} + +bool ApplicationDelegate::ConfigureOutgoingConnection( + ApplicationConnection* connection) { + return true; +} + +void ApplicationDelegate::Quit() { +} + +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/application_impl.cc b/mojo/application/public/cpp/lib/application_impl.cc new file mode 100644 index 0000000..018729f --- /dev/null +++ b/mojo/application/public/cpp/lib/application_impl.cc @@ -0,0 +1,117 @@ +// 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/public/cpp/application_impl.h" + +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/lib/service_registry.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/environment/logging.h" + +namespace mojo { + +class ApplicationImpl::ShellPtrWatcher : public ErrorHandler { + public: + ShellPtrWatcher(ApplicationImpl* impl) : impl_(impl) {} + + ~ShellPtrWatcher() override {} + + void OnConnectionError() override { impl_->OnShellError(); } + + private: + ApplicationImpl* impl_; + MOJO_DISALLOW_COPY_AND_ASSIGN(ShellPtrWatcher); +}; + +ApplicationImpl::ApplicationImpl(ApplicationDelegate* delegate, + InterfaceRequest<Application> request) + : delegate_(delegate), + binding_(this, request.Pass()), + shell_watch_(nullptr) { +} + +bool ApplicationImpl::HasArg(const std::string& arg) const { + return std::find(args_.begin(), args_.end(), arg) != args_.end(); +} + +void ApplicationImpl::ClearConnections() { + for (ServiceRegistryList::iterator i(incoming_service_registries_.begin()); + i != incoming_service_registries_.end(); + ++i) + delete *i; + for (ServiceRegistryList::iterator i(outgoing_service_registries_.begin()); + i != outgoing_service_registries_.end(); + ++i) + delete *i; + incoming_service_registries_.clear(); + outgoing_service_registries_.clear(); +} + +ApplicationImpl::~ApplicationImpl() { + ClearConnections(); + delete shell_watch_; +} + +ApplicationConnection* ApplicationImpl::ConnectToApplication( + const String& application_url) { + MOJO_CHECK(shell_); + ServiceProviderPtr local_services; + InterfaceRequest<ServiceProvider> local_request = GetProxy(&local_services); + ServiceProviderPtr remote_services; + shell_->ConnectToApplication(application_url, GetProxy(&remote_services), + local_services.Pass()); + internal::ServiceRegistry* registry = new internal::ServiceRegistry( + this, application_url, application_url, remote_services.Pass(), + local_request.Pass()); + if (!delegate_->ConfigureOutgoingConnection(registry)) { + delete registry; + return nullptr; + } + outgoing_service_registries_.push_back(registry); + return registry; +} + +void ApplicationImpl::Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) { + shell_ = shell.Pass(); + shell_watch_ = new ShellPtrWatcher(this); + shell_.set_error_handler(shell_watch_); + url_ = url; + args_ = args.To<std::vector<std::string>>(); + delegate_->Initialize(this); +} + +void ApplicationImpl::WaitForInitialize() { + if (!shell_) + binding_.WaitForIncomingMethodCall(); +} + +void ApplicationImpl::UnbindConnections( + InterfaceRequest<Application>* application_request, + ShellPtr* shell) { + *application_request = binding_.Unbind(); + shell->Bind(shell_.PassInterface()); +} + +void ApplicationImpl::AcceptConnection( + const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const String& url) { + internal::ServiceRegistry* registry = new internal::ServiceRegistry( + this, url, requestor_url, exposed_services.Pass(), services.Pass()); + if (!delegate_->ConfigureIncomingConnection(registry)) { + delete registry; + return; + } + incoming_service_registries_.push_back(registry); +} + +void ApplicationImpl::RequestQuit() { + delegate_->Quit(); + Terminate(); +} + +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/application_runner.cc b/mojo/application/public/cpp/lib/application_runner.cc new file mode 100644 index 0000000..c1d4c0a --- /dev/null +++ b/mojo/application/public/cpp/lib/application_runner.cc @@ -0,0 +1,40 @@ +// 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/public/cpp/application_runner.h" + +#include "mojo/application/public/cpp/application_delegate.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/utility/run_loop.h" + +namespace mojo { + +// static +void ApplicationImpl::Terminate() { + RunLoop::current()->Quit(); +} + +ApplicationRunner::ApplicationRunner(ApplicationDelegate* delegate) + : delegate_(delegate) { +} +ApplicationRunner::~ApplicationRunner() { + assert(!delegate_); +} + +MojoResult ApplicationRunner::Run(MojoHandle app_request_handle) { + Environment env; + { + RunLoop loop; + ApplicationImpl app(delegate_, MakeRequest<Application>(MakeScopedHandle( + MessagePipeHandle(app_request_handle)))); + loop.Run(); + } + + delete delegate_; + delegate_ = nullptr; + return MOJO_RESULT_OK; +} + +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/application_test_base.cc b/mojo/application/public/cpp/lib/application_test_base.cc new file mode 100644 index 0000000..f3048da --- /dev/null +++ b/mojo/application/public/cpp/lib/application_test_base.cc @@ -0,0 +1,165 @@ +// 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/cpp/application/application_test_base.h" + +#include "mojo/application/public/interfaces/application.mojom.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/environment/environment.h" +#include "mojo/public/cpp/system/message_pipe.h" + +namespace mojo { +namespace test { + +namespace { +// Share the application command-line arguments with multiple application tests. +Array<String> g_args; + +// Share the application URL with multiple application tests. +String g_url; + +// Application request handle passed from the shell in MojoMain, stored in +// between SetUp()/TearDown() so we can (re-)intialize new ApplicationImpls. +InterfaceRequest<Application> g_application_request; + +// Shell pointer passed in the initial mojo.Application.Initialize() call, +// stored in between initial setup and the first test and between SetUp/TearDown +// calls so we can (re-)initialize new ApplicationImpls. +ShellPtr g_shell; + +void InitializeArgs(int argc, std::vector<const char*> argv) { + MOJO_CHECK(g_args.is_null()); + for (const char* arg : argv) { + if (arg) + g_args.push_back(arg); + } +} + +class ShellAndArgumentGrabber : public Application { + public: + ShellAndArgumentGrabber(Array<String>* args, + InterfaceRequest<Application> application_request) + : args_(args), binding_(this, application_request.Pass()) {} + + void WaitForInitialize() { + // Initialize is always the first call made on Application. + MOJO_CHECK(binding_.WaitForIncomingMethodCall()); + } + + private: + // Application implementation. + void Initialize(ShellPtr shell, + Array<String> args, + const mojo::String& url) override { + *args_ = args.Pass(); + g_url = url; + g_application_request = binding_.Unbind(); + g_shell = shell.Pass(); + } + + void AcceptConnection(const String& requestor_url, + InterfaceRequest<ServiceProvider> services, + ServiceProviderPtr exposed_services, + const String& url) override { + MOJO_CHECK(false); + } + + void RequestQuit() override { MOJO_CHECK(false); } + + Array<String>* args_; + Binding<Application> binding_; +}; + +} // namespace + +const Array<String>& Args() { + return g_args; +} + +MojoResult RunAllTests(MojoHandle application_request_handle) { + { + // This loop is used for init, and then destroyed before running tests. + Environment::InstantiateDefaultRunLoop(); + + // Grab the shell handle and GTEST commandline arguments. + // GTEST command line arguments are supported amid application arguments: + // $ mojo_shell mojo:example_apptests + // --args-for='mojo:example_apptests arg1 --gtest_filter=foo arg2' + Array<String> args; + ShellAndArgumentGrabber grabber( + &args, MakeRequest<Application>(MakeScopedHandle( + MessagePipeHandle(application_request_handle)))); + grabber.WaitForInitialize(); + MOJO_CHECK(g_shell); + MOJO_CHECK(g_application_request.is_pending()); + + // InitGoogleTest expects (argc + 1) elements, including a terminating null. + // It also removes GTEST arguments from |argv| and updates the |argc| count. + MOJO_CHECK(args.size() < + static_cast<size_t>(std::numeric_limits<int>::max())); + int argc = static_cast<int>(args.size()); + std::vector<const char*> argv(argc + 1); + for (int i = 0; i < argc; ++i) + argv[i] = args[i].get().c_str(); + argv[argc] = nullptr; + + testing::InitGoogleTest(&argc, const_cast<char**>(&(argv[0]))); + InitializeArgs(argc, argv); + + Environment::DestroyDefaultRunLoop(); + } + + int result = RUN_ALL_TESTS(); + + // Shut down our message pipes before exiting. + (void)g_application_request.PassMessagePipe(); + (void)g_shell.PassInterface(); + + return (result == 0) ? MOJO_RESULT_OK : MOJO_RESULT_UNKNOWN; +} + +ApplicationTestBase::ApplicationTestBase() : application_impl_(nullptr) { +} + +ApplicationTestBase::~ApplicationTestBase() { +} + +ApplicationDelegate* ApplicationTestBase::GetApplicationDelegate() { + return &default_application_delegate_; +} + +void ApplicationTestBase::SetUp() { + // A run loop is recommended for ApplicationImpl initialization and + // communication. + if (ShouldCreateDefaultRunLoop()) + Environment::InstantiateDefaultRunLoop(); + + MOJO_CHECK(g_application_request.is_pending()); + MOJO_CHECK(g_shell); + + // New applications are constructed for each test to avoid persisting state. + application_impl_ = new ApplicationImpl(GetApplicationDelegate(), + g_application_request.Pass()); + + // Fake application initialization with the given command line arguments. + application_impl_->Initialize(g_shell.Pass(), g_args.Clone(), g_url); +} + +void ApplicationTestBase::TearDown() { + MOJO_CHECK(!g_application_request.is_pending()); + MOJO_CHECK(!g_shell); + + application_impl_->UnbindConnections(&g_application_request, &g_shell); + delete application_impl_; + if (ShouldCreateDefaultRunLoop()) + Environment::DestroyDefaultRunLoop(); +} + +bool ApplicationTestBase::ShouldCreateDefaultRunLoop() { + return true; +} + +} // namespace test +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/application_test_main.cc b/mojo/application/public/cpp/lib/application_test_main.cc new file mode 100644 index 0000000..2df150a --- /dev/null +++ b/mojo/application/public/cpp/lib/application_test_main.cc @@ -0,0 +1,14 @@ +// 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/public/cpp/application_test_base.h" +#include "mojo/public/c/system/main.h" +#include "mojo/public/cpp/environment/environment.h" + +MojoResult MojoMain(MojoHandle handle) { + // An Environment instance is needed to construct run loops. + mojo::Environment environment; + + return mojo::test::RunAllTests(handle); +} diff --git a/mojo/application/public/cpp/lib/interface_factory_connector.h b/mojo/application/public/cpp/lib/interface_factory_connector.h new file mode 100644 index 0000000..8d13bc2 --- /dev/null +++ b/mojo/application/public/cpp/lib/interface_factory_connector.h @@ -0,0 +1,37 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_ + +#include "mojo/application/public/cpp/interface_factory.h" +#include "mojo/application/public/cpp/service_connector.h" +#include "mojo/public/cpp/bindings/interface_request.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfaceFactoryConnector : public ServiceConnector { + public: + explicit InterfaceFactoryConnector(InterfaceFactory<Interface>* factory) + : factory_(factory) {} + ~InterfaceFactoryConnector() override {} + + void ConnectToService(ApplicationConnection* application_connection, + const std::string& interface_name, + ScopedMessagePipeHandle client_handle) override { + factory_->Create(application_connection, + MakeRequest<Interface>(client_handle.Pass())); + } + + private: + InterfaceFactory<Interface>* factory_; + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceFactoryConnector); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_LIB_INTERFACE_FACTORY_CONNECTOR_H_ diff --git a/mojo/application/public/cpp/lib/service_connector_registry.cc b/mojo/application/public/cpp/lib/service_connector_registry.cc new file mode 100644 index 0000000..97c4316 --- /dev/null +++ b/mojo/application/public/cpp/lib/service_connector_registry.cc @@ -0,0 +1,59 @@ +// Copyright 2015 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/public/cpp/lib/service_connector_registry.h" + +#include "mojo/application/public/cpp/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceConnectorRegistry::ServiceConnectorRegistry() + : service_connector_(nullptr) { +} + +ServiceConnectorRegistry::~ServiceConnectorRegistry() { + for (NameToServiceConnectorMap::iterator i = + name_to_service_connector_.begin(); + i != name_to_service_connector_.end(); ++i) { + delete i->second; + } + name_to_service_connector_.clear(); +} + +void ServiceConnectorRegistry::SetServiceConnectorForName( + ServiceConnector* service_connector, + const std::string& interface_name) { + RemoveServiceConnectorForName(interface_name); + name_to_service_connector_[interface_name] = service_connector; +} + +void ServiceConnectorRegistry::RemoveServiceConnectorForName( + const std::string& interface_name) { + NameToServiceConnectorMap::iterator it = + name_to_service_connector_.find(interface_name); + if (it == name_to_service_connector_.end()) + return; + delete it->second; + name_to_service_connector_.erase(it); +} + +void ServiceConnectorRegistry::ConnectToService( + ApplicationConnection* application_connection, + const std::string& interface_name, + ScopedMessagePipeHandle client_handle) { + auto iter = name_to_service_connector_.find(interface_name); + if (iter != name_to_service_connector_.end()) { + iter->second->ConnectToService(application_connection, interface_name, + client_handle.Pass()); + return; + } + if (service_connector_) { + service_connector_->ConnectToService(application_connection, interface_name, + client_handle.Pass()); + } +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/service_connector_registry.h b/mojo/application/public/cpp/lib/service_connector_registry.h new file mode 100644 index 0000000..b196353 --- /dev/null +++ b/mojo/application/public/cpp/lib/service_connector_registry.h @@ -0,0 +1,62 @@ +// Copyright 2015 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_APPLICATION_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_ + +#include <map> +#include <string> + +#include "mojo/public/cpp/system/message_pipe.h" + +namespace mojo { + +class ApplicationConnection; +class ServiceConnector; + +namespace internal { + +// ServiceConnectorRegistry maintains a default ServiceConnector as well as at +// most one ServiceConnector per interface name. When ConnectToService() is +// invoked the ServiceConnector registered by name is given the request. If +// a ServiceConnector has not been registered by name than the default +// ServiceConnector is given the request. +class ServiceConnectorRegistry { + public: + ServiceConnectorRegistry(); + ~ServiceConnectorRegistry(); + + // Sets the default ServiceConnector. ServiceConnectorRegistry does *not* + // take ownership of |service_connector|. + void set_service_connector(ServiceConnector* service_connector) { + service_connector_ = service_connector; + } + + // Returns true if non ServiceConnectors have been registered by name. + bool empty() const { return name_to_service_connector_.empty(); } + + // Sets a ServiceConnector by name. This deletes the existing ServiceConnector + // and takes ownership of |service_connector|. + void SetServiceConnectorForName(ServiceConnector* service_connector, + const std::string& interface_name); + void RemoveServiceConnectorForName(const std::string& interface_name); + + void ConnectToService(ApplicationConnection* application_connection, + const std::string& interface_name, + ScopedMessagePipeHandle client_handle); + + private: + using NameToServiceConnectorMap = std::map<std::string, ServiceConnector*>; + + ServiceConnector* service_connector_; + + NameToServiceConnectorMap name_to_service_connector_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceConnectorRegistry); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_LIB_SERVICE_CONNECTOR_REGISTRY_H_ diff --git a/mojo/application/public/cpp/lib/service_provider_impl.cc b/mojo/application/public/cpp/lib/service_provider_impl.cc new file mode 100644 index 0000000..3d6ee6e --- /dev/null +++ b/mojo/application/public/cpp/lib/service_provider_impl.cc @@ -0,0 +1,48 @@ +// 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/public/cpp/service_provider_impl.h" + +#include "mojo/application/public/cpp/service_connector.h" +#include "mojo/public/cpp/environment/logging.h" + +namespace mojo { + +ServiceProviderImpl::ServiceProviderImpl() : binding_(this) { +} + +ServiceProviderImpl::ServiceProviderImpl( + InterfaceRequest<ServiceProvider> request) + : binding_(this, request.Pass()) { +} + +ServiceProviderImpl::~ServiceProviderImpl() { +} + +void ServiceProviderImpl::Bind(InterfaceRequest<ServiceProvider> request) { + binding_.Bind(request.Pass()); +} + +void ServiceProviderImpl::Close() { + if (binding_.is_bound()) + binding_.Close(); +} + +void ServiceProviderImpl::ConnectToService( + const String& service_name, + ScopedMessagePipeHandle client_handle) { + // TODO(beng): perhaps take app connection thru ctor so that we can pass + // ApplicationConnection through? + service_connector_registry_.ConnectToService(nullptr, service_name, + client_handle.Pass()); +} + +void ServiceProviderImpl::SetServiceConnectorForName( + ServiceConnector* service_connector, + const std::string& interface_name) { + service_connector_registry_.SetServiceConnectorForName(service_connector, + interface_name); +} + +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/service_registry.cc b/mojo/application/public/cpp/lib/service_registry.cc new file mode 100644 index 0000000..844ec3a --- /dev/null +++ b/mojo/application/public/cpp/lib/service_registry.cc @@ -0,0 +1,73 @@ +// 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/public/cpp/lib/service_registry.h" + +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/application_impl.h" +#include "mojo/application/public/cpp/service_connector.h" + +namespace mojo { +namespace internal { + +ServiceRegistry::ServiceRegistry( + ApplicationImpl* application_impl, + const std::string& connection_url, + const std::string& remote_url, + ServiceProviderPtr remote_services, + InterfaceRequest<ServiceProvider> local_services) + : application_impl_(application_impl), + connection_url_(connection_url), + remote_url_(remote_url), + local_binding_(this), + remote_service_provider_(remote_services.Pass()) { + if (local_services.is_pending()) + local_binding_.Bind(local_services.Pass()); +} + +ServiceRegistry::ServiceRegistry() + : application_impl_(nullptr), local_binding_(this) { +} + +ServiceRegistry::~ServiceRegistry() { +} + +void ServiceRegistry::SetServiceConnector(ServiceConnector* connector) { + service_connector_registry_.set_service_connector(connector); +} + +void ServiceRegistry::SetServiceConnectorForName( + ServiceConnector* service_connector, + const std::string& interface_name) { + service_connector_registry_.SetServiceConnectorForName(service_connector, + interface_name); +} + +void ServiceRegistry::RemoveServiceConnectorForName( + const std::string& interface_name) { + service_connector_registry_.RemoveServiceConnectorForName(interface_name); + if (service_connector_registry_.empty()) + remote_service_provider_.reset(); +} + +const std::string& ServiceRegistry::GetConnectionURL() { + return connection_url_; +} + +const std::string& ServiceRegistry::GetRemoteApplicationURL() { + return remote_url_; +} + +ServiceProvider* ServiceRegistry::GetServiceProvider() { + return remote_service_provider_.get(); +} + +void ServiceRegistry::ConnectToService(const mojo::String& service_name, + ScopedMessagePipeHandle client_handle) { + service_connector_registry_.ConnectToService(this, service_name, + client_handle.Pass()); +} + +} // namespace internal +} // namespace mojo diff --git a/mojo/application/public/cpp/lib/service_registry.h b/mojo/application/public/cpp/lib/service_registry.h new file mode 100644 index 0000000..9eee695 --- /dev/null +++ b/mojo/application/public/cpp/lib/service_registry.h @@ -0,0 +1,67 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_ + +#include <string> + +#include "mojo/application/public/cpp/application_connection.h" +#include "mojo/application/public/cpp/lib/service_connector_registry.h" +#include "mojo/application/public/interfaces/service_provider.mojom.h" + +namespace mojo { + +class Application; +class ApplicationImpl; + +namespace internal { + +// A ServiceRegistry represents each half of a connection between two +// applications, allowing customization of which services are published to the +// other. +class ServiceRegistry : public ServiceProvider, public ApplicationConnection { + public: + ServiceRegistry(); + ServiceRegistry(ApplicationImpl* application_impl, + const std::string& connection_url, + const std::string& remote_url, + ServiceProviderPtr remote_services, + InterfaceRequest<ServiceProvider> local_services); + ~ServiceRegistry() override; + + // ApplicationConnection overrides. + void SetServiceConnector(ServiceConnector* service_connector) override; + void SetServiceConnectorForName(ServiceConnector* service_connector, + const std::string& interface_name) override; + const std::string& GetConnectionURL() override; + const std::string& GetRemoteApplicationURL() override; + ServiceProvider* GetServiceProvider() override; + + void RemoveServiceConnectorForName(const std::string& interface_name); + + private: + // ServiceProvider method. + void ConnectToService(const mojo::String& service_name, + ScopedMessagePipeHandle client_handle) override; + + ApplicationImpl* application_impl_; + const std::string connection_url_; + const std::string remote_url_; + + private: + void RemoveServiceConnectorForNameInternal(const std::string& interface_name); + + Application* application_; + Binding<ServiceProvider> local_binding_; + ServiceProviderPtr remote_service_provider_; + ServiceConnectorRegistry service_connector_registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceRegistry); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_LIB_SERVICE_REGISTRY_H_ diff --git a/mojo/application/public/cpp/service_connector.h b/mojo/application/public/cpp/service_connector.h new file mode 100644 index 0000000..3a7d656 --- /dev/null +++ b/mojo/application/public/cpp/service_connector.h @@ -0,0 +1,30 @@ +// Copyright 2015 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_APPLICATION_PUBLIC_CPP_SERVICE_CONNECTOR_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_SERVICE_CONNECTOR_H_ + +#include <string> + +#include "mojo/public/cpp/system/message_pipe.h" + +namespace mojo { + +class ApplicationConnection; + +class ServiceConnector { + public: + virtual ~ServiceConnector() {} + + // Asks the ServiceConnector to connect to the specified service. If the + // ServiceConnector connects to the service it should take ownership of + // the handle in |handle|. + virtual void ConnectToService(ApplicationConnection* application_connection, + const std::string& interface_name, + ScopedMessagePipeHandle handle) = 0; +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_SERVICE_CONNECTOR_H_ diff --git a/mojo/application/public/cpp/service_provider_impl.h b/mojo/application/public/cpp/service_provider_impl.h new file mode 100644 index 0000000..033bdac --- /dev/null +++ b/mojo/application/public/cpp/service_provider_impl.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef MOJO_APPLICATION_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_ +#define MOJO_APPLICATION_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_ + +#include <string> + +#include "mojo/application/public/cpp/lib/interface_factory_connector.h" +#include "mojo/application/public/cpp/lib/service_connector_registry.h" +#include "mojo/application/public/interfaces/service_provider.mojom.h" +#include "mojo/public/cpp/bindings/binding.h" + +namespace mojo { + +// Implements a registry that can be used to expose services to another app. +class ServiceProviderImpl : public ServiceProvider { + public: + ServiceProviderImpl(); + explicit ServiceProviderImpl(InterfaceRequest<ServiceProvider> request); + ~ServiceProviderImpl() override; + + void Bind(InterfaceRequest<ServiceProvider> request); + // Disconnect this service provider and put it in a state where it can be + // rebound to a new request. + void Close(); + + template <typename Interface> + void AddService(InterfaceFactory<Interface>* factory) { + SetServiceConnectorForName( + new internal::InterfaceFactoryConnector<Interface>(factory), + Interface::Name_); + } + + private: + // Overridden from ServiceProvider: + void ConnectToService(const String& service_name, + ScopedMessagePipeHandle client_handle) override; + + void SetServiceConnectorForName(ServiceConnector* service_connector, + const std::string& interface_name); + + Binding<ServiceProvider> binding_; + + internal::ServiceConnectorRegistry service_connector_registry_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(ServiceProviderImpl); +}; + +} // namespace mojo + +#endif // MOJO_APPLICATION_PUBLIC_CPP_SERVICE_PROVIDER_IMPL_H_ diff --git a/mojo/application/public/cpp/tests/BUILD.gn b/mojo/application/public/cpp/tests/BUILD.gn new file mode 100644 index 0000000..88690d0 --- /dev/null +++ b/mojo/application/public/cpp/tests/BUILD.gn @@ -0,0 +1,19 @@ +# 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. + +import("//testing/test.gni") + +test("mojo_public_application_unittests") { + sources = [ + "service_registry_unittest.cc", + ] + + deps = [ + "//mojo/application/public/cpp:standalone", + "//testing/gtest", + "//third_party/mojo/src/mojo/edk/test:run_all_unittests", + "//third_party/mojo/src/mojo/public/cpp/environment:standalone", + "//third_party/mojo/src/mojo/public/cpp/utility", + ] +} diff --git a/mojo/application/public/cpp/tests/service_registry_unittest.cc b/mojo/application/public/cpp/tests/service_registry_unittest.cc new file mode 100644 index 0000000..a746026 --- /dev/null +++ b/mojo/application/public/cpp/tests/service_registry_unittest.cc @@ -0,0 +1,70 @@ +// 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/public/cpp/lib/service_registry.h" + +#include "mojo/application/public/cpp/service_connector.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace mojo { +namespace internal { +namespace { + +class TestConnector : public ServiceConnector { + public: + explicit TestConnector(int* delete_count) : delete_count_(delete_count) {} + ~TestConnector() override { (*delete_count_)++; } + void ConnectToService(ApplicationConnection* application_connection, + const std::string& interface_name, + ScopedMessagePipeHandle client_handle) override {} + + private: + int* delete_count_; +}; + +TEST(ServiceRegistryTest, Ownership) { + int delete_count = 0; + + // Destruction. + { + ServiceRegistry registry; + registry.SetServiceConnectorForName(new TestConnector(&delete_count), + "TC1"); + } + EXPECT_EQ(1, delete_count); + + // Removal. + { + ServiceRegistry registry; + ServiceConnector* c = new TestConnector(&delete_count); + registry.SetServiceConnectorForName(c, "TC1"); + registry.RemoveServiceConnectorForName("TC1"); + EXPECT_EQ(2, delete_count); + } + + // Multiple. + { + ServiceRegistry registry; + registry.SetServiceConnectorForName(new TestConnector(&delete_count), + "TC1"); + registry.SetServiceConnectorForName(new TestConnector(&delete_count), + "TC2"); + } + EXPECT_EQ(4, delete_count); + + // Re-addition. + { + ServiceRegistry registry; + registry.SetServiceConnectorForName(new TestConnector(&delete_count), + "TC1"); + registry.SetServiceConnectorForName(new TestConnector(&delete_count), + "TC1"); + EXPECT_EQ(5, delete_count); + } + EXPECT_EQ(6, delete_count); +} + +} // namespace +} // namespace internal +} // namespace mojo diff --git a/mojo/application/public/interfaces/BUILD.gn b/mojo/application/public/interfaces/BUILD.gn new file mode 100644 index 0000000..37d91b0 --- /dev/null +++ b/mojo/application/public/interfaces/BUILD.gn @@ -0,0 +1,14 @@ +# 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. + +import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") + +# GYP version: mojo/mojo_base.gyp:mojo_application_bindings +mojom("interfaces") { + sources = [ + "application.mojom", + "service_provider.mojom", + "shell.mojom", + ] +} diff --git a/mojo/application/public/interfaces/application.mojom b/mojo/application/public/interfaces/application.mojom new file mode 100644 index 0000000..dc9f2f63 --- /dev/null +++ b/mojo/application/public/interfaces/application.mojom @@ -0,0 +1,59 @@ +// 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. + +module mojo; + +import "mojo/application/public/interfaces/service_provider.mojom"; +import "mojo/application/public/interfaces/shell.mojom"; + +// This is the primary interface implemented by every Mojo application. It +// allows the application to receive its startup arguments from the shell, and +// to be notified of events that occur during its execution. +// +// TODO(aa): It would be good to reorder the parameters once we have interface +// versioning. +interface Application { + // Initializes the application with the specified arguments. This method is + // guaranteed to be called before any other method is called, and will only be + // called once. + // + // The |url| parameter is the identity of the application as far as the shell + // is concerned. This will be the URL the application was found at, after all + // mappings, resolution, and redirects. And it will not include the + // querystring, since the querystring is not part of an application's + // identity. + Initialize(Shell shell, array<string>? args, string url); + + // Called when another application (identified by |requestor_url|) attempts to + // open a connection to this application. + // + // If the other application wants to request services from this application, + // it will have passed a valid interface request through the |services| + // parameter (i.e. one containing a valid message pipe endpoint). This + // application may then bind an implementation of |ServiceProvider| to that + // request in order to make services available to the other application. + // + // If the other application wants to offer services to this application, it + // will have passed a bound interface through the |exposed_services| + // parameter. This application may then request services through that + // interface. + // + // It is possible that both parameters will be valid/bound if the other + // application wants to both request services from and offer services to this + // application. + // + // This application is free to ignore the |services| or |exposed_services| + // parameters if it does not wish to offer or request services. + // + // resolved_url is the URL that was requested to create this connection, after + // all mappings, resolutions, and redirects. This will include any querystring + // that was part of the request. + AcceptConnection(string requestor_url, + ServiceProvider&? services, + ServiceProvider? exposed_services, + string resolved_url); + + // Called to request the application shut itself down gracefully. + RequestQuit(); +}; diff --git a/mojo/application/public/interfaces/service_provider.mojom b/mojo/application/public/interfaces/service_provider.mojom new file mode 100644 index 0000000..8c81879 --- /dev/null +++ b/mojo/application/public/interfaces/service_provider.mojom @@ -0,0 +1,17 @@ +// 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. + +module mojo; + +// An interface through which a client may request services from a host. +// Instances of this interface are created within the context of an +// already-identified client and host pair, so there is no need to explicitly +// identify the client or host in the methods below. +interface ServiceProvider { + // Asks the host to provide the service identified by |interface_name| through + // the message |pipe| endpoint supplied by the caller. If the host is not + // willing or able to provide the requested service, it should close the + // |pipe|. + ConnectToService(string interface_name, handle<message_pipe> pipe); +}; diff --git a/mojo/application/public/interfaces/shell.mojom b/mojo/application/public/interfaces/shell.mojom new file mode 100644 index 0000000..b6b1319 --- /dev/null +++ b/mojo/application/public/interfaces/shell.mojom @@ -0,0 +1,38 @@ +// 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. + +module mojo; + +import "mojo/application/public/interfaces/service_provider.mojom"; + +// An interface through which a Mojo application may communicate with the Mojo +// system and request connections to other applications. +interface Shell { + // Establishes a connection with another application (located at + // |application_url|) through which the calling application and the other + // application may request services from one another. + // + // If the calling application would like to request services from the other + // application, it should pass a valid interface request in the |services| + // parameter (i.e. one containing a valid message pipe endpoint). If the other + // application does not wish to offer services, it may either not bind an + // implementation to the interface request, or else bind an implementation + // that will reject some or all service requests. + // + // If the calling application would like to offer services to the other + // application, it should pass a bound interface through the + // |exposed_services| parameter. The other application may then request + // services through that interface. + // + // At least one of |services| or |exposed_services| should be valid/bound in + // the call. + // + // If the |application_url| does not contain a domain, but is of the form + // "mojo:{service}", it is up to the Mojo shell to select an appropriate + // application for the service. Currently, the shell does this based on the + // value of its --origin flag. + ConnectToApplication(string application_url, + ServiceProvider&? services, + ServiceProvider? exposed_services); +}; |