Re: Cannot call RegisterDataSource on a own datasource
mcben <[email protected]> Mon, 4 Feb 2008 07:42:59 -0800 (PST)
| Newsgroups | gmane.comp.mozilla.devel.rdf |
|---|---|
| Organization | http://groups.google.com |
| Message-ID | <195daffc-b6ef-4845-88f9-93d460fffdf4@c23g2000hsa.googlegroups.com> |
On 4 fév, 15:47, Axel Hecht <[email protected]> wrote: > 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? Good point. I just tried that : function myDataSourceImplementation(struct) { this.__proto__ = Components.classes["@mozilla.org/rdf/datasource;1? name=in-memory-datasource"] .createInstance(Components.interfaces.nsIRDFDataSource); this.init = function() { // load data with XMLHttpRequest }; this.QueryInterface = function(iid) { ConsoleService.logStringMessage("QI called:" + iid); if (!iid.equals(Components.interfaces.nsIDOMEventListener) && !iid.equals(Components.interfaces.nsIRDFDataSource) && !iid.equals(Components.interfaces.nsIRDFRemoteDataSource) && !iid.equals(Components.interfaces.nsISupports)) throw Components.results.NS_ERROR_NO_INTERFACE; return this; }; this.init(); } As you can see, i'm compelled to binds new methods in the constructor since, the prototype is overriden by "this.__proto__". Not a real problem. Code works (i see the data in the chrome). But my new QI is never called, like before, and prevents me from implementing other interfaces :-( > > But I guess for real questions on this, you should try .js-engine. Maybe. This evening, I'll try XPCOM aggregation (like in "Aggregating In Memory Datasource"), and will ask .js-engine for any clues. I'll post back here any progress about this subject. Thanks for your time.