Re: Cannot call RegisterDataSource on a own datasource

Axel Hecht <[email protected]> Mon, 04 Feb 2008 14:52:25 +0100
Newsgroups gmane.comp.mozilla.devel.rdf
Message-ID <[email protected]>
mcben wrote:
> On 4 fév, 09:27, Axel Hecht <[email protected]> wrote:
>> mcben wrote:
>>> Hi folks,
>>> Here is quite a long post about a problem with a own datasource
>>> implementation based on a xml-datasource.
>>> I'm looking for any clues or links that could help me to achieve my
>>> first goal : a custom datasource that i could fill from a CSV file.
>>> Thanks in advance for reading me :)
>>> I'm creating a javascript component that fetches a CSV file with
>>> XMLHttpRequest, parses it, then adds lines as RDF resources in a RDF
>>> datasource.
>>> Its contractid is like "@mozilla.org/rdf/datasource;1?name=mydatasource"
>>> so as to get it in the chrome with the "rdf:mydatasource" keyword.
>>> I started this work by using an in-memory-datasource as the __proto__
>>> properties of my javascript prototype.
>>> I could fetch my file and appends data in the datasource : the result
>>> was shown in a rdf tree.
>>> The first problem with this design was that i was not able to overwrite
>>> some nsIRDFDataSource methods (not a real problem in fact), nor extends
>>> the in-memory-datasource component with other interfaces : the QI method
>>> of my component was never called, so i got a NS_ERROR_NO_INTERFACE
>>> error, when i QI another interface (eg: nsIDOMListener to adds
>>> XMLHttpRequest callback in my chrome).
>>> Then i took a look a the rdf:localstore C++ implementation
>>> (nsLocalStore.cpp) and i'm quite happy with its design : it works like a
>>> wrapper around a xml-datasource. It "justs" load data from
>>> localstore.rdf in the profile directory or creates it if it does not exist.
>>> Then with that, I could even read and store a cached version of my CSV
>>> file on disk.
>>> So, I've made the same design in my javascript component, all
>>> nsIRDFDataSource related methods are forwarded to a "mInner"
>>> xml-datasource property.
>>> But when i try to call RegisterDataSource to register my datasource in
>>> the constructor of my component, it throws a NS_ERROR_FAILURE :
>>> Here is the code :
>>> this._loadLocalData();
>>> RDF.RegisterDataSource(this, false);
>>> this._loadRemoteData();
>>> If i log "this" the console service returns me that is an Object.
>>> That's the problem ?
>>> In fact I get from the chrome : [xpconnect wrapped (nsISupports,
>>> nsIRDFDataSource, nsIRDFRemoteDataSource)] after the registration, even
>>> if the registration fails.
>>> But, the nsIRDFRemoteDatasource Init method is called at every calls
>>> from chrome.
>>> Maybe the real problem comes from the xml-datasource initialization.
>>> The following code is called by the constructor of my component :
>>> this.mInner = Components
>>>        .classes["@mozilla.org/rdf/datasource;1?name=xml-datasource"]
>>>        .createInstance(Components.interfaces.nsIRDFDataSource);
>>> var remote = this.mInner
>>>        .QueryInterface(Components.interfaces.nsIRDFRemoteDataSource);
>>> remote.Init(filespec);
>>> The "Init" call throws an exception with the following code
>>> "0x804b000a". Its related with nsISocketTransport and means
>>> STATUS_WAITING_FOR. Ok, why not.
>>> Then remote.loaded returns false, and calling remote.Refresh(false)
>>> throws a NS_ERROR_FAILURE
>>> What is wrong with that ?
>>> So i catch this Init exception and get my remote datasource with the RDF
>>> Service like this :
>>> remote = RDF.GetDataSource(filespec)
>>>           .QueryInterface(Components.interfaces.nsIRDFRemoteDataSource)
>>> this.mInner = remote
>>>           .QueryInterface(Components.interfaces.nsIRDFDataSource);
>>> In that case no problem with remote ds, but the RegisterDataSource go on
>>> failing.
>>> And later, in the chrome, when i call a method or property that is
>>> forwarded to the inner, i got back a undefined result.
>>> And i cant look any result in my xul tree.
>>> I can post the full source code of the component if needed.
>> I suspect that it has something to do with your move from an in-memory
>> datasource as inner to an rdf/xml as inner. I didn't get why you made
>> that move, was that intentional?
> 
> Hi Axel,
> Thank you for your answer.
> 
> To begin, you can grab my component source code here, with the "second
> design" implementation (with inner):
> http://pastebin.mozilla.org/319272
> 
> And the xul tree that should show my results look quite simple :
> <tree id="itemtypes-tree" flex="1"
>         datasources="rdf:bi-itemtypes" ref="bi:itemtypes-list">
>   <treecols>
>     <treecol id="col-name" primary="true" label="Name" flex="1"/>
>   </treecols>
>   <template>
>     <treechildren>
>       <treeitem uri="rdf:*">
>         <treerow>
>           <treecell label="rdf:*" />
>         </treerow>
>       </treeitem>
>     </treechildren>
>   </template>
> </tree>
> 
> 
> Hum. yes, the move was partially intentional :
> 
>  * My first try with an in-memory datasource was with the instance set
> as __proto__ property in the prototype of my component. That is to
> say, that it was not with the "inner" design.
> The main problem with this design was that i could not extends my
> component by implementing other public interface : the QI function of
> my component was never called, nor any method that i though they
> overrode existing methods of the in-mem. The only thing that i could
> improve in this design was the init phase of my component (by filling
> in-mem with XMLHttpRequest) nothing else.
> 
> Is it normal that with the following code, the QueryInterface method
> is never called, that's why i cant implement any other interfaces ? (i
> think that the __proto__ QI is called instead).
> 
> function myComponentImplementation() {
> }
> myComponentImplementation.prototype {
>     __proto__ : Components.classes["@mozilla.org/rdf/datasource;1?
> name=in-memory-datasource"]
>                          .createInstance(Components.interfaces.nsIRDFDataSource),
> 
>     QueryInterface : function(iid) {
>         if (!iid.equals(C_i.nsIDOMEventListener) &&
>             !iid.equals(C_i.nsIRDFDataSource) &&
>             !iid.equals(C_i.nsIRDFRemoteDataSource) &&
>             !iid.equals(C_i.nsISupports))
>             throw Components.results.NS_ERROR_NO_INTERFACE;
>         ConsoleService.logStringMessage("QI called:" + iid);
>         return this;
>     }
> }
> 
> 
>  * With the "inner" design, i immediatly use a xml-datasource, just
> like the nsLocalStore implementation. With that, i could load a cached
> version of the rdf file from disk, and then update it with
> XMLHttpRequest only if it really needed.
> 
> Since, you are thinking that the problem can come from the xml-
> datasource, i took the same component, and just replaced the xml-
> datasource inner, with an in-memory-datasource.
> Indeed, it seems there is no major failure with initialization, i can
> register the datasource, but the content that i downloaded with
> XMLHttpRequest and that i put in the ds is not reflected in my chrome
> xul tree, nor i can query my datasource for any target that sould
> exists.
> 
> More precisely, about any errors, i had to create the container (the
> one to wich I append downloaded resources) with this.mInner (the in-
> mem ds) and not my component. Is it normal ?
> Look:
> this._container = RDFContainer.MakeSeq(this.mInner,
> RDF.GetResource(this._struct.ref));
> Even though my component should implement nsIRDFDataSource, that's why
> i thought i could do that :
> this._container = RDFContainer.MakeSeq(this,
> RDF.GetResource(this._struct.ref));
> 
> But it seems that append does not work anyway.
> 
> 
> * Finally, why I made the move to xml-datasource ?
> (I thought) I could parse a local rdf file at init, and flushes the
> modified results at destruction. I even could observe the download
> progress from chrome (eg: with a progressbar), etc.
> 
> So any clue ?
> What do you think is the best implementation ?
> 
> The first design could be perfect if i could override and extends
> methods and interfaces of the __proto__ instance.
> 
> Thank you for reading me.

I suspect that something in your implementation is broken. There is 
http://developer.mozilla.org/en/docs/Aggregating_the_In-Memory_Datasource, 
but that hasn't been maintained in years, same goes for its sibling 
documents.

Sorry, no better idea, maybe if you post parts of your code there's 
better chances.

Axel