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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/addon-sdk/source/lib/sdk/core/disposable.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,132 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +"use strict";
     1.9 +
    1.10 +module.metadata = {
    1.11 +  "stability": "experimental"
    1.12 +};
    1.13 +
    1.14 +
    1.15 +const { Class } = require("./heritage");
    1.16 +const { Observer, subscribe, unsubscribe, observe } = require("./observer");
    1.17 +const { isWeak, WeakReference } = require("./reference");
    1.18 +const method = require("../../method/core");
    1.19 +
    1.20 +const unloadSubject = require('@loader/unload');
    1.21 +const addonUnloadTopic = "sdk:loader:destroy";
    1.22 +
    1.23 +
    1.24 +
    1.25 +const uninstall = method("disposable/uninstall");
    1.26 +exports.uninstall = uninstall;
    1.27 +
    1.28 +
    1.29 +const shutdown = method("disposable/shutdown");
    1.30 +exports.shutdown = shutdown;
    1.31 +
    1.32 +const disable = method("disposable/disable");
    1.33 +exports.disable = disable;
    1.34 +
    1.35 +const upgrade = method("disposable/upgrade");
    1.36 +exports.upgrade = upgrade;
    1.37 +
    1.38 +const downgrade = method("disposable/downgrade");
    1.39 +exports.downgrade = downgrade;
    1.40 +
    1.41 +const unload = method("disposable/unload");
    1.42 +exports.unload = unload;
    1.43 +
    1.44 +const dispose = method("disposable/dispose");
    1.45 +exports.dispose = dispose;
    1.46 +dispose.define(Object, object => object.dispose());
    1.47 +
    1.48 +
    1.49 +const setup = method("disposable/setup");
    1.50 +exports.setup = setup;
    1.51 +setup.define(Object, (object, ...args) => object.setup(...args));
    1.52 +
    1.53 +
    1.54 +// Set's up disposable instance.
    1.55 +const setupDisposable = disposable => {
    1.56 +  subscribe(disposable, addonUnloadTopic, isWeak(disposable));
    1.57 +};
    1.58 +
    1.59 +// Tears down disposable instance.
    1.60 +const disposeDisposable = disposable => {
    1.61 +  unsubscribe(disposable, addonUnloadTopic);
    1.62 +};
    1.63 +
    1.64 +// Base type that takes care of disposing it's instances on add-on unload.
    1.65 +// Also makes sure to remove unload listener if it's already being disposed.
    1.66 +const Disposable = Class({
    1.67 +  implements: [Observer],
    1.68 +  initialize: function(...args) {
    1.69 +    // First setup instance before initializing it's disposal. If instance
    1.70 +    // fails to initialize then there is no instance to be disposed at the
    1.71 +    // unload.
    1.72 +    setup(this, ...args);
    1.73 +    setupDisposable(this);
    1.74 +  },
    1.75 +  destroy: function(reason) {
    1.76 +    // Destroying disposable removes unload handler so that attempt to dispose
    1.77 +    // won't be made at unload & delegates to dispose.
    1.78 +    disposeDisposable(this);
    1.79 +    unload(this, reason);
    1.80 +  },
    1.81 +  setup: function() {
    1.82 +    // Implement your initialize logic here.
    1.83 +  },
    1.84 +  dispose: function() {
    1.85 +    // Implement your cleanup logic here.
    1.86 +  }
    1.87 +});
    1.88 +exports.Disposable = Disposable;
    1.89 +
    1.90 +// Disposable instances observe add-on unload notifications in
    1.91 +// order to trigger `unload` on them.
    1.92 +observe.define(Disposable, (disposable, subject, topic, data) => {
    1.93 +  const isUnloadTopic = topic === addonUnloadTopic;
    1.94 +  const isUnloadSubject = subject.wrappedJSObject === unloadSubject;
    1.95 +  if (isUnloadTopic && isUnloadSubject) {
    1.96 +    unsubscribe(disposable, topic);
    1.97 +    unload(disposable);
    1.98 +  }
    1.99 +});
   1.100 +
   1.101 +const unloaders = {
   1.102 +  destroy: dispose,
   1.103 +  uninstall: uninstall,
   1.104 +  shutdown: shutdown,
   1.105 +  disable: disable,
   1.106 +  upgrade: upgrade,
   1.107 +  downgrade: downgrade
   1.108 +}
   1.109 +const unloaded = new WeakMap();
   1.110 +unload.define(Disposable, (disposable, reason) => {
   1.111 +  if (!unloaded.get(disposable)) {
   1.112 +    unloaded.set(disposable, true);
   1.113 +    // Pick an unload handler associated with an unload
   1.114 +    // reason (falling back to destroy if not found) and
   1.115 +    // delegate unloading to it.
   1.116 +    const unload = unloaders[reason] || unloaders.destroy;
   1.117 +    unload(disposable);
   1.118 +  }
   1.119 +});
   1.120 +
   1.121 +
   1.122 +// If add-on is disabled munally, it's being upgraded, downgraded
   1.123 +// or uniststalled `dispose` is invoked to undo any changes that
   1.124 +// has being done by it in this session.
   1.125 +disable.define(Disposable, dispose);
   1.126 +downgrade.define(Disposable, dispose);
   1.127 +upgrade.define(Disposable, dispose);
   1.128 +uninstall.define(Disposable, dispose);
   1.129 +
   1.130 +// If application is shut down no dispose is invoked as undo-ing
   1.131 +// changes made by instance is likely to just waste of resources &
   1.132 +// increase shutdown time. Although specefic components may choose
   1.133 +// to implement shutdown handler that does something better.
   1.134 +shutdown.define(Disposable, disposable => {});
   1.135 +

mercurial