michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: michael@0: A simple composite data source implementation. A composit data michael@0: source is just a strategy for combining individual data sources into michael@0: a collective graph. michael@0: michael@0: michael@0: 1) A composite data source holds a sequence of data sources. The set michael@0: of data sources can be specified during creation of the michael@0: database. Data sources can also be added/deleted from a database michael@0: later. michael@0: michael@0: 2) The aggregation mechanism is based on simple super-positioning of michael@0: the graphs from the datasources. If there is a conflict (i.e., michael@0: data source A has a true arc from foo to bar while data source B michael@0: has a false arc from foo to bar), the data source that it earlier michael@0: in the sequence wins. michael@0: michael@0: The implementation below doesn't really do this and needs to be michael@0: fixed. michael@0: michael@0: */ michael@0: michael@0: #include "xpcom-config.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIRDFCompositeDataSource.h" michael@0: #include "nsIRDFNode.h" michael@0: #include "nsIRDFObserver.h" michael@0: #include "nsIRDFRemoteDataSource.h" michael@0: #include "nsTArray.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsArrayEnumerator.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "rdf.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: michael@0: #include "nsEnumeratorUtils.h" michael@0: michael@0: #ifdef PR_LOGGING michael@0: #include "prlog.h" michael@0: #include "prprf.h" michael@0: #include michael@0: PRLogModuleInfo* nsRDFLog = nullptr; michael@0: #endif michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // CompositeDataSourceImpl michael@0: // michael@0: michael@0: class CompositeEnumeratorImpl; michael@0: class CompositeArcsInOutEnumeratorImpl; michael@0: class CompositeAssertionEnumeratorImpl; michael@0: michael@0: class CompositeDataSourceImpl : public nsIRDFCompositeDataSource, michael@0: public nsIRDFObserver michael@0: { michael@0: public: michael@0: CompositeDataSourceImpl(void); michael@0: CompositeDataSourceImpl(char** dataSources); michael@0: michael@0: // nsISupports interface michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CompositeDataSourceImpl, michael@0: nsIRDFCompositeDataSource) michael@0: michael@0: // nsIRDFDataSource interface michael@0: NS_DECL_NSIRDFDATASOURCE michael@0: michael@0: // nsIRDFCompositeDataSource interface michael@0: NS_DECL_NSIRDFCOMPOSITEDATASOURCE michael@0: michael@0: // nsIRDFObserver interface michael@0: NS_DECL_NSIRDFOBSERVER michael@0: michael@0: bool HasAssertionN(int n, nsIRDFResource* source, michael@0: nsIRDFResource* property, michael@0: nsIRDFNode* target, michael@0: bool tv); michael@0: michael@0: protected: michael@0: nsCOMArray mObservers; michael@0: nsCOMArray mDataSources; michael@0: michael@0: bool mAllowNegativeAssertions; michael@0: bool mCoalesceDuplicateArcs; michael@0: int32_t mUpdateBatchNest; michael@0: michael@0: virtual ~CompositeDataSourceImpl() {} michael@0: michael@0: friend class CompositeEnumeratorImpl; michael@0: friend class CompositeArcsInOutEnumeratorImpl; michael@0: friend class CompositeAssertionEnumeratorImpl; michael@0: }; michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // CompositeEnumeratorImpl michael@0: // michael@0: michael@0: class CompositeEnumeratorImpl : public nsISimpleEnumerator michael@0: { michael@0: // nsISupports michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: // nsISimpleEnumerator interface michael@0: NS_DECL_NSISIMPLEENUMERATOR michael@0: michael@0: // pure abstract methods to be overridden michael@0: virtual nsresult michael@0: GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult) = 0; michael@0: michael@0: virtual nsresult michael@0: HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult) = 0; michael@0: michael@0: protected: michael@0: CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs); michael@0: michael@0: virtual ~CompositeEnumeratorImpl(); michael@0: michael@0: CompositeDataSourceImpl* mCompositeDataSource; michael@0: michael@0: nsISimpleEnumerator* mCurrent; michael@0: nsIRDFNode* mResult; michael@0: int32_t mNext; michael@0: nsAutoTArray, 8> mAlreadyReturned; michael@0: bool mAllowNegativeAssertions; michael@0: bool mCoalesceDuplicateArcs; michael@0: }; michael@0: michael@0: michael@0: CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs) michael@0: : mCompositeDataSource(aCompositeDataSource), michael@0: mCurrent(nullptr), michael@0: mResult(nullptr), michael@0: mNext(0), michael@0: mAllowNegativeAssertions(aAllowNegativeAssertions), michael@0: mCoalesceDuplicateArcs(aCoalesceDuplicateArcs) michael@0: { michael@0: NS_ADDREF(mCompositeDataSource); michael@0: } michael@0: michael@0: michael@0: CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void) michael@0: { michael@0: NS_IF_RELEASE(mCurrent); michael@0: NS_IF_RELEASE(mResult); michael@0: NS_RELEASE(mCompositeDataSource); michael@0: } michael@0: michael@0: NS_IMPL_ADDREF(CompositeEnumeratorImpl) michael@0: NS_IMPL_RELEASE(CompositeEnumeratorImpl) michael@0: NS_IMPL_QUERY_INTERFACE(CompositeEnumeratorImpl, nsISimpleEnumerator) michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeEnumeratorImpl::HasMoreElements(bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: // If we've already queued up a next target, then yep, there are michael@0: // more elements. michael@0: if (mResult) { michael@0: *aResult = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Otherwise, we'll need to find a next target, switching cursors michael@0: // if necessary. michael@0: for ( ; mNext < mCompositeDataSource->mDataSources.Count(); ++mNext) { michael@0: if (! mCurrent) { michael@0: // We don't have a current enumerator, so create a new one on michael@0: // the next data source. michael@0: nsIRDFDataSource* datasource = michael@0: mCompositeDataSource->mDataSources[mNext]; michael@0: michael@0: rv = GetEnumerator(datasource, &mCurrent); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (rv == NS_RDF_NO_VALUE) michael@0: continue; michael@0: michael@0: NS_ASSERTION(mCurrent != nullptr, "you're always supposed to return an enumerator from GetEnumerator, punk."); michael@0: if (! mCurrent) michael@0: continue; michael@0: } michael@0: michael@0: do { michael@0: int32_t i; michael@0: michael@0: bool hasMore; michael@0: rv = mCurrent->HasMoreElements(&hasMore); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Is the current enumerator depleted? michael@0: if (! hasMore) { michael@0: NS_RELEASE(mCurrent); michael@0: break; michael@0: } michael@0: michael@0: // Even if the current enumerator has more elements, we still michael@0: // need to check that the current element isn't masked by michael@0: // a negation in an earlier data source. michael@0: michael@0: // "Peek" ahead and pull out the next target. michael@0: nsCOMPtr result; michael@0: rv = mCurrent->GetNext(getter_AddRefs(result)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = result->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) &mResult); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (mAllowNegativeAssertions) michael@0: { michael@0: // See if any previous data source negates this michael@0: bool hasNegation = false; michael@0: for (i = mNext - 1; i >= 0; --i) michael@0: { michael@0: nsIRDFDataSource* datasource = michael@0: mCompositeDataSource->mDataSources[i]; michael@0: michael@0: rv = HasNegation(datasource, mResult, &hasNegation); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (hasNegation) michael@0: break; michael@0: } michael@0: michael@0: // if so, we've gotta keep looking michael@0: if (hasNegation) michael@0: { michael@0: NS_RELEASE(mResult); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: if (mCoalesceDuplicateArcs) michael@0: { michael@0: // Now see if we've returned it once already. michael@0: // XXX N.B. performance here...may want to hash if things get large? michael@0: bool alreadyReturned = false; michael@0: for (i = mAlreadyReturned.Length() - 1; i >= 0; --i) michael@0: { michael@0: if (mAlreadyReturned[i] == mResult) michael@0: { michael@0: alreadyReturned = true; michael@0: break; michael@0: } michael@0: } michael@0: if (alreadyReturned) michael@0: { michael@0: NS_RELEASE(mResult); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: // If we get here, then we've really found one. It'll michael@0: // remain cached in mResult until GetNext() sucks it out. michael@0: *aResult = true; michael@0: michael@0: // Remember that we returned it, so we don't return duplicates. michael@0: michael@0: // XXX I wonder if we should make unique-checking be michael@0: // optional. This could get to be pretty expensive (this michael@0: // implementation turns iteration into O(n^2)). michael@0: michael@0: if (mCoalesceDuplicateArcs) michael@0: { michael@0: mAlreadyReturned.AppendElement(mResult); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } while (1); michael@0: } michael@0: michael@0: // if we get here, there aren't any elements left. michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeEnumeratorImpl::GetNext(nsISupports** aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: bool hasMore; michael@0: rv = HasMoreElements(&hasMore); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (! hasMore) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: // Don't AddRef: we "transfer" ownership to the caller michael@0: *aResult = mResult; michael@0: mResult = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // CompositeArcsInOutEnumeratorImpl michael@0: // michael@0: // michael@0: michael@0: class CompositeArcsInOutEnumeratorImpl : public CompositeEnumeratorImpl michael@0: { michael@0: public: michael@0: enum Type { eArcsIn, eArcsOut }; michael@0: michael@0: virtual ~CompositeArcsInOutEnumeratorImpl(); michael@0: michael@0: virtual nsresult michael@0: GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult); michael@0: michael@0: virtual nsresult michael@0: HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult); michael@0: michael@0: CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource, michael@0: nsIRDFNode* aNode, michael@0: Type aType, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs); michael@0: michael@0: private: michael@0: nsIRDFNode* mNode; michael@0: Type mType; michael@0: }; michael@0: michael@0: michael@0: CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl( michael@0: CompositeDataSourceImpl* aCompositeDataSource, michael@0: nsIRDFNode* aNode, michael@0: Type aType, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs) michael@0: : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs), michael@0: mNode(aNode), michael@0: mType(aType) michael@0: { michael@0: NS_ADDREF(mNode); michael@0: } michael@0: michael@0: CompositeArcsInOutEnumeratorImpl::~CompositeArcsInOutEnumeratorImpl() michael@0: { michael@0: NS_RELEASE(mNode); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: CompositeArcsInOutEnumeratorImpl::GetEnumerator( michael@0: nsIRDFDataSource* aDataSource, michael@0: nsISimpleEnumerator** aResult) michael@0: { michael@0: if (mType == eArcsIn) { michael@0: return aDataSource->ArcLabelsIn(mNode, aResult); michael@0: } michael@0: else { michael@0: nsCOMPtr resource( do_QueryInterface(mNode) ); michael@0: return aDataSource->ArcLabelsOut(resource, aResult); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: CompositeArcsInOutEnumeratorImpl::HasNegation( michael@0: nsIRDFDataSource* aDataSource, michael@0: nsIRDFNode* aNode, michael@0: bool* aResult) michael@0: { michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // CompositeAssertionEnumeratorImpl michael@0: // michael@0: michael@0: class CompositeAssertionEnumeratorImpl : public CompositeEnumeratorImpl michael@0: { michael@0: public: michael@0: virtual nsresult michael@0: GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult); michael@0: michael@0: virtual nsresult michael@0: HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult); michael@0: michael@0: CompositeAssertionEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs); michael@0: michael@0: virtual ~CompositeAssertionEnumeratorImpl(); michael@0: michael@0: private: michael@0: nsIRDFResource* mSource; michael@0: nsIRDFResource* mProperty; michael@0: nsIRDFNode* mTarget; michael@0: bool mTruthValue; michael@0: }; michael@0: michael@0: michael@0: CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl( michael@0: CompositeDataSourceImpl* aCompositeDataSource, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue, michael@0: bool aAllowNegativeAssertions, michael@0: bool aCoalesceDuplicateArcs) michael@0: : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs), michael@0: mSource(aSource), michael@0: mProperty(aProperty), michael@0: mTarget(aTarget), michael@0: mTruthValue(aTruthValue) michael@0: { michael@0: NS_IF_ADDREF(mSource); michael@0: NS_ADDREF(mProperty); // always must be specified michael@0: NS_IF_ADDREF(mTarget); michael@0: } michael@0: michael@0: CompositeAssertionEnumeratorImpl::~CompositeAssertionEnumeratorImpl() michael@0: { michael@0: NS_IF_RELEASE(mSource); michael@0: NS_RELEASE(mProperty); michael@0: NS_IF_RELEASE(mTarget); michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: CompositeAssertionEnumeratorImpl::GetEnumerator( michael@0: nsIRDFDataSource* aDataSource, michael@0: nsISimpleEnumerator** aResult) michael@0: { michael@0: if (mSource) { michael@0: return aDataSource->GetTargets(mSource, mProperty, mTruthValue, aResult); michael@0: } michael@0: else { michael@0: return aDataSource->GetSources(mProperty, mTarget, mTruthValue, aResult); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: CompositeAssertionEnumeratorImpl::HasNegation( michael@0: nsIRDFDataSource* aDataSource, michael@0: nsIRDFNode* aNode, michael@0: bool* aResult) michael@0: { michael@0: if (mSource) { michael@0: return aDataSource->HasAssertion(mSource, mProperty, aNode, !mTruthValue, aResult); michael@0: } michael@0: else { michael@0: nsCOMPtr source( do_QueryInterface(aNode) ); michael@0: return aDataSource->HasAssertion(source, mProperty, mTarget, !mTruthValue, aResult); michael@0: } michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: michael@0: nsresult michael@0: NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result) michael@0: { michael@0: CompositeDataSourceImpl* db = new CompositeDataSourceImpl(); michael@0: if (! db) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: *result = db; michael@0: NS_ADDREF(*result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: CompositeDataSourceImpl::CompositeDataSourceImpl(void) michael@0: : mAllowNegativeAssertions(true), michael@0: mCoalesceDuplicateArcs(true), michael@0: mUpdateBatchNest(0) michael@0: { michael@0: #ifdef PR_LOGGING michael@0: if (nsRDFLog == nullptr) michael@0: nsRDFLog = PR_NewLogModule("RDF"); michael@0: #endif michael@0: } michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // nsISupports interface michael@0: // michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_CLASS(CompositeDataSourceImpl) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CompositeDataSourceImpl) michael@0: uint32_t i, count = tmp->mDataSources.Count(); michael@0: for (i = count; i > 0; --i) { michael@0: tmp->mDataSources[i - 1]->RemoveObserver(tmp); michael@0: tmp->mDataSources.RemoveObjectAt(i - 1); michael@0: } michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers); michael@0: NS_IMPL_CYCLE_COLLECTION_UNLINK_END michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CompositeDataSourceImpl) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataSources) michael@0: NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END michael@0: michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(CompositeDataSourceImpl) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(CompositeDataSourceImpl) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositeDataSourceImpl) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRDFObserver) michael@0: NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource) michael@0: NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFCompositeDataSource) michael@0: NS_INTERFACE_MAP_END michael@0: michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // michael@0: // nsIRDFDataSource interface michael@0: // michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetURI(char* *uri) michael@0: { michael@0: *uri = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetSource(nsIRDFResource* property, michael@0: nsIRDFNode* target, michael@0: bool tv, michael@0: nsIRDFResource** source) michael@0: { michael@0: if (!mAllowNegativeAssertions && !tv) michael@0: return(NS_RDF_NO_VALUE); michael@0: michael@0: int32_t count = mDataSources.Count(); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: nsresult rv; michael@0: rv = mDataSources[i]->GetSource(property, target, tv, source); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (rv == NS_RDF_NO_VALUE) michael@0: continue; michael@0: michael@0: if (!mAllowNegativeAssertions) return(NS_OK); michael@0: michael@0: // okay, found it. make sure we don't have the opposite michael@0: // asserted in a more local data source michael@0: if (!HasAssertionN(count-1, *source, property, target, !tv)) michael@0: return NS_OK; michael@0: michael@0: NS_RELEASE(*source); michael@0: return NS_RDF_NO_VALUE; michael@0: } michael@0: return NS_RDF_NO_VALUE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue, michael@0: nsISimpleEnumerator** aResult) michael@0: { michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aTarget != nullptr, "null ptr"); michael@0: if (! aTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (! mAllowNegativeAssertions && ! aTruthValue) michael@0: return(NS_RDF_NO_VALUE); michael@0: michael@0: *aResult = new CompositeAssertionEnumeratorImpl(this, nullptr, aProperty, michael@0: aTarget, aTruthValue, michael@0: mAllowNegativeAssertions, michael@0: mCoalesceDuplicateArcs); michael@0: michael@0: if (! *aResult) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: bool aTruthValue, michael@0: nsIRDFNode** aResult) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (! mAllowNegativeAssertions && ! aTruthValue) michael@0: return(NS_RDF_NO_VALUE); michael@0: michael@0: int32_t count = mDataSources.Count(); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: nsresult rv; michael@0: rv = mDataSources[i]->GetTarget(aSource, aProperty, aTruthValue, michael@0: aResult); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (rv == NS_OK) { michael@0: // okay, found it. make sure we don't have the opposite michael@0: // asserted in an earlier data source michael@0: michael@0: if (mAllowNegativeAssertions) { michael@0: if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) { michael@0: // whoops, it's been negated. michael@0: NS_RELEASE(*aResult); michael@0: return NS_RDF_NO_VALUE; michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: // Otherwise, we couldn't find it at all. michael@0: return NS_RDF_NO_VALUE; michael@0: } michael@0: michael@0: bool michael@0: CompositeDataSourceImpl::HasAssertionN(int n, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue) michael@0: { michael@0: nsresult rv; michael@0: for (int32_t m = 0; m < n; ++m) { michael@0: bool result; michael@0: rv = mDataSources[m]->HasAssertion(aSource, aProperty, aTarget, michael@0: aTruthValue, &result); michael@0: if (NS_FAILED(rv)) michael@0: return false; michael@0: michael@0: // found it! michael@0: if (result) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: bool aTruthValue, michael@0: nsISimpleEnumerator** aResult) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (! mAllowNegativeAssertions && ! aTruthValue) michael@0: return(NS_RDF_NO_VALUE); michael@0: michael@0: *aResult = michael@0: new CompositeAssertionEnumeratorImpl(this, michael@0: aSource, aProperty, nullptr, michael@0: aTruthValue, michael@0: mAllowNegativeAssertions, michael@0: mCoalesceDuplicateArcs); michael@0: michael@0: if (! *aResult) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(*aResult); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::Assert(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aTarget != nullptr, "null ptr"); michael@0: if (! aTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (! mAllowNegativeAssertions && ! aTruthValue) michael@0: return(NS_RDF_ASSERTION_REJECTED); michael@0: michael@0: nsresult rv; michael@0: michael@0: // XXX Need to add back the stuff for unblocking ... michael@0: michael@0: // We iterate backwards from the last data source which was added michael@0: // ("the most remote") to the first ("the most local"), trying to michael@0: // apply the assertion in each. michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, aTruthValue); michael@0: if (NS_RDF_ASSERTION_ACCEPTED == rv) michael@0: return rv; michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: // nobody wanted to accept it michael@0: return NS_RDF_ASSERTION_REJECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::Unassert(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aTarget != nullptr, "null ptr"); michael@0: if (! aTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: // Iterate through each of the datasources, starting with "the michael@0: // most local" and moving to "the most remote". If _any_ of the michael@0: // datasources have the assertion, attempt to unassert it. michael@0: bool unasserted = true; michael@0: int32_t i; michael@0: int32_t count = mDataSources.Count(); michael@0: for (i = 0; i < count; ++i) { michael@0: nsIRDFDataSource* ds = mDataSources[i]; michael@0: michael@0: bool hasAssertion; michael@0: rv = ds->HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (hasAssertion) { michael@0: rv = ds->Unassert(aSource, aProperty, aTarget); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (rv != NS_RDF_ASSERTION_ACCEPTED) { michael@0: unasserted = false; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Either none of the datasources had it, or they were all willing michael@0: // to let it be unasserted. michael@0: if (unasserted) michael@0: return NS_RDF_ASSERTION_ACCEPTED; michael@0: michael@0: // If we get here, one of the datasources already had the michael@0: // assertion, and was adamant about not letting us remove michael@0: // it. Iterate from the "most local" to the "most remote" michael@0: // attempting to assert the negation... michael@0: for (i = 0; i < count; ++i) { michael@0: rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, false); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // Did it take? michael@0: if (rv == NS_RDF_ASSERTION_ACCEPTED) michael@0: return rv; michael@0: } michael@0: michael@0: // Couln't get anyone to accept the negation, either. michael@0: return NS_RDF_ASSERTION_REJECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::Change(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aOldTarget, michael@0: nsIRDFNode* aNewTarget) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aOldTarget != nullptr, "null ptr"); michael@0: if (! aOldTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aNewTarget != nullptr, "null ptr"); michael@0: if (! aNewTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: // XXX So we're assuming that a datasource _must_ accept the michael@0: // atomic change; i.e., we can't split it up across two michael@0: // datasources. That sucks. michael@0: michael@0: // We iterate backwards from the last data source which was added michael@0: // ("the most remote") to the first ("the most local"), trying to michael@0: // apply the change in each. michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: rv = mDataSources[i]->Change(aSource, aProperty, aOldTarget, aNewTarget); michael@0: if (NS_RDF_ASSERTION_ACCEPTED == rv) michael@0: return rv; michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: // nobody wanted to accept it michael@0: return NS_RDF_ASSERTION_REJECTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::Move(nsIRDFResource* aOldSource, michael@0: nsIRDFResource* aNewSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget) michael@0: { michael@0: NS_PRECONDITION(aOldSource != nullptr, "null ptr"); michael@0: if (! aOldSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aNewSource != nullptr, "null ptr"); michael@0: if (! aNewSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aTarget != nullptr, "null ptr"); michael@0: if (! aTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsresult rv; michael@0: michael@0: // XXX So we're assuming that a datasource _must_ accept the michael@0: // atomic move; i.e., we can't split it up across two michael@0: // datasources. That sucks. michael@0: michael@0: // We iterate backwards from the last data source which was added michael@0: // ("the most remote") to the first ("the most local"), trying to michael@0: // apply the assertion in each. michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: rv = mDataSources[i]->Move(aOldSource, aNewSource, aProperty, aTarget); michael@0: if (NS_RDF_ASSERTION_ACCEPTED == rv) michael@0: return rv; michael@0: michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: } michael@0: michael@0: // nobody wanted to accept it michael@0: return NS_RDF_ASSERTION_REJECTED; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget, michael@0: bool aTruthValue, michael@0: bool* aResult) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aProperty != nullptr, "null ptr"); michael@0: if (! aProperty) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: if (! mAllowNegativeAssertions && ! aTruthValue) michael@0: { michael@0: *aResult = false; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: nsresult rv; michael@0: michael@0: // Otherwise, look through all the data sources to see if anyone michael@0: // has the positive... michael@0: int32_t count = mDataSources.Count(); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: nsIRDFDataSource* datasource = mDataSources[i]; michael@0: rv = datasource->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (*aResult) michael@0: return NS_OK; michael@0: michael@0: if (mAllowNegativeAssertions) michael@0: { michael@0: bool hasNegation; michael@0: rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (hasNegation) michael@0: { michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // If we get here, nobody had the assertion at all michael@0: *aResult = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::AddObserver(nsIRDFObserver* aObserver) michael@0: { michael@0: NS_PRECONDITION(aObserver != nullptr, "null ptr"); michael@0: if (! aObserver) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: // XXX ensure uniqueness? michael@0: mObservers.AppendObject(aObserver); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::RemoveObserver(nsIRDFObserver* aObserver) michael@0: { michael@0: NS_PRECONDITION(aObserver != nullptr, "null ptr"); michael@0: if (! aObserver) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: mObservers.RemoveObject(aObserver); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) michael@0: { michael@0: nsresult rv; michael@0: *result = false; michael@0: int32_t count = mDataSources.Count(); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: rv = mDataSources[i]->HasArcIn(aNode, aArc, result); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (*result) michael@0: return NS_OK; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result) michael@0: { michael@0: nsresult rv; michael@0: *result = false; michael@0: int32_t count = mDataSources.Count(); michael@0: for (int32_t i = 0; i < count; ++i) { michael@0: rv = mDataSources[i]->HasArcOut(aSource, aArc, result); michael@0: if (NS_FAILED(rv)) return rv; michael@0: if (*result) michael@0: return NS_OK; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult) michael@0: { michael@0: NS_PRECONDITION(aTarget != nullptr, "null ptr"); michael@0: if (! aTarget) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsISimpleEnumerator* result = michael@0: new CompositeArcsInOutEnumeratorImpl(this, aTarget, michael@0: CompositeArcsInOutEnumeratorImpl::eArcsIn, michael@0: mAllowNegativeAssertions, michael@0: mCoalesceDuplicateArcs); michael@0: michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(result); michael@0: *aResult = result; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource, michael@0: nsISimpleEnumerator** aResult) michael@0: { michael@0: NS_PRECONDITION(aSource != nullptr, "null ptr"); michael@0: if (! aSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: NS_PRECONDITION(aResult != nullptr, "null ptr"); michael@0: if (! aResult) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: nsISimpleEnumerator* result = michael@0: new CompositeArcsInOutEnumeratorImpl(this, aSource, michael@0: CompositeArcsInOutEnumeratorImpl::eArcsOut, michael@0: mAllowNegativeAssertions, michael@0: mCoalesceDuplicateArcs); michael@0: michael@0: if (! result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: NS_ADDREF(result); michael@0: *aResult = result; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetAllResources(nsISimpleEnumerator** aResult) michael@0: { michael@0: NS_NOTYETIMPLEMENTED("CompositeDataSourceImpl::GetAllResources"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetAllCmds(nsIRDFResource* source, michael@0: nsISimpleEnumerator/**/** result) michael@0: { michael@0: nsresult rv; michael@0: nsCOMPtr set; michael@0: michael@0: for (int32_t i = 0; i < mDataSources.Count(); i++) michael@0: { michael@0: nsCOMPtr dsCmds; michael@0: michael@0: rv = mDataSources[i]->GetAllCmds(source, getter_AddRefs(dsCmds)); michael@0: if (NS_SUCCEEDED(rv)) michael@0: { michael@0: nsCOMPtr tmp; michael@0: rv = NS_NewUnionEnumerator(getter_AddRefs(tmp), set, dsCmds); michael@0: set.swap(tmp); michael@0: if (NS_FAILED(rv)) return(rv); michael@0: } michael@0: } michael@0: michael@0: set.forget(result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::IsCommandEnabled(nsISupportsArray/**/* aSources, michael@0: nsIRDFResource* aCommand, michael@0: nsISupportsArray/**/* aArguments, michael@0: bool* aResult) michael@0: { michael@0: nsresult rv; michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: bool enabled = true; michael@0: rv = mDataSources[i]->IsCommandEnabled(aSources, aCommand, aArguments, &enabled); michael@0: if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED)) michael@0: { michael@0: return(rv); michael@0: } michael@0: michael@0: if (! enabled) { michael@0: *aResult = false; michael@0: return(NS_OK); michael@0: } michael@0: } michael@0: *aResult = true; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::DoCommand(nsISupportsArray/**/* aSources, michael@0: nsIRDFResource* aCommand, michael@0: nsISupportsArray/**/* aArguments) michael@0: { michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: nsresult rv = mDataSources[i]->DoCommand(aSources, aCommand, aArguments); michael@0: if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED)) michael@0: { michael@0: return(rv); // all datasources must succeed michael@0: } michael@0: } michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::BeginUpdateBatch() michael@0: { michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: mDataSources[i]->BeginUpdateBatch(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::EndUpdateBatch() michael@0: { michael@0: for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) { michael@0: mDataSources[i]->EndUpdateBatch(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////// michael@0: // nsIRDFCompositeDataSource methods michael@0: // XXX rvg We should make this take an additional argument specifying where michael@0: // in the sequence of data sources (of the db), the new data source should michael@0: // fit in. Right now, the new datasource gets stuck at the end. michael@0: // need to add the observers of the CompositeDataSourceImpl to the new data source. michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetAllowNegativeAssertions(bool *aAllowNegativeAssertions) michael@0: { michael@0: *aAllowNegativeAssertions = mAllowNegativeAssertions; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::SetAllowNegativeAssertions(bool aAllowNegativeAssertions) michael@0: { michael@0: mAllowNegativeAssertions = aAllowNegativeAssertions; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetCoalesceDuplicateArcs(bool *aCoalesceDuplicateArcs) michael@0: { michael@0: *aCoalesceDuplicateArcs = mCoalesceDuplicateArcs; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::SetCoalesceDuplicateArcs(bool aCoalesceDuplicateArcs) michael@0: { michael@0: mCoalesceDuplicateArcs = aCoalesceDuplicateArcs; michael@0: return(NS_OK); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource) michael@0: { michael@0: NS_ASSERTION(aDataSource != nullptr, "null ptr"); michael@0: if (! aDataSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: mDataSources.AppendObject(aDataSource); michael@0: aDataSource->AddObserver(this); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::RemoveDataSource(nsIRDFDataSource* aDataSource) michael@0: { michael@0: NS_ASSERTION(aDataSource != nullptr, "null ptr"); michael@0: if (! aDataSource) michael@0: return NS_ERROR_NULL_POINTER; michael@0: michael@0: michael@0: if (mDataSources.IndexOf(aDataSource) >= 0) { michael@0: aDataSource->RemoveObserver(this); michael@0: mDataSources.RemoveObject(aDataSource); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::GetDataSources(nsISimpleEnumerator** _result) michael@0: { michael@0: // NS_NewArrayEnumerator for an nsCOMArray takes a snapshot of the michael@0: // current state. michael@0: return NS_NewArrayEnumerator(_result, mDataSources); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget) michael@0: { michael@0: // Make sure that the assertion isn't masked by another michael@0: // datasource. michael@0: // michael@0: // XXX We could make this more efficient if we knew _which_ michael@0: // datasource actually served up the OnAssert(): we could use michael@0: // HasAssertionN() to only search datasources _before_ the michael@0: // datasource that coughed up the assertion. michael@0: nsresult rv = NS_OK; michael@0: michael@0: if (mAllowNegativeAssertions) michael@0: { michael@0: bool hasAssertion; michael@0: rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (! hasAssertion) michael@0: return(NS_OK); michael@0: } michael@0: michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnAssert(this, aSource, aProperty, aTarget); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget) michael@0: { michael@0: // Make sure that the un-assertion doesn't just unmask the michael@0: // same assertion in a different datasource. michael@0: // michael@0: // XXX We could make this more efficient if we knew _which_ michael@0: // datasource actually served up the OnAssert(): we could use michael@0: // HasAssertionN() to only search datasources _before_ the michael@0: // datasource that coughed up the assertion. michael@0: nsresult rv; michael@0: michael@0: if (mAllowNegativeAssertions) michael@0: { michael@0: bool hasAssertion; michael@0: rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: if (hasAssertion) michael@0: return NS_OK; michael@0: } michael@0: michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource, michael@0: nsIRDFResource* aSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aOldTarget, michael@0: nsIRDFNode* aNewTarget) michael@0: { michael@0: // Make sure that the change is actually visible, and not hidden michael@0: // by an assertion in a different datasource. michael@0: // michael@0: // XXX Because of aggregation, this could actually mutate into a michael@0: // variety of OnAssert or OnChange notifications, which we'll michael@0: // ignore for now :-/. michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnChange(this, aSource, aProperty, michael@0: aOldTarget, aNewTarget); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource, michael@0: nsIRDFResource* aOldSource, michael@0: nsIRDFResource* aNewSource, michael@0: nsIRDFResource* aProperty, michael@0: nsIRDFNode* aTarget) michael@0: { michael@0: // Make sure that the move is actually visible, and not hidden michael@0: // by an assertion in a different datasource. michael@0: // michael@0: // XXX Because of aggregation, this could actually mutate into a michael@0: // variety of OnAssert or OnMove notifications, which we'll michael@0: // ignore for now :-/. michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnMove(this, aOldSource, aNewSource, michael@0: aProperty, aTarget); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource) michael@0: { michael@0: if (mUpdateBatchNest++ == 0) { michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnBeginUpdateBatch(this); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource) michael@0: { michael@0: NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch"); michael@0: if (--mUpdateBatchNest == 0) { michael@0: for (int32_t i = mObservers.Count() - 1; i >= 0; --i) { michael@0: mObservers[i]->OnEndUpdateBatch(this); michael@0: } michael@0: } michael@0: return NS_OK; michael@0: }