Oct 09 2009

Implementing an XPCOM Firefox Interface and Creating Observers

Category: Firefox, JavaScriptJonathan Fingland @ 4:05 am

There are lots of cases when it is desirable to implement one of the XPCOM interfaces in use by Firefox, or other mozilla-based browsers. There are three cases where PirateQuesting does so, but once you see the concept, it should be easy to adapt to your situation.

  • You must have a QueryInterface to enjoy this ride

    First off, all XPCOM interfaces in Firefox inherit from nsISupports (Also see details on oxymoronical.com here). Only one method is scriptable and part of XPCOM — QueryInterface — and it must be present in all implementations of XPCOM interfaces.

    
    //"implements" nsISupports
    var InterfaceImplementation = function() {
      QueryInterface: function (aIID) {
          if (aIID.equals(Components.interfaces.nsISupports))
          {
             return this;
          }
          throw Components.results.NS_NOINTERFACE;
      }
    }
    

    The above is an example of the very minimum required to support any interface. QueryInterface requires a first parameter which is an aIID from Components.interfaces.*. There is also a second, optional, parameter, but as I have never come across this in use, it’s not worth pursuing here.

  • Now what?

    A very common (and useful) use of XPCOM interface implementation is creating your own observers, for example:

    
    var myObserver = {
    
      observe: function(request, aTopic, aData){
        if (aTopic == "http-on-examine-response")
        {
          //response has come back, now what?
        }
        else if (aTopic == "http-on-modify-request")
        {
          //opportunity to modify headers on request
        }
      },
    
      QueryInterface: function(aIID){
         if (aIID.equals(Components.interfaces.nsIObserver) ||
             aIID.equals(Components.interfaces.nsISupports))
        {
          return this;
        }
        throw Components.results.NS_NOINTERFACE;
      },
    };
    

    The nsIObserver interface is fairly simple as it only adds one new method. As you can see now, though, QueryInterface now checks for both nsIObserver and nsISupports. Remember: any interface you implement must have a QueryInterface supporting all interfaces in the inheritance chain.

  • Observer registration

    If you then wanted to register your observer, it’s as easy as:

    
    var observerService = Components.classes["@mozilla.org/observer-service;1"]
                                   .getService(Components.interfaces.nsIObserverService);
    
    observerService.addObserver(myObserver,"http-on-examine-response", false);
    observerService.addObserver(myObserver,"http-on-modify-request", false);
    

    Then to unregister, you do:

    
    observerService.removeObserver(myObserver, "http-on-examine-response");
    observerService.removeObserver(myObserver, "http-on-modify-request");
    

    When I have a chance, I’ll add a more complete example of using observers to watch http requests, but in the meantime check out the list of Observer Notifications at MDC.

Tags: , ,