Re: Cannot call RegisterDataSource on a own datasource
Axel Hecht <[email protected]> Mon, 04 Feb 2008 15:47:27 +0100
| Newsgroups | gmane.comp.mozilla.devel.rdf |
|---|---|
| Message-ID | <[email protected]> |
mcben wrote: > On 4 fév, 14:52, Axel Hecht <[email protected]> wrote: >> 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 ishttp://developer.mozilla.org/en/docs/Aggregating_the_In-Memory_Dataso..., >> but that hasn't been maintained in years, same goes for its sibling >> documents. > > Yes, i know this document, and tried some months ago to agregate a xml- > datasource (for another project) and gave up when i saw that xml- > datasource cant be aggregated ;-) > > Maybe i should give another try with the in-mem datasource. > > But can you confirm me that i could try that with a javascript > implementation ? > > >> Sorry, no better idea, maybe if you post parts of your code there's >> better chances. > > Héhé. The whole component is too long / time consuming for you to take > a look ? > I understand. > > So first question, that i previously asked. WIth a component > implementation below, is it normal that I cant override public methods > of the __proto__. In fact, I can only add private method, that cant be > accessed by the chrome ? > > 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; > } > > } That is more of a js/xpconnect question. Trying function A(){this.bar=3;} function B(){this.__proto__ = new A();this.foo=6}; b=new B() [object Object] props(b) Fields: foo Fields of prototype: bar Methods of prototype of prototype of prototype: extend b.bar 3 b.foo 6 makes me think that you should set the __proto__ to a new instance of the in-mem ds in the Constructor. Which makes sense, as you don't want to share the in-mem ds across all instances of myComponentImplementation, right? But I guess for real questions on this, you should try .js-engine. Axel