function MyComponent() {
}
MyComponent.prototype = {
  classID: Components.ID("{xxxxxxxx-be3a-2b41-7a76-12533ba32166}"), // xxx generate guid
  contractID: "@mozilla.doslash.org/test/component;1",
  classDescription: "Test component",

  QueryInterface: function(aIID) {
    if(!aIID.equals(CI.nsISupports) && !aIID.equals(CI.nsIObserver))
      throw CR.NS_ERROR_NO_INTERFACE;
    return this;
  },

  observe: function(aSubject, aTopic, aData) {
    switch(aTopic) {
      // this is run very early, right after XPCOM is initialized, but before 
      // user profile information is applied. Register ourselves as an observer
      // for 'profile-after-change' and 'quit-application'.
      case "xpcom-startup":
        var obsSvc = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);
        obsSvc.addObserver(this, "profile-after-change", false);
        obsSvc.addObserver(this, "quit-application", false);
        break;

      // This happens after profile has been loaded and user preferences have been read.
      case "profile-after-change":
        // startup code here
        break;
      case "quit-application":
        // shutdown code here
        break;
      default:
        throw Components.Exception("Unknown topic: " + aTopic);
    }
  }
};


// constructors for objects we want to XPCOMify
var objects = [MyComponent];

/*
 * Registration code.
 *
 */

const CI = Components.interfaces, CC = Components.classes, CR = Components.results;

const MY_OBSERVER_NAME = "My Observer";

function FactoryHolder(aObj) {
  this.CID        = aObj.prototype.classID;
  this.contractID = aObj.prototype.contractID;
  this.className  = aObj.prototype.classDescription;
  this.factory = {
    createInstance: function(aOuter, aIID) {
      if(aOuter)
        throw CR.NS_ERROR_NO_AGGREGATION;
      return (new this.constructor).QueryInterface(aIID);
    }
  };
  this.factory.constructor = aObj;
}

var gModule = {
  registerSelf: function (aComponentManager, aFileSpec, aLocation, aType)
  {
    aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
    for (var key in this._objects) {
      var obj = this._objects[key];
      aComponentManager.registerFactoryLocation(obj.CID, obj.className,
        obj.contractID, aFileSpec, aLocation, aType);
    }

    var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
    catman.addCategoryEntry("xpcom-startup", MY_OBSERVER_NAME, 
      MyComponent.prototype.contractID, true, true);
    catman.addCategoryEntry("xpcom-shutdown", MY_OBSERVER_NAME, 
      MyComponent.prototype.contractID, true, true);
  },

  unregisterSelf: function(aCompMgr, aFileSpec, aLocation) {
    var catman = CC["@mozilla.org/categorymanager;1"].getService(CI.nsICategoryManager);
    catman.deleteCategoryEntry("xpcom-startup", MY_OBSERVER_NAME, true);

    aComponentManager.QueryInterface(CI.nsIComponentRegistrar);
    for (var key in this._objects) {
      var obj = this._objects[key];
      aComponentManager.unregisterFactoryLocation(obj.CID, aFileSpec);
    }
  },

  getClassObject: function(aComponentManager, aCID, aIID) {
    if (!aIID.equals(CI.nsIFactory)) throw CR.NS_ERROR_NOT_IMPLEMENTED;

    for (var key in this._objects) {
      if (aCID.equals(this._objects[key].CID))
        return this._objects[key].factory;
    }
    
    throw CR.NS_ERROR_NO_INTERFACE;
  },

  canUnload: function(aComponentManager) {
    return true;
  },

  _objects: {} //FactoryHolder
};

function NSGetModule(compMgr, fileSpec) 
{
  for(var i in objects)
    gModule._objects[i] = new FactoryHolder(objects[i]);
  return gModule;
}

