michael@0: /* -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: /** michael@0: * Methods shared between RootActor and BrowserTabActor. michael@0: */ michael@0: michael@0: /** michael@0: * Populate |this._extraActors| as specified by |aFactories|, reusing whatever michael@0: * actors are already there. Add all actors in the final extra actors table to michael@0: * |aPool|. michael@0: * michael@0: * The root actor and the tab actor use this to instantiate actors that other michael@0: * parts of the browser have specified with DebuggerServer.addTabActor antd michael@0: * DebuggerServer.addGlobalActor. michael@0: * michael@0: * @param aFactories michael@0: * An object whose own property names are the names of properties to add to michael@0: * some reply packet (say, a tab actor grip or the "listTabs" response michael@0: * form), and whose own property values are actor constructor functions, as michael@0: * documented for addTabActor and addGlobalActor. michael@0: * michael@0: * @param this michael@0: * The BrowserRootActor or BrowserTabActor with which the new actors will michael@0: * be associated. It should support whatever API the |aFactories| michael@0: * constructor functions might be interested in, as it is passed to them. michael@0: * For the sake of CommonCreateExtraActors itself, it should have at least michael@0: * the following properties: michael@0: * michael@0: * - _extraActors michael@0: * An object whose own property names are factory table (and packet) michael@0: * property names, and whose values are no-argument actor constructors, michael@0: * of the sort that one can add to an ActorPool. michael@0: * michael@0: * - conn michael@0: * The DebuggerServerConnection in which the new actors will participate. michael@0: * michael@0: * - actorID michael@0: * The actor's name, for use as the new actors' parentID. michael@0: */ michael@0: exports.createExtraActors = function createExtraActors(aFactories, aPool) { michael@0: // Walk over global actors added by extensions. michael@0: for (let name in aFactories) { michael@0: let actor = this._extraActors[name]; michael@0: if (!actor) { michael@0: actor = aFactories[name].bind(null, this.conn, this); michael@0: actor.prototype = aFactories[name].prototype; michael@0: actor.parentID = this.actorID; michael@0: this._extraActors[name] = actor; michael@0: } michael@0: aPool.addActor(actor); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Append the extra actors in |this._extraActors|, constructed by a prior call michael@0: * to CommonCreateExtraActors, to |aObject|. michael@0: * michael@0: * @param aObject michael@0: * The object to which the extra actors should be added, under the michael@0: * property names given in the |aFactories| table passed to michael@0: * CommonCreateExtraActors. michael@0: * michael@0: * @param this michael@0: * The BrowserRootActor or BrowserTabActor whose |_extraActors| table we michael@0: * should use; see above. michael@0: */ michael@0: exports.appendExtraActors = function appendExtraActors(aObject) { michael@0: for (let name in this._extraActors) { michael@0: let actor = this._extraActors[name]; michael@0: aObject[name] = actor.actorID; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Construct an ActorPool. michael@0: * michael@0: * ActorPools are actorID -> actor mapping and storage. These are michael@0: * used to accumulate and quickly dispose of groups of actors that michael@0: * share a lifetime. michael@0: */ michael@0: function ActorPool(aConnection) michael@0: { michael@0: this.conn = aConnection; michael@0: this._cleanups = {}; michael@0: this._actors = {}; michael@0: } michael@0: michael@0: ActorPool.prototype = { michael@0: /** michael@0: * Add an actor to the actor pool. If the actor doesn't have an ID, michael@0: * allocate one from the connection. michael@0: * michael@0: * @param aActor object michael@0: * The actor implementation. If the object has a michael@0: * 'disconnect' property, it will be called when the actor michael@0: * pool is cleaned up. michael@0: */ michael@0: addActor: function AP_addActor(aActor) { michael@0: aActor.conn = this.conn; michael@0: if (!aActor.actorID) { michael@0: let prefix = aActor.actorPrefix; michael@0: if (typeof aActor == "function") { michael@0: // typeName is a convention used with protocol.js-based actors michael@0: prefix = aActor.prototype.actorPrefix || aActor.prototype.typeName; michael@0: } michael@0: aActor.actorID = this.conn.allocID(prefix || undefined); michael@0: } michael@0: michael@0: if (aActor.registeredPool) { michael@0: aActor.registeredPool.removeActor(aActor); michael@0: } michael@0: aActor.registeredPool = this; michael@0: michael@0: this._actors[aActor.actorID] = aActor; michael@0: if (aActor.disconnect) { michael@0: this._cleanups[aActor.actorID] = aActor; michael@0: } michael@0: }, michael@0: michael@0: get: function AP_get(aActorID) { michael@0: return this._actors[aActorID]; michael@0: }, michael@0: michael@0: has: function AP_has(aActorID) { michael@0: return aActorID in this._actors; michael@0: }, michael@0: michael@0: /** michael@0: * Returns true if the pool is empty. michael@0: */ michael@0: isEmpty: function AP_isEmpty() { michael@0: return Object.keys(this._actors).length == 0; michael@0: }, michael@0: michael@0: /** michael@0: * Remove an actor from the actor pool. michael@0: */ michael@0: removeActor: function AP_remove(aActor) { michael@0: delete this._actors[aActor.actorID]; michael@0: delete this._cleanups[aActor.actorID]; michael@0: }, michael@0: michael@0: /** michael@0: * Match the api expected by the protocol library. michael@0: */ michael@0: unmanage: function(aActor) { michael@0: return this.removeActor(aActor); michael@0: }, michael@0: michael@0: /** michael@0: * Run all actor cleanups. michael@0: */ michael@0: cleanup: function AP_cleanup() { michael@0: for each (let actor in this._cleanups) { michael@0: actor.disconnect(); michael@0: } michael@0: this._cleanups = {}; michael@0: } michael@0: } michael@0: michael@0: exports.ActorPool = ActorPool; michael@0: