diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/aggregating_the_in-memory_datasource | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/aggregating_the_in-memory_datasource')
-rw-r--r-- | files/zh-cn/aggregating_the_in-memory_datasource/index.html | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/files/zh-cn/aggregating_the_in-memory_datasource/index.html b/files/zh-cn/aggregating_the_in-memory_datasource/index.html new file mode 100644 index 0000000000..6ecf148dff --- /dev/null +++ b/files/zh-cn/aggregating_the_in-memory_datasource/index.html @@ -0,0 +1,112 @@ +--- +title: 收集 In-Memory 数据源 +slug: Aggregating_the_In-Memory_Datasource +tags: + - RDF +translation_of: Mozilla/Tech/XPCOM/Aggregating_the_In-Memory_Datasource +--- +<p> </p> +<h3 id="Introduction" name="Introduction">Introduction</h3> +<p>You can use XPCOM aggregation<sup>1</sup> with the in-memory datasource. Why would you want to do this? Say you were writing a datasource<sup>2</sup>, and the way you chose to implement it was to "wrap" the in-memory datasource; i.e.,</p> +<pre>MyClass : public nsIMyInterface, public nsIRDFDataSource { +private: + nsCOMPtr<nsIRDFDataSource> mInner; + +public: + // nsIRDFDataSource methods + NS_IMETHOD Init(const char* aURI) { + return mInner->Init(aURI); + } + + NS_IMETHOD GetURI(char* *aURI) { + return mInner->GetURI(aURI); + } + + // etc., for each method in nsIRDFDataSource! +}; +</pre> +<p>Very painful, prone to errors, and fragile as the interfaces are still in flux (a wee bit). Aggregation to the rescue! Here are the gory details on how.</p> +<h3 id="When_It_Won.27t_Work" name="When_It_Won.27t_Work">When It Won't Work</h3> +<p>Although this magic is terribly convenient to use, it won't work in the case that you want to "override" some of the in-memory datasource's methods. For example, while writing the <a class="external" href="http://lxr.mozilla.org/mozilla/source/browser/components/bookmarks/src/nsBookmarksService.cpp">bookmarks datasource</a>, I wanted to be able to trap <code>Assert()</code> to enforce the bookmarks datasource would only accept "bookmarks related" assertions. If I'd just delegated to the in-memory datasource, <code>Assert()</code> would've taken any old random garbage. Similarly, I wanted to trap <code>Flush()</code> so that I could write the <code>bookmarks.html</code> file back to disk.</p> +<p>In short, the only case where this technique is useful is when you're implementing a datasource to get "read-only reflection". That is, you want to reflect the contents of something as an RDF graph (presumably so that it can be aggregated with other information or displayed as styled content).</p> +<h3 id="Technical_Details" name="Technical_Details">Technical Details</h3> +<p>As before, have an <code>nsCOMPtr</code> as your delegate, but this time around, + <i> + don't</i> + derive from <code>nsIRDFDataSource</code>. Also, instead of keeping an <code>nsCOMPtr<nsIRDFDataSource></code>, you'll just want an <code>nsCOMPtr<nsISupports></code>:</p> +<pre>class MyClass : public nsIMyInterface { + ... +private: + nsCOMPtr<nsISupports> mInner; +}; +</pre> +<p>Construct the datasource delegate when your object is constructed (or, at worst, when somebody QI's for it):</p> +<pre>rv = nsComponentManager::CreateInstance( + kRDFInMemoryDataSourceCID, + this, /* the "outer" */ + nsCOMTypeInfo<nsISupports>::GetIID(), + getter_AddRefs(mInner)); +</pre> +<p>Note passing <code>this</code> as the "outer" parameter.</p> +<p>Now, if the in-memory datasource's implementation of <code>QueryInterface()</code> fails because it doesn't support the requested interface, it will + <i> + forward</i> + the query interface to its "outer" (which is "us"). This preserves the symmetrical property of <code>QueryInterface()</code>.</p> +<p>For us to preserve symmetry, our <code>QueryInterface()</code> implementation needs to forward <code>nsIRDFDataSource</code> to the delegate<sup>3</sup>:</p> +<pre>NS_IMETHODIMP +MyClass::QueryInterface(REFNSIID aIID, void** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + if (aIID.Equals(nsCOMTypeInfo<nsIMyInterface>::GetIID()) || + aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) { + *aResult = NS_STATIC_CAST(nsIGlobalHistory*, this); + } + else if (aIID.Equals(nsCOMTypeInfo<nsIRDFDataSource>::GetIID())) { + return mInner->QueryInterface(aIID, aResult); + } + else { + *aResult = nsnull; + return NS_NOINTERFACE; + } + + NS_ADDREF(NS_STATIC_CAST(nsISupports*, aResult)); + return NS_OK; +} +</pre> +<p>The only other thing that you'll need to be aware of is that you'll need to <code>QueryInterface()</code> from <code>nsISupports</code> to <code>nsIRDFDataSource</code> before you can actually do anything useful with the datasource from within your object. For example:</p> +<pre>NS_IMETHODIMP +MyClass::DoSomething() +{ + nsCOMPtr<nsIRDFDataSopurce> ds = do_QueryInterface(mInner); + + rv = ds->Assert(/* something useful here */); + + // etc... + + return NS_OK; +} +</pre> +<p>It may be tempting to keep a pointer to the aggregate's <code>nsIRDFDataSource</code> in a member variable, but + <i> + you can't do that</i> + . Why? Because if you did, you'd hold a circular reference that would never unwind.</p> +<h3 id="Notes" name="Notes">Notes</h3> +<ol> + <li>Describing all of the vagaries of <a href="cn/XPCOM">XPCOM</a> aggregation is beyond the scope of this document. The basic idea is to overload <code>QueryInterface()</code>, allowing it to return a + <i> + delegate</i> + object that supports the interface. There is some trickery involved on the delegate's part to ensure that reference counting is done sanely, and that the reflexive, symmetric, and transitive properties of <code>QueryInterface()</code> are preserved. If you're really interested, I'd recommend reading about it in a COM book.</li> + <li>For more information on writing a datasource, see the <a href="cn/RDF_Datasource_How-To">RDF Datasource How-To</a> document.</li> + <li>You could also forward other interfaces to the <code>mInner</code> that you + <i> + know</i> + it can support; however, this is <b>extremely risky</b>. It's risky because another implementation of the same object might + <i> + not</i> + support those interfaces. Then the <code>QueryInterface()</code> will be forwarded back to you, and we'll recurse off to infinity (and beyond!...)</li> +</ol> +<p><span class="comment">Interwiki Language Links</span></p> +<p></p> |