Implementing XPCOM components in JavaScript: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
 
(10 intermediate revisions by 6 users not shown)
Line 4: Line 4:
'''Welcome to Implementing XPCOM components in JavaScript.'''
'''Welcome to Implementing XPCOM components in JavaScript.'''


This article provides information about creating a Javascript XPCOM class.  The hope is to help explain how to create a class, and what processes are used to register and iinstanciate it.  It does not describe how to create interfaces for your class.  [http://developer.mozilla.org/en/docs/How_to_Build_an_XPCOM_Component_in_Javascript How to Build an XPCOM Component in Javascript] at developer.mozilla.org has example of doing this if you need more help in that area.  There are also a couple of forum discussion with some explanations, example code, and troubleshooting tips:   
This article provides information about creating a Javascript XPCOM class.  The hope is to help explain how to create a class, and what processes are used to register and instanciate it.  It does not describe how to create interfaces for your class.  [http://developer.mozilla.org/en/docs/How_to_Build_an_XPCOM_Component_in_Javascript How to Build an XPCOM Component in Javascript] at developer.mozilla.org has example of doing this if you need more help in that area.  There are also a couple of forum discussion with some explanations, example code, and troubleshooting tips:   
* http://forums.mozillazine.org/viewtopic.php?t=308369
* http://forums.mozillazine.org/viewtopic.php?t=308369
* http://forums.mozillazine.org/viewtopic.php?t=367298
* http://forums.mozillazine.org/viewtopic.php?t=367298
Line 10: Line 10:


==About XPCOM==
==About XPCOM==
Mozilla applications are built from a collection of XPCOM (Cross-platform Component Object Model) classes.  They are used to perform certain tasks or to get specific functionality.  For example, there is a directory service class that can be used to access files on your file system.  Classes can be constructed using several programming languages, including: javascript, c++, and python.  Mozilla then uses "interfaces" to describe what a class can do.  The most basic interface [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] is used to retrieve the different interfaces that a class implements.
Mozilla applications are built from a collection of XPCOM (Cross-platform Component Object Model) components.  They are used to perform certain tasks or to get specific functionality.  For example, there is a directory service component that can be used to access files on your file system.  Classes can be constructed using several programming languages, including: JavaScript, C++, and Python (See [http://developer.mozilla.org/en/docs/PyXPCOM PyXPCOM]).  Mozilla then uses "interfaces" to describe what a component can do.  The most basic interface [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] is used to retrieve the different interfaces that a component implements.


=== Benefits of XPCOM ===
=== Benefits of XPCOM ===
*  XPCOM classes can be used by any programming language mozilla supports.
*  XPCOM components can be used by any programming language mozilla supports.
*  Objects implemented as XPCOM are global to an application, and are not dependent on the scope of any one window.
*  Objects implemented as XPCOM can be global to an application, and are not dependent on the scope of any one window. You can use an XPCOM service to [http://developer.mozilla.org/en/docs/Working_with_windows_in_chrome_code#Using_an_XPCOM_singleton_component share data between windows], for example.
Programming logic can be encapsulated within a class.
XPCOM encourages modular programming - programming logic can be encapsulated within a component.


=== XPCOM Drawbacks ===
=== XPCOM Drawbacks ===
*  Objects must be accessed from their defined interfaces.  Javascript shortcuts such as the global window object cannot be accessed.
*  Objects must be accessed from their defined interfaces.  Javascript shortcuts such as the global window object cannot be accessed.
** The only exception to this rules, is if you set a magical property [http://www.mozilla.org/scriptable/js-components-status.html wrappedJSObject] equal to your class, then the underlining javascript object can be accessed.  
** The only exception to this rule, is if you set a magical property [http://www.mozilla.org/scriptable/js-components-status.html wrappedJSObject] on your component implemented in JavaScript, the object this property refers to will be accessible from the calling side. You can set <code>this.wrappedJSObject = this</code> in your component's constructor and avoid writing any interfaces altogether.
* It is easier to have memory leaks. [http://www.mozilla.org/scriptable/avoiding-leaks.html This article] on the Mozilla.org website provides an explanation of how and why this can occur, and tips on avoiding leakage in Javascript.
* It is easier to have memory leaks. [http://www.mozilla.org/scriptable/avoiding-leaks.html This article] on the Mozilla.org website provides an explanation of how and why this can occur, and tips on avoiding leakage in Javascript.


== XPCOM Concepts ==
== XPCOM Concepts ==
There are basically 4 concepts you need to understand when developing XPCOM objects.  They are classes, interfaces, modules, and factories.  I will give a brief summary of each, then go into more details later.
There are basically 4 concepts you need to understand when developing XPCOM objects.  They are components, interfaces, modules, and factories.  I will give a brief summary of each, then go into more details later.


=== Classes ===
=== Components ===
A class is simply an XPCOM object that implements interfaces, and is registered with the component manager.  In our case we are going to implement a Javascript object which will be our class.
A component is simply an object that implements interfaces, and is registered with the component manager.  In our case the implementation will be a Javascript object.


=== Interfaces ===
=== Interfaces ===
Interfaces are used to define what functions and attributes an xpcom class provides.  [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] is an interface that all classes must implement.  It provides a function to request the interfaces on a class.
Interfaces are used to define what functions and attributes an XPCOM component provides.  [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] is an interface that all classes must implement.  It provides a function to request the interfaces on a class.


=== Factories ===
=== Factories ===
Factories are objects used to instantiate classesit implements the [http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIFactory.idl nsIFactory] interface.
Factories are objects used to instantiate componentsEach factory object implements the [http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIFactory.idl nsIFactory] interface.


=== Modules ===
=== Modules ===
Multiple classes can be defined in a file.  A module is an object that is used to register, unregister and provide factories for classes.  It implement the [http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIModule.idl nsIModule] interface.
Multiple classes can be defined in a file.  A module is an object that is used to register, unregister and provide factories for classes.  It implements the [http://lxr.mozilla.org/mozilla/source/xpcom/components/nsIModule.idl nsIModule] interface.


== Getting Started ==
== Example Code ==
For our example, we are going to create a file that contains one class, one module, and one factory. The class will implement the required [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] interface, and the [http://lxr.mozilla.org/mozilla/source/xpcom/threads/nsISupportsPriority.idl nsISupportsPriority] interface. A simple example of an actual Mozilla component is the [http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsDictionary.js#103 nsDictionary] class. A complex example that implements multiple classes is the [http://lxr.mozilla.org/mozilla/source/toolkit/mozapps/update/src/nsUpdateService.js.in#2625 nsUpdateService].
For our example, we are going to create a file that contains one component, one module, and one factory. The component will implement the required [http://lxr.mozilla.org/mozilla/source/xpcom/base/nsISupports.idl nsISupports] interface, and the [http://lxr.mozilla.org/mozilla/source/xpcom/threads/nsISupportsPriority.idl nsISupportsPriority] interface. A simple example of an actual Mozilla component is [http://lxr.mozilla.org/mozilla/source/extensions/xml-rpc/src/nsDictionary.js#103 nsDictionary]. A complex example that implements multiple interfaces is [http://lxr.mozilla.org/mozilla/source/toolkit/mozapps/update/src/nsUpdateService.js.in#2625 nsUpdateService].


Note: This example implements pre-existing interfaces, and therefore does not address the creation or compilation of interface descriptions (IDL) for our component. A more comprehensive tutorial that covers creating an XPCOM in Javascript from scratch can be found [http://www.builderau.com.au/program/print.htm?TYPE=story&AT=39206503-39024614t-20000000c here].
Note: This example implements pre-existing interfaces, and therefore does not address the creation or compilation of interface descriptions (IDL) for our component. A more comprehensive tutorial that covers creating an XPCOM in Javascript from scratch can be found [http://www.builderau.com.au/program/soa/Creating_XPCOM_components_with_JavaScript/0,339024614,339206503,00.htm here].


== How it Works ==
=== Constants ===
First lets add some constants to our file that will be used later.
 
<pre>
//interfaces we support
const nsISupportsPriority = Components.interfaces.nsISupportsPriority;
const nsISupports = Components.interfaces.nsISupports;
 
//class constants
const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}");
const CLASS_NAME = "My Supports Priority Component";
const CONTRACT_ID = "@mozillazine.org/example/priority;1";
</pre>
 
=== Class Construction ===
Next we will add a JavaScript function which will be used for our class construction.
 
<pre>
//class constructor
function MyPriority() {
  this._priority = nsISupportsPriority.PRIORITY_LOWEST;
};
</pre>
 
=== Class Definition ===
Now we will use JavaScript prototyping to define our class.  The class will expose the methods and properties from our selected interfaces.
 
<pre>
//class definition
MyPriority.prototype = {
  _priority: null,
 
  //property of nsISupportsPriority interface
  get priority() { return this._priority; },
  set priority(aValue) { this._priority = aValue; },
 
  //method of nsISupportsPriority interface
  adjustPriority: function(aDelta) {
    this._priority += aDelta;
  },
 
  //method of nsISupports interface
  QueryInterface: function(aIID)
  {
    if (!aIID.equals(nsISupportsPriority) &&   
        !aIID.equals(nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  }
};
</pre>


=== Startup and Registration ===
=== Factory Object ===
During the startup process if the file compreg.dat is missing or the file .autoreg exists, the application knows that it needs to register components.  It then loads files from each of the components folders, including the components folder in each extension directory.  It then calls the function NSGetModule on each file to get the object that implements the nsIModule interface.
Now we will add a JavaScript object that implements the nsIFactory interface.


<pre>
<pre>
//module initialization
var MyPriorityFactory = {
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
};
</pre>
</pre>


The module object is then used to register your module.  This is used to simplify the process of retrieving the module later in class creation.  The registerSelf function is called to do the actual registering.  When removing a class, the unregisterSelf function is called.
=== Module Object ===
This object implements the nsIModule interface.


<pre>
<pre>
Line 89: Line 146:
</pre>
</pre>


=== Class Creation ===
=== Module Function ===
Using the code below to access your class, calls the getClassObject on your module.  The code within your module is used to return a class factory.  The factory then has a method called createInstance which is used to create the actual class object.
Last we will add a function used to locate the module object.
<pre>
var MyPriorityFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
};
</pre>
 
=== Accessing your Class ===
You can now access your class by using the following code.
<pre>
// instanciate component object
var oMyPriority = Components.classes['@mozillazine.org/example/priority;1'].
                            createInstance(Components.interfaces.nsISupportsPriority);


// lower priority
oMyPriority.adjustPriority(10);
</pre>
Mozilla also provides a component construction process to easy creation with javascript.  It can be accessed with the following code.
<pre>
<pre>
//component constructor
//module initialization
var Priority = new Components.Constructor('@mozillazine.org/example/priority;1','nsISupportsPriority');
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }
 
//instanciate component objects
var oMyPriority1 = new Priority();
var oMyPriority2 = new Priority();
 
//lower priority
oMyPriority1.adjustPriority(10);
oMyPriority2.priority = oMyPriority1.priority;
</pre>
</pre>


==Finished Code==
==Finished Code==
Below is how the finished code may look.
Below is how the finished code may look.


Line 212: Line 238:


</pre>
</pre>
== How it Works ==
=== Startup and Registration ===
During the startup process if the file compreg.dat is missing or the file .autoreg exists, the application knows that it needs to register components.  It then loads files from each of the components folders, including the components folder in each extension directory.  It then calls the function NSGetModule on each file to get the object that implements the nsIModule interface.
<pre>
//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }
</pre>
The module object is then used to register your module.  This is used to simplify the process of retrieving the module later in class creation.  The registerSelf function is called to do the actual registering.  When removing a class, the unregisterSelf function is called.
<pre>
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    if (this._firstTime) {
      this._firstTime = false;
      throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
    };
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  },
</pre>
=== Class Creation ===
Using the code below to access your class, calls the getClassObject on your module. 
<pre>
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
    if (aCID.equals(CLASS_ID))
      return MyPriorityFactory;
    throw Components.results.NS_ERROR_NO_INTERFACE;
  },
</pre>
The code within your module is used to return a class factory.  The factory then has a method called createInstance which is used to create the actual class object.
<pre>
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
</pre>
=== Accessing your component ===
You can now access your component by using the following code.
<pre>
// instantiate component object
var oMyPriority = Components.classes['@mozillazine.org/example/priority;1'].
                            createInstance(Components.interfaces.nsISupportsPriority);
// lower priority
oMyPriority.adjustPriority(10);
</pre>
Mozilla also provides a component construction process to easy creation with JavaScript.  It can be accessed with the following code.
<pre>
//component constructor
var Priority = new Components.Constructor('@mozillazine.org/example/priority;1','nsISupportsPriority');
//instantiate component objects
var oMyPriority1 = new Priority();
var oMyPriority2 = new Priority();
//lower priority
oMyPriority1.adjustPriority(10);
oMyPriority2.priority = oMyPriority1.priority;
</pre>
[[Category:Development]]

Latest revision as of 10:41, 12 January 2012

This page is part of the extension development documentation project.

Ask your questions in MozillaZine Forums. Also try browsing example code.

Note: development documentation is in process of being moved to Mozilla Development Center (MDC).


Welcome to Implementing XPCOM components in JavaScript.

This article provides information about creating a Javascript XPCOM class. The hope is to help explain how to create a class, and what processes are used to register and instanciate it. It does not describe how to create interfaces for your class. How to Build an XPCOM Component in Javascript at developer.mozilla.org has example of doing this if you need more help in that area. There are also a couple of forum discussion with some explanations, example code, and troubleshooting tips:


About XPCOM

Mozilla applications are built from a collection of XPCOM (Cross-platform Component Object Model) components. They are used to perform certain tasks or to get specific functionality. For example, there is a directory service component that can be used to access files on your file system. Classes can be constructed using several programming languages, including: JavaScript, C++, and Python (See PyXPCOM). Mozilla then uses "interfaces" to describe what a component can do. The most basic interface nsISupports is used to retrieve the different interfaces that a component implements.

Benefits of XPCOM

  • XPCOM components can be used by any programming language mozilla supports.
  • Objects implemented as XPCOM can be global to an application, and are not dependent on the scope of any one window. You can use an XPCOM service to share data between windows, for example.
  • XPCOM encourages modular programming - programming logic can be encapsulated within a component.

XPCOM Drawbacks

  • Objects must be accessed from their defined interfaces. Javascript shortcuts such as the global window object cannot be accessed.
    • The only exception to this rule, is if you set a magical property wrappedJSObject on your component implemented in JavaScript, the object this property refers to will be accessible from the calling side. You can set this.wrappedJSObject = this in your component's constructor and avoid writing any interfaces altogether.
  • It is easier to have memory leaks. This article on the Mozilla.org website provides an explanation of how and why this can occur, and tips on avoiding leakage in Javascript.

XPCOM Concepts

There are basically 4 concepts you need to understand when developing XPCOM objects. They are components, interfaces, modules, and factories. I will give a brief summary of each, then go into more details later.

Components

A component is simply an object that implements interfaces, and is registered with the component manager. In our case the implementation will be a Javascript object.

Interfaces

Interfaces are used to define what functions and attributes an XPCOM component provides. nsISupports is an interface that all classes must implement. It provides a function to request the interfaces on a class.

Factories

Factories are objects used to instantiate components. Each factory object implements the nsIFactory interface.

Modules

Multiple classes can be defined in a file. A module is an object that is used to register, unregister and provide factories for classes. It implements the nsIModule interface.

Example Code

For our example, we are going to create a file that contains one component, one module, and one factory. The component will implement the required nsISupports interface, and the nsISupportsPriority interface. A simple example of an actual Mozilla component is nsDictionary. A complex example that implements multiple interfaces is nsUpdateService.

Note: This example implements pre-existing interfaces, and therefore does not address the creation or compilation of interface descriptions (IDL) for our component. A more comprehensive tutorial that covers creating an XPCOM in Javascript from scratch can be found here.

Constants

First lets add some constants to our file that will be used later.

//interfaces we support
const nsISupportsPriority = Components.interfaces.nsISupportsPriority;
const nsISupports = Components.interfaces.nsISupports;

//class constants
const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}");
const CLASS_NAME = "My Supports Priority Component";
const CONTRACT_ID = "@mozillazine.org/example/priority;1";

Class Construction

Next we will add a JavaScript function which will be used for our class construction.

//class constructor
function MyPriority() {
  this._priority = nsISupportsPriority.PRIORITY_LOWEST;
};

Class Definition

Now we will use JavaScript prototyping to define our class. The class will expose the methods and properties from our selected interfaces.

//class definition
MyPriority.prototype = {
  _priority: null,

  //property of nsISupportsPriority interface
  get priority() { return this._priority; },
  set priority(aValue) { this._priority = aValue; },

  //method of nsISupportsPriority interface
  adjustPriority: function(aDelta) {
    this._priority += aDelta;
  },

  //method of nsISupports interface
  QueryInterface: function(aIID)
  {
    if (!aIID.equals(nsISupportsPriority) &&    
        !aIID.equals(nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  }
};

Factory Object

Now we will add a JavaScript object that implements the nsIFactory interface.

var MyPriorityFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
};

Module Object

This object implements the nsIModule interface.

//module definition (xpcom registration)
var MyPriorityModule = {
  _firstTime: true,
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    if (this._firstTime) {
      this._firstTime = false;
      throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
    };
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType)
  {
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return MyPriorityFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};

Module Function

Last we will add a function used to locate the module object.

//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }

Finished Code

Below is how the finished code may look.


// constants
const nsISupportsPriority = Components.interfaces.nsISupportsPriority;
const nsISupports = Components.interfaces.nsISupports;
const CLASS_ID = Components.ID("{1C0E8D86-B661-40d0-AE3D-CA012FADF170}");
const CLASS_NAME = "My Supports Priority Component";
const CONTRACT_ID = "@mozillazine.org/example/priority;1";

//class constructor
function MyPriority() {
  this._priority = nsISupportsPriority.PRIORITY_LOWEST;
};

//class definition
MyPriority.prototype = {
  _priority: null,

  get priority() { return this._priority; },
  set priority(aValue) { this._priority = aValue; },

  adjustPriority: function(aDelta) {
    this._priority += aDelta;
  },

  QueryInterface: function(aIID)
  {
    if (!aIID.equals(nsISupportsPriority) &&    
        !aIID.equals(nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  }
};

//class factory
var MyPriorityFactory = {
  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }
};

//module definition (xpcom registration)
var MyPriorityModule = {
  _firstTime: true,
  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    if (this._firstTime) {
      this._firstTime = false;
      throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
    };
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  },

  unregisterSelf: function(aCompMgr, aLocation, aType)
  {
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
  },
  
  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return MyPriorityFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aCompMgr) { return true; }
};

//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }

How it Works

Startup and Registration

During the startup process if the file compreg.dat is missing or the file .autoreg exists, the application knows that it needs to register components. It then loads files from each of the components folders, including the components folder in each extension directory. It then calls the function NSGetModule on each file to get the object that implements the nsIModule interface.

//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return MyPriorityModule; }

The module object is then used to register your module. This is used to simplify the process of retrieving the module later in class creation. The registerSelf function is called to do the actual registering. When removing a class, the unregisterSelf function is called.

  registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
  {
    if (this._firstTime) {
      this._firstTime = false;
      throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
    };
    aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
  },

Class Creation

Using the code below to access your class, calls the getClassObject on your module.

  getClassObject: function(aCompMgr, aCID, aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIFactory))
      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;

    if (aCID.equals(CLASS_ID))
      return MyPriorityFactory;

    throw Components.results.NS_ERROR_NO_INTERFACE;
  },

The code within your module is used to return a class factory. The factory then has a method called createInstance which is used to create the actual class object.

  createInstance: function (aOuter, aIID)
  {
    if (aOuter != null)
      throw Components.results.NS_ERROR_NO_AGGREGATION;
    return (new MyPriority()).QueryInterface(aIID);
  }

Accessing your component

You can now access your component by using the following code.

// instantiate component object
var oMyPriority = Components.classes['@mozillazine.org/example/priority;1'].
                             createInstance(Components.interfaces.nsISupportsPriority);

// lower priority
oMyPriority.adjustPriority(10);

Mozilla also provides a component construction process to easy creation with JavaScript. It can be accessed with the following code.

//component constructor
var Priority = new Components.Constructor('@mozillazine.org/example/priority;1','nsISupportsPriority');

//instantiate component objects
var oMyPriority1 = new Priority();
var oMyPriority2 = new Priority();

//lower priority
oMyPriority1.adjustPriority(10);
oMyPriority2.priority = oMyPriority1.priority;