home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 December / PCWorld_2007-12_cd.bin / audio-video / songbird / Songbird_0.3_windows-i686.exe / components / XPCOMUtils.jsm < prev   
Text File  |  2007-10-27  |  8KB  |  233 lines

  1. /*
  2.  * NOTE: This was snagged from https://bugzilla.mozilla.org/show_bug.cgi?id=381651
  3.  * This will go away when this lands
  4.  */
  5.  
  6. /*
  7.  * ***** BEGIN LICENSE BLOCK *****
  8.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License Version
  11.  * 1.1 (the "License"); you may not use this file except in compliance with
  12.  * the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS" basis,
  16.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  17.  * for the specific language governing rights and limitations under the
  18.  * License.
  19.  *
  20.  * The Original Code is Mozilla code.
  21.  *
  22.  * The Initial Developer of the Original Code is
  23.  * Netscape Communications Corporation.
  24.  * Portions created by the Initial Developer are Copyright (C) 2004
  25.  * the Initial Developer. All Rights Reserved.
  26.  *
  27.  * Contributor(s):
  28.  *    Alex Fritze <alex@croczilla.com> (original author)
  29.  *    Nickolay Ponomarev <asqueella@gmail.com>
  30.  *
  31.  * Alternatively, the contents of this file may be used under the terms of
  32.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  33.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  34.  * in which case the provisions of the GPL or the LGPL are applicable instead
  35.  * of those above. If you wish to allow use of your version of this file only
  36.  * under the terms of either the GPL or the LGPL, and not to allow others to
  37.  * use your version of this file under the terms of the MPL, indicate your
  38.  * decision by deleting the provisions above and replace them with the notice
  39.  * and other provisions required by the GPL or the LGPL. If you do not delete
  40.  * the provisions above, a recipient may use your version of this file under
  41.  * the terms of any one of the MPL, the GPL or the LGPL.
  42.  *
  43.  * ***** END LICENSE BLOCK ***** */
  44.  
  45. /**
  46.  * Utilities for JavaScript components loaded by the JS component
  47.  * loader.
  48.  *
  49.  * Import into a JS component using
  50.  * 'Components.utils.import("rel:XPCOMUtils.jsm");'
  51.  *
  52.  * Exposing a JS 'class' as a component using these utility methods consists
  53.  * of several steps:
  54.  * 0. Import XPCOMUtils, as described above.
  55.  * 1. Declare the 'class' (or multiple classes) implementing the component(s):
  56.  *  function MyComponent() {
  57.  *    // constructor
  58.  *  }
  59.  *  MyComponent.prototype = {
  60.  *    // properties required for XPCOM registration:
  61.  *    classDescription: "unique text description",
  62.  *    classID:          Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
  63.  *    contractID:       "@example.com/xxx;1",
  64.  *
  65.  *    // [optional] custom factory (an object implementing nsIFactory). If not
  66.  *    // provided, the default factory is used, which returns
  67.  *    // |(new MyComponent()).QueryInterface(iid)| in its createInterface().
  68.  *    _xpcom_factory: { ... }
  69.  *
  70.  *    // QueryInterface implementation, e.g. using the generateQI helper
  71.  *    QueryInterface: XPCOMUtils.generateQI(
  72.  *      [Components.interfaces.nsIObserver,
  73.  *       Components.interfaces.nsIMyInterface]),
  74.  *
  75.  *    // ...component implementation...
  76.  *  };
  77.  *
  78.  * 2. Create an array of component constructors (like the one
  79.  * created in step 1):
  80.  *  var components = [MyComponent];
  81.  *
  82.  * 3. Define the NSGetModule entry point:
  83.  *  function NSGetModule(compMgr, fileSpec) {
  84.  *    // components is the array created in step 2.
  85.  *    return XPCOMUtils.generateModule(components);
  86.  *  }
  87.  */
  88.  
  89.  
  90. EXPORTED_SYMBOLS = [ "XPCOMUtils" ];
  91.  
  92. debug("*** loading XPCOMUtils\n");
  93.  
  94. const Ci = Components.interfaces;
  95.  
  96. var XPCOMUtils = {
  97.   /**
  98.    * Generate a QueryInterface implementation. The returned function must be
  99.    * assigned to the 'QueryInterface' property of a JS object. When invoked on
  100.    * that object, it checks if the given iid is listed in the |interfaces|
  101.    * param, and if it is, returns |this| (the object it was called on).
  102.    */
  103.   generateQI: function(interfaces) {
  104.     return makeQI([i.name for each(i in interfaces)]);
  105.   },
  106.  
  107.   /**
  108.    * Generate the NSGetModule function (along with the module definition).
  109.    * See the parameters to generateModule.
  110.    */
  111.   generateNSGetModule: function(componentsArray, postRegister, preUnregister) {
  112.     return function NSGetModule(compMgr, fileSpec) {
  113.       return XPCOMUtils.generateModule(componentsArray,
  114.                                        postRegister,
  115.                                        preUnregister);
  116.     }
  117.   },
  118.  
  119.   /**
  120.    * Generate a module implementation.
  121.    *
  122.    * @param componentsArray  Array of component constructors. See the comment
  123.    *                         at the top of this file for details.
  124.    * @param postRegister  optional post-registration function with
  125.    *                      signature 'postRegister(nsIComponentManager,
  126.    *                                              nsIFile, componentsArray)'
  127.    * @param preUnregister optional pre-unregistration function with
  128.    *                      signature 'preUnregister(nsIComponentManager,
  129.    *                                               nsIFile, componentsArray)'
  130.    */
  131.   generateModule: function(componentsArray, postRegister, preUnregister) {
  132.     let classes = [];
  133.     for each (let component in componentsArray) {
  134.       classes.push({
  135.         cid:          component.prototype.classID,
  136.         className:    component.prototype.classDescription,
  137.         contractID:   component.prototype.contractID,
  138.         factory:      this._getFactory(component),
  139.       });
  140.     }
  141.  
  142.     return { // nsIModule impl.
  143.       getClassObject: function(compMgr, cid, iid) {
  144.         if (!iid.equals(Ci.nsIFactory))
  145.           throw Components.results.NS_ERROR_NO_INTERFACE;
  146.  
  147.         for each (let classDesc in classes) {
  148.           if (classDesc.cid.equals(cid))
  149.             return classDesc.factory;
  150.         }
  151.  
  152.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  153.       },
  154.  
  155.       registerSelf: function(compMgr, fileSpec, location, type) {
  156.         debug("*** registering " + fileSpec.leafName + ": [ ");
  157.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  158.         for each (let classDesc in classes) {
  159.           debug(classDesc.cid + " ");
  160.           compMgr.registerFactoryLocation(classDesc.cid,
  161.                                           classDesc.className,
  162.                                           classDesc.contractID,
  163.                                           fileSpec,
  164.                                           location,
  165.                                           type);
  166.         }
  167.  
  168.         if (postRegister)
  169.           postRegister(compMgr, fileSpec, componentsArray);
  170.         debug("]\n");
  171.       },
  172.  
  173.       unregisterSelf: function(compMgr, fileSpec, location) {
  174.         debug("*** unregistering " + fileSpec.leafName + ": [ ");
  175.         compMgr.QueryInterface(Ci.nsIComponentRegistrar);
  176.         if (preUnregister)
  177.           preUnregister(compMgr, fileSpec, componentsArray);
  178.  
  179.         for each (let classDesc in classes) {
  180.           debug(classDesc.className + " ");
  181.           compMgr.unregisterFactoryLocation(classDesc.cid, fileSpec);
  182.         }
  183.         debug("]\n");
  184.       },
  185.  
  186.       canUnload: function(compMgr) {
  187.         return true;
  188.       }
  189.     };
  190.   },
  191.  
  192.   /**
  193.    * Convenience access to category manager
  194.    */
  195.   get categoryManager() {
  196.     return Components.classes["@mozilla.org/categorymanager;1"]
  197.            .getService(Ci.nsICategoryManager);
  198.   },
  199.  
  200.   /**
  201.    * Returns an nsIFactory for |component|.
  202.    */
  203.   _getFactory: function(component) {
  204.     var factory = component.prototype._xpcom_factory;
  205.     if (!factory) {
  206.       factory = {
  207.         createInstance: function(outer, iid) {
  208.           if(outer)
  209.             throw CR.NS_ERROR_NO_AGGREGATION;
  210.           return (new component()).QueryInterface(iid);
  211.         }
  212.       }
  213.     }
  214.     return factory;
  215.   }
  216. };
  217.  
  218. /**
  219.  * Helper for XPCOMUtils.generateQI to avoid leaks - see bug 381651#c1
  220.  */
  221. function makeQI(interfaceNames) {
  222.   return function XPCOMUtils_QueryInterface(iid) {
  223.     if (iid.equals(Ci.nsISupports))
  224.       return this;
  225.     for each(let interfaceName in interfaceNames) {
  226.       if (Ci[interfaceName].equals(iid))
  227.         return this;
  228.     }
  229.  
  230.     throw Components.results.NS_ERROR_NO_INTERFACE;
  231.   };
  232. }
  233.