OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 define("mojo/services/public/js/service_provider", [ | 5 define("mojo/services/public/js/service_provider", [ |
6 "mojo/public/interfaces/application/service_provider.mojom", | 6 "mojo/public/interfaces/application/service_provider.mojom", |
7 "mojo/public/js/connection", | 7 "mojo/public/js/connection", |
8 "mojo/public/js/core", | 8 ], function(serviceProviderMojom, connection) { |
9 ], function(spInterfaceModule, connectionModule, coreModule) { | |
10 | 9 |
11 // Implementation of the Mojo ServiceProvider interface. | 10 const ServiceProviderInterface = serviceProviderMojom.ServiceProvider; |
12 function connectToServiceImpl(serviceName, serviceHandle) { | |
13 var provider = this.providers_.get(serviceName); | |
14 if (!provider) { | |
15 this.pendingRequests_.set(serviceName, serviceHandle); | |
16 return; | |
17 } | |
18 | |
19 var serviceConnection = new connectionModule.Connection( | |
20 serviceHandle, | |
21 provider.service.stubClass, | |
22 provider.service.client && provider.service.client.proxyClass); | |
23 | |
24 serviceConnection.local.delegate$ = | |
25 new provider.factory(serviceConnection.remote); | |
26 | |
27 provider.connections.push(serviceConnection); | |
28 } | |
29 | 11 |
30 function checkServiceProvider(sp) { | 12 function checkServiceProvider(sp) { |
31 if (!sp.connections_) | 13 if (!sp.providers_) |
32 throw new Error("Service was closed"); | 14 throw new Error("Service was closed"); |
33 } | 15 } |
34 | 16 |
35 class ServiceProvider { | 17 class ServiceProvider { |
36 constructor(service) { | 18 constructor(service) { |
37 if (!(service instanceof spInterfaceModule.ServiceProvider.proxyClass)) | 19 if (!(service instanceof ServiceProviderInterface.proxyClass)) |
38 throw new Error("service must be a ServiceProvider proxy"); | 20 throw new Error("service must be a ServiceProvider proxy"); |
| 21 service.local$ = this; // Implicitly sets this.remote$ to service. |
| 22 this.providers_ = new Map(); // serviceName => see provideService() below |
| 23 this.pendingRequests_ = new Map(); // serviceName => serviceHandle |
| 24 } |
39 | 25 |
40 service.client$ = { | 26 // Incoming requests |
41 connectToService: connectToServiceImpl.bind(this) | 27 connectToService(serviceName, serviceHandle) { |
42 }; | 28 if (!this.providers_) // We're closed. |
| 29 return; |
43 | 30 |
44 this.connections_ = new Map(); | 31 var provider = this.providers_.get(serviceName); |
45 this.providers_ = new Map(); | 32 if (!provider) { |
46 this.pendingRequests_ = new Map(); | 33 this.pendingRequests_.set(serviceName, serviceHandle); |
47 this.connection_ = null; | 34 return; |
48 this.connection_ = service.getConnection$(); | 35 } |
| 36 var proxy = connection.bindProxyHandle( |
| 37 serviceHandle, provider.service, provider.service.client); |
| 38 proxy.local$ = new provider.factory(proxy); |
| 39 provider.connections.push(proxy.connection$); |
49 } | 40 } |
50 | 41 |
51 provideService(service, factory) { | 42 provideService(service, factory) { |
52 // TODO(hansmuller): if !factory, remove provider and close its | |
53 // connections. | |
54 checkServiceProvider(this); | 43 checkServiceProvider(this); |
55 | 44 |
56 var provider = { | 45 var provider = { |
57 service: service, // A JS bindings interface object. | 46 service: service, // A JS bindings interface object. |
58 factory: factory, // factory(clientProxy) => interface implemntation. | 47 factory: factory, // factory(clientProxy) => interface implemntation |
59 connections: [], | 48 connections: [], |
60 }; | 49 }; |
61 this.providers_.set(service.name, provider); | 50 this.providers_.set(service.name, provider); |
62 | 51 |
63 if (this.pendingRequests_.has(service.name)) { | 52 if (this.pendingRequests_.has(service.name)) { |
64 connectToServiceImpl(service.name, pendingRequests_.get(service.name)); | 53 this.connectToService(service.name, pendingRequests_.get(service.name)); |
65 pendingRequests_.delete(service.name); | 54 pendingRequests_.delete(service.name); |
66 } | 55 } |
67 | |
68 return this; | 56 return this; |
69 } | 57 } |
70 | 58 |
71 connectToService(service, client) { | 59 // Outgoing requests |
| 60 requestService(interfaceObject, clientImpl) { |
72 checkServiceProvider(this); | 61 checkServiceProvider(this); |
73 if (!service.name) | 62 if (!interfaceObject.name) |
74 throw new Error("Invalid service parameter"); | 63 throw new Error("Invalid service parameter"); |
| 64 if (!clientImpl && interfaceObject.client) |
| 65 throw new Error("Client implementation must be provided"); |
75 | 66 |
76 var serviceConnection = this.connections_.get(service.name); | 67 if (!clientImpl) |
77 if (serviceConnection) | 68 clientImpl = {}; |
78 return serviceConnection.remote; | 69 var messagePipeHandle = connection.bindProxyClient( |
79 | 70 clientImpl, interfaceObject.client, interfaceObject); |
80 var pipe = coreModule.createMessagePipe(); | 71 this.remote$.connectToService(interfaceObject.name, messagePipeHandle); |
81 this.connection_.remote.connectToService(service.name, pipe.handle1); | 72 return clientImpl.remote$; |
82 var clientClass = client && service.client.stubClass; | |
83 var serviceConnection = new connectionModule.Connection( | |
84 pipe.handle0, clientClass, service.proxyClass); | |
85 if (serviceConnection.local) | |
86 serviceConnection.local.delegate$ = client; | |
87 | |
88 this.connections_.set(service.name, serviceConnection); | |
89 return serviceConnection.remote; | |
90 }; | 73 }; |
91 | 74 |
92 close() { | 75 close() { |
93 if (!this.connection_) | 76 this.providers_ = null; |
94 return; | 77 this.pendingRequests_ = null; |
95 | |
96 try { | |
97 // Outgoing connections | |
98 this.connections_.forEach(function(connection, serviceName) { | |
99 connection.close(); | |
100 }); | |
101 // Incoming connections | |
102 this.providers_.forEach(function(provider, serviceName) { | |
103 provider.connections.forEach(function(connection) { | |
104 connection.close(); | |
105 }); | |
106 }); | |
107 this.connection_.close(); | |
108 } finally { | |
109 this.connections_ = null; | |
110 this.providers_ = null; | |
111 this.pendingRequests_ = null; | |
112 this.connection_ = null; | |
113 this.handle_ = null; | |
114 } | |
115 } | 78 } |
116 } | 79 } |
117 | 80 |
118 var exports = {}; | 81 var exports = {}; |
119 exports.ServiceProvider = ServiceProvider; | 82 exports.ServiceProvider = ServiceProvider; |
120 return exports; | 83 return exports; |
121 }); | 84 }); |
OLD | NEW |