1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <stdio.h> 6 7 #include "mojo/service_manager/service_manager.h" 8 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/macros.h" 12 #include "base/stl_util.h" 13 #include "mojo/service_manager/service_loader.h" 14 15 namespace mojo { 16 17 namespace { 18 // Used by TestAPI. 19 bool has_created_instance = false; 20 } 21 22 class ServiceManager::ServiceFactory : public InterfaceImpl<ServiceProvider> { 23 public: 24 ServiceFactory(ServiceManager* manager, const GURL& url) 25 : manager_(manager), 26 url_(url) { 27 } 28 29 virtual ~ServiceFactory() { 30 } 31 32 void ConnectToClient(const std::string& service_name, 33 ScopedMessagePipeHandle handle, 34 const GURL& requestor_url) { 35 if (handle.is_valid()) { 36 client()->ConnectToService( 37 url_.spec(), service_name, handle.Pass(), requestor_url.spec()); 38 } 39 } 40 41 // ServiceProvider implementation: 42 virtual void ConnectToService(const String& service_url, 43 const String& service_name, 44 ScopedMessagePipeHandle client_pipe, 45 const String& requestor_url) OVERRIDE { 46 // Ignore provided requestor_url and use url from connection. 47 manager_->ConnectToService( 48 GURL(service_url), service_name, client_pipe.Pass(), url_); 49 } 50 51 const GURL& url() const { return url_; } 52 53 private: 54 virtual void OnConnectionError() OVERRIDE { 55 manager_->OnServiceFactoryError(this); 56 } 57 58 ServiceManager* const manager_; 59 const GURL url_; 60 61 DISALLOW_COPY_AND_ASSIGN(ServiceFactory); 62 }; 63 64 class ServiceManager::TestAPI::TestServiceProviderConnection 65 : public InterfaceImpl<ServiceProvider> { 66 public: 67 explicit TestServiceProviderConnection(ServiceManager* manager) 68 : manager_(manager) {} 69 virtual ~TestServiceProviderConnection() {} 70 71 virtual void OnConnectionError() OVERRIDE { 72 // TODO(darin): How should we handle this error? 73 } 74 75 // ServiceProvider: 76 virtual void ConnectToService(const String& service_url, 77 const String& service_name, 78 ScopedMessagePipeHandle client_pipe, 79 const String& requestor_url) OVERRIDE { 80 manager_->ConnectToService(GURL(service_url), 81 service_name, 82 client_pipe.Pass(), 83 GURL(requestor_url)); 84 } 85 86 private: 87 ServiceManager* manager_; 88 89 DISALLOW_COPY_AND_ASSIGN(TestServiceProviderConnection); 90 }; 91 92 // static 93 ServiceManager::TestAPI::TestAPI(ServiceManager* manager) : manager_(manager) { 94 } 95 96 ServiceManager::TestAPI::~TestAPI() { 97 } 98 99 bool ServiceManager::TestAPI::HasCreatedInstance() { 100 return has_created_instance; 101 } 102 103 ScopedMessagePipeHandle ServiceManager::TestAPI::GetServiceProviderHandle() { 104 MessagePipe pipe; 105 service_provider_.reset( 106 BindToPipe(new TestServiceProviderConnection(manager_), 107 pipe.handle0.Pass())); 108 return pipe.handle1.Pass(); 109 } 110 111 bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const { 112 return manager_->url_to_service_factory_.find(url) != 113 manager_->url_to_service_factory_.end(); 114 } 115 116 ServiceManager::ServiceManager() 117 : interceptor_(NULL) { 118 } 119 120 ServiceManager::~ServiceManager() { 121 STLDeleteValues(&url_to_service_factory_); 122 STLDeleteValues(&url_to_loader_); 123 STLDeleteValues(&scheme_to_loader_); 124 } 125 126 // static 127 ServiceManager* ServiceManager::GetInstance() { 128 static base::LazyInstance<ServiceManager> instance = 129 LAZY_INSTANCE_INITIALIZER; 130 has_created_instance = true; 131 return &instance.Get(); 132 } 133 134 void ServiceManager::ConnectToService(const GURL& url, 135 const std::string& name, 136 ScopedMessagePipeHandle client_handle, 137 const GURL& requestor_url) { 138 URLToServiceFactoryMap::const_iterator service_it = 139 url_to_service_factory_.find(url); 140 ServiceFactory* service_factory; 141 if (service_it != url_to_service_factory_.end()) { 142 service_factory = service_it->second; 143 } else { 144 MessagePipe pipe; 145 GetLoaderForURL(url)->LoadService(this, url, pipe.handle0.Pass()); 146 147 service_factory = 148 BindToPipe(new ServiceFactory(this, url), pipe.handle1.Pass()); 149 150 url_to_service_factory_[url] = service_factory; 151 } 152 if (interceptor_) { 153 service_factory->ConnectToClient( 154 name, 155 interceptor_->OnConnectToClient(url, client_handle.Pass()), 156 requestor_url); 157 } else { 158 service_factory->ConnectToClient(name, client_handle.Pass(), requestor_url); 159 } 160 } 161 162 void ServiceManager::SetLoaderForURL(scoped_ptr<ServiceLoader> loader, 163 const GURL& url) { 164 URLToLoaderMap::iterator it = url_to_loader_.find(url); 165 if (it != url_to_loader_.end()) 166 delete it->second; 167 url_to_loader_[url] = loader.release(); 168 } 169 170 void ServiceManager::SetLoaderForScheme(scoped_ptr<ServiceLoader> loader, 171 const std::string& scheme) { 172 SchemeToLoaderMap::iterator it = scheme_to_loader_.find(scheme); 173 if (it != scheme_to_loader_.end()) 174 delete it->second; 175 scheme_to_loader_[scheme] = loader.release(); 176 } 177 178 void ServiceManager::SetInterceptor(Interceptor* interceptor) { 179 interceptor_ = interceptor; 180 } 181 182 ServiceLoader* ServiceManager::GetLoaderForURL(const GURL& url) { 183 URLToLoaderMap::const_iterator url_it = url_to_loader_.find(url); 184 if (url_it != url_to_loader_.end()) 185 return url_it->second; 186 SchemeToLoaderMap::const_iterator scheme_it = 187 scheme_to_loader_.find(url.scheme()); 188 if (scheme_it != scheme_to_loader_.end()) 189 return scheme_it->second; 190 DCHECK(default_loader_); 191 return default_loader_.get(); 192 } 193 194 void ServiceManager::OnServiceFactoryError(ServiceFactory* service_factory) { 195 // Called from ~ServiceFactory, so we do not need to call Destroy here. 196 const GURL url = service_factory->url(); 197 URLToServiceFactoryMap::iterator it = url_to_service_factory_.find(url); 198 DCHECK(it != url_to_service_factory_.end()); 199 delete it->second; 200 url_to_service_factory_.erase(it); 201 ServiceLoader* loader = GetLoaderForURL(url); 202 if (loader) 203 loader->OnServiceError(this, url); 204 } 205 206 } // namespace mojo 207