Back to index

lightning-sunbird  0.9+nobinonly
nsCompositeDataSource.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Ramanathan Guha <guha@netscape.com>
00024  *   Chris Waterson <waterson@netscape.com
00025  *   Pierre Phaneuf <pp@ludusdesign.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /*
00042 
00043   A simple composite data source implementation. A composit data
00044   source is just a strategy for combining individual data sources into
00045   a collective graph.
00046 
00047 
00048   1) A composite data source holds a sequence of data sources. The set
00049      of data sources can be specified during creation of the
00050      database. Data sources can also be added/deleted from a database
00051      later.
00052 
00053   2) The aggregation mechanism is based on simple super-positioning of
00054      the graphs from the datasources. If there is a conflict (i.e., 
00055      data source A has a true arc from foo to bar while data source B
00056      has a false arc from foo to bar), the data source that it earlier
00057      in the sequence wins.
00058 
00059      The implementation below doesn't really do this and needs to be
00060      fixed.
00061 
00062 */
00063 
00064 #include "xpcom-config.h"
00065 #include NEW_H
00066 #include "nsCOMPtr.h"
00067 #include "nsIComponentManager.h"
00068 #include "nsIEnumerator.h"
00069 #include "nsIRDFCompositeDataSource.h"
00070 #include "nsIRDFNode.h"
00071 #include "nsIRDFObserver.h"
00072 #include "nsIRDFRemoteDataSource.h"
00073 #include "nsFixedSizeAllocator.h"
00074 #include "nsVoidArray.h"
00075 #include "nsCOMArray.h"
00076 #include "nsArrayEnumerator.h"
00077 #include "nsXPIDLString.h"
00078 #include "rdf.h"
00079 
00080 #include "nsEnumeratorUtils.h"
00081 
00082 #ifdef NS_DEBUG
00083 #include "prlog.h"
00084 #include "prprf.h"
00085 #include <stdio.h>
00086 PRLogModuleInfo* nsRDFLog = nsnull;
00087 #endif
00088 
00089 static NS_DEFINE_IID(kISupportsIID,           NS_ISUPPORTS_IID);
00090 
00091 //----------------------------------------------------------------------
00092 //
00093 // CompositeDataSourceImpl
00094 //
00095 
00096 class CompositeEnumeratorImpl;
00097 class CompositeArcsInOutEnumeratorImpl;
00098 class CompositeAssertionEnumeratorImpl;
00099 
00100 class CompositeDataSourceImpl : public nsIRDFCompositeDataSource,
00101                                 public nsIRDFObserver
00102 {
00103 public:
00104     CompositeDataSourceImpl(void);
00105     CompositeDataSourceImpl(char** dataSources);
00106 
00107     // nsISupports interface
00108     NS_DECL_ISUPPORTS
00109 
00110     // nsIRDFDataSource interface
00111     NS_DECL_NSIRDFDATASOURCE
00112 
00113     // nsIRDFCompositeDataSource interface
00114     NS_DECL_NSIRDFCOMPOSITEDATASOURCE
00115 
00116     // nsIRDFObserver interface
00117     NS_DECL_NSIRDFOBSERVER
00118 
00119     PRBool HasAssertionN(int n, nsIRDFResource* source,
00120                             nsIRDFResource* property,
00121                             nsIRDFNode* target,
00122                             PRBool tv);
00123 
00124 protected:
00125     nsCOMArray<nsIRDFObserver> mObservers;
00126     nsCOMArray<nsIRDFDataSource> mDataSources;
00127 
00128        PRBool      mAllowNegativeAssertions;
00129        PRBool      mCoalesceDuplicateArcs;
00130     PRInt32     mUpdateBatchNest;
00131 
00132     nsFixedSizeAllocator mAllocator;
00133 
00134        virtual ~CompositeDataSourceImpl() {}
00135 
00136     friend class CompositeEnumeratorImpl;
00137     friend class CompositeArcsInOutEnumeratorImpl;
00138     friend class CompositeAssertionEnumeratorImpl;
00139 };
00140 
00141 //----------------------------------------------------------------------
00142 //
00143 // CompositeEnumeratorImpl
00144 //
00145 
00146 class CompositeEnumeratorImpl : public nsISimpleEnumerator
00147 {
00148     // nsISupports
00149     NS_DECL_ISUPPORTS
00150 
00151     // nsISimpleEnumerator interface
00152     NS_DECL_NSISIMPLEENUMERATOR
00153 
00154     // pure abstract methods to be overridden
00155     virtual nsresult
00156     GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult) = 0;
00157 
00158     virtual nsresult
00159     HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, PRBool* aResult) = 0;
00160 
00161     virtual void Destroy() = 0;
00162 
00163 protected:
00164     CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
00165                             PRBool aAllowNegativeAssertions,
00166                             PRBool aCoalesceDuplicateArcs);
00167 
00168     virtual ~CompositeEnumeratorImpl();
00169     
00170     CompositeDataSourceImpl* mCompositeDataSource;
00171 
00172     nsISimpleEnumerator* mCurrent;
00173     nsIRDFNode*  mResult;
00174     PRInt32      mNext;
00175     nsAutoVoidArray  mAlreadyReturned;
00176     PRPackedBool mAllowNegativeAssertions;
00177     PRPackedBool mCoalesceDuplicateArcs;
00178 };
00179 
00180 
00181 CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
00182                                                  PRBool aAllowNegativeAssertions,
00183                                                  PRBool aCoalesceDuplicateArcs)
00184     : mCompositeDataSource(aCompositeDataSource),
00185       mCurrent(nsnull),
00186       mResult(nsnull),
00187          mNext(0),
00188       mAllowNegativeAssertions(aAllowNegativeAssertions),
00189       mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
00190 {
00191        NS_ADDREF(mCompositeDataSource);
00192 }
00193 
00194 
00195 CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void)
00196 {
00197        if (mCoalesceDuplicateArcs == PR_TRUE)
00198        {
00199               for (PRInt32 i = mAlreadyReturned.Count() - 1; i >= 0; --i)
00200               {
00201                      nsIRDFNode *node = (nsIRDFNode *) mAlreadyReturned[i];
00202                      NS_RELEASE(node);
00203               }
00204        }
00205 
00206        NS_IF_RELEASE(mCurrent);
00207        NS_IF_RELEASE(mResult);
00208        NS_RELEASE(mCompositeDataSource);
00209 }
00210 
00211 NS_IMPL_ADDREF(CompositeEnumeratorImpl)
00212 NS_IMPL_RELEASE_WITH_DESTROY(CompositeEnumeratorImpl, Destroy())
00213 NS_IMPL_QUERY_INTERFACE1(CompositeEnumeratorImpl, nsISimpleEnumerator)
00214 
00215 NS_IMETHODIMP
00216 CompositeEnumeratorImpl::HasMoreElements(PRBool* aResult)
00217 {
00218     NS_PRECONDITION(aResult != nsnull, "null ptr");
00219     if (! aResult)
00220         return NS_ERROR_NULL_POINTER;
00221 
00222     nsresult rv;
00223 
00224     // If we've already queued up a next target, then yep, there are
00225     // more elements.
00226     if (mResult) {
00227         *aResult = PR_TRUE;
00228         return NS_OK;
00229     }
00230 
00231     // Otherwise, we'll need to find a next target, switching cursors
00232     // if necessary.
00233     for ( ; mNext < mCompositeDataSource->mDataSources.Count(); ++mNext) {
00234         if (! mCurrent) {
00235             // We don't have a current enumerator, so create a new one on
00236             // the next data source.
00237             nsIRDFDataSource* datasource =
00238                 mCompositeDataSource->mDataSources[mNext];
00239 
00240             rv = GetEnumerator(datasource, &mCurrent);
00241             if (NS_FAILED(rv)) return rv;
00242             if (rv == NS_RDF_NO_VALUE)
00243                 continue;
00244 
00245             NS_ASSERTION(mCurrent != nsnull, "you're always supposed to return an enumerator from GetEnumerator, punk.");
00246             if (! mCurrent)
00247                 continue;
00248         }
00249 
00250         do {
00251             PRInt32 i;
00252 
00253             PRBool hasMore;
00254             rv = mCurrent->HasMoreElements(&hasMore);
00255             if (NS_FAILED(rv)) return rv;
00256 
00257             // Is the current enumerator depleted?
00258             if (! hasMore) {
00259                 NS_RELEASE(mCurrent);
00260                 break;
00261             }
00262 
00263             // Even if the current enumerator has more elements, we still
00264             // need to check that the current element isn't masked by
00265             // a negation in an earlier data source.
00266 
00267             // "Peek" ahead and pull out the next target.
00268             nsCOMPtr<nsISupports> result;
00269             rv = mCurrent->GetNext(getter_AddRefs(result));
00270             if (NS_FAILED(rv)) return rv;
00271 
00272             rv = result->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) &mResult);
00273             if (NS_FAILED(rv)) return rv;
00274 
00275             if (mAllowNegativeAssertions == PR_TRUE)
00276             {
00277                 // See if any previous data source negates this
00278                 PRBool hasNegation = PR_FALSE;
00279                 for (i = mNext - 1; i >= 0; --i)
00280                 {
00281                     nsIRDFDataSource* datasource =
00282                         mCompositeDataSource->mDataSources[i];
00283 
00284                     rv = HasNegation(datasource, mResult, &hasNegation);
00285                     if (NS_FAILED(rv)) return rv;
00286 
00287                     if (hasNegation)
00288                         break;
00289                 }
00290 
00291                 // if so, we've gotta keep looking
00292                 if (hasNegation)
00293                 {
00294                     NS_RELEASE(mResult);
00295                     continue;
00296                 }
00297             }
00298 
00299             if (mCoalesceDuplicateArcs == PR_TRUE)
00300             {
00301                 // Now see if we've returned it once already.
00302                 // XXX N.B. performance here...may want to hash if things get large?
00303                 PRBool alreadyReturned = PR_FALSE;
00304                 for (i = mAlreadyReturned.Count() - 1; i >= 0; --i)
00305                 {
00306                     if (mAlreadyReturned[i] == mResult)
00307                     {
00308                         alreadyReturned = PR_TRUE;
00309                         break;
00310                     }
00311                 }
00312                 if (alreadyReturned == PR_TRUE)
00313                 {
00314                     NS_RELEASE(mResult);
00315                     continue;
00316                 }
00317             }
00318 
00319             // If we get here, then we've really found one. It'll
00320             // remain cached in mResult until GetNext() sucks it out.
00321             *aResult = PR_TRUE;
00322 
00323             // Remember that we returned it, so we don't return duplicates.
00324 
00325             // XXX I wonder if we should make unique-checking be
00326             // optional. This could get to be pretty expensive (this
00327             // implementation turns iteration into O(n^2)).
00328 
00329             if (mCoalesceDuplicateArcs == PR_TRUE)
00330             {
00331                 mAlreadyReturned.AppendElement(mResult);
00332                 NS_ADDREF(mResult);
00333             }
00334 
00335             return NS_OK;
00336         } while (1);
00337     }
00338 
00339     // if we get here, there aren't any elements left.
00340     *aResult = PR_FALSE;
00341     return NS_OK;
00342 }
00343 
00344 
00345 NS_IMETHODIMP
00346 CompositeEnumeratorImpl::GetNext(nsISupports** aResult)
00347 {
00348     nsresult rv;
00349 
00350     PRBool hasMore;
00351     rv = HasMoreElements(&hasMore);
00352     if (NS_FAILED(rv)) return rv;
00353 
00354     if (! hasMore)
00355         return NS_ERROR_UNEXPECTED;
00356 
00357     // Don't AddRef: we "transfer" ownership to the caller
00358     *aResult = mResult;
00359     mResult = nsnull;
00360 
00361     return NS_OK;
00362 }
00363 
00364 //----------------------------------------------------------------------
00365 //
00366 // CompositeArcsInOutEnumeratorImpl
00367 //
00368 //
00369 
00370 class CompositeArcsInOutEnumeratorImpl : public CompositeEnumeratorImpl
00371 {
00372 public:
00373     enum Type { eArcsIn, eArcsOut };
00374 
00375     static CompositeArcsInOutEnumeratorImpl*
00376     Create(nsFixedSizeAllocator& aAllocator,
00377            CompositeDataSourceImpl* aCompositeDataSource,
00378            nsIRDFNode* aNode,
00379            Type aType,
00380            PRBool aAllowNegativeAssertions,
00381            PRBool aCoalesceDuplicateArcs) {
00382         void* place = aAllocator.Alloc(sizeof(CompositeArcsInOutEnumeratorImpl));
00383         return place
00384             ? ::new (place) CompositeArcsInOutEnumeratorImpl(aCompositeDataSource,
00385                                                              aNode, aType,
00386                                                              aAllowNegativeAssertions,
00387                                                              aCoalesceDuplicateArcs)
00388             : nsnull; }
00389 
00390     virtual ~CompositeArcsInOutEnumeratorImpl();
00391 
00392     virtual nsresult
00393     GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
00394 
00395     virtual nsresult
00396     HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, PRBool* aResult);
00397 
00398     virtual void Destroy();
00399 
00400 protected:
00401     CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
00402                                      nsIRDFNode* aNode,
00403                                      Type aType,
00404                                      PRBool aAllowNegativeAssertions,
00405                                      PRBool aCoalesceDuplicateArcs);
00406 
00407 private:
00408     nsIRDFNode* mNode;
00409     Type        mType;
00410     PRBool        mAllowNegativeAssertions;
00411     PRBool      mCoalesceDuplicateArcs;
00412 
00413     // Hide so that only Create() and Destroy() can be used to
00414     // allocate and deallocate from the heap
00415     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
00416     static void operator delete(void*, size_t) {}
00417 };
00418 
00419 
00420 CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl(
00421                 CompositeDataSourceImpl* aCompositeDataSource,
00422                 nsIRDFNode* aNode,
00423                 Type aType,
00424                 PRBool aAllowNegativeAssertions,
00425                 PRBool aCoalesceDuplicateArcs)
00426     : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
00427       mNode(aNode),
00428       mType(aType),
00429       mAllowNegativeAssertions(aAllowNegativeAssertions),
00430       mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
00431 {
00432     NS_ADDREF(mNode);
00433 }
00434 
00435 CompositeArcsInOutEnumeratorImpl::~CompositeArcsInOutEnumeratorImpl()
00436 {
00437     NS_RELEASE(mNode);
00438 }
00439 
00440 
00441 nsresult
00442 CompositeArcsInOutEnumeratorImpl::GetEnumerator(
00443                  nsIRDFDataSource* aDataSource,
00444                  nsISimpleEnumerator** aResult)
00445 {
00446     if (mType == eArcsIn) {
00447         return aDataSource->ArcLabelsIn(mNode, aResult);
00448     }
00449     else {
00450         nsCOMPtr<nsIRDFResource> resource( do_QueryInterface(mNode) );
00451         return aDataSource->ArcLabelsOut(resource, aResult);
00452     }
00453 }
00454 
00455 nsresult
00456 CompositeArcsInOutEnumeratorImpl::HasNegation(
00457                  nsIRDFDataSource* aDataSource,
00458                  nsIRDFNode* aNode,
00459                  PRBool* aResult)
00460 {
00461     *aResult = PR_FALSE;
00462     return NS_OK;
00463 }
00464 
00465 void
00466 CompositeArcsInOutEnumeratorImpl::Destroy()
00467 {
00468     // Keep the datasource alive for the duration of the stack
00469     // frame so its allocator stays valid.
00470     nsCOMPtr<nsIRDFCompositeDataSource> kungFuDeathGrip = mCompositeDataSource;
00471 
00472     nsFixedSizeAllocator& pool = mCompositeDataSource->mAllocator;
00473     this->~CompositeArcsInOutEnumeratorImpl();
00474     pool.Free(this, sizeof(*this));
00475 }
00476 
00477 
00478 //----------------------------------------------------------------------
00479 //
00480 // CompositeAssertionEnumeratorImpl
00481 //
00482 
00483 class CompositeAssertionEnumeratorImpl : public CompositeEnumeratorImpl
00484 {
00485 public:
00486     static CompositeAssertionEnumeratorImpl*
00487     Create(nsFixedSizeAllocator& aAllocator,
00488            CompositeDataSourceImpl* aCompositeDataSource,
00489            nsIRDFResource* aSource,
00490            nsIRDFResource* aProperty,
00491            nsIRDFNode* aTarget,
00492            PRBool aTruthValue,
00493            PRBool aAllowNegativeAssertions,
00494            PRBool aCoalesceDuplicateArcs) {
00495         void* place = aAllocator.Alloc(sizeof(CompositeAssertionEnumeratorImpl));
00496         return place
00497             ? ::new (place) CompositeAssertionEnumeratorImpl(aCompositeDataSource,
00498                                                              aSource, aProperty, aTarget,
00499                                                              aTruthValue,
00500                                                              aAllowNegativeAssertions,
00501                                                              aCoalesceDuplicateArcs)
00502             : nsnull; }
00503 
00504     virtual nsresult
00505     GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
00506 
00507     virtual nsresult
00508     HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, PRBool* aResult);
00509 
00510     virtual void Destroy();
00511 
00512 protected:
00513     CompositeAssertionEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
00514                                      nsIRDFResource* aSource,
00515                                      nsIRDFResource* aProperty,
00516                                      nsIRDFNode* aTarget,
00517                                      PRBool aTruthValue,
00518                                      PRBool aAllowNegativeAssertions,
00519                                      PRBool aCoalesceDuplicateArcs);
00520 
00521     virtual ~CompositeAssertionEnumeratorImpl();
00522 
00523 private:
00524     nsIRDFResource* mSource;
00525     nsIRDFResource* mProperty;
00526     nsIRDFNode*     mTarget;
00527     PRBool          mTruthValue;
00528     PRBool          mAllowNegativeAssertions;
00529     PRBool          mCoalesceDuplicateArcs;
00530 
00531     // Hide so that only Create() and Destroy() can be used to
00532     // allocate and deallocate from the heap
00533     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
00534     static void operator delete(void*, size_t) {}
00535 };
00536 
00537 
00538 CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl(
00539                   CompositeDataSourceImpl* aCompositeDataSource,
00540                   nsIRDFResource* aSource,
00541                   nsIRDFResource* aProperty,
00542                   nsIRDFNode* aTarget,
00543                   PRBool aTruthValue,
00544                   PRBool aAllowNegativeAssertions,
00545                   PRBool aCoalesceDuplicateArcs)
00546     : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
00547       mSource(aSource),
00548       mProperty(aProperty),
00549       mTarget(aTarget),
00550       mTruthValue(aTruthValue),
00551       mAllowNegativeAssertions(aAllowNegativeAssertions),
00552       mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
00553 {
00554     NS_IF_ADDREF(mSource);
00555     NS_ADDREF(mProperty); // always must be specified
00556     NS_IF_ADDREF(mTarget);
00557 }
00558 
00559 CompositeAssertionEnumeratorImpl::~CompositeAssertionEnumeratorImpl()
00560 {
00561     NS_IF_RELEASE(mSource);
00562     NS_RELEASE(mProperty);
00563     NS_IF_RELEASE(mTarget);
00564 }
00565 
00566 
00567 nsresult
00568 CompositeAssertionEnumeratorImpl::GetEnumerator(
00569                  nsIRDFDataSource* aDataSource,
00570                  nsISimpleEnumerator** aResult)
00571 {
00572     if (mSource) {
00573         return aDataSource->GetTargets(mSource, mProperty, mTruthValue, aResult);
00574     }
00575     else {
00576         return aDataSource->GetSources(mProperty, mTarget, mTruthValue, aResult);
00577     }
00578 }
00579 
00580 nsresult
00581 CompositeAssertionEnumeratorImpl::HasNegation(
00582                  nsIRDFDataSource* aDataSource,
00583                  nsIRDFNode* aNode,
00584                  PRBool* aResult)
00585 {
00586     if (mSource) {
00587         return aDataSource->HasAssertion(mSource, mProperty, aNode, !mTruthValue, aResult);
00588     }
00589     else {
00590         nsCOMPtr<nsIRDFResource> source( do_QueryInterface(aNode) );
00591         return aDataSource->HasAssertion(source, mProperty, mTarget, !mTruthValue, aResult);
00592     }
00593 }
00594 
00595 void
00596 CompositeAssertionEnumeratorImpl::Destroy()
00597 {
00598     // Keep the datasource alive for the duration of the stack
00599     // frame so its allocator stays valid.
00600     nsCOMPtr<nsIRDFCompositeDataSource> kungFuDeathGrip = mCompositeDataSource;
00601 
00602     nsFixedSizeAllocator& pool = mCompositeDataSource->mAllocator;
00603     this->~CompositeAssertionEnumeratorImpl();
00604     pool.Free(this, sizeof(*this));
00605 }
00606 
00608 
00609 nsresult
00610 NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result)
00611 {
00612     CompositeDataSourceImpl* db = new CompositeDataSourceImpl();
00613     if (! db)
00614         return NS_ERROR_OUT_OF_MEMORY;
00615 
00616     *result = db;
00617     NS_ADDREF(*result);
00618     return NS_OK;
00619 }
00620 
00621 
00622 CompositeDataSourceImpl::CompositeDataSourceImpl(void)
00623        : mAllowNegativeAssertions(PR_TRUE),
00624          mCoalesceDuplicateArcs(PR_TRUE),
00625       mUpdateBatchNest(0)
00626 {
00627     static const size_t kBucketSizes[] = {
00628         sizeof(CompositeAssertionEnumeratorImpl),
00629         sizeof(CompositeArcsInOutEnumeratorImpl) };
00630 
00631     static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
00632 
00633     // Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
00634     static const PRInt32 kInitialSize = 256;
00635 
00636     mAllocator.Init("nsCompositeDataSource", kBucketSizes, kNumBuckets, kInitialSize);
00637 
00638 #ifdef PR_LOGGING
00639     if (nsRDFLog == nsnull) 
00640         nsRDFLog = PR_NewLogModule("RDF");
00641 #endif
00642 }
00643 
00644 //----------------------------------------------------------------------
00645 //
00646 // nsISupports interface
00647 //
00648 
00649 NS_IMPL_THREADSAFE_ADDREF(CompositeDataSourceImpl)
00650 
00651 NS_IMETHODIMP_(nsrefcnt)
00652 CompositeDataSourceImpl::Release()
00653 {
00654     // We need a special implementation of Release() because the
00655     // composite datasource holds a reference to each datasource that
00656     // it "composes", and each database that the composite datasource
00657     // observes holds a reference _back_ to the composite datasource.
00658     NS_PRECONDITION(PRInt32(mRefCnt) > 0, "duplicate release");
00659     nsrefcnt count =
00660       PR_AtomicDecrement(NS_REINTERPRET_CAST(PRInt32 *, &mRefCnt));
00661 
00662     // When the number of references == the number of datasources,
00663     // then we know that all that remains are the circular
00664     // references from those datasources back to us. Release them.
00665     if (count == 0) {
00666         NS_LOG_RELEASE(this, count, "CompositeDataSourceImpl");
00667         mRefCnt = 1;
00668         NS_DELETEXPCOM(this);
00669         return 0;
00670     }
00671     else if (PRInt32(count) == mDataSources.Count()) {
00672         // We must add 1 here because otherwise the nested releases
00673         // on this object will enter this same code path.
00674         PR_AtomicIncrement(NS_REINTERPRET_CAST(PRInt32 *, &mRefCnt));
00675         
00676         PRInt32 dsCount;
00677         while (0 != (dsCount = mDataSources.Count())) {
00678             // Take ref so it won't die before its time.
00679             nsCOMPtr<nsIRDFDataSource> ds = mDataSources[dsCount-1];
00680             mDataSources.RemoveObjectAt(dsCount-1);
00681             ds->RemoveObserver(this);
00682         }
00683         // Nest into Release to deal with the one last reference we added above.
00684         // We don't want to assume that we can 'delete this' because an
00685         // extra reference might have been added by other code while we were 
00686         // calling out.
00687         NS_ASSERTION(mRefCnt >= 1, "bad mRefCnt");
00688         return Release();
00689     }
00690     else {
00691         NS_LOG_RELEASE(this, count, "CompositeDataSourceImpl");
00692         return count;
00693     }
00694 }
00695 
00696 NS_IMETHODIMP
00697 CompositeDataSourceImpl::QueryInterface(REFNSIID iid, void** result)
00698 {
00699     if (! result)
00700         return NS_ERROR_NULL_POINTER;
00701 
00702     if (iid.Equals(NS_GET_IID(nsIRDFCompositeDataSource)) ||
00703         iid.Equals(NS_GET_IID(nsIRDFDataSource)) ||
00704         iid.Equals(kISupportsIID)) {
00705         *result = NS_STATIC_CAST(nsIRDFCompositeDataSource*, this);
00706               NS_ADDREF(this);
00707         return NS_OK;
00708     }
00709     else if (iid.Equals(NS_GET_IID(nsIRDFObserver))) {
00710         *result = NS_STATIC_CAST(nsIRDFObserver*, this);
00711         NS_ADDREF(this);
00712         return NS_OK;
00713     }
00714     else {
00715         *result = nsnull;
00716         return NS_NOINTERFACE;
00717     }
00718 }
00719 
00720 
00721 
00722 //----------------------------------------------------------------------
00723 //
00724 // nsIRDFDataSource interface
00725 //
00726 
00727 NS_IMETHODIMP
00728 CompositeDataSourceImpl::GetURI(char* *uri)
00729 {
00730     *uri = nsnull;
00731     return NS_OK;
00732 }
00733 
00734 NS_IMETHODIMP
00735 CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
00736                                    nsIRDFNode* target,
00737                                    PRBool tv,
00738                                    nsIRDFResource** source)
00739 {
00740        if ((mAllowNegativeAssertions == PR_FALSE) && (tv == PR_FALSE))
00741               return(NS_RDF_NO_VALUE);
00742 
00743     PRInt32 count = mDataSources.Count();
00744     for (PRInt32 i = 0; i < count; ++i) {
00745         nsresult rv;
00746         rv = mDataSources[i]->GetSource(property, target, tv, source);
00747         if (NS_FAILED(rv)) return rv;
00748 
00749         if (rv == NS_RDF_NO_VALUE)
00750             continue;
00751 
00752         if (mAllowNegativeAssertions == PR_FALSE)       return(NS_OK);
00753 
00754         // okay, found it. make sure we don't have the opposite
00755         // asserted in a more local data source
00756         if (!HasAssertionN(count-1, *source, property, target, !tv)) 
00757             return NS_OK;
00758 
00759         NS_RELEASE(*source);
00760         return NS_RDF_NO_VALUE;
00761     }
00762     return NS_RDF_NO_VALUE;
00763 }
00764 
00765 NS_IMETHODIMP
00766 CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty,
00767                                     nsIRDFNode* aTarget,
00768                                     PRBool aTruthValue,
00769                                     nsISimpleEnumerator** aResult)
00770 {
00771     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00772     if (! aProperty)
00773         return NS_ERROR_NULL_POINTER;
00774 
00775     NS_PRECONDITION(aTarget != nsnull, "null ptr");
00776     if (! aTarget)
00777         return NS_ERROR_NULL_POINTER;
00778 
00779     NS_PRECONDITION(aResult != nsnull, "null ptr");
00780     if (! aResult)
00781         return NS_ERROR_NULL_POINTER;
00782 
00783     if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
00784         return(NS_RDF_NO_VALUE);
00785 
00786     *aResult = CompositeAssertionEnumeratorImpl::Create(mAllocator,
00787                                                         this, nsnull, aProperty,
00788                                                         aTarget, aTruthValue,
00789                                                         mAllowNegativeAssertions,
00790                                                         mCoalesceDuplicateArcs);
00791 
00792     if (! *aResult)
00793         return NS_ERROR_OUT_OF_MEMORY;
00794 
00795     NS_ADDREF(*aResult);
00796     return NS_OK;
00797 }
00798 
00799 NS_IMETHODIMP
00800 CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
00801                                    nsIRDFResource* aProperty,
00802                                    PRBool aTruthValue,
00803                                    nsIRDFNode** aResult)
00804 {
00805     NS_PRECONDITION(aSource != nsnull, "null ptr");
00806     if (! aSource)
00807         return NS_ERROR_NULL_POINTER;
00808 
00809     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00810     if (! aProperty)
00811         return NS_ERROR_NULL_POINTER;
00812 
00813     NS_PRECONDITION(aResult != nsnull, "null ptr");
00814     if (! aResult)
00815         return NS_ERROR_NULL_POINTER;
00816 
00817     if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
00818         return(NS_RDF_NO_VALUE);
00819 
00820     PRInt32 count = mDataSources.Count();
00821     for (PRInt32 i = 0; i < count; ++i) {
00822         nsresult rv;
00823         rv = mDataSources[i]->GetTarget(aSource, aProperty, aTruthValue,
00824                                         aResult);
00825         if (NS_FAILED(rv))
00826             return rv;
00827 
00828         if (rv == NS_OK) {
00829             // okay, found it. make sure we don't have the opposite
00830             // asserted in an earlier data source
00831 
00832             if (mAllowNegativeAssertions == PR_TRUE) {
00833                 if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
00834                     // whoops, it's been negated.
00835                     NS_RELEASE(*aResult);
00836                     return NS_RDF_NO_VALUE;
00837                 }
00838             }
00839             return NS_OK;
00840         }
00841     }
00842 
00843     // Otherwise, we couldn't find it at all.
00844     return NS_RDF_NO_VALUE;
00845 }
00846 
00847 PRBool
00848 CompositeDataSourceImpl::HasAssertionN(int n,
00849                                        nsIRDFResource* aSource,
00850                                        nsIRDFResource* aProperty,
00851                                        nsIRDFNode* aTarget,
00852                                        PRBool aTruthValue)
00853 {
00854     nsresult rv;
00855     for (PRInt32 m = 0; m < n; ++m) {
00856         PRBool result;
00857         rv = mDataSources[m]->HasAssertion(aSource, aProperty, aTarget,
00858                                            aTruthValue, &result);
00859         if (NS_FAILED(rv))
00860             return PR_FALSE;
00861 
00862         // found it!
00863         if (result)
00864             return PR_TRUE;
00865     }
00866     return PR_FALSE;
00867 }
00868     
00869 
00870 
00871 NS_IMETHODIMP
00872 CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource,
00873                                     nsIRDFResource* aProperty,
00874                                     PRBool aTruthValue,
00875                                     nsISimpleEnumerator** aResult)
00876 {
00877     NS_PRECONDITION(aSource != nsnull, "null ptr");
00878     if (! aSource)
00879         return NS_ERROR_NULL_POINTER;
00880 
00881     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00882     if (! aProperty)
00883         return NS_ERROR_NULL_POINTER;
00884 
00885     NS_PRECONDITION(aResult != nsnull, "null ptr");
00886     if (! aResult)
00887         return NS_ERROR_NULL_POINTER;
00888 
00889     if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
00890         return(NS_RDF_NO_VALUE);
00891 
00892     *aResult =
00893         CompositeAssertionEnumeratorImpl::Create(mAllocator, this,
00894                                                  aSource, aProperty, nsnull,
00895                                                  aTruthValue,
00896                                                  mAllowNegativeAssertions,
00897                                                  mCoalesceDuplicateArcs);
00898 
00899     if (! *aResult)
00900         return NS_ERROR_OUT_OF_MEMORY;
00901 
00902     NS_ADDREF(*aResult);
00903     return NS_OK;
00904 }
00905 
00906 NS_IMETHODIMP
00907 CompositeDataSourceImpl::Assert(nsIRDFResource* aSource, 
00908                                 nsIRDFResource* aProperty, 
00909                                 nsIRDFNode* aTarget,
00910                                 PRBool aTruthValue)
00911 {
00912     NS_PRECONDITION(aSource != nsnull, "null ptr");
00913     if (! aSource)
00914         return NS_ERROR_NULL_POINTER;
00915 
00916     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00917     if (! aProperty)
00918         return NS_ERROR_NULL_POINTER;
00919 
00920     NS_PRECONDITION(aTarget != nsnull, "null ptr");
00921     if (! aTarget)
00922         return NS_ERROR_NULL_POINTER;
00923 
00924     if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
00925         return(NS_RDF_ASSERTION_REJECTED);
00926 
00927     nsresult rv;
00928 
00929     // XXX Need to add back the stuff for unblocking ...
00930 
00931     // We iterate backwards from the last data source which was added
00932     // ("the most remote") to the first ("the most local"), trying to
00933     // apply the assertion in each.
00934     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
00935         rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, aTruthValue);
00936         if (NS_RDF_ASSERTION_ACCEPTED == rv)
00937             return rv;
00938 
00939         if (NS_FAILED(rv))
00940             return rv;
00941     }
00942 
00943     // nobody wanted to accept it
00944     return NS_RDF_ASSERTION_REJECTED;
00945 }
00946 
00947 NS_IMETHODIMP
00948 CompositeDataSourceImpl::Unassert(nsIRDFResource* aSource,
00949                                   nsIRDFResource* aProperty,
00950                                   nsIRDFNode* aTarget)
00951 {
00952     NS_PRECONDITION(aSource != nsnull, "null ptr");
00953     if (! aSource)
00954         return NS_ERROR_NULL_POINTER;
00955 
00956     NS_PRECONDITION(aProperty != nsnull, "null ptr");
00957     if (! aProperty)
00958         return NS_ERROR_NULL_POINTER;
00959 
00960     NS_PRECONDITION(aTarget != nsnull, "null ptr");
00961     if (! aTarget)
00962         return NS_ERROR_NULL_POINTER;
00963 
00964     nsresult rv;
00965 
00966     // Iterate through each of the datasources, starting with "the
00967     // most local" and moving to "the most remote". If _any_ of the
00968     // datasources have the assertion, attempt to unassert it.
00969     PRBool unasserted = PR_TRUE;
00970     PRInt32 i;
00971     PRInt32 count = mDataSources.Count();
00972     for (i = 0; i < count; ++i) {
00973         nsIRDFDataSource* ds = mDataSources[i];
00974 
00975         PRBool hasAssertion;
00976         rv = ds->HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
00977         if (NS_FAILED(rv)) return rv;
00978 
00979         if (hasAssertion) {
00980             rv = ds->Unassert(aSource, aProperty, aTarget);
00981             if (NS_FAILED(rv)) return rv;
00982 
00983             if (rv != NS_RDF_ASSERTION_ACCEPTED) {
00984                 unasserted = PR_FALSE;
00985                 break;
00986             }
00987         }
00988     }
00989 
00990     // Either none of the datasources had it, or they were all willing
00991     // to let it be unasserted.
00992     if (unasserted)
00993         return NS_RDF_ASSERTION_ACCEPTED;
00994 
00995     // If we get here, one of the datasources already had the
00996     // assertion, and was adamant about not letting us remove
00997     // it. Iterate from the "most local" to the "most remote"
00998     // attempting to assert the negation...
00999     for (i = 0; i < count; ++i) {
01000         rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, PR_FALSE);
01001         if (NS_FAILED(rv)) return rv;
01002 
01003         // Did it take?
01004         if (rv == NS_RDF_ASSERTION_ACCEPTED)
01005             return rv;
01006     }
01007 
01008     // Couln't get anyone to accept the negation, either.
01009     return NS_RDF_ASSERTION_REJECTED;
01010 }
01011 
01012 NS_IMETHODIMP
01013 CompositeDataSourceImpl::Change(nsIRDFResource* aSource,
01014                                 nsIRDFResource* aProperty,
01015                                 nsIRDFNode* aOldTarget,
01016                                 nsIRDFNode* aNewTarget)
01017 {
01018     NS_PRECONDITION(aSource != nsnull, "null ptr");
01019     if (! aSource)
01020         return NS_ERROR_NULL_POINTER;
01021 
01022     NS_PRECONDITION(aProperty != nsnull, "null ptr");
01023     if (! aProperty)
01024         return NS_ERROR_NULL_POINTER;
01025 
01026     NS_PRECONDITION(aOldTarget != nsnull, "null ptr");
01027     if (! aOldTarget)
01028         return NS_ERROR_NULL_POINTER;
01029 
01030     NS_PRECONDITION(aNewTarget != nsnull, "null ptr");
01031     if (! aNewTarget)
01032         return NS_ERROR_NULL_POINTER;
01033 
01034     nsresult rv;
01035 
01036     // XXX So we're assuming that a datasource _must_ accept the
01037     // atomic change; i.e., we can't split it up across two
01038     // datasources. That sucks.
01039 
01040     // We iterate backwards from the last data source which was added
01041     // ("the most remote") to the first ("the most local"), trying to
01042     // apply the change in each.
01043     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01044         rv = mDataSources[i]->Change(aSource, aProperty, aOldTarget, aNewTarget);
01045         if (NS_RDF_ASSERTION_ACCEPTED == rv)
01046             return rv;
01047 
01048         if (NS_FAILED(rv))
01049             return rv;
01050     }
01051 
01052     // nobody wanted to accept it
01053     return NS_RDF_ASSERTION_REJECTED;
01054 }
01055 
01056 NS_IMETHODIMP
01057 CompositeDataSourceImpl::Move(nsIRDFResource* aOldSource,
01058                               nsIRDFResource* aNewSource,
01059                               nsIRDFResource* aProperty,
01060                               nsIRDFNode* aTarget)
01061 {
01062     NS_PRECONDITION(aOldSource != nsnull, "null ptr");
01063     if (! aOldSource)
01064         return NS_ERROR_NULL_POINTER;
01065 
01066     NS_PRECONDITION(aNewSource != nsnull, "null ptr");
01067     if (! aNewSource)
01068         return NS_ERROR_NULL_POINTER;
01069 
01070     NS_PRECONDITION(aProperty != nsnull, "null ptr");
01071     if (! aProperty)
01072         return NS_ERROR_NULL_POINTER;
01073 
01074     NS_PRECONDITION(aTarget != nsnull, "null ptr");
01075     if (! aTarget)
01076         return NS_ERROR_NULL_POINTER;
01077 
01078     nsresult rv;
01079 
01080     // XXX So we're assuming that a datasource _must_ accept the
01081     // atomic move; i.e., we can't split it up across two
01082     // datasources. That sucks.
01083 
01084     // We iterate backwards from the last data source which was added
01085     // ("the most remote") to the first ("the most local"), trying to
01086     // apply the assertion in each.
01087     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01088         rv = mDataSources[i]->Move(aOldSource, aNewSource, aProperty, aTarget);
01089         if (NS_RDF_ASSERTION_ACCEPTED == rv)
01090             return rv;
01091 
01092         if (NS_FAILED(rv))
01093             return rv;
01094     }
01095 
01096     // nobody wanted to accept it
01097     return NS_RDF_ASSERTION_REJECTED;
01098 }
01099 
01100 
01101 NS_IMETHODIMP
01102 CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
01103                                       nsIRDFResource* aProperty,
01104                                       nsIRDFNode* aTarget,
01105                                       PRBool aTruthValue,
01106                                       PRBool* aResult)
01107 {
01108     NS_PRECONDITION(aSource != nsnull, "null ptr");
01109     if (! aSource)
01110         return NS_ERROR_NULL_POINTER;
01111 
01112     NS_PRECONDITION(aProperty != nsnull, "null ptr");
01113     if (! aProperty)
01114         return NS_ERROR_NULL_POINTER;
01115 
01116     NS_PRECONDITION(aResult != nsnull, "null ptr");
01117     if (! aResult)
01118         return NS_ERROR_NULL_POINTER;
01119 
01120     if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
01121     {
01122         *aResult = PR_FALSE;
01123         return(NS_OK);
01124     }
01125 
01126     nsresult rv;
01127 
01128     // Otherwise, look through all the data sources to see if anyone
01129     // has the positive...
01130     PRInt32 count = mDataSources.Count();
01131     for (PRInt32 i = 0; i < count; ++i) {
01132         nsIRDFDataSource* datasource = mDataSources[i];
01133         rv = datasource->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult);
01134         if (NS_FAILED(rv)) return rv;
01135 
01136         if (*aResult)
01137             return NS_OK;
01138 
01139         if (mAllowNegativeAssertions == PR_TRUE)
01140         {
01141             PRBool hasNegation;
01142             rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
01143             if (NS_FAILED(rv)) return rv;
01144 
01145             if (hasNegation)
01146             {
01147                 *aResult = PR_FALSE;
01148                 return NS_OK;
01149             }
01150         }
01151     }
01152 
01153     // If we get here, nobody had the assertion at all
01154     *aResult = PR_FALSE;
01155     return NS_OK;
01156 }
01157 
01158 NS_IMETHODIMP
01159 CompositeDataSourceImpl::AddObserver(nsIRDFObserver* aObserver)
01160 {
01161     NS_PRECONDITION(aObserver != nsnull, "null ptr");
01162     if (! aObserver)
01163         return NS_ERROR_NULL_POINTER;
01164 
01165     // XXX ensure uniqueness?
01166     mObservers.AppendObject(aObserver);
01167 
01168     return NS_OK;
01169 }
01170 
01171 NS_IMETHODIMP
01172 CompositeDataSourceImpl::RemoveObserver(nsIRDFObserver* aObserver)
01173 {
01174     NS_PRECONDITION(aObserver != nsnull, "null ptr");
01175     if (! aObserver)
01176         return NS_ERROR_NULL_POINTER;
01177 
01178     mObservers.RemoveObject(aObserver);
01179 
01180     return NS_OK;
01181 }
01182 
01183 NS_IMETHODIMP 
01184 CompositeDataSourceImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
01185 {
01186     nsresult rv;
01187     *result = PR_FALSE;
01188     PRInt32 count = mDataSources.Count();
01189     for (PRInt32 i = 0; i < count; ++i) {
01190         rv = mDataSources[i]->HasArcIn(aNode, aArc, result);
01191         if (NS_FAILED(rv)) return rv;
01192         if (*result == PR_TRUE)
01193             return NS_OK;
01194     }
01195     return NS_OK;
01196 }
01197 
01198 NS_IMETHODIMP 
01199 CompositeDataSourceImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
01200 {
01201     nsresult rv;
01202     *result = PR_FALSE;
01203     PRInt32 count = mDataSources.Count();
01204     for (PRInt32 i = 0; i < count; ++i) {
01205         rv = mDataSources[i]->HasArcOut(aSource, aArc, result);
01206         if (NS_FAILED(rv)) return rv;
01207         if (*result == PR_TRUE)
01208             return NS_OK;
01209     }
01210     return NS_OK;
01211 }
01212 
01213 NS_IMETHODIMP
01214 CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
01215 {
01216     NS_PRECONDITION(aTarget != nsnull, "null ptr");
01217     if (! aTarget)
01218         return NS_ERROR_NULL_POINTER;
01219 
01220     NS_PRECONDITION(aResult != nsnull, "null ptr");
01221     if (! aResult)
01222         return NS_ERROR_NULL_POINTER;
01223 
01224     nsISimpleEnumerator* result = 
01225         CompositeArcsInOutEnumeratorImpl::Create(mAllocator, this, aTarget,
01226                                                  CompositeArcsInOutEnumeratorImpl::eArcsIn,
01227                                                  mAllowNegativeAssertions,
01228                                                  mCoalesceDuplicateArcs);
01229 
01230     if (! result)
01231         return NS_ERROR_OUT_OF_MEMORY;
01232 
01233     NS_ADDREF(result);
01234     *aResult = result;
01235     return NS_OK;
01236 }
01237 
01238 NS_IMETHODIMP
01239 CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource,
01240                                       nsISimpleEnumerator** aResult)
01241 {
01242     NS_PRECONDITION(aSource != nsnull, "null ptr");
01243     if (! aSource)
01244         return NS_ERROR_NULL_POINTER;
01245 
01246     NS_PRECONDITION(aResult != nsnull, "null ptr");
01247     if (! aResult)
01248         return NS_ERROR_NULL_POINTER;
01249 
01250     nsISimpleEnumerator* result =
01251         CompositeArcsInOutEnumeratorImpl::Create(mAllocator, this, aSource,
01252                                                  CompositeArcsInOutEnumeratorImpl::eArcsOut,
01253                                                  mAllowNegativeAssertions,
01254                                                  mCoalesceDuplicateArcs);
01255 
01256     if (! result)
01257         return NS_ERROR_OUT_OF_MEMORY;
01258 
01259     NS_ADDREF(result);
01260     *aResult = result;
01261     return NS_OK;
01262 }
01263 
01264 NS_IMETHODIMP
01265 CompositeDataSourceImpl::GetAllResources(nsISimpleEnumerator** aResult)
01266 {
01267     NS_NOTYETIMPLEMENTED("write me!");
01268     return NS_ERROR_NOT_IMPLEMENTED;
01269 }
01270 
01271 NS_IMETHODIMP
01272 CompositeDataSourceImpl::GetAllCmds(nsIRDFResource* source,
01273                                     nsISimpleEnumerator/*<nsIRDFResource>*/** result)
01274 {
01275     nsCOMPtr<nsISupportsArray> cmdArray;
01276     nsresult rv;
01277 
01278     rv = NS_NewISupportsArray(getter_AddRefs(cmdArray));
01279     if (NS_FAILED(rv)) return(rv);
01280 
01281     for (PRInt32 i = 0; i < mDataSources.Count(); i++)
01282     {
01283         nsCOMPtr<nsISimpleEnumerator> dsCmds;
01284 
01285         rv = mDataSources[i]->GetAllCmds(source, getter_AddRefs(dsCmds));
01286         if (NS_SUCCEEDED(rv))
01287         {
01288             PRBool   hasMore = PR_FALSE;
01289             while(NS_SUCCEEDED(rv = dsCmds->HasMoreElements(&hasMore)) && (hasMore == PR_TRUE))
01290             {
01291                 nsCOMPtr<nsISupports>     item;
01292                 if (NS_SUCCEEDED(rv = dsCmds->GetNext(getter_AddRefs(item))))
01293                 {
01294                     // rjc: do NOT strip out duplicate commands here
01295                     // (due to items such as separators, it is done at a higher level)
01296                     cmdArray->AppendElement(item);
01297                 }
01298             }
01299             if (NS_FAILED(rv)) return(rv);
01300         }
01301     }
01302 
01303     return NS_NewArrayEnumerator(result, cmdArray);
01304 }
01305 
01306 NS_IMETHODIMP
01307 CompositeDataSourceImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
01308                                           nsIRDFResource*   aCommand,
01309                                           nsISupportsArray/*<nsIRDFResource>*/* aArguments,
01310                                           PRBool* aResult)
01311 {
01312     nsresult rv;
01313     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01314         PRBool enabled = PR_TRUE;
01315         rv = mDataSources[i]->IsCommandEnabled(aSources, aCommand, aArguments, &enabled);
01316         if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
01317         {
01318             return(rv);
01319         }
01320 
01321         if (! enabled) {
01322             *aResult = PR_FALSE;
01323             return(NS_OK);
01324         }
01325     }
01326     *aResult = PR_TRUE;
01327     return(NS_OK);
01328 }
01329 
01330 NS_IMETHODIMP
01331 CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
01332                                    nsIRDFResource*   aCommand,
01333                                    nsISupportsArray/*<nsIRDFResource>*/* aArguments)
01334 {
01335     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01336         nsresult rv = mDataSources[i]->DoCommand(aSources, aCommand, aArguments);
01337         if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
01338         {
01339             return(rv);   // all datasources must succeed
01340         }
01341     }
01342     return(NS_OK);
01343 }
01344 
01345 NS_IMETHODIMP
01346 CompositeDataSourceImpl::BeginUpdateBatch()
01347 {
01348     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01349         mDataSources[i]->BeginUpdateBatch();
01350     }
01351     return NS_OK;
01352 }
01353 
01354 NS_IMETHODIMP
01355 CompositeDataSourceImpl::EndUpdateBatch()
01356 {
01357     for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
01358         mDataSources[i]->EndUpdateBatch();
01359     }
01360     return NS_OK;
01361 }
01362 
01364 // nsIRDFCompositeDataSource methods
01365 // XXX rvg We should make this take an additional argument specifying where
01366 // in the sequence of data sources (of the db), the new data source should
01367 // fit in. Right now, the new datasource gets stuck at the end.
01368 // need to add the observers of the CompositeDataSourceImpl to the new data source.
01369 
01370 NS_IMETHODIMP
01371 CompositeDataSourceImpl::GetAllowNegativeAssertions(PRBool *aAllowNegativeAssertions)
01372 {
01373        *aAllowNegativeAssertions = mAllowNegativeAssertions;
01374        return(NS_OK);
01375 }
01376 
01377 NS_IMETHODIMP
01378 CompositeDataSourceImpl::SetAllowNegativeAssertions(PRBool aAllowNegativeAssertions)
01379 {
01380        mAllowNegativeAssertions = aAllowNegativeAssertions;
01381        return(NS_OK);
01382 }
01383 
01384 NS_IMETHODIMP
01385 CompositeDataSourceImpl::GetCoalesceDuplicateArcs(PRBool *aCoalesceDuplicateArcs)
01386 {
01387        *aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
01388        return(NS_OK);
01389 }
01390 
01391 NS_IMETHODIMP
01392 CompositeDataSourceImpl::SetCoalesceDuplicateArcs(PRBool aCoalesceDuplicateArcs)
01393 {
01394        mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
01395        return(NS_OK);
01396 }
01397 
01398 NS_IMETHODIMP
01399 CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource)
01400 {
01401     NS_ASSERTION(aDataSource != nsnull, "null ptr");
01402     if (! aDataSource)
01403         return NS_ERROR_NULL_POINTER;
01404 
01405     mDataSources.AppendObject(aDataSource);
01406     aDataSource->AddObserver(this);
01407     return NS_OK;
01408 }
01409 
01410 
01411 
01412 NS_IMETHODIMP
01413 CompositeDataSourceImpl::RemoveDataSource(nsIRDFDataSource* aDataSource)
01414 {
01415     NS_ASSERTION(aDataSource != nsnull, "null ptr");
01416     if (! aDataSource)
01417         return NS_ERROR_NULL_POINTER;
01418 
01419 
01420     if (mDataSources.IndexOf(aDataSource) >= 0) {
01421         aDataSource->RemoveObserver(this);
01422         mDataSources.RemoveObject(aDataSource);
01423     }
01424     return NS_OK;
01425 }
01426 
01427 
01428 NS_IMETHODIMP
01429 CompositeDataSourceImpl::GetDataSources(nsISimpleEnumerator** _result)
01430 {
01431     // NS_NewArrayEnumerator for an nsCOMArray takes a snapshot of the
01432     // current state.
01433     return NS_NewArrayEnumerator(_result, mDataSources);
01434 }
01435 
01436 NS_IMETHODIMP
01437 CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource,
01438                                   nsIRDFResource* aSource,
01439                                   nsIRDFResource* aProperty,
01440                                   nsIRDFNode* aTarget)
01441 {
01442     // Make sure that the assertion isn't masked by another
01443     // datasource.
01444     //
01445     // XXX We could make this more efficient if we knew _which_
01446     // datasource actually served up the OnAssert(): we could use
01447     // HasAssertionN() to only search datasources _before_ the
01448     // datasource that coughed up the assertion.
01449        nsresult      rv = NS_OK;
01450 
01451        if (mAllowNegativeAssertions == PR_TRUE)
01452        {   
01453               PRBool hasAssertion;
01454               rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
01455               if (NS_FAILED(rv)) return rv;
01456 
01457               if (! hasAssertion)
01458                      return(NS_OK);
01459        }
01460 
01461     for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01462         mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
01463     }
01464     return NS_OK;
01465 }
01466 
01467 NS_IMETHODIMP
01468 CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource,
01469                                     nsIRDFResource* aSource,
01470                                     nsIRDFResource* aProperty,
01471                                     nsIRDFNode* aTarget)
01472 {
01473     // Make sure that the un-assertion doesn't just unmask the
01474     // same assertion in a different datasource.
01475     //
01476     // XXX We could make this more efficient if we knew _which_
01477     // datasource actually served up the OnAssert(): we could use
01478     // HasAssertionN() to only search datasources _before_ the
01479     // datasource that coughed up the assertion.
01480     nsresult rv;
01481 
01482        if (mAllowNegativeAssertions == PR_TRUE)
01483        {   
01484               PRBool hasAssertion;
01485               rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
01486               if (NS_FAILED(rv)) return rv;
01487 
01488               if (hasAssertion)
01489                      return NS_OK;
01490        }
01491 
01492     for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01493         mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget);
01494     }
01495     return NS_OK;
01496 }
01497 
01498 
01499 NS_IMETHODIMP
01500 CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource,
01501                                   nsIRDFResource* aSource,
01502                                   nsIRDFResource* aProperty,
01503                                   nsIRDFNode* aOldTarget,
01504                                   nsIRDFNode* aNewTarget)
01505 {
01506     // Make sure that the change is actually visible, and not hidden
01507     // by an assertion in a different datasource.
01508     //
01509     // XXX Because of aggregation, this could actually mutate into a
01510     // variety of OnAssert or OnChange notifications, which we'll
01511     // ignore for now :-/.
01512     for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01513         mObservers[i]->OnChange(this, aSource, aProperty,
01514                                 aOldTarget, aNewTarget);
01515     }
01516     return NS_OK;
01517 }
01518 
01519 
01520 NS_IMETHODIMP
01521 CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource,
01522                                 nsIRDFResource* aOldSource,
01523                                 nsIRDFResource* aNewSource,
01524                                 nsIRDFResource* aProperty,
01525                                 nsIRDFNode* aTarget)
01526 {
01527     // Make sure that the move is actually visible, and not hidden
01528     // by an assertion in a different datasource.
01529     //
01530     // XXX Because of aggregation, this could actually mutate into a
01531     // variety of OnAssert or OnMove notifications, which we'll
01532     // ignore for now :-/.
01533     for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01534         mObservers[i]->OnMove(this, aOldSource, aNewSource,
01535                               aProperty, aTarget);
01536     }
01537     return NS_OK;
01538 }
01539 
01540 
01541 NS_IMETHODIMP
01542 CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
01543 {
01544     if (mUpdateBatchNest++ == 0) {
01545         for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01546             mObservers[i]->OnBeginUpdateBatch(this);
01547         }
01548     }
01549     return NS_OK;
01550 }
01551 
01552 
01553 NS_IMETHODIMP
01554 CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
01555 {
01556     NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
01557     if (--mUpdateBatchNest == 0) {
01558         for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
01559             mObservers[i]->OnEndUpdateBatch(this);
01560         }
01561     }
01562     return NS_OK;
01563 }