addon-sdk/source/lib/sdk/core/disposable.js

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:5dd5e2164568
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 "use strict";
6
7 module.metadata = {
8 "stability": "experimental"
9 };
10
11
12 const { Class } = require("./heritage");
13 const { Observer, subscribe, unsubscribe, observe } = require("./observer");
14 const { isWeak, WeakReference } = require("./reference");
15 const method = require("../../method/core");
16
17 const unloadSubject = require('@loader/unload');
18 const addonUnloadTopic = "sdk:loader:destroy";
19
20
21
22 const uninstall = method("disposable/uninstall");
23 exports.uninstall = uninstall;
24
25
26 const shutdown = method("disposable/shutdown");
27 exports.shutdown = shutdown;
28
29 const disable = method("disposable/disable");
30 exports.disable = disable;
31
32 const upgrade = method("disposable/upgrade");
33 exports.upgrade = upgrade;
34
35 const downgrade = method("disposable/downgrade");
36 exports.downgrade = downgrade;
37
38 const unload = method("disposable/unload");
39 exports.unload = unload;
40
41 const dispose = method("disposable/dispose");
42 exports.dispose = dispose;
43 dispose.define(Object, object => object.dispose());
44
45
46 const setup = method("disposable/setup");
47 exports.setup = setup;
48 setup.define(Object, (object, ...args) => object.setup(...args));
49
50
51 // Set's up disposable instance.
52 const setupDisposable = disposable => {
53 subscribe(disposable, addonUnloadTopic, isWeak(disposable));
54 };
55
56 // Tears down disposable instance.
57 const disposeDisposable = disposable => {
58 unsubscribe(disposable, addonUnloadTopic);
59 };
60
61 // Base type that takes care of disposing it's instances on add-on unload.
62 // Also makes sure to remove unload listener if it's already being disposed.
63 const Disposable = Class({
64 implements: [Observer],
65 initialize: function(...args) {
66 // First setup instance before initializing it's disposal. If instance
67 // fails to initialize then there is no instance to be disposed at the
68 // unload.
69 setup(this, ...args);
70 setupDisposable(this);
71 },
72 destroy: function(reason) {
73 // Destroying disposable removes unload handler so that attempt to dispose
74 // won't be made at unload & delegates to dispose.
75 disposeDisposable(this);
76 unload(this, reason);
77 },
78 setup: function() {
79 // Implement your initialize logic here.
80 },
81 dispose: function() {
82 // Implement your cleanup logic here.
83 }
84 });
85 exports.Disposable = Disposable;
86
87 // Disposable instances observe add-on unload notifications in
88 // order to trigger `unload` on them.
89 observe.define(Disposable, (disposable, subject, topic, data) => {
90 const isUnloadTopic = topic === addonUnloadTopic;
91 const isUnloadSubject = subject.wrappedJSObject === unloadSubject;
92 if (isUnloadTopic && isUnloadSubject) {
93 unsubscribe(disposable, topic);
94 unload(disposable);
95 }
96 });
97
98 const unloaders = {
99 destroy: dispose,
100 uninstall: uninstall,
101 shutdown: shutdown,
102 disable: disable,
103 upgrade: upgrade,
104 downgrade: downgrade
105 }
106 const unloaded = new WeakMap();
107 unload.define(Disposable, (disposable, reason) => {
108 if (!unloaded.get(disposable)) {
109 unloaded.set(disposable, true);
110 // Pick an unload handler associated with an unload
111 // reason (falling back to destroy if not found) and
112 // delegate unloading to it.
113 const unload = unloaders[reason] || unloaders.destroy;
114 unload(disposable);
115 }
116 });
117
118
119 // If add-on is disabled munally, it's being upgraded, downgraded
120 // or uniststalled `dispose` is invoked to undo any changes that
121 // has being done by it in this session.
122 disable.define(Disposable, dispose);
123 downgrade.define(Disposable, dispose);
124 upgrade.define(Disposable, dispose);
125 uninstall.define(Disposable, dispose);
126
127 // If application is shut down no dispose is invoked as undo-ing
128 // changes made by instance is likely to just waste of resources &
129 // increase shutdown time. Although specefic components may choose
130 // to implement shutdown handler that does something better.
131 shutdown.define(Disposable, disposable => {});
132

mercurial