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