blob: 97021883f88a62dc6c4e30838158b92b54d48b25 [file] [log] [blame]
// 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.
define("mojo/apps/js/mojo", [
"mojo/public/interfaces/application/service_provider.mojom",
"mojo/public/js/bindings/connection",
"mojo/public/js/bindings/core",
"mojo/apps/js/bridge",
], function(service, connection, core, bridge) {
function Shell() {
this.applications_ = new Map();
}
Shell.prototype.connectToApplication = function(url) {
var application = this.applications_.get(url);
if (application)
return application;
application = new ServiceProvider(bridge.connectToApplication(url));
this.applications_.set(url, application);
return application;
};
Shell.prototype.connectToService = function (url, service, client) {
return this.connectToApplication(url).connectToService(service, client);
};
Shell.prototype.close = function() {
shell().applications_.forEach(function(application, url) {
application.close();
});
shell().applications_.clear();
};
var shellValue = null;
function shell() {
if (!shellValue)
shellValue = new Shell();
return shellValue;
}
var requestorValue = null;
function requestor() {
if (!requestorValue) {
var handle = bridge.requestorMessagePipeHandle();
requestorValue = handle && new ServiceProvider(handle);
}
return requestorValue;
}
function connectToServiceImpl(serviceName, serviceHandle) {
var provider = this.providers_.get(serviceName);
if (!provider) {
this.pendingRequests_.set(serviceName, serviceHandle);
return;
}
var serviceConnection = new connection.Connection(
serviceHandle,
provider.service.delegatingStubClass,
provider.service.client && provider.service.client.proxyClass);
serviceConnection.local.connection$ = serviceConnection;
serviceConnection.local.delegate$ =
new provider.factory(serviceConnection.remote);
provider.connections.push(serviceConnection);
}
function ServiceProvider(messagePipeHandle) {
// TODO(hansmuller): if messagePipeHandle is null, throw an exception.
this.connections_ = new Map();
this.providers_ = new Map();
this.pendingRequests_ = new Map();
this.connection_ = null;
this.handle_ = messagePipeHandle;
this.connection_ = new connection.Connection(
this.handle_,
service.ServiceProvider.client.delegatingStubClass,
service.ServiceProvider.proxyClass);
this.connection_.local.delegate$ = {
connectToService: connectToServiceImpl.bind(this)
};
}
ServiceProvider.prototype.provideService = function(service, factory) {
// TODO(hansmuller): if !factory, remove provider and close its connections.
// TODO(hansmuller): if this.connection_ is null, throw an error.
var provider = {
service: service,
factory: factory,
connections: [],
};
this.providers_.set(service.name, provider);
if (this.pendingRequests_.has(service.name)) {
connectToServiceImpl(service.name, pendingRequests_.get(service.name));
pendingRequests_.delete(service.name);
}
return this;
};
ServiceProvider.prototype.connectToService = function(service, client) {
// TODO(hansmuler): if service.name isn't defined, throw an error.
// TODO(hansmuller): if this.connection_ is null, throw an error.
var serviceConnection = this.connections_.get(service.name);
if (serviceConnection)
return serviceConnection.remote;
var pipe = core.createMessagePipe();
this.connection_.remote.connectToService(service.name, pipe.handle1);
var clientClass = client && service.client.delegatingStubClass;
var serviceConnection =
new connection.Connection(pipe.handle0, clientClass, service.proxyClass);
if (serviceConnection.local)
serviceConnection.local.delegate$ = client;
this.connections_.set(service.name, serviceConnection);
return serviceConnection.remote;
};
ServiceProvider.prototype.close = function() {
if (!this.connection_)
return;
try {
// Outgoing connections
this.connections_.forEach(function(connection, serviceName) {
connection.close();
});
// Incoming connections
this.providers_.forEach(function(provider, serviceName) {
provider.connections.forEach(function(connection) {
connection.close();
});
});
this.connection_.close();
} finally {
this.connections_ = null;
this.providers_ = null;
this.pendingRequests_ = null;
this.connection_ = null;
this.handle_ = null;
shell().applications_.forEach(function(application, url) {
if (application === this)
shell().applications_.delete(url);
}, this);
}
};
function quit() {
if (requestorValue)
requestor().close();
if (shellValue)
shell().close();
bridge.quit();
}
var exports = {};
exports.requestor = requestor;
exports.shell = shell;
exports.quit = quit;
return exports;
});