rdf/base/src/nsCompositeDataSource.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rdf/base/src/nsCompositeDataSource.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1364 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +/*
    1.10 +
    1.11 +  A simple composite data source implementation. A composit data
    1.12 +  source is just a strategy for combining individual data sources into
    1.13 +  a collective graph.
    1.14 +
    1.15 +
    1.16 +  1) A composite data source holds a sequence of data sources. The set
    1.17 +     of data sources can be specified during creation of the
    1.18 +     database. Data sources can also be added/deleted from a database
    1.19 +     later.
    1.20 +
    1.21 +  2) The aggregation mechanism is based on simple super-positioning of
    1.22 +     the graphs from the datasources. If there is a conflict (i.e., 
    1.23 +     data source A has a true arc from foo to bar while data source B
    1.24 +     has a false arc from foo to bar), the data source that it earlier
    1.25 +     in the sequence wins.
    1.26 +
    1.27 +     The implementation below doesn't really do this and needs to be
    1.28 +     fixed.
    1.29 +
    1.30 +*/
    1.31 +
    1.32 +#include "xpcom-config.h"
    1.33 +#include "nsCOMPtr.h"
    1.34 +#include "nsIComponentManager.h"
    1.35 +#include "nsIRDFCompositeDataSource.h"
    1.36 +#include "nsIRDFNode.h"
    1.37 +#include "nsIRDFObserver.h"
    1.38 +#include "nsIRDFRemoteDataSource.h"
    1.39 +#include "nsTArray.h"
    1.40 +#include "nsCOMArray.h"
    1.41 +#include "nsArrayEnumerator.h"
    1.42 +#include "nsXPIDLString.h"
    1.43 +#include "rdf.h"
    1.44 +#include "nsCycleCollectionParticipant.h"
    1.45 +
    1.46 +#include "nsEnumeratorUtils.h"
    1.47 +
    1.48 +#ifdef PR_LOGGING
    1.49 +#include "prlog.h"
    1.50 +#include "prprf.h"
    1.51 +#include <stdio.h>
    1.52 +PRLogModuleInfo* nsRDFLog = nullptr;
    1.53 +#endif
    1.54 +
    1.55 +//----------------------------------------------------------------------
    1.56 +//
    1.57 +// CompositeDataSourceImpl
    1.58 +//
    1.59 +
    1.60 +class CompositeEnumeratorImpl;
    1.61 +class CompositeArcsInOutEnumeratorImpl;
    1.62 +class CompositeAssertionEnumeratorImpl;
    1.63 +
    1.64 +class CompositeDataSourceImpl : public nsIRDFCompositeDataSource,
    1.65 +                                public nsIRDFObserver
    1.66 +{
    1.67 +public:
    1.68 +    CompositeDataSourceImpl(void);
    1.69 +    CompositeDataSourceImpl(char** dataSources);
    1.70 +
    1.71 +    // nsISupports interface
    1.72 +    NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    1.73 +    NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CompositeDataSourceImpl,
    1.74 +                                             nsIRDFCompositeDataSource)
    1.75 +
    1.76 +    // nsIRDFDataSource interface
    1.77 +    NS_DECL_NSIRDFDATASOURCE
    1.78 +
    1.79 +    // nsIRDFCompositeDataSource interface
    1.80 +    NS_DECL_NSIRDFCOMPOSITEDATASOURCE
    1.81 +
    1.82 +    // nsIRDFObserver interface
    1.83 +    NS_DECL_NSIRDFOBSERVER
    1.84 +
    1.85 +    bool HasAssertionN(int n, nsIRDFResource* source,
    1.86 +                            nsIRDFResource* property,
    1.87 +                            nsIRDFNode* target,
    1.88 +                            bool tv);
    1.89 +
    1.90 +protected:
    1.91 +    nsCOMArray<nsIRDFObserver> mObservers;
    1.92 +    nsCOMArray<nsIRDFDataSource> mDataSources;
    1.93 +
    1.94 +    bool        mAllowNegativeAssertions;
    1.95 +    bool        mCoalesceDuplicateArcs;
    1.96 +    int32_t     mUpdateBatchNest;
    1.97 +
    1.98 +    virtual ~CompositeDataSourceImpl() {}
    1.99 +
   1.100 +    friend class CompositeEnumeratorImpl;
   1.101 +    friend class CompositeArcsInOutEnumeratorImpl;
   1.102 +    friend class CompositeAssertionEnumeratorImpl;
   1.103 +};
   1.104 +
   1.105 +//----------------------------------------------------------------------
   1.106 +//
   1.107 +// CompositeEnumeratorImpl
   1.108 +//
   1.109 +
   1.110 +class CompositeEnumeratorImpl : public nsISimpleEnumerator
   1.111 +{
   1.112 +    // nsISupports
   1.113 +    NS_DECL_ISUPPORTS
   1.114 +
   1.115 +    // nsISimpleEnumerator interface
   1.116 +    NS_DECL_NSISIMPLEENUMERATOR
   1.117 +
   1.118 +    // pure abstract methods to be overridden
   1.119 +    virtual nsresult
   1.120 +    GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult) = 0;
   1.121 +
   1.122 +    virtual nsresult
   1.123 +    HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult) = 0;
   1.124 +
   1.125 +protected:
   1.126 +    CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
   1.127 +                            bool aAllowNegativeAssertions,
   1.128 +                            bool aCoalesceDuplicateArcs);
   1.129 +
   1.130 +    virtual ~CompositeEnumeratorImpl();
   1.131 +
   1.132 +    CompositeDataSourceImpl* mCompositeDataSource;
   1.133 +
   1.134 +    nsISimpleEnumerator* mCurrent;
   1.135 +    nsIRDFNode*  mResult;
   1.136 +    int32_t      mNext;
   1.137 +    nsAutoTArray<nsCOMPtr<nsIRDFNode>, 8>  mAlreadyReturned;
   1.138 +    bool mAllowNegativeAssertions;
   1.139 +    bool mCoalesceDuplicateArcs;
   1.140 +};
   1.141 +
   1.142 +
   1.143 +CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
   1.144 +                                                 bool aAllowNegativeAssertions,
   1.145 +                                                 bool aCoalesceDuplicateArcs)
   1.146 +    : mCompositeDataSource(aCompositeDataSource),
   1.147 +      mCurrent(nullptr),
   1.148 +      mResult(nullptr),
   1.149 +	  mNext(0),
   1.150 +      mAllowNegativeAssertions(aAllowNegativeAssertions),
   1.151 +      mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
   1.152 +{
   1.153 +    NS_ADDREF(mCompositeDataSource);
   1.154 +}
   1.155 +
   1.156 +
   1.157 +CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void)
   1.158 +{
   1.159 +    NS_IF_RELEASE(mCurrent);
   1.160 +    NS_IF_RELEASE(mResult);
   1.161 +    NS_RELEASE(mCompositeDataSource);
   1.162 +}
   1.163 +
   1.164 +NS_IMPL_ADDREF(CompositeEnumeratorImpl)
   1.165 +NS_IMPL_RELEASE(CompositeEnumeratorImpl)
   1.166 +NS_IMPL_QUERY_INTERFACE(CompositeEnumeratorImpl, nsISimpleEnumerator)
   1.167 +
   1.168 +NS_IMETHODIMP
   1.169 +CompositeEnumeratorImpl::HasMoreElements(bool* aResult)
   1.170 +{
   1.171 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.172 +    if (! aResult)
   1.173 +        return NS_ERROR_NULL_POINTER;
   1.174 +
   1.175 +    nsresult rv;
   1.176 +
   1.177 +    // If we've already queued up a next target, then yep, there are
   1.178 +    // more elements.
   1.179 +    if (mResult) {
   1.180 +        *aResult = true;
   1.181 +        return NS_OK;
   1.182 +    }
   1.183 +
   1.184 +    // Otherwise, we'll need to find a next target, switching cursors
   1.185 +    // if necessary.
   1.186 +    for ( ; mNext < mCompositeDataSource->mDataSources.Count(); ++mNext) {
   1.187 +        if (! mCurrent) {
   1.188 +            // We don't have a current enumerator, so create a new one on
   1.189 +            // the next data source.
   1.190 +            nsIRDFDataSource* datasource =
   1.191 +                mCompositeDataSource->mDataSources[mNext];
   1.192 +
   1.193 +            rv = GetEnumerator(datasource, &mCurrent);
   1.194 +            if (NS_FAILED(rv)) return rv;
   1.195 +            if (rv == NS_RDF_NO_VALUE)
   1.196 +                continue;
   1.197 +
   1.198 +            NS_ASSERTION(mCurrent != nullptr, "you're always supposed to return an enumerator from GetEnumerator, punk.");
   1.199 +            if (! mCurrent)
   1.200 +                continue;
   1.201 +        }
   1.202 +
   1.203 +        do {
   1.204 +            int32_t i;
   1.205 +
   1.206 +            bool hasMore;
   1.207 +            rv = mCurrent->HasMoreElements(&hasMore);
   1.208 +            if (NS_FAILED(rv)) return rv;
   1.209 +
   1.210 +            // Is the current enumerator depleted?
   1.211 +            if (! hasMore) {
   1.212 +                NS_RELEASE(mCurrent);
   1.213 +                break;
   1.214 +            }
   1.215 +
   1.216 +            // Even if the current enumerator has more elements, we still
   1.217 +            // need to check that the current element isn't masked by
   1.218 +            // a negation in an earlier data source.
   1.219 +
   1.220 +            // "Peek" ahead and pull out the next target.
   1.221 +            nsCOMPtr<nsISupports> result;
   1.222 +            rv = mCurrent->GetNext(getter_AddRefs(result));
   1.223 +            if (NS_FAILED(rv)) return rv;
   1.224 +
   1.225 +            rv = result->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) &mResult);
   1.226 +            if (NS_FAILED(rv)) return rv;
   1.227 +
   1.228 +            if (mAllowNegativeAssertions)
   1.229 +            {
   1.230 +                // See if any previous data source negates this
   1.231 +                bool hasNegation = false;
   1.232 +                for (i = mNext - 1; i >= 0; --i)
   1.233 +                {
   1.234 +                    nsIRDFDataSource* datasource =
   1.235 +                        mCompositeDataSource->mDataSources[i];
   1.236 +
   1.237 +                    rv = HasNegation(datasource, mResult, &hasNegation);
   1.238 +                    if (NS_FAILED(rv)) return rv;
   1.239 +
   1.240 +                    if (hasNegation)
   1.241 +                        break;
   1.242 +                }
   1.243 +
   1.244 +                // if so, we've gotta keep looking
   1.245 +                if (hasNegation)
   1.246 +                {
   1.247 +                    NS_RELEASE(mResult);
   1.248 +                    continue;
   1.249 +                }
   1.250 +            }
   1.251 +
   1.252 +            if (mCoalesceDuplicateArcs)
   1.253 +            {
   1.254 +                // Now see if we've returned it once already.
   1.255 +                // XXX N.B. performance here...may want to hash if things get large?
   1.256 +                bool alreadyReturned = false;
   1.257 +                for (i = mAlreadyReturned.Length() - 1; i >= 0; --i)
   1.258 +                {
   1.259 +                    if (mAlreadyReturned[i] == mResult)
   1.260 +                    {
   1.261 +                        alreadyReturned = true;
   1.262 +                        break;
   1.263 +                    }
   1.264 +                }
   1.265 +                if (alreadyReturned)
   1.266 +                {
   1.267 +                    NS_RELEASE(mResult);
   1.268 +                    continue;
   1.269 +                }
   1.270 +            }
   1.271 +
   1.272 +            // If we get here, then we've really found one. It'll
   1.273 +            // remain cached in mResult until GetNext() sucks it out.
   1.274 +            *aResult = true;
   1.275 +
   1.276 +            // Remember that we returned it, so we don't return duplicates.
   1.277 +
   1.278 +            // XXX I wonder if we should make unique-checking be
   1.279 +            // optional. This could get to be pretty expensive (this
   1.280 +            // implementation turns iteration into O(n^2)).
   1.281 +
   1.282 +            if (mCoalesceDuplicateArcs)
   1.283 +            {
   1.284 +                mAlreadyReturned.AppendElement(mResult);
   1.285 +            }
   1.286 +
   1.287 +            return NS_OK;
   1.288 +        } while (1);
   1.289 +    }
   1.290 +
   1.291 +    // if we get here, there aren't any elements left.
   1.292 +    *aResult = false;
   1.293 +    return NS_OK;
   1.294 +}
   1.295 +
   1.296 +
   1.297 +NS_IMETHODIMP
   1.298 +CompositeEnumeratorImpl::GetNext(nsISupports** aResult)
   1.299 +{
   1.300 +    nsresult rv;
   1.301 +
   1.302 +    bool hasMore;
   1.303 +    rv = HasMoreElements(&hasMore);
   1.304 +    if (NS_FAILED(rv)) return rv;
   1.305 +
   1.306 +    if (! hasMore)
   1.307 +        return NS_ERROR_UNEXPECTED;
   1.308 +
   1.309 +    // Don't AddRef: we "transfer" ownership to the caller
   1.310 +    *aResult = mResult;
   1.311 +    mResult = nullptr;
   1.312 +
   1.313 +    return NS_OK;
   1.314 +}
   1.315 +
   1.316 +//----------------------------------------------------------------------
   1.317 +//
   1.318 +// CompositeArcsInOutEnumeratorImpl
   1.319 +//
   1.320 +//
   1.321 +
   1.322 +class CompositeArcsInOutEnumeratorImpl : public CompositeEnumeratorImpl
   1.323 +{
   1.324 +public:
   1.325 +    enum Type { eArcsIn, eArcsOut };
   1.326 +
   1.327 +    virtual ~CompositeArcsInOutEnumeratorImpl();
   1.328 +
   1.329 +    virtual nsresult
   1.330 +    GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
   1.331 +
   1.332 +    virtual nsresult
   1.333 +    HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
   1.334 +
   1.335 +    CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
   1.336 +                                     nsIRDFNode* aNode,
   1.337 +                                     Type aType,
   1.338 +                                     bool aAllowNegativeAssertions,
   1.339 +                                     bool aCoalesceDuplicateArcs);
   1.340 +
   1.341 +private:
   1.342 +    nsIRDFNode* mNode;
   1.343 +    Type        mType;
   1.344 +};
   1.345 +
   1.346 +
   1.347 +CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl(
   1.348 +                CompositeDataSourceImpl* aCompositeDataSource,
   1.349 +                nsIRDFNode* aNode,
   1.350 +                Type aType,
   1.351 +                bool aAllowNegativeAssertions,
   1.352 +                bool aCoalesceDuplicateArcs)
   1.353 +    : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
   1.354 +      mNode(aNode),
   1.355 +      mType(aType)
   1.356 +{
   1.357 +    NS_ADDREF(mNode);
   1.358 +}
   1.359 +
   1.360 +CompositeArcsInOutEnumeratorImpl::~CompositeArcsInOutEnumeratorImpl()
   1.361 +{
   1.362 +    NS_RELEASE(mNode);
   1.363 +}
   1.364 +
   1.365 +
   1.366 +nsresult
   1.367 +CompositeArcsInOutEnumeratorImpl::GetEnumerator(
   1.368 +                 nsIRDFDataSource* aDataSource,
   1.369 +                 nsISimpleEnumerator** aResult)
   1.370 +{
   1.371 +    if (mType == eArcsIn) {
   1.372 +        return aDataSource->ArcLabelsIn(mNode, aResult);
   1.373 +    }
   1.374 +    else {
   1.375 +        nsCOMPtr<nsIRDFResource> resource( do_QueryInterface(mNode) );
   1.376 +        return aDataSource->ArcLabelsOut(resource, aResult);
   1.377 +    }
   1.378 +}
   1.379 +
   1.380 +nsresult
   1.381 +CompositeArcsInOutEnumeratorImpl::HasNegation(
   1.382 +                 nsIRDFDataSource* aDataSource,
   1.383 +                 nsIRDFNode* aNode,
   1.384 +                 bool* aResult)
   1.385 +{
   1.386 +    *aResult = false;
   1.387 +    return NS_OK;
   1.388 +}
   1.389 +
   1.390 +
   1.391 +//----------------------------------------------------------------------
   1.392 +//
   1.393 +// CompositeAssertionEnumeratorImpl
   1.394 +//
   1.395 +
   1.396 +class CompositeAssertionEnumeratorImpl : public CompositeEnumeratorImpl
   1.397 +{
   1.398 +public:
   1.399 +    virtual nsresult
   1.400 +    GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
   1.401 +
   1.402 +    virtual nsresult
   1.403 +    HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
   1.404 +
   1.405 +    CompositeAssertionEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
   1.406 +                                     nsIRDFResource* aSource,
   1.407 +                                     nsIRDFResource* aProperty,
   1.408 +                                     nsIRDFNode* aTarget,
   1.409 +                                     bool aTruthValue,
   1.410 +                                     bool aAllowNegativeAssertions,
   1.411 +                                     bool aCoalesceDuplicateArcs);
   1.412 +
   1.413 +    virtual ~CompositeAssertionEnumeratorImpl();
   1.414 +
   1.415 +private:
   1.416 +    nsIRDFResource* mSource;
   1.417 +    nsIRDFResource* mProperty;
   1.418 +    nsIRDFNode*     mTarget;
   1.419 +    bool            mTruthValue;
   1.420 +};
   1.421 +
   1.422 +
   1.423 +CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl(
   1.424 +                  CompositeDataSourceImpl* aCompositeDataSource,
   1.425 +                  nsIRDFResource* aSource,
   1.426 +                  nsIRDFResource* aProperty,
   1.427 +                  nsIRDFNode* aTarget,
   1.428 +                  bool aTruthValue,
   1.429 +                  bool aAllowNegativeAssertions,
   1.430 +                  bool aCoalesceDuplicateArcs)
   1.431 +    : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
   1.432 +      mSource(aSource),
   1.433 +      mProperty(aProperty),
   1.434 +      mTarget(aTarget),
   1.435 +      mTruthValue(aTruthValue)
   1.436 +{
   1.437 +    NS_IF_ADDREF(mSource);
   1.438 +    NS_ADDREF(mProperty); // always must be specified
   1.439 +    NS_IF_ADDREF(mTarget);
   1.440 +}
   1.441 +
   1.442 +CompositeAssertionEnumeratorImpl::~CompositeAssertionEnumeratorImpl()
   1.443 +{
   1.444 +    NS_IF_RELEASE(mSource);
   1.445 +    NS_RELEASE(mProperty);
   1.446 +    NS_IF_RELEASE(mTarget);
   1.447 +}
   1.448 +
   1.449 +
   1.450 +nsresult
   1.451 +CompositeAssertionEnumeratorImpl::GetEnumerator(
   1.452 +                 nsIRDFDataSource* aDataSource,
   1.453 +                 nsISimpleEnumerator** aResult)
   1.454 +{
   1.455 +    if (mSource) {
   1.456 +        return aDataSource->GetTargets(mSource, mProperty, mTruthValue, aResult);
   1.457 +    }
   1.458 +    else {
   1.459 +        return aDataSource->GetSources(mProperty, mTarget, mTruthValue, aResult);
   1.460 +    }
   1.461 +}
   1.462 +
   1.463 +nsresult
   1.464 +CompositeAssertionEnumeratorImpl::HasNegation(
   1.465 +                 nsIRDFDataSource* aDataSource,
   1.466 +                 nsIRDFNode* aNode,
   1.467 +                 bool* aResult)
   1.468 +{
   1.469 +    if (mSource) {
   1.470 +        return aDataSource->HasAssertion(mSource, mProperty, aNode, !mTruthValue, aResult);
   1.471 +    }
   1.472 +    else {
   1.473 +        nsCOMPtr<nsIRDFResource> source( do_QueryInterface(aNode) );
   1.474 +        return aDataSource->HasAssertion(source, mProperty, mTarget, !mTruthValue, aResult);
   1.475 +    }
   1.476 +}
   1.477 +
   1.478 +////////////////////////////////////////////////////////////////////////
   1.479 +
   1.480 +nsresult
   1.481 +NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result)
   1.482 +{
   1.483 +    CompositeDataSourceImpl* db = new CompositeDataSourceImpl();
   1.484 +    if (! db)
   1.485 +        return NS_ERROR_OUT_OF_MEMORY;
   1.486 +
   1.487 +    *result = db;
   1.488 +    NS_ADDREF(*result);
   1.489 +    return NS_OK;
   1.490 +}
   1.491 +
   1.492 +
   1.493 +CompositeDataSourceImpl::CompositeDataSourceImpl(void)
   1.494 +	: mAllowNegativeAssertions(true),
   1.495 +	  mCoalesceDuplicateArcs(true),
   1.496 +      mUpdateBatchNest(0)
   1.497 +{
   1.498 +#ifdef PR_LOGGING
   1.499 +    if (nsRDFLog == nullptr) 
   1.500 +        nsRDFLog = PR_NewLogModule("RDF");
   1.501 +#endif
   1.502 +}
   1.503 +
   1.504 +//----------------------------------------------------------------------
   1.505 +//
   1.506 +// nsISupports interface
   1.507 +//
   1.508 +
   1.509 +NS_IMPL_CYCLE_COLLECTION_CLASS(CompositeDataSourceImpl)
   1.510 +
   1.511 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CompositeDataSourceImpl)
   1.512 +    uint32_t i, count = tmp->mDataSources.Count();
   1.513 +    for (i = count; i > 0; --i) {
   1.514 +        tmp->mDataSources[i - 1]->RemoveObserver(tmp);
   1.515 +        tmp->mDataSources.RemoveObjectAt(i - 1);
   1.516 +    }
   1.517 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers);
   1.518 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.519 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CompositeDataSourceImpl)
   1.520 +    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
   1.521 +    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataSources)
   1.522 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.523 +
   1.524 +
   1.525 +NS_IMPL_CYCLE_COLLECTING_ADDREF(CompositeDataSourceImpl)
   1.526 +NS_IMPL_CYCLE_COLLECTING_RELEASE(CompositeDataSourceImpl)
   1.527 +
   1.528 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositeDataSourceImpl)
   1.529 +    NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
   1.530 +    NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
   1.531 +    NS_INTERFACE_MAP_ENTRY(nsIRDFObserver)
   1.532 +    NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
   1.533 +    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFCompositeDataSource)
   1.534 +NS_INTERFACE_MAP_END
   1.535 +
   1.536 +
   1.537 +//----------------------------------------------------------------------
   1.538 +//
   1.539 +// nsIRDFDataSource interface
   1.540 +//
   1.541 +
   1.542 +NS_IMETHODIMP
   1.543 +CompositeDataSourceImpl::GetURI(char* *uri)
   1.544 +{
   1.545 +    *uri = nullptr;
   1.546 +    return NS_OK;
   1.547 +}
   1.548 +
   1.549 +NS_IMETHODIMP
   1.550 +CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
   1.551 +                                   nsIRDFNode* target,
   1.552 +                                   bool tv,
   1.553 +                                   nsIRDFResource** source)
   1.554 +{
   1.555 +	if (!mAllowNegativeAssertions && !tv)
   1.556 +		return(NS_RDF_NO_VALUE);
   1.557 +
   1.558 +    int32_t count = mDataSources.Count();
   1.559 +    for (int32_t i = 0; i < count; ++i) {
   1.560 +        nsresult rv;
   1.561 +        rv = mDataSources[i]->GetSource(property, target, tv, source);
   1.562 +        if (NS_FAILED(rv)) return rv;
   1.563 +
   1.564 +        if (rv == NS_RDF_NO_VALUE)
   1.565 +            continue;
   1.566 +
   1.567 +        if (!mAllowNegativeAssertions) return(NS_OK);
   1.568 +
   1.569 +        // okay, found it. make sure we don't have the opposite
   1.570 +        // asserted in a more local data source
   1.571 +        if (!HasAssertionN(count-1, *source, property, target, !tv)) 
   1.572 +            return NS_OK;
   1.573 +
   1.574 +        NS_RELEASE(*source);
   1.575 +        return NS_RDF_NO_VALUE;
   1.576 +    }
   1.577 +    return NS_RDF_NO_VALUE;
   1.578 +}
   1.579 +
   1.580 +NS_IMETHODIMP
   1.581 +CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty,
   1.582 +                                    nsIRDFNode* aTarget,
   1.583 +                                    bool aTruthValue,
   1.584 +                                    nsISimpleEnumerator** aResult)
   1.585 +{
   1.586 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.587 +    if (! aProperty)
   1.588 +        return NS_ERROR_NULL_POINTER;
   1.589 +
   1.590 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
   1.591 +    if (! aTarget)
   1.592 +        return NS_ERROR_NULL_POINTER;
   1.593 +
   1.594 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.595 +    if (! aResult)
   1.596 +        return NS_ERROR_NULL_POINTER;
   1.597 +
   1.598 +    if (! mAllowNegativeAssertions && ! aTruthValue)
   1.599 +        return(NS_RDF_NO_VALUE);
   1.600 +
   1.601 +    *aResult = new CompositeAssertionEnumeratorImpl(this, nullptr, aProperty,
   1.602 +                                                    aTarget, aTruthValue,
   1.603 +                                                    mAllowNegativeAssertions,
   1.604 +                                                    mCoalesceDuplicateArcs);
   1.605 +
   1.606 +    if (! *aResult)
   1.607 +        return NS_ERROR_OUT_OF_MEMORY;
   1.608 +
   1.609 +    NS_ADDREF(*aResult);
   1.610 +    return NS_OK;
   1.611 +}
   1.612 +
   1.613 +NS_IMETHODIMP
   1.614 +CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
   1.615 +                                   nsIRDFResource* aProperty,
   1.616 +                                   bool aTruthValue,
   1.617 +                                   nsIRDFNode** aResult)
   1.618 +{
   1.619 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.620 +    if (! aSource)
   1.621 +        return NS_ERROR_NULL_POINTER;
   1.622 +
   1.623 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.624 +    if (! aProperty)
   1.625 +        return NS_ERROR_NULL_POINTER;
   1.626 +
   1.627 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.628 +    if (! aResult)
   1.629 +        return NS_ERROR_NULL_POINTER;
   1.630 +
   1.631 +    if (! mAllowNegativeAssertions && ! aTruthValue)
   1.632 +        return(NS_RDF_NO_VALUE);
   1.633 +
   1.634 +    int32_t count = mDataSources.Count();
   1.635 +    for (int32_t i = 0; i < count; ++i) {
   1.636 +        nsresult rv;
   1.637 +        rv = mDataSources[i]->GetTarget(aSource, aProperty, aTruthValue,
   1.638 +                                        aResult);
   1.639 +        if (NS_FAILED(rv))
   1.640 +            return rv;
   1.641 +
   1.642 +        if (rv == NS_OK) {
   1.643 +            // okay, found it. make sure we don't have the opposite
   1.644 +            // asserted in an earlier data source
   1.645 +
   1.646 +            if (mAllowNegativeAssertions) {
   1.647 +                if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
   1.648 +                    // whoops, it's been negated.
   1.649 +                    NS_RELEASE(*aResult);
   1.650 +                    return NS_RDF_NO_VALUE;
   1.651 +                }
   1.652 +            }
   1.653 +            return NS_OK;
   1.654 +        }
   1.655 +    }
   1.656 +
   1.657 +    // Otherwise, we couldn't find it at all.
   1.658 +    return NS_RDF_NO_VALUE;
   1.659 +}
   1.660 +
   1.661 +bool
   1.662 +CompositeDataSourceImpl::HasAssertionN(int n,
   1.663 +                                       nsIRDFResource* aSource,
   1.664 +                                       nsIRDFResource* aProperty,
   1.665 +                                       nsIRDFNode* aTarget,
   1.666 +                                       bool aTruthValue)
   1.667 +{
   1.668 +    nsresult rv;
   1.669 +    for (int32_t m = 0; m < n; ++m) {
   1.670 +        bool result;
   1.671 +        rv = mDataSources[m]->HasAssertion(aSource, aProperty, aTarget,
   1.672 +                                           aTruthValue, &result);
   1.673 +        if (NS_FAILED(rv))
   1.674 +            return false;
   1.675 +
   1.676 +        // found it!
   1.677 +        if (result)
   1.678 +            return true;
   1.679 +    }
   1.680 +    return false;
   1.681 +}
   1.682 +    
   1.683 +
   1.684 +
   1.685 +NS_IMETHODIMP
   1.686 +CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource,
   1.687 +                                    nsIRDFResource* aProperty,
   1.688 +                                    bool aTruthValue,
   1.689 +                                    nsISimpleEnumerator** aResult)
   1.690 +{
   1.691 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.692 +    if (! aSource)
   1.693 +        return NS_ERROR_NULL_POINTER;
   1.694 +
   1.695 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.696 +    if (! aProperty)
   1.697 +        return NS_ERROR_NULL_POINTER;
   1.698 +
   1.699 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.700 +    if (! aResult)
   1.701 +        return NS_ERROR_NULL_POINTER;
   1.702 +
   1.703 +    if (! mAllowNegativeAssertions && ! aTruthValue)
   1.704 +        return(NS_RDF_NO_VALUE);
   1.705 +
   1.706 +    *aResult =
   1.707 +        new CompositeAssertionEnumeratorImpl(this,
   1.708 +                                             aSource, aProperty, nullptr,
   1.709 +                                             aTruthValue,
   1.710 +                                             mAllowNegativeAssertions,
   1.711 +                                             mCoalesceDuplicateArcs);
   1.712 +
   1.713 +    if (! *aResult)
   1.714 +        return NS_ERROR_OUT_OF_MEMORY;
   1.715 +
   1.716 +    NS_ADDREF(*aResult);
   1.717 +    return NS_OK;
   1.718 +}
   1.719 +
   1.720 +NS_IMETHODIMP
   1.721 +CompositeDataSourceImpl::Assert(nsIRDFResource* aSource, 
   1.722 +                                nsIRDFResource* aProperty, 
   1.723 +                                nsIRDFNode* aTarget,
   1.724 +                                bool aTruthValue)
   1.725 +{
   1.726 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.727 +    if (! aSource)
   1.728 +        return NS_ERROR_NULL_POINTER;
   1.729 +
   1.730 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.731 +    if (! aProperty)
   1.732 +        return NS_ERROR_NULL_POINTER;
   1.733 +
   1.734 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
   1.735 +    if (! aTarget)
   1.736 +        return NS_ERROR_NULL_POINTER;
   1.737 +
   1.738 +    if (! mAllowNegativeAssertions && ! aTruthValue)
   1.739 +        return(NS_RDF_ASSERTION_REJECTED);
   1.740 +
   1.741 +    nsresult rv;
   1.742 +
   1.743 +    // XXX Need to add back the stuff for unblocking ...
   1.744 +
   1.745 +    // We iterate backwards from the last data source which was added
   1.746 +    // ("the most remote") to the first ("the most local"), trying to
   1.747 +    // apply the assertion in each.
   1.748 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
   1.749 +        rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, aTruthValue);
   1.750 +        if (NS_RDF_ASSERTION_ACCEPTED == rv)
   1.751 +            return rv;
   1.752 +
   1.753 +        if (NS_FAILED(rv))
   1.754 +            return rv;
   1.755 +    }
   1.756 +
   1.757 +    // nobody wanted to accept it
   1.758 +    return NS_RDF_ASSERTION_REJECTED;
   1.759 +}
   1.760 +
   1.761 +NS_IMETHODIMP
   1.762 +CompositeDataSourceImpl::Unassert(nsIRDFResource* aSource,
   1.763 +                                  nsIRDFResource* aProperty,
   1.764 +                                  nsIRDFNode* aTarget)
   1.765 +{
   1.766 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.767 +    if (! aSource)
   1.768 +        return NS_ERROR_NULL_POINTER;
   1.769 +
   1.770 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.771 +    if (! aProperty)
   1.772 +        return NS_ERROR_NULL_POINTER;
   1.773 +
   1.774 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
   1.775 +    if (! aTarget)
   1.776 +        return NS_ERROR_NULL_POINTER;
   1.777 +
   1.778 +    nsresult rv;
   1.779 +
   1.780 +    // Iterate through each of the datasources, starting with "the
   1.781 +    // most local" and moving to "the most remote". If _any_ of the
   1.782 +    // datasources have the assertion, attempt to unassert it.
   1.783 +    bool unasserted = true;
   1.784 +    int32_t i;
   1.785 +    int32_t count = mDataSources.Count();
   1.786 +    for (i = 0; i < count; ++i) {
   1.787 +        nsIRDFDataSource* ds = mDataSources[i];
   1.788 +
   1.789 +        bool hasAssertion;
   1.790 +        rv = ds->HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
   1.791 +        if (NS_FAILED(rv)) return rv;
   1.792 +
   1.793 +        if (hasAssertion) {
   1.794 +            rv = ds->Unassert(aSource, aProperty, aTarget);
   1.795 +            if (NS_FAILED(rv)) return rv;
   1.796 +
   1.797 +            if (rv != NS_RDF_ASSERTION_ACCEPTED) {
   1.798 +                unasserted = false;
   1.799 +                break;
   1.800 +            }
   1.801 +        }
   1.802 +    }
   1.803 +
   1.804 +    // Either none of the datasources had it, or they were all willing
   1.805 +    // to let it be unasserted.
   1.806 +    if (unasserted)
   1.807 +        return NS_RDF_ASSERTION_ACCEPTED;
   1.808 +
   1.809 +    // If we get here, one of the datasources already had the
   1.810 +    // assertion, and was adamant about not letting us remove
   1.811 +    // it. Iterate from the "most local" to the "most remote"
   1.812 +    // attempting to assert the negation...
   1.813 +    for (i = 0; i < count; ++i) {
   1.814 +        rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, false);
   1.815 +        if (NS_FAILED(rv)) return rv;
   1.816 +
   1.817 +        // Did it take?
   1.818 +        if (rv == NS_RDF_ASSERTION_ACCEPTED)
   1.819 +            return rv;
   1.820 +    }
   1.821 +
   1.822 +    // Couln't get anyone to accept the negation, either.
   1.823 +    return NS_RDF_ASSERTION_REJECTED;
   1.824 +}
   1.825 +
   1.826 +NS_IMETHODIMP
   1.827 +CompositeDataSourceImpl::Change(nsIRDFResource* aSource,
   1.828 +                                nsIRDFResource* aProperty,
   1.829 +                                nsIRDFNode* aOldTarget,
   1.830 +                                nsIRDFNode* aNewTarget)
   1.831 +{
   1.832 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.833 +    if (! aSource)
   1.834 +        return NS_ERROR_NULL_POINTER;
   1.835 +
   1.836 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.837 +    if (! aProperty)
   1.838 +        return NS_ERROR_NULL_POINTER;
   1.839 +
   1.840 +    NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
   1.841 +    if (! aOldTarget)
   1.842 +        return NS_ERROR_NULL_POINTER;
   1.843 +
   1.844 +    NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
   1.845 +    if (! aNewTarget)
   1.846 +        return NS_ERROR_NULL_POINTER;
   1.847 +
   1.848 +    nsresult rv;
   1.849 +
   1.850 +    // XXX So we're assuming that a datasource _must_ accept the
   1.851 +    // atomic change; i.e., we can't split it up across two
   1.852 +    // datasources. That sucks.
   1.853 +
   1.854 +    // We iterate backwards from the last data source which was added
   1.855 +    // ("the most remote") to the first ("the most local"), trying to
   1.856 +    // apply the change in each.
   1.857 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
   1.858 +        rv = mDataSources[i]->Change(aSource, aProperty, aOldTarget, aNewTarget);
   1.859 +        if (NS_RDF_ASSERTION_ACCEPTED == rv)
   1.860 +            return rv;
   1.861 +
   1.862 +        if (NS_FAILED(rv))
   1.863 +            return rv;
   1.864 +    }
   1.865 +
   1.866 +    // nobody wanted to accept it
   1.867 +    return NS_RDF_ASSERTION_REJECTED;
   1.868 +}
   1.869 +
   1.870 +NS_IMETHODIMP
   1.871 +CompositeDataSourceImpl::Move(nsIRDFResource* aOldSource,
   1.872 +                              nsIRDFResource* aNewSource,
   1.873 +                              nsIRDFResource* aProperty,
   1.874 +                              nsIRDFNode* aTarget)
   1.875 +{
   1.876 +    NS_PRECONDITION(aOldSource != nullptr, "null ptr");
   1.877 +    if (! aOldSource)
   1.878 +        return NS_ERROR_NULL_POINTER;
   1.879 +
   1.880 +    NS_PRECONDITION(aNewSource != nullptr, "null ptr");
   1.881 +    if (! aNewSource)
   1.882 +        return NS_ERROR_NULL_POINTER;
   1.883 +
   1.884 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.885 +    if (! aProperty)
   1.886 +        return NS_ERROR_NULL_POINTER;
   1.887 +
   1.888 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
   1.889 +    if (! aTarget)
   1.890 +        return NS_ERROR_NULL_POINTER;
   1.891 +
   1.892 +    nsresult rv;
   1.893 +
   1.894 +    // XXX So we're assuming that a datasource _must_ accept the
   1.895 +    // atomic move; i.e., we can't split it up across two
   1.896 +    // datasources. That sucks.
   1.897 +
   1.898 +    // We iterate backwards from the last data source which was added
   1.899 +    // ("the most remote") to the first ("the most local"), trying to
   1.900 +    // apply the assertion in each.
   1.901 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
   1.902 +        rv = mDataSources[i]->Move(aOldSource, aNewSource, aProperty, aTarget);
   1.903 +        if (NS_RDF_ASSERTION_ACCEPTED == rv)
   1.904 +            return rv;
   1.905 +
   1.906 +        if (NS_FAILED(rv))
   1.907 +            return rv;
   1.908 +    }
   1.909 +
   1.910 +    // nobody wanted to accept it
   1.911 +    return NS_RDF_ASSERTION_REJECTED;
   1.912 +}
   1.913 +
   1.914 +
   1.915 +NS_IMETHODIMP
   1.916 +CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
   1.917 +                                      nsIRDFResource* aProperty,
   1.918 +                                      nsIRDFNode* aTarget,
   1.919 +                                      bool aTruthValue,
   1.920 +                                      bool* aResult)
   1.921 +{
   1.922 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
   1.923 +    if (! aSource)
   1.924 +        return NS_ERROR_NULL_POINTER;
   1.925 +
   1.926 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
   1.927 +    if (! aProperty)
   1.928 +        return NS_ERROR_NULL_POINTER;
   1.929 +
   1.930 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.931 +    if (! aResult)
   1.932 +        return NS_ERROR_NULL_POINTER;
   1.933 +
   1.934 +    if (! mAllowNegativeAssertions && ! aTruthValue)
   1.935 +    {
   1.936 +        *aResult = false;
   1.937 +        return(NS_OK);
   1.938 +    }
   1.939 +
   1.940 +    nsresult rv;
   1.941 +
   1.942 +    // Otherwise, look through all the data sources to see if anyone
   1.943 +    // has the positive...
   1.944 +    int32_t count = mDataSources.Count();
   1.945 +    for (int32_t i = 0; i < count; ++i) {
   1.946 +        nsIRDFDataSource* datasource = mDataSources[i];
   1.947 +        rv = datasource->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult);
   1.948 +        if (NS_FAILED(rv)) return rv;
   1.949 +
   1.950 +        if (*aResult)
   1.951 +            return NS_OK;
   1.952 +
   1.953 +        if (mAllowNegativeAssertions)
   1.954 +        {
   1.955 +            bool hasNegation;
   1.956 +            rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
   1.957 +            if (NS_FAILED(rv)) return rv;
   1.958 +
   1.959 +            if (hasNegation)
   1.960 +            {
   1.961 +                *aResult = false;
   1.962 +                return NS_OK;
   1.963 +            }
   1.964 +        }
   1.965 +    }
   1.966 +
   1.967 +    // If we get here, nobody had the assertion at all
   1.968 +    *aResult = false;
   1.969 +    return NS_OK;
   1.970 +}
   1.971 +
   1.972 +NS_IMETHODIMP
   1.973 +CompositeDataSourceImpl::AddObserver(nsIRDFObserver* aObserver)
   1.974 +{
   1.975 +    NS_PRECONDITION(aObserver != nullptr, "null ptr");
   1.976 +    if (! aObserver)
   1.977 +        return NS_ERROR_NULL_POINTER;
   1.978 +
   1.979 +    // XXX ensure uniqueness?
   1.980 +    mObservers.AppendObject(aObserver);
   1.981 +
   1.982 +    return NS_OK;
   1.983 +}
   1.984 +
   1.985 +NS_IMETHODIMP
   1.986 +CompositeDataSourceImpl::RemoveObserver(nsIRDFObserver* aObserver)
   1.987 +{
   1.988 +    NS_PRECONDITION(aObserver != nullptr, "null ptr");
   1.989 +    if (! aObserver)
   1.990 +        return NS_ERROR_NULL_POINTER;
   1.991 +
   1.992 +    mObservers.RemoveObject(aObserver);
   1.993 +
   1.994 +    return NS_OK;
   1.995 +}
   1.996 +
   1.997 +NS_IMETHODIMP 
   1.998 +CompositeDataSourceImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
   1.999 +{
  1.1000 +    nsresult rv;
  1.1001 +    *result = false;
  1.1002 +    int32_t count = mDataSources.Count();
  1.1003 +    for (int32_t i = 0; i < count; ++i) {
  1.1004 +        rv = mDataSources[i]->HasArcIn(aNode, aArc, result);
  1.1005 +        if (NS_FAILED(rv)) return rv;
  1.1006 +        if (*result)
  1.1007 +            return NS_OK;
  1.1008 +    }
  1.1009 +    return NS_OK;
  1.1010 +}
  1.1011 +
  1.1012 +NS_IMETHODIMP 
  1.1013 +CompositeDataSourceImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
  1.1014 +{
  1.1015 +    nsresult rv;
  1.1016 +    *result = false;
  1.1017 +    int32_t count = mDataSources.Count();
  1.1018 +    for (int32_t i = 0; i < count; ++i) {
  1.1019 +        rv = mDataSources[i]->HasArcOut(aSource, aArc, result);
  1.1020 +        if (NS_FAILED(rv)) return rv;
  1.1021 +        if (*result)
  1.1022 +            return NS_OK;
  1.1023 +    }
  1.1024 +    return NS_OK;
  1.1025 +}
  1.1026 +
  1.1027 +NS_IMETHODIMP
  1.1028 +CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
  1.1029 +{
  1.1030 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1031 +    if (! aTarget)
  1.1032 +        return NS_ERROR_NULL_POINTER;
  1.1033 +
  1.1034 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
  1.1035 +    if (! aResult)
  1.1036 +        return NS_ERROR_NULL_POINTER;
  1.1037 +
  1.1038 +    nsISimpleEnumerator* result =
  1.1039 +        new CompositeArcsInOutEnumeratorImpl(this, aTarget,
  1.1040 +                                             CompositeArcsInOutEnumeratorImpl::eArcsIn,
  1.1041 +                                             mAllowNegativeAssertions,
  1.1042 +                                             mCoalesceDuplicateArcs);
  1.1043 +
  1.1044 +    if (! result)
  1.1045 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1046 +
  1.1047 +    NS_ADDREF(result);
  1.1048 +    *aResult = result;
  1.1049 +    return NS_OK;
  1.1050 +}
  1.1051 +
  1.1052 +NS_IMETHODIMP
  1.1053 +CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource,
  1.1054 +                                      nsISimpleEnumerator** aResult)
  1.1055 +{
  1.1056 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1057 +    if (! aSource)
  1.1058 +        return NS_ERROR_NULL_POINTER;
  1.1059 +
  1.1060 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
  1.1061 +    if (! aResult)
  1.1062 +        return NS_ERROR_NULL_POINTER;
  1.1063 +
  1.1064 +    nsISimpleEnumerator* result =
  1.1065 +        new CompositeArcsInOutEnumeratorImpl(this, aSource,
  1.1066 +                                             CompositeArcsInOutEnumeratorImpl::eArcsOut,
  1.1067 +                                             mAllowNegativeAssertions,
  1.1068 +                                             mCoalesceDuplicateArcs);
  1.1069 +
  1.1070 +    if (! result)
  1.1071 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1072 +
  1.1073 +    NS_ADDREF(result);
  1.1074 +    *aResult = result;
  1.1075 +    return NS_OK;
  1.1076 +}
  1.1077 +
  1.1078 +NS_IMETHODIMP
  1.1079 +CompositeDataSourceImpl::GetAllResources(nsISimpleEnumerator** aResult)
  1.1080 +{
  1.1081 +    NS_NOTYETIMPLEMENTED("CompositeDataSourceImpl::GetAllResources");
  1.1082 +    return NS_ERROR_NOT_IMPLEMENTED;
  1.1083 +}
  1.1084 +
  1.1085 +NS_IMETHODIMP
  1.1086 +CompositeDataSourceImpl::GetAllCmds(nsIRDFResource* source,
  1.1087 +                                    nsISimpleEnumerator/*<nsIRDFResource>*/** result)
  1.1088 +{
  1.1089 +    nsresult rv;
  1.1090 +    nsCOMPtr<nsISimpleEnumerator> set;
  1.1091 +
  1.1092 +    for (int32_t i = 0; i < mDataSources.Count(); i++)
  1.1093 +    {
  1.1094 +        nsCOMPtr<nsISimpleEnumerator> dsCmds;
  1.1095 +
  1.1096 +        rv = mDataSources[i]->GetAllCmds(source, getter_AddRefs(dsCmds));
  1.1097 +        if (NS_SUCCEEDED(rv))
  1.1098 +        {
  1.1099 +            nsCOMPtr<nsISimpleEnumerator> tmp;
  1.1100 +            rv = NS_NewUnionEnumerator(getter_AddRefs(tmp), set, dsCmds);
  1.1101 +            set.swap(tmp);
  1.1102 +            if (NS_FAILED(rv)) return(rv);
  1.1103 +        }
  1.1104 +    }
  1.1105 +
  1.1106 +    set.forget(result);
  1.1107 +    return NS_OK;
  1.1108 +}
  1.1109 +
  1.1110 +NS_IMETHODIMP
  1.1111 +CompositeDataSourceImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1.1112 +                                          nsIRDFResource*   aCommand,
  1.1113 +                                          nsISupportsArray/*<nsIRDFResource>*/* aArguments,
  1.1114 +                                          bool* aResult)
  1.1115 +{
  1.1116 +    nsresult rv;
  1.1117 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
  1.1118 +        bool enabled = true;
  1.1119 +        rv = mDataSources[i]->IsCommandEnabled(aSources, aCommand, aArguments, &enabled);
  1.1120 +        if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
  1.1121 +        {
  1.1122 +            return(rv);
  1.1123 +        }
  1.1124 +
  1.1125 +        if (! enabled) {
  1.1126 +            *aResult = false;
  1.1127 +            return(NS_OK);
  1.1128 +        }
  1.1129 +    }
  1.1130 +    *aResult = true;
  1.1131 +    return(NS_OK);
  1.1132 +}
  1.1133 +
  1.1134 +NS_IMETHODIMP
  1.1135 +CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1.1136 +                                   nsIRDFResource*   aCommand,
  1.1137 +                                   nsISupportsArray/*<nsIRDFResource>*/* aArguments)
  1.1138 +{
  1.1139 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
  1.1140 +        nsresult rv = mDataSources[i]->DoCommand(aSources, aCommand, aArguments);
  1.1141 +        if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
  1.1142 +        {
  1.1143 +            return(rv);   // all datasources must succeed
  1.1144 +        }
  1.1145 +    }
  1.1146 +    return(NS_OK);
  1.1147 +}
  1.1148 +
  1.1149 +NS_IMETHODIMP
  1.1150 +CompositeDataSourceImpl::BeginUpdateBatch()
  1.1151 +{
  1.1152 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
  1.1153 +        mDataSources[i]->BeginUpdateBatch();
  1.1154 +    }
  1.1155 +    return NS_OK;
  1.1156 +}
  1.1157 +
  1.1158 +NS_IMETHODIMP
  1.1159 +CompositeDataSourceImpl::EndUpdateBatch()
  1.1160 +{
  1.1161 +    for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
  1.1162 +        mDataSources[i]->EndUpdateBatch();
  1.1163 +    }
  1.1164 +    return NS_OK;
  1.1165 +}
  1.1166 +
  1.1167 +////////////////////////////////////////////////////////////////////////
  1.1168 +// nsIRDFCompositeDataSource methods
  1.1169 +// XXX rvg We should make this take an additional argument specifying where
  1.1170 +// in the sequence of data sources (of the db), the new data source should
  1.1171 +// fit in. Right now, the new datasource gets stuck at the end.
  1.1172 +// need to add the observers of the CompositeDataSourceImpl to the new data source.
  1.1173 +
  1.1174 +NS_IMETHODIMP
  1.1175 +CompositeDataSourceImpl::GetAllowNegativeAssertions(bool *aAllowNegativeAssertions)
  1.1176 +{
  1.1177 +	*aAllowNegativeAssertions = mAllowNegativeAssertions;
  1.1178 +	return(NS_OK);
  1.1179 +}
  1.1180 +
  1.1181 +NS_IMETHODIMP
  1.1182 +CompositeDataSourceImpl::SetAllowNegativeAssertions(bool aAllowNegativeAssertions)
  1.1183 +{
  1.1184 +	mAllowNegativeAssertions = aAllowNegativeAssertions;
  1.1185 +	return(NS_OK);
  1.1186 +}
  1.1187 +
  1.1188 +NS_IMETHODIMP
  1.1189 +CompositeDataSourceImpl::GetCoalesceDuplicateArcs(bool *aCoalesceDuplicateArcs)
  1.1190 +{
  1.1191 +	*aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
  1.1192 +	return(NS_OK);
  1.1193 +}
  1.1194 +
  1.1195 +NS_IMETHODIMP
  1.1196 +CompositeDataSourceImpl::SetCoalesceDuplicateArcs(bool aCoalesceDuplicateArcs)
  1.1197 +{
  1.1198 +	mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
  1.1199 +	return(NS_OK);
  1.1200 +}
  1.1201 +
  1.1202 +NS_IMETHODIMP
  1.1203 +CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource)
  1.1204 +{
  1.1205 +    NS_ASSERTION(aDataSource != nullptr, "null ptr");
  1.1206 +    if (! aDataSource)
  1.1207 +        return NS_ERROR_NULL_POINTER;
  1.1208 +
  1.1209 +    mDataSources.AppendObject(aDataSource);
  1.1210 +    aDataSource->AddObserver(this);
  1.1211 +    return NS_OK;
  1.1212 +}
  1.1213 +
  1.1214 +
  1.1215 +
  1.1216 +NS_IMETHODIMP
  1.1217 +CompositeDataSourceImpl::RemoveDataSource(nsIRDFDataSource* aDataSource)
  1.1218 +{
  1.1219 +    NS_ASSERTION(aDataSource != nullptr, "null ptr");
  1.1220 +    if (! aDataSource)
  1.1221 +        return NS_ERROR_NULL_POINTER;
  1.1222 +
  1.1223 +
  1.1224 +    if (mDataSources.IndexOf(aDataSource) >= 0) {
  1.1225 +        aDataSource->RemoveObserver(this);
  1.1226 +        mDataSources.RemoveObject(aDataSource);
  1.1227 +    }
  1.1228 +    return NS_OK;
  1.1229 +}
  1.1230 +
  1.1231 +
  1.1232 +NS_IMETHODIMP
  1.1233 +CompositeDataSourceImpl::GetDataSources(nsISimpleEnumerator** _result)
  1.1234 +{
  1.1235 +    // NS_NewArrayEnumerator for an nsCOMArray takes a snapshot of the
  1.1236 +    // current state.
  1.1237 +    return NS_NewArrayEnumerator(_result, mDataSources);
  1.1238 +}
  1.1239 +
  1.1240 +NS_IMETHODIMP
  1.1241 +CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource,
  1.1242 +                                  nsIRDFResource* aSource,
  1.1243 +                                  nsIRDFResource* aProperty,
  1.1244 +                                  nsIRDFNode* aTarget)
  1.1245 +{
  1.1246 +    // Make sure that the assertion isn't masked by another
  1.1247 +    // datasource.
  1.1248 +    //
  1.1249 +    // XXX We could make this more efficient if we knew _which_
  1.1250 +    // datasource actually served up the OnAssert(): we could use
  1.1251 +    // HasAssertionN() to only search datasources _before_ the
  1.1252 +    // datasource that coughed up the assertion.
  1.1253 +	nsresult	rv = NS_OK;
  1.1254 +
  1.1255 +	if (mAllowNegativeAssertions)
  1.1256 +	{   
  1.1257 +		bool hasAssertion;
  1.1258 +		rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
  1.1259 +		if (NS_FAILED(rv)) return rv;
  1.1260 +
  1.1261 +		if (! hasAssertion)
  1.1262 +			return(NS_OK);
  1.1263 +	}
  1.1264 +
  1.1265 +    for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1266 +        mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
  1.1267 +    }
  1.1268 +    return NS_OK;
  1.1269 +}
  1.1270 +
  1.1271 +NS_IMETHODIMP
  1.1272 +CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource,
  1.1273 +                                    nsIRDFResource* aSource,
  1.1274 +                                    nsIRDFResource* aProperty,
  1.1275 +                                    nsIRDFNode* aTarget)
  1.1276 +{
  1.1277 +    // Make sure that the un-assertion doesn't just unmask the
  1.1278 +    // same assertion in a different datasource.
  1.1279 +    //
  1.1280 +    // XXX We could make this more efficient if we knew _which_
  1.1281 +    // datasource actually served up the OnAssert(): we could use
  1.1282 +    // HasAssertionN() to only search datasources _before_ the
  1.1283 +    // datasource that coughed up the assertion.
  1.1284 +    nsresult rv;
  1.1285 +
  1.1286 +	if (mAllowNegativeAssertions)
  1.1287 +	{   
  1.1288 +		bool hasAssertion;
  1.1289 +		rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
  1.1290 +		if (NS_FAILED(rv)) return rv;
  1.1291 +
  1.1292 +		if (hasAssertion)
  1.1293 +			return NS_OK;
  1.1294 +	}
  1.1295 +
  1.1296 +    for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1297 +        mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget);
  1.1298 +    }
  1.1299 +    return NS_OK;
  1.1300 +}
  1.1301 +
  1.1302 +
  1.1303 +NS_IMETHODIMP
  1.1304 +CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource,
  1.1305 +                                  nsIRDFResource* aSource,
  1.1306 +                                  nsIRDFResource* aProperty,
  1.1307 +                                  nsIRDFNode* aOldTarget,
  1.1308 +                                  nsIRDFNode* aNewTarget)
  1.1309 +{
  1.1310 +    // Make sure that the change is actually visible, and not hidden
  1.1311 +    // by an assertion in a different datasource.
  1.1312 +    //
  1.1313 +    // XXX Because of aggregation, this could actually mutate into a
  1.1314 +    // variety of OnAssert or OnChange notifications, which we'll
  1.1315 +    // ignore for now :-/.
  1.1316 +    for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1317 +        mObservers[i]->OnChange(this, aSource, aProperty,
  1.1318 +                                aOldTarget, aNewTarget);
  1.1319 +    }
  1.1320 +    return NS_OK;
  1.1321 +}
  1.1322 +
  1.1323 +
  1.1324 +NS_IMETHODIMP
  1.1325 +CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource,
  1.1326 +                                nsIRDFResource* aOldSource,
  1.1327 +                                nsIRDFResource* aNewSource,
  1.1328 +                                nsIRDFResource* aProperty,
  1.1329 +                                nsIRDFNode* aTarget)
  1.1330 +{
  1.1331 +    // Make sure that the move is actually visible, and not hidden
  1.1332 +    // by an assertion in a different datasource.
  1.1333 +    //
  1.1334 +    // XXX Because of aggregation, this could actually mutate into a
  1.1335 +    // variety of OnAssert or OnMove notifications, which we'll
  1.1336 +    // ignore for now :-/.
  1.1337 +    for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1338 +        mObservers[i]->OnMove(this, aOldSource, aNewSource,
  1.1339 +                              aProperty, aTarget);
  1.1340 +    }
  1.1341 +    return NS_OK;
  1.1342 +}
  1.1343 +
  1.1344 +
  1.1345 +NS_IMETHODIMP
  1.1346 +CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
  1.1347 +{
  1.1348 +    if (mUpdateBatchNest++ == 0) {
  1.1349 +        for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1350 +            mObservers[i]->OnBeginUpdateBatch(this);
  1.1351 +        }
  1.1352 +    }
  1.1353 +    return NS_OK;
  1.1354 +}
  1.1355 +
  1.1356 +
  1.1357 +NS_IMETHODIMP
  1.1358 +CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
  1.1359 +{
  1.1360 +    NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
  1.1361 +    if (--mUpdateBatchNest == 0) {
  1.1362 +        for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
  1.1363 +            mObservers[i]->OnEndUpdateBatch(this);
  1.1364 +        }
  1.1365 +    }
  1.1366 +    return NS_OK;
  1.1367 +}

mercurial