Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / mojo / service_manager / service_manager.cc
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/public/cpp/bindings/allocation_scope.h"
14 #include "mojo/service_manager/service_loader.h"
15
16 namespace mojo {
17
18 namespace {
19 // Used by TestAPI.
20 bool has_created_instance = false;
21 }
22
23 class ServiceManager::ServiceFactory : public InterfaceImpl<Shell> {
24  public:
25   ServiceFactory(ServiceManager* manager, const GURL& url)
26       : manager_(manager),
27         url_(url),
28         client_(NULL) {
29   }
30
31   virtual ~ServiceFactory() {
32   }
33
34   void ConnectToClient(ScopedMessagePipeHandle handle) {
35     if (!handle.is_valid()) {
36       assert(false);
37       return;
38     }
39     AllocationScope scope;
40     client_->AcceptConnection(url_.spec(), handle.Pass());
41   }
42
43   // Shell implementation:
44   virtual void SetClient(ShellClient* client) OVERRIDE {
45     client_ = client;
46   }
47   virtual void Connect(const String& url,
48                        ScopedMessagePipeHandle client_pipe) OVERRIDE {
49     manager_->Connect(GURL(url.To<std::string>()), client_pipe.Pass());
50   }
51
52   const GURL& url() const { return url_; }
53
54  private:
55   virtual void OnConnectionError() OVERRIDE {
56     manager_->OnServiceFactoryError(this);
57   }
58
59   ServiceManager* const manager_;
60   const GURL url_;
61   ShellClient* client_;
62
63   DISALLOW_COPY_AND_ASSIGN(ServiceFactory);
64 };
65
66 class ServiceManager::TestAPI::TestShellConnection
67     : public InterfaceImpl<Shell> {
68  public:
69   explicit TestShellConnection(ServiceManager* manager)
70       : manager_(manager),
71         client_(NULL) {
72   }
73   virtual ~TestShellConnection() {}
74
75   virtual void OnConnectionError() OVERRIDE {
76     // TODO(darin): How should we handle this error?
77   }
78
79   // Shell:
80   virtual void SetClient(ShellClient* client) OVERRIDE {
81     client_ = client;
82   }
83   virtual void Connect(const String& url,
84                        ScopedMessagePipeHandle client_pipe) OVERRIDE {
85     manager_->Connect(GURL(url.To<std::string>()), client_pipe.Pass());
86   }
87
88  private:
89   ServiceManager* manager_;
90   ShellClient* client_;
91
92   DISALLOW_COPY_AND_ASSIGN(TestShellConnection);
93 };
94
95 // static
96 ServiceManager::TestAPI::TestAPI(ServiceManager* manager) : manager_(manager) {
97 }
98
99 ServiceManager::TestAPI::~TestAPI() {
100 }
101
102 bool ServiceManager::TestAPI::HasCreatedInstance() {
103   return has_created_instance;
104 }
105
106 ScopedMessagePipeHandle ServiceManager::TestAPI::GetShellHandle() {
107   MessagePipe pipe;
108   shell_.reset(
109       BindToPipe(new TestShellConnection(manager_), pipe.handle0.Pass()));
110   return pipe.handle1.Pass();
111 }
112
113 bool ServiceManager::TestAPI::HasFactoryForURL(const GURL& url) const {
114   return manager_->url_to_service_factory_.find(url) !=
115          manager_->url_to_service_factory_.end();
116 }
117
118 ServiceManager::ServiceManager()
119     : interceptor_(NULL) {
120 }
121
122 ServiceManager::~ServiceManager() {
123   STLDeleteValues(&url_to_service_factory_);
124   STLDeleteValues(&url_to_loader_);
125   STLDeleteValues(&scheme_to_loader_);
126 }
127
128 // static
129 ServiceManager* ServiceManager::GetInstance() {
130   static base::LazyInstance<ServiceManager> instance =
131       LAZY_INSTANCE_INITIALIZER;
132   has_created_instance = true;
133   return &instance.Get();
134 }
135
136 void ServiceManager::Connect(const GURL& url,
137                              ScopedMessagePipeHandle client_handle) {
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         interceptor_->OnConnectToClient(url, client_handle.Pass()));
155   } else {
156     service_factory->ConnectToClient(client_handle.Pass());
157   }
158 }
159
160 void ServiceManager::SetLoaderForURL(scoped_ptr<ServiceLoader> loader,
161                                      const GURL& url) {
162   URLToLoaderMap::iterator it = url_to_loader_.find(url);
163   if (it != url_to_loader_.end())
164     delete it->second;
165   url_to_loader_[url] = loader.release();
166 }
167
168 void ServiceManager::SetLoaderForScheme(scoped_ptr<ServiceLoader> loader,
169                                         const std::string& scheme) {
170   SchemeToLoaderMap::iterator it = scheme_to_loader_.find(scheme);
171   if (it != scheme_to_loader_.end())
172     delete it->second;
173   scheme_to_loader_[scheme] = loader.release();
174 }
175
176 void ServiceManager::SetInterceptor(Interceptor* interceptor) {
177   interceptor_ = interceptor;
178 }
179
180 ServiceLoader* ServiceManager::GetLoaderForURL(const GURL& url) {
181   URLToLoaderMap::const_iterator url_it = url_to_loader_.find(url);
182   if (url_it != url_to_loader_.end())
183     return url_it->second;
184   SchemeToLoaderMap::const_iterator scheme_it =
185       scheme_to_loader_.find(url.scheme());
186   if (scheme_it != scheme_to_loader_.end())
187     return scheme_it->second;
188   DCHECK(default_loader_);
189   return default_loader_.get();
190 }
191
192 void ServiceManager::OnServiceFactoryError(ServiceFactory* service_factory) {
193   // Called from ~ServiceFactory, so we do not need to call Destroy here.
194   const GURL url = service_factory->url();
195   URLToServiceFactoryMap::iterator it = url_to_service_factory_.find(url);
196   DCHECK(it != url_to_service_factory_.end());
197   delete it->second;
198   url_to_service_factory_.erase(it);
199   GetLoaderForURL(url)->OnServiceError(this, url);
200 }
201
202 }  // namespace mojo