1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Ramanathan Guha <guha@netscape.com>
24 : * Chris Waterson <waterson@netscape.com
25 : * Pierre Phaneuf <pp@ludusdesign.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /*
42 :
43 : A simple composite data source implementation. A composit data
44 : source is just a strategy for combining individual data sources into
45 : a collective graph.
46 :
47 :
48 : 1) A composite data source holds a sequence of data sources. The set
49 : of data sources can be specified during creation of the
50 : database. Data sources can also be added/deleted from a database
51 : later.
52 :
53 : 2) The aggregation mechanism is based on simple super-positioning of
54 : the graphs from the datasources. If there is a conflict (i.e.,
55 : data source A has a true arc from foo to bar while data source B
56 : has a false arc from foo to bar), the data source that it earlier
57 : in the sequence wins.
58 :
59 : The implementation below doesn't really do this and needs to be
60 : fixed.
61 :
62 : */
63 :
64 : #include "xpcom-config.h"
65 : #include NEW_H
66 : #include "nsCOMPtr.h"
67 : #include "nsIComponentManager.h"
68 : #include "nsIEnumerator.h"
69 : #include "nsIRDFCompositeDataSource.h"
70 : #include "nsIRDFNode.h"
71 : #include "nsIRDFObserver.h"
72 : #include "nsIRDFRemoteDataSource.h"
73 : #include "nsFixedSizeAllocator.h"
74 : #include "nsTArray.h"
75 : #include "nsCOMArray.h"
76 : #include "nsArrayEnumerator.h"
77 : #include "nsXPIDLString.h"
78 : #include "rdf.h"
79 : #include "nsCycleCollectionParticipant.h"
80 :
81 : #include "nsEnumeratorUtils.h"
82 :
83 : #ifdef NS_DEBUG
84 : #include "prlog.h"
85 : #include "prprf.h"
86 : #include <stdio.h>
87 : PRLogModuleInfo* nsRDFLog = nsnull;
88 : #endif
89 :
90 : static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
91 :
92 : //----------------------------------------------------------------------
93 : //
94 : // CompositeDataSourceImpl
95 : //
96 :
97 : class CompositeEnumeratorImpl;
98 : class CompositeArcsInOutEnumeratorImpl;
99 : class CompositeAssertionEnumeratorImpl;
100 :
101 : class CompositeDataSourceImpl : public nsIRDFCompositeDataSource,
102 : public nsIRDFObserver
103 : {
104 : public:
105 : CompositeDataSourceImpl(void);
106 : CompositeDataSourceImpl(char** dataSources);
107 :
108 : // nsISupports interface
109 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
110 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CompositeDataSourceImpl,
111 : nsIRDFCompositeDataSource)
112 :
113 : // nsIRDFDataSource interface
114 : NS_DECL_NSIRDFDATASOURCE
115 :
116 : // nsIRDFCompositeDataSource interface
117 : NS_DECL_NSIRDFCOMPOSITEDATASOURCE
118 :
119 : // nsIRDFObserver interface
120 : NS_DECL_NSIRDFOBSERVER
121 :
122 : bool HasAssertionN(int n, nsIRDFResource* source,
123 : nsIRDFResource* property,
124 : nsIRDFNode* target,
125 : bool tv);
126 :
127 : protected:
128 : nsCOMArray<nsIRDFObserver> mObservers;
129 : nsCOMArray<nsIRDFDataSource> mDataSources;
130 :
131 : bool mAllowNegativeAssertions;
132 : bool mCoalesceDuplicateArcs;
133 : PRInt32 mUpdateBatchNest;
134 :
135 : nsFixedSizeAllocator mAllocator;
136 :
137 0 : virtual ~CompositeDataSourceImpl() {}
138 :
139 : friend class CompositeEnumeratorImpl;
140 : friend class CompositeArcsInOutEnumeratorImpl;
141 : friend class CompositeAssertionEnumeratorImpl;
142 : };
143 :
144 : //----------------------------------------------------------------------
145 : //
146 : // CompositeEnumeratorImpl
147 : //
148 :
149 : class CompositeEnumeratorImpl : public nsISimpleEnumerator
150 : {
151 : // nsISupports
152 : NS_DECL_ISUPPORTS
153 :
154 : // nsISimpleEnumerator interface
155 : NS_DECL_NSISIMPLEENUMERATOR
156 :
157 : // pure abstract methods to be overridden
158 : virtual nsresult
159 : GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult) = 0;
160 :
161 : virtual nsresult
162 : HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult) = 0;
163 :
164 : virtual void Destroy() = 0;
165 :
166 : protected:
167 : CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
168 : bool aAllowNegativeAssertions,
169 : bool aCoalesceDuplicateArcs);
170 :
171 : virtual ~CompositeEnumeratorImpl();
172 :
173 : CompositeDataSourceImpl* mCompositeDataSource;
174 :
175 : nsISimpleEnumerator* mCurrent;
176 : nsIRDFNode* mResult;
177 : PRInt32 mNext;
178 : nsAutoTArray<nsCOMPtr<nsIRDFNode>, 8> mAlreadyReturned;
179 : bool mAllowNegativeAssertions;
180 : bool mCoalesceDuplicateArcs;
181 : };
182 :
183 :
184 0 : CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
185 : bool aAllowNegativeAssertions,
186 : bool aCoalesceDuplicateArcs)
187 : : mCompositeDataSource(aCompositeDataSource),
188 : mCurrent(nsnull),
189 : mResult(nsnull),
190 : mNext(0),
191 : mAllowNegativeAssertions(aAllowNegativeAssertions),
192 0 : mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
193 : {
194 0 : NS_ADDREF(mCompositeDataSource);
195 0 : }
196 :
197 :
198 0 : CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void)
199 : {
200 0 : NS_IF_RELEASE(mCurrent);
201 0 : NS_IF_RELEASE(mResult);
202 0 : NS_RELEASE(mCompositeDataSource);
203 0 : }
204 :
205 0 : NS_IMPL_ADDREF(CompositeEnumeratorImpl)
206 0 : NS_IMPL_RELEASE_WITH_DESTROY(CompositeEnumeratorImpl, Destroy())
207 0 : NS_IMPL_QUERY_INTERFACE1(CompositeEnumeratorImpl, nsISimpleEnumerator)
208 :
209 : NS_IMETHODIMP
210 0 : CompositeEnumeratorImpl::HasMoreElements(bool* aResult)
211 : {
212 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
213 0 : if (! aResult)
214 0 : return NS_ERROR_NULL_POINTER;
215 :
216 : nsresult rv;
217 :
218 : // If we've already queued up a next target, then yep, there are
219 : // more elements.
220 0 : if (mResult) {
221 0 : *aResult = true;
222 0 : return NS_OK;
223 : }
224 :
225 : // Otherwise, we'll need to find a next target, switching cursors
226 : // if necessary.
227 0 : for ( ; mNext < mCompositeDataSource->mDataSources.Count(); ++mNext) {
228 0 : if (! mCurrent) {
229 : // We don't have a current enumerator, so create a new one on
230 : // the next data source.
231 : nsIRDFDataSource* datasource =
232 0 : mCompositeDataSource->mDataSources[mNext];
233 :
234 0 : rv = GetEnumerator(datasource, &mCurrent);
235 0 : if (NS_FAILED(rv)) return rv;
236 0 : if (rv == NS_RDF_NO_VALUE)
237 0 : continue;
238 :
239 0 : NS_ASSERTION(mCurrent != nsnull, "you're always supposed to return an enumerator from GetEnumerator, punk.");
240 0 : if (! mCurrent)
241 0 : continue;
242 : }
243 :
244 0 : do {
245 : PRInt32 i;
246 :
247 : bool hasMore;
248 0 : rv = mCurrent->HasMoreElements(&hasMore);
249 0 : if (NS_FAILED(rv)) return rv;
250 :
251 : // Is the current enumerator depleted?
252 0 : if (! hasMore) {
253 0 : NS_RELEASE(mCurrent);
254 0 : break;
255 : }
256 :
257 : // Even if the current enumerator has more elements, we still
258 : // need to check that the current element isn't masked by
259 : // a negation in an earlier data source.
260 :
261 : // "Peek" ahead and pull out the next target.
262 0 : nsCOMPtr<nsISupports> result;
263 0 : rv = mCurrent->GetNext(getter_AddRefs(result));
264 0 : if (NS_FAILED(rv)) return rv;
265 :
266 0 : rv = result->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) &mResult);
267 0 : if (NS_FAILED(rv)) return rv;
268 :
269 0 : if (mAllowNegativeAssertions)
270 : {
271 : // See if any previous data source negates this
272 0 : bool hasNegation = false;
273 0 : for (i = mNext - 1; i >= 0; --i)
274 : {
275 : nsIRDFDataSource* datasource =
276 0 : mCompositeDataSource->mDataSources[i];
277 :
278 0 : rv = HasNegation(datasource, mResult, &hasNegation);
279 0 : if (NS_FAILED(rv)) return rv;
280 :
281 0 : if (hasNegation)
282 0 : break;
283 : }
284 :
285 : // if so, we've gotta keep looking
286 0 : if (hasNegation)
287 : {
288 0 : NS_RELEASE(mResult);
289 0 : continue;
290 : }
291 : }
292 :
293 0 : if (mCoalesceDuplicateArcs)
294 : {
295 : // Now see if we've returned it once already.
296 : // XXX N.B. performance here...may want to hash if things get large?
297 0 : bool alreadyReturned = false;
298 0 : for (i = mAlreadyReturned.Length() - 1; i >= 0; --i)
299 : {
300 0 : if (mAlreadyReturned[i] == mResult)
301 : {
302 0 : alreadyReturned = true;
303 0 : break;
304 : }
305 : }
306 0 : if (alreadyReturned)
307 : {
308 0 : NS_RELEASE(mResult);
309 0 : continue;
310 : }
311 : }
312 :
313 : // If we get here, then we've really found one. It'll
314 : // remain cached in mResult until GetNext() sucks it out.
315 0 : *aResult = true;
316 :
317 : // Remember that we returned it, so we don't return duplicates.
318 :
319 : // XXX I wonder if we should make unique-checking be
320 : // optional. This could get to be pretty expensive (this
321 : // implementation turns iteration into O(n^2)).
322 :
323 0 : if (mCoalesceDuplicateArcs)
324 : {
325 0 : mAlreadyReturned.AppendElement(mResult);
326 : }
327 :
328 0 : return NS_OK;
329 : } while (1);
330 : }
331 :
332 : // if we get here, there aren't any elements left.
333 0 : *aResult = false;
334 0 : return NS_OK;
335 : }
336 :
337 :
338 : NS_IMETHODIMP
339 0 : CompositeEnumeratorImpl::GetNext(nsISupports** aResult)
340 : {
341 : nsresult rv;
342 :
343 : bool hasMore;
344 0 : rv = HasMoreElements(&hasMore);
345 0 : if (NS_FAILED(rv)) return rv;
346 :
347 0 : if (! hasMore)
348 0 : return NS_ERROR_UNEXPECTED;
349 :
350 : // Don't AddRef: we "transfer" ownership to the caller
351 0 : *aResult = mResult;
352 0 : mResult = nsnull;
353 :
354 0 : return NS_OK;
355 : }
356 :
357 : //----------------------------------------------------------------------
358 : //
359 : // CompositeArcsInOutEnumeratorImpl
360 : //
361 : //
362 :
363 : class CompositeArcsInOutEnumeratorImpl : public CompositeEnumeratorImpl
364 : {
365 : public:
366 : enum Type { eArcsIn, eArcsOut };
367 :
368 : static CompositeArcsInOutEnumeratorImpl*
369 0 : Create(nsFixedSizeAllocator& aAllocator,
370 : CompositeDataSourceImpl* aCompositeDataSource,
371 : nsIRDFNode* aNode,
372 : Type aType,
373 : bool aAllowNegativeAssertions,
374 : bool aCoalesceDuplicateArcs) {
375 0 : void* place = aAllocator.Alloc(sizeof(CompositeArcsInOutEnumeratorImpl));
376 : return place
377 : ? ::new (place) CompositeArcsInOutEnumeratorImpl(aCompositeDataSource,
378 : aNode, aType,
379 : aAllowNegativeAssertions,
380 0 : aCoalesceDuplicateArcs)
381 0 : : nsnull; }
382 :
383 : virtual ~CompositeArcsInOutEnumeratorImpl();
384 :
385 : virtual nsresult
386 : GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
387 :
388 : virtual nsresult
389 : HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
390 :
391 : virtual void Destroy();
392 :
393 : protected:
394 : CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
395 : nsIRDFNode* aNode,
396 : Type aType,
397 : bool aAllowNegativeAssertions,
398 : bool aCoalesceDuplicateArcs);
399 :
400 : private:
401 : nsIRDFNode* mNode;
402 : Type mType;
403 : bool mAllowNegativeAssertions;
404 : bool mCoalesceDuplicateArcs;
405 :
406 : // Hide so that only Create() and Destroy() can be used to
407 : // allocate and deallocate from the heap
408 : static void* operator new(size_t) CPP_THROW_NEW { return 0; }
409 0 : static void operator delete(void*, size_t) {}
410 : };
411 :
412 :
413 0 : CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl(
414 : CompositeDataSourceImpl* aCompositeDataSource,
415 : nsIRDFNode* aNode,
416 : Type aType,
417 : bool aAllowNegativeAssertions,
418 : bool aCoalesceDuplicateArcs)
419 : : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
420 : mNode(aNode),
421 : mType(aType),
422 : mAllowNegativeAssertions(aAllowNegativeAssertions),
423 0 : mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
424 : {
425 0 : NS_ADDREF(mNode);
426 0 : }
427 :
428 0 : CompositeArcsInOutEnumeratorImpl::~CompositeArcsInOutEnumeratorImpl()
429 : {
430 0 : NS_RELEASE(mNode);
431 0 : }
432 :
433 :
434 : nsresult
435 0 : CompositeArcsInOutEnumeratorImpl::GetEnumerator(
436 : nsIRDFDataSource* aDataSource,
437 : nsISimpleEnumerator** aResult)
438 : {
439 0 : if (mType == eArcsIn) {
440 0 : return aDataSource->ArcLabelsIn(mNode, aResult);
441 : }
442 : else {
443 0 : nsCOMPtr<nsIRDFResource> resource( do_QueryInterface(mNode) );
444 0 : return aDataSource->ArcLabelsOut(resource, aResult);
445 : }
446 : }
447 :
448 : nsresult
449 0 : CompositeArcsInOutEnumeratorImpl::HasNegation(
450 : nsIRDFDataSource* aDataSource,
451 : nsIRDFNode* aNode,
452 : bool* aResult)
453 : {
454 0 : *aResult = false;
455 0 : return NS_OK;
456 : }
457 :
458 : void
459 0 : CompositeArcsInOutEnumeratorImpl::Destroy()
460 : {
461 : // Keep the datasource alive for the duration of the stack
462 : // frame so its allocator stays valid.
463 0 : nsCOMPtr<nsIRDFCompositeDataSource> kungFuDeathGrip = mCompositeDataSource;
464 :
465 0 : nsFixedSizeAllocator& pool = mCompositeDataSource->mAllocator;
466 0 : this->~CompositeArcsInOutEnumeratorImpl();
467 0 : pool.Free(this, sizeof(*this));
468 0 : }
469 :
470 :
471 : //----------------------------------------------------------------------
472 : //
473 : // CompositeAssertionEnumeratorImpl
474 : //
475 :
476 : class CompositeAssertionEnumeratorImpl : public CompositeEnumeratorImpl
477 : {
478 : public:
479 : static CompositeAssertionEnumeratorImpl*
480 0 : Create(nsFixedSizeAllocator& aAllocator,
481 : CompositeDataSourceImpl* aCompositeDataSource,
482 : nsIRDFResource* aSource,
483 : nsIRDFResource* aProperty,
484 : nsIRDFNode* aTarget,
485 : bool aTruthValue,
486 : bool aAllowNegativeAssertions,
487 : bool aCoalesceDuplicateArcs) {
488 0 : void* place = aAllocator.Alloc(sizeof(CompositeAssertionEnumeratorImpl));
489 : return place
490 : ? ::new (place) CompositeAssertionEnumeratorImpl(aCompositeDataSource,
491 : aSource, aProperty, aTarget,
492 : aTruthValue,
493 : aAllowNegativeAssertions,
494 0 : aCoalesceDuplicateArcs)
495 0 : : nsnull; }
496 :
497 : virtual nsresult
498 : GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
499 :
500 : virtual nsresult
501 : HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
502 :
503 : virtual void Destroy();
504 :
505 : protected:
506 : CompositeAssertionEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
507 : nsIRDFResource* aSource,
508 : nsIRDFResource* aProperty,
509 : nsIRDFNode* aTarget,
510 : bool aTruthValue,
511 : bool aAllowNegativeAssertions,
512 : bool aCoalesceDuplicateArcs);
513 :
514 : virtual ~CompositeAssertionEnumeratorImpl();
515 :
516 : private:
517 : nsIRDFResource* mSource;
518 : nsIRDFResource* mProperty;
519 : nsIRDFNode* mTarget;
520 : bool mTruthValue;
521 : bool mAllowNegativeAssertions;
522 : bool mCoalesceDuplicateArcs;
523 :
524 : // Hide so that only Create() and Destroy() can be used to
525 : // allocate and deallocate from the heap
526 : static void* operator new(size_t) CPP_THROW_NEW { return 0; }
527 0 : static void operator delete(void*, size_t) {}
528 : };
529 :
530 :
531 0 : CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl(
532 : CompositeDataSourceImpl* aCompositeDataSource,
533 : nsIRDFResource* aSource,
534 : nsIRDFResource* aProperty,
535 : nsIRDFNode* aTarget,
536 : bool aTruthValue,
537 : bool aAllowNegativeAssertions,
538 : bool aCoalesceDuplicateArcs)
539 : : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
540 : mSource(aSource),
541 : mProperty(aProperty),
542 : mTarget(aTarget),
543 : mTruthValue(aTruthValue),
544 : mAllowNegativeAssertions(aAllowNegativeAssertions),
545 0 : mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
546 : {
547 0 : NS_IF_ADDREF(mSource);
548 0 : NS_ADDREF(mProperty); // always must be specified
549 0 : NS_IF_ADDREF(mTarget);
550 0 : }
551 :
552 0 : CompositeAssertionEnumeratorImpl::~CompositeAssertionEnumeratorImpl()
553 : {
554 0 : NS_IF_RELEASE(mSource);
555 0 : NS_RELEASE(mProperty);
556 0 : NS_IF_RELEASE(mTarget);
557 0 : }
558 :
559 :
560 : nsresult
561 0 : CompositeAssertionEnumeratorImpl::GetEnumerator(
562 : nsIRDFDataSource* aDataSource,
563 : nsISimpleEnumerator** aResult)
564 : {
565 0 : if (mSource) {
566 0 : return aDataSource->GetTargets(mSource, mProperty, mTruthValue, aResult);
567 : }
568 : else {
569 0 : return aDataSource->GetSources(mProperty, mTarget, mTruthValue, aResult);
570 : }
571 : }
572 :
573 : nsresult
574 0 : CompositeAssertionEnumeratorImpl::HasNegation(
575 : nsIRDFDataSource* aDataSource,
576 : nsIRDFNode* aNode,
577 : bool* aResult)
578 : {
579 0 : if (mSource) {
580 0 : return aDataSource->HasAssertion(mSource, mProperty, aNode, !mTruthValue, aResult);
581 : }
582 : else {
583 0 : nsCOMPtr<nsIRDFResource> source( do_QueryInterface(aNode) );
584 0 : return aDataSource->HasAssertion(source, mProperty, mTarget, !mTruthValue, aResult);
585 : }
586 : }
587 :
588 : void
589 0 : CompositeAssertionEnumeratorImpl::Destroy()
590 : {
591 : // Keep the datasource alive for the duration of the stack
592 : // frame so its allocator stays valid.
593 0 : nsCOMPtr<nsIRDFCompositeDataSource> kungFuDeathGrip = mCompositeDataSource;
594 :
595 0 : nsFixedSizeAllocator& pool = mCompositeDataSource->mAllocator;
596 0 : this->~CompositeAssertionEnumeratorImpl();
597 0 : pool.Free(this, sizeof(*this));
598 0 : }
599 :
600 : ////////////////////////////////////////////////////////////////////////
601 :
602 : nsresult
603 0 : NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result)
604 : {
605 0 : CompositeDataSourceImpl* db = new CompositeDataSourceImpl();
606 0 : if (! db)
607 0 : return NS_ERROR_OUT_OF_MEMORY;
608 :
609 0 : *result = db;
610 0 : NS_ADDREF(*result);
611 0 : return NS_OK;
612 : }
613 :
614 :
615 0 : CompositeDataSourceImpl::CompositeDataSourceImpl(void)
616 : : mAllowNegativeAssertions(true),
617 : mCoalesceDuplicateArcs(true),
618 0 : mUpdateBatchNest(0)
619 : {
620 : static const size_t kBucketSizes[] = {
621 : sizeof(CompositeAssertionEnumeratorImpl),
622 : sizeof(CompositeArcsInOutEnumeratorImpl) };
623 :
624 : static const PRInt32 kNumBuckets = sizeof(kBucketSizes) / sizeof(size_t);
625 :
626 : // Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
627 : static const PRInt32 kInitialSize = 256;
628 :
629 0 : mAllocator.Init("nsCompositeDataSource", kBucketSizes, kNumBuckets, kInitialSize);
630 :
631 : #ifdef PR_LOGGING
632 0 : if (nsRDFLog == nsnull)
633 0 : nsRDFLog = PR_NewLogModule("RDF");
634 : #endif
635 0 : }
636 :
637 : //----------------------------------------------------------------------
638 : //
639 : // nsISupports interface
640 : //
641 :
642 1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(CompositeDataSourceImpl)
643 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CompositeDataSourceImpl)
644 0 : PRUint32 i, count = tmp->mDataSources.Count();
645 0 : for (i = count; i > 0; --i) {
646 0 : tmp->mDataSources[i - 1]->RemoveObserver(tmp);
647 0 : tmp->mDataSources.RemoveObjectAt(i - 1);
648 : }
649 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mObservers);
650 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
651 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CompositeDataSourceImpl)
652 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mObservers)
653 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mDataSources)
654 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
655 :
656 :
657 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(CompositeDataSourceImpl)
658 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(CompositeDataSourceImpl)
659 :
660 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositeDataSourceImpl)
661 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
662 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
663 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFObserver)
664 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
665 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFCompositeDataSource)
666 0 : NS_INTERFACE_MAP_END
667 :
668 :
669 : //----------------------------------------------------------------------
670 : //
671 : // nsIRDFDataSource interface
672 : //
673 :
674 : NS_IMETHODIMP
675 0 : CompositeDataSourceImpl::GetURI(char* *uri)
676 : {
677 0 : *uri = nsnull;
678 0 : return NS_OK;
679 : }
680 :
681 : NS_IMETHODIMP
682 0 : CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
683 : nsIRDFNode* target,
684 : bool tv,
685 : nsIRDFResource** source)
686 : {
687 0 : if (!mAllowNegativeAssertions && !tv)
688 0 : return(NS_RDF_NO_VALUE);
689 :
690 0 : PRInt32 count = mDataSources.Count();
691 0 : for (PRInt32 i = 0; i < count; ++i) {
692 : nsresult rv;
693 0 : rv = mDataSources[i]->GetSource(property, target, tv, source);
694 0 : if (NS_FAILED(rv)) return rv;
695 :
696 0 : if (rv == NS_RDF_NO_VALUE)
697 0 : continue;
698 :
699 0 : if (!mAllowNegativeAssertions) return(NS_OK);
700 :
701 : // okay, found it. make sure we don't have the opposite
702 : // asserted in a more local data source
703 0 : if (!HasAssertionN(count-1, *source, property, target, !tv))
704 0 : return NS_OK;
705 :
706 0 : NS_RELEASE(*source);
707 0 : return NS_RDF_NO_VALUE;
708 : }
709 0 : return NS_RDF_NO_VALUE;
710 : }
711 :
712 : NS_IMETHODIMP
713 0 : CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty,
714 : nsIRDFNode* aTarget,
715 : bool aTruthValue,
716 : nsISimpleEnumerator** aResult)
717 : {
718 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
719 0 : if (! aProperty)
720 0 : return NS_ERROR_NULL_POINTER;
721 :
722 0 : NS_PRECONDITION(aTarget != nsnull, "null ptr");
723 0 : if (! aTarget)
724 0 : return NS_ERROR_NULL_POINTER;
725 :
726 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
727 0 : if (! aResult)
728 0 : return NS_ERROR_NULL_POINTER;
729 :
730 0 : if (! mAllowNegativeAssertions && ! aTruthValue)
731 0 : return(NS_RDF_NO_VALUE);
732 :
733 : *aResult = CompositeAssertionEnumeratorImpl::Create(mAllocator,
734 : this, nsnull, aProperty,
735 : aTarget, aTruthValue,
736 : mAllowNegativeAssertions,
737 0 : mCoalesceDuplicateArcs);
738 :
739 0 : if (! *aResult)
740 0 : return NS_ERROR_OUT_OF_MEMORY;
741 :
742 0 : NS_ADDREF(*aResult);
743 0 : return NS_OK;
744 : }
745 :
746 : NS_IMETHODIMP
747 0 : CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
748 : nsIRDFResource* aProperty,
749 : bool aTruthValue,
750 : nsIRDFNode** aResult)
751 : {
752 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
753 0 : if (! aSource)
754 0 : return NS_ERROR_NULL_POINTER;
755 :
756 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
757 0 : if (! aProperty)
758 0 : return NS_ERROR_NULL_POINTER;
759 :
760 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
761 0 : if (! aResult)
762 0 : return NS_ERROR_NULL_POINTER;
763 :
764 0 : if (! mAllowNegativeAssertions && ! aTruthValue)
765 0 : return(NS_RDF_NO_VALUE);
766 :
767 0 : PRInt32 count = mDataSources.Count();
768 0 : for (PRInt32 i = 0; i < count; ++i) {
769 : nsresult rv;
770 0 : rv = mDataSources[i]->GetTarget(aSource, aProperty, aTruthValue,
771 0 : aResult);
772 0 : if (NS_FAILED(rv))
773 0 : return rv;
774 :
775 0 : if (rv == NS_OK) {
776 : // okay, found it. make sure we don't have the opposite
777 : // asserted in an earlier data source
778 :
779 0 : if (mAllowNegativeAssertions) {
780 0 : if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
781 : // whoops, it's been negated.
782 0 : NS_RELEASE(*aResult);
783 0 : return NS_RDF_NO_VALUE;
784 : }
785 : }
786 0 : return NS_OK;
787 : }
788 : }
789 :
790 : // Otherwise, we couldn't find it at all.
791 0 : return NS_RDF_NO_VALUE;
792 : }
793 :
794 : bool
795 0 : CompositeDataSourceImpl::HasAssertionN(int n,
796 : nsIRDFResource* aSource,
797 : nsIRDFResource* aProperty,
798 : nsIRDFNode* aTarget,
799 : bool aTruthValue)
800 : {
801 : nsresult rv;
802 0 : for (PRInt32 m = 0; m < n; ++m) {
803 : bool result;
804 0 : rv = mDataSources[m]->HasAssertion(aSource, aProperty, aTarget,
805 0 : aTruthValue, &result);
806 0 : if (NS_FAILED(rv))
807 0 : return false;
808 :
809 : // found it!
810 0 : if (result)
811 0 : return true;
812 : }
813 0 : return false;
814 : }
815 :
816 :
817 :
818 : NS_IMETHODIMP
819 0 : CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource,
820 : nsIRDFResource* aProperty,
821 : bool aTruthValue,
822 : nsISimpleEnumerator** aResult)
823 : {
824 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
825 0 : if (! aSource)
826 0 : return NS_ERROR_NULL_POINTER;
827 :
828 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
829 0 : if (! aProperty)
830 0 : return NS_ERROR_NULL_POINTER;
831 :
832 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
833 0 : if (! aResult)
834 0 : return NS_ERROR_NULL_POINTER;
835 :
836 0 : if (! mAllowNegativeAssertions && ! aTruthValue)
837 0 : return(NS_RDF_NO_VALUE);
838 :
839 : *aResult =
840 : CompositeAssertionEnumeratorImpl::Create(mAllocator, this,
841 : aSource, aProperty, nsnull,
842 : aTruthValue,
843 : mAllowNegativeAssertions,
844 0 : mCoalesceDuplicateArcs);
845 :
846 0 : if (! *aResult)
847 0 : return NS_ERROR_OUT_OF_MEMORY;
848 :
849 0 : NS_ADDREF(*aResult);
850 0 : return NS_OK;
851 : }
852 :
853 : NS_IMETHODIMP
854 0 : CompositeDataSourceImpl::Assert(nsIRDFResource* aSource,
855 : nsIRDFResource* aProperty,
856 : nsIRDFNode* aTarget,
857 : bool aTruthValue)
858 : {
859 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
860 0 : if (! aSource)
861 0 : return NS_ERROR_NULL_POINTER;
862 :
863 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
864 0 : if (! aProperty)
865 0 : return NS_ERROR_NULL_POINTER;
866 :
867 0 : NS_PRECONDITION(aTarget != nsnull, "null ptr");
868 0 : if (! aTarget)
869 0 : return NS_ERROR_NULL_POINTER;
870 :
871 0 : if (! mAllowNegativeAssertions && ! aTruthValue)
872 0 : return(NS_RDF_ASSERTION_REJECTED);
873 :
874 : nsresult rv;
875 :
876 : // XXX Need to add back the stuff for unblocking ...
877 :
878 : // We iterate backwards from the last data source which was added
879 : // ("the most remote") to the first ("the most local"), trying to
880 : // apply the assertion in each.
881 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
882 0 : rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, aTruthValue);
883 0 : if (NS_RDF_ASSERTION_ACCEPTED == rv)
884 0 : return rv;
885 :
886 0 : if (NS_FAILED(rv))
887 0 : return rv;
888 : }
889 :
890 : // nobody wanted to accept it
891 0 : return NS_RDF_ASSERTION_REJECTED;
892 : }
893 :
894 : NS_IMETHODIMP
895 0 : CompositeDataSourceImpl::Unassert(nsIRDFResource* aSource,
896 : nsIRDFResource* aProperty,
897 : nsIRDFNode* aTarget)
898 : {
899 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
900 0 : if (! aSource)
901 0 : return NS_ERROR_NULL_POINTER;
902 :
903 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
904 0 : if (! aProperty)
905 0 : return NS_ERROR_NULL_POINTER;
906 :
907 0 : NS_PRECONDITION(aTarget != nsnull, "null ptr");
908 0 : if (! aTarget)
909 0 : return NS_ERROR_NULL_POINTER;
910 :
911 : nsresult rv;
912 :
913 : // Iterate through each of the datasources, starting with "the
914 : // most local" and moving to "the most remote". If _any_ of the
915 : // datasources have the assertion, attempt to unassert it.
916 0 : bool unasserted = true;
917 : PRInt32 i;
918 0 : PRInt32 count = mDataSources.Count();
919 0 : for (i = 0; i < count; ++i) {
920 0 : nsIRDFDataSource* ds = mDataSources[i];
921 :
922 : bool hasAssertion;
923 0 : rv = ds->HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
924 0 : if (NS_FAILED(rv)) return rv;
925 :
926 0 : if (hasAssertion) {
927 0 : rv = ds->Unassert(aSource, aProperty, aTarget);
928 0 : if (NS_FAILED(rv)) return rv;
929 :
930 0 : if (rv != NS_RDF_ASSERTION_ACCEPTED) {
931 0 : unasserted = false;
932 0 : break;
933 : }
934 : }
935 : }
936 :
937 : // Either none of the datasources had it, or they were all willing
938 : // to let it be unasserted.
939 0 : if (unasserted)
940 0 : return NS_RDF_ASSERTION_ACCEPTED;
941 :
942 : // If we get here, one of the datasources already had the
943 : // assertion, and was adamant about not letting us remove
944 : // it. Iterate from the "most local" to the "most remote"
945 : // attempting to assert the negation...
946 0 : for (i = 0; i < count; ++i) {
947 0 : rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, false);
948 0 : if (NS_FAILED(rv)) return rv;
949 :
950 : // Did it take?
951 0 : if (rv == NS_RDF_ASSERTION_ACCEPTED)
952 0 : return rv;
953 : }
954 :
955 : // Couln't get anyone to accept the negation, either.
956 0 : return NS_RDF_ASSERTION_REJECTED;
957 : }
958 :
959 : NS_IMETHODIMP
960 0 : CompositeDataSourceImpl::Change(nsIRDFResource* aSource,
961 : nsIRDFResource* aProperty,
962 : nsIRDFNode* aOldTarget,
963 : nsIRDFNode* aNewTarget)
964 : {
965 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
966 0 : if (! aSource)
967 0 : return NS_ERROR_NULL_POINTER;
968 :
969 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
970 0 : if (! aProperty)
971 0 : return NS_ERROR_NULL_POINTER;
972 :
973 0 : NS_PRECONDITION(aOldTarget != nsnull, "null ptr");
974 0 : if (! aOldTarget)
975 0 : return NS_ERROR_NULL_POINTER;
976 :
977 0 : NS_PRECONDITION(aNewTarget != nsnull, "null ptr");
978 0 : if (! aNewTarget)
979 0 : return NS_ERROR_NULL_POINTER;
980 :
981 : nsresult rv;
982 :
983 : // XXX So we're assuming that a datasource _must_ accept the
984 : // atomic change; i.e., we can't split it up across two
985 : // datasources. That sucks.
986 :
987 : // We iterate backwards from the last data source which was added
988 : // ("the most remote") to the first ("the most local"), trying to
989 : // apply the change in each.
990 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
991 0 : rv = mDataSources[i]->Change(aSource, aProperty, aOldTarget, aNewTarget);
992 0 : if (NS_RDF_ASSERTION_ACCEPTED == rv)
993 0 : return rv;
994 :
995 0 : if (NS_FAILED(rv))
996 0 : return rv;
997 : }
998 :
999 : // nobody wanted to accept it
1000 0 : return NS_RDF_ASSERTION_REJECTED;
1001 : }
1002 :
1003 : NS_IMETHODIMP
1004 0 : CompositeDataSourceImpl::Move(nsIRDFResource* aOldSource,
1005 : nsIRDFResource* aNewSource,
1006 : nsIRDFResource* aProperty,
1007 : nsIRDFNode* aTarget)
1008 : {
1009 0 : NS_PRECONDITION(aOldSource != nsnull, "null ptr");
1010 0 : if (! aOldSource)
1011 0 : return NS_ERROR_NULL_POINTER;
1012 :
1013 0 : NS_PRECONDITION(aNewSource != nsnull, "null ptr");
1014 0 : if (! aNewSource)
1015 0 : return NS_ERROR_NULL_POINTER;
1016 :
1017 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
1018 0 : if (! aProperty)
1019 0 : return NS_ERROR_NULL_POINTER;
1020 :
1021 0 : NS_PRECONDITION(aTarget != nsnull, "null ptr");
1022 0 : if (! aTarget)
1023 0 : return NS_ERROR_NULL_POINTER;
1024 :
1025 : nsresult rv;
1026 :
1027 : // XXX So we're assuming that a datasource _must_ accept the
1028 : // atomic move; i.e., we can't split it up across two
1029 : // datasources. That sucks.
1030 :
1031 : // We iterate backwards from the last data source which was added
1032 : // ("the most remote") to the first ("the most local"), trying to
1033 : // apply the assertion in each.
1034 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
1035 0 : rv = mDataSources[i]->Move(aOldSource, aNewSource, aProperty, aTarget);
1036 0 : if (NS_RDF_ASSERTION_ACCEPTED == rv)
1037 0 : return rv;
1038 :
1039 0 : if (NS_FAILED(rv))
1040 0 : return rv;
1041 : }
1042 :
1043 : // nobody wanted to accept it
1044 0 : return NS_RDF_ASSERTION_REJECTED;
1045 : }
1046 :
1047 :
1048 : NS_IMETHODIMP
1049 0 : CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
1050 : nsIRDFResource* aProperty,
1051 : nsIRDFNode* aTarget,
1052 : bool aTruthValue,
1053 : bool* aResult)
1054 : {
1055 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
1056 0 : if (! aSource)
1057 0 : return NS_ERROR_NULL_POINTER;
1058 :
1059 0 : NS_PRECONDITION(aProperty != nsnull, "null ptr");
1060 0 : if (! aProperty)
1061 0 : return NS_ERROR_NULL_POINTER;
1062 :
1063 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
1064 0 : if (! aResult)
1065 0 : return NS_ERROR_NULL_POINTER;
1066 :
1067 0 : if (! mAllowNegativeAssertions && ! aTruthValue)
1068 : {
1069 0 : *aResult = false;
1070 0 : return(NS_OK);
1071 : }
1072 :
1073 : nsresult rv;
1074 :
1075 : // Otherwise, look through all the data sources to see if anyone
1076 : // has the positive...
1077 0 : PRInt32 count = mDataSources.Count();
1078 0 : for (PRInt32 i = 0; i < count; ++i) {
1079 0 : nsIRDFDataSource* datasource = mDataSources[i];
1080 0 : rv = datasource->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult);
1081 0 : if (NS_FAILED(rv)) return rv;
1082 :
1083 0 : if (*aResult)
1084 0 : return NS_OK;
1085 :
1086 0 : if (mAllowNegativeAssertions)
1087 : {
1088 : bool hasNegation;
1089 0 : rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
1090 0 : if (NS_FAILED(rv)) return rv;
1091 :
1092 0 : if (hasNegation)
1093 : {
1094 0 : *aResult = false;
1095 0 : return NS_OK;
1096 : }
1097 : }
1098 : }
1099 :
1100 : // If we get here, nobody had the assertion at all
1101 0 : *aResult = false;
1102 0 : return NS_OK;
1103 : }
1104 :
1105 : NS_IMETHODIMP
1106 0 : CompositeDataSourceImpl::AddObserver(nsIRDFObserver* aObserver)
1107 : {
1108 0 : NS_PRECONDITION(aObserver != nsnull, "null ptr");
1109 0 : if (! aObserver)
1110 0 : return NS_ERROR_NULL_POINTER;
1111 :
1112 : // XXX ensure uniqueness?
1113 0 : mObservers.AppendObject(aObserver);
1114 :
1115 0 : return NS_OK;
1116 : }
1117 :
1118 : NS_IMETHODIMP
1119 0 : CompositeDataSourceImpl::RemoveObserver(nsIRDFObserver* aObserver)
1120 : {
1121 0 : NS_PRECONDITION(aObserver != nsnull, "null ptr");
1122 0 : if (! aObserver)
1123 0 : return NS_ERROR_NULL_POINTER;
1124 :
1125 0 : mObservers.RemoveObject(aObserver);
1126 :
1127 0 : return NS_OK;
1128 : }
1129 :
1130 : NS_IMETHODIMP
1131 0 : CompositeDataSourceImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
1132 : {
1133 : nsresult rv;
1134 0 : *result = false;
1135 0 : PRInt32 count = mDataSources.Count();
1136 0 : for (PRInt32 i = 0; i < count; ++i) {
1137 0 : rv = mDataSources[i]->HasArcIn(aNode, aArc, result);
1138 0 : if (NS_FAILED(rv)) return rv;
1139 0 : if (*result)
1140 0 : return NS_OK;
1141 : }
1142 0 : return NS_OK;
1143 : }
1144 :
1145 : NS_IMETHODIMP
1146 0 : CompositeDataSourceImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
1147 : {
1148 : nsresult rv;
1149 0 : *result = false;
1150 0 : PRInt32 count = mDataSources.Count();
1151 0 : for (PRInt32 i = 0; i < count; ++i) {
1152 0 : rv = mDataSources[i]->HasArcOut(aSource, aArc, result);
1153 0 : if (NS_FAILED(rv)) return rv;
1154 0 : if (*result)
1155 0 : return NS_OK;
1156 : }
1157 0 : return NS_OK;
1158 : }
1159 :
1160 : NS_IMETHODIMP
1161 0 : CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
1162 : {
1163 0 : NS_PRECONDITION(aTarget != nsnull, "null ptr");
1164 0 : if (! aTarget)
1165 0 : return NS_ERROR_NULL_POINTER;
1166 :
1167 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
1168 0 : if (! aResult)
1169 0 : return NS_ERROR_NULL_POINTER;
1170 :
1171 : nsISimpleEnumerator* result =
1172 : CompositeArcsInOutEnumeratorImpl::Create(mAllocator, this, aTarget,
1173 : CompositeArcsInOutEnumeratorImpl::eArcsIn,
1174 : mAllowNegativeAssertions,
1175 0 : mCoalesceDuplicateArcs);
1176 :
1177 0 : if (! result)
1178 0 : return NS_ERROR_OUT_OF_MEMORY;
1179 :
1180 0 : NS_ADDREF(result);
1181 0 : *aResult = result;
1182 0 : return NS_OK;
1183 : }
1184 :
1185 : NS_IMETHODIMP
1186 0 : CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource,
1187 : nsISimpleEnumerator** aResult)
1188 : {
1189 0 : NS_PRECONDITION(aSource != nsnull, "null ptr");
1190 0 : if (! aSource)
1191 0 : return NS_ERROR_NULL_POINTER;
1192 :
1193 0 : NS_PRECONDITION(aResult != nsnull, "null ptr");
1194 0 : if (! aResult)
1195 0 : return NS_ERROR_NULL_POINTER;
1196 :
1197 : nsISimpleEnumerator* result =
1198 : CompositeArcsInOutEnumeratorImpl::Create(mAllocator, this, aSource,
1199 : CompositeArcsInOutEnumeratorImpl::eArcsOut,
1200 : mAllowNegativeAssertions,
1201 0 : mCoalesceDuplicateArcs);
1202 :
1203 0 : if (! result)
1204 0 : return NS_ERROR_OUT_OF_MEMORY;
1205 :
1206 0 : NS_ADDREF(result);
1207 0 : *aResult = result;
1208 0 : return NS_OK;
1209 : }
1210 :
1211 : NS_IMETHODIMP
1212 0 : CompositeDataSourceImpl::GetAllResources(nsISimpleEnumerator** aResult)
1213 : {
1214 0 : NS_NOTYETIMPLEMENTED("CompositeDataSourceImpl::GetAllResources");
1215 0 : return NS_ERROR_NOT_IMPLEMENTED;
1216 : }
1217 :
1218 : NS_IMETHODIMP
1219 0 : CompositeDataSourceImpl::GetAllCmds(nsIRDFResource* source,
1220 : nsISimpleEnumerator/*<nsIRDFResource>*/** result)
1221 : {
1222 0 : nsCOMPtr<nsISupportsArray> cmdArray;
1223 : nsresult rv;
1224 :
1225 0 : rv = NS_NewISupportsArray(getter_AddRefs(cmdArray));
1226 0 : if (NS_FAILED(rv)) return(rv);
1227 :
1228 0 : for (PRInt32 i = 0; i < mDataSources.Count(); i++)
1229 : {
1230 0 : nsCOMPtr<nsISimpleEnumerator> dsCmds;
1231 :
1232 0 : rv = mDataSources[i]->GetAllCmds(source, getter_AddRefs(dsCmds));
1233 0 : if (NS_SUCCEEDED(rv))
1234 : {
1235 0 : bool hasMore = false;
1236 0 : while(NS_SUCCEEDED(rv = dsCmds->HasMoreElements(&hasMore)) &&
1237 : hasMore)
1238 : {
1239 0 : nsCOMPtr<nsISupports> item;
1240 0 : if (NS_SUCCEEDED(rv = dsCmds->GetNext(getter_AddRefs(item))))
1241 : {
1242 : // rjc: do NOT strip out duplicate commands here
1243 : // (due to items such as separators, it is done at a higher level)
1244 0 : cmdArray->AppendElement(item);
1245 : }
1246 : }
1247 0 : if (NS_FAILED(rv)) return(rv);
1248 : }
1249 : }
1250 :
1251 0 : return NS_NewArrayEnumerator(result, cmdArray);
1252 : }
1253 :
1254 : NS_IMETHODIMP
1255 0 : CompositeDataSourceImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1256 : nsIRDFResource* aCommand,
1257 : nsISupportsArray/*<nsIRDFResource>*/* aArguments,
1258 : bool* aResult)
1259 : {
1260 : nsresult rv;
1261 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
1262 0 : bool enabled = true;
1263 0 : rv = mDataSources[i]->IsCommandEnabled(aSources, aCommand, aArguments, &enabled);
1264 0 : if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
1265 : {
1266 0 : return(rv);
1267 : }
1268 :
1269 0 : if (! enabled) {
1270 0 : *aResult = false;
1271 0 : return(NS_OK);
1272 : }
1273 : }
1274 0 : *aResult = true;
1275 0 : return(NS_OK);
1276 : }
1277 :
1278 : NS_IMETHODIMP
1279 0 : CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1280 : nsIRDFResource* aCommand,
1281 : nsISupportsArray/*<nsIRDFResource>*/* aArguments)
1282 : {
1283 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
1284 0 : nsresult rv = mDataSources[i]->DoCommand(aSources, aCommand, aArguments);
1285 0 : if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
1286 : {
1287 0 : return(rv); // all datasources must succeed
1288 : }
1289 : }
1290 0 : return(NS_OK);
1291 : }
1292 :
1293 : NS_IMETHODIMP
1294 0 : CompositeDataSourceImpl::BeginUpdateBatch()
1295 : {
1296 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
1297 0 : mDataSources[i]->BeginUpdateBatch();
1298 : }
1299 0 : return NS_OK;
1300 : }
1301 :
1302 : NS_IMETHODIMP
1303 0 : CompositeDataSourceImpl::EndUpdateBatch()
1304 : {
1305 0 : for (PRInt32 i = mDataSources.Count() - 1; i >= 0; --i) {
1306 0 : mDataSources[i]->EndUpdateBatch();
1307 : }
1308 0 : return NS_OK;
1309 : }
1310 :
1311 : ////////////////////////////////////////////////////////////////////////
1312 : // nsIRDFCompositeDataSource methods
1313 : // XXX rvg We should make this take an additional argument specifying where
1314 : // in the sequence of data sources (of the db), the new data source should
1315 : // fit in. Right now, the new datasource gets stuck at the end.
1316 : // need to add the observers of the CompositeDataSourceImpl to the new data source.
1317 :
1318 : NS_IMETHODIMP
1319 0 : CompositeDataSourceImpl::GetAllowNegativeAssertions(bool *aAllowNegativeAssertions)
1320 : {
1321 0 : *aAllowNegativeAssertions = mAllowNegativeAssertions;
1322 0 : return(NS_OK);
1323 : }
1324 :
1325 : NS_IMETHODIMP
1326 0 : CompositeDataSourceImpl::SetAllowNegativeAssertions(bool aAllowNegativeAssertions)
1327 : {
1328 0 : mAllowNegativeAssertions = aAllowNegativeAssertions;
1329 0 : return(NS_OK);
1330 : }
1331 :
1332 : NS_IMETHODIMP
1333 0 : CompositeDataSourceImpl::GetCoalesceDuplicateArcs(bool *aCoalesceDuplicateArcs)
1334 : {
1335 0 : *aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
1336 0 : return(NS_OK);
1337 : }
1338 :
1339 : NS_IMETHODIMP
1340 0 : CompositeDataSourceImpl::SetCoalesceDuplicateArcs(bool aCoalesceDuplicateArcs)
1341 : {
1342 0 : mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
1343 0 : return(NS_OK);
1344 : }
1345 :
1346 : NS_IMETHODIMP
1347 0 : CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource)
1348 : {
1349 0 : NS_ASSERTION(aDataSource != nsnull, "null ptr");
1350 0 : if (! aDataSource)
1351 0 : return NS_ERROR_NULL_POINTER;
1352 :
1353 0 : mDataSources.AppendObject(aDataSource);
1354 0 : aDataSource->AddObserver(this);
1355 0 : return NS_OK;
1356 : }
1357 :
1358 :
1359 :
1360 : NS_IMETHODIMP
1361 0 : CompositeDataSourceImpl::RemoveDataSource(nsIRDFDataSource* aDataSource)
1362 : {
1363 0 : NS_ASSERTION(aDataSource != nsnull, "null ptr");
1364 0 : if (! aDataSource)
1365 0 : return NS_ERROR_NULL_POINTER;
1366 :
1367 :
1368 0 : if (mDataSources.IndexOf(aDataSource) >= 0) {
1369 0 : aDataSource->RemoveObserver(this);
1370 0 : mDataSources.RemoveObject(aDataSource);
1371 : }
1372 0 : return NS_OK;
1373 : }
1374 :
1375 :
1376 : NS_IMETHODIMP
1377 0 : CompositeDataSourceImpl::GetDataSources(nsISimpleEnumerator** _result)
1378 : {
1379 : // NS_NewArrayEnumerator for an nsCOMArray takes a snapshot of the
1380 : // current state.
1381 0 : return NS_NewArrayEnumerator(_result, mDataSources);
1382 : }
1383 :
1384 : NS_IMETHODIMP
1385 0 : CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource,
1386 : nsIRDFResource* aSource,
1387 : nsIRDFResource* aProperty,
1388 : nsIRDFNode* aTarget)
1389 : {
1390 : // Make sure that the assertion isn't masked by another
1391 : // datasource.
1392 : //
1393 : // XXX We could make this more efficient if we knew _which_
1394 : // datasource actually served up the OnAssert(): we could use
1395 : // HasAssertionN() to only search datasources _before_ the
1396 : // datasource that coughed up the assertion.
1397 0 : nsresult rv = NS_OK;
1398 :
1399 0 : if (mAllowNegativeAssertions)
1400 : {
1401 : bool hasAssertion;
1402 0 : rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
1403 0 : if (NS_FAILED(rv)) return rv;
1404 :
1405 0 : if (! hasAssertion)
1406 0 : return(NS_OK);
1407 : }
1408 :
1409 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1410 0 : mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
1411 : }
1412 0 : return NS_OK;
1413 : }
1414 :
1415 : NS_IMETHODIMP
1416 0 : CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource,
1417 : nsIRDFResource* aSource,
1418 : nsIRDFResource* aProperty,
1419 : nsIRDFNode* aTarget)
1420 : {
1421 : // Make sure that the un-assertion doesn't just unmask the
1422 : // same assertion in a different datasource.
1423 : //
1424 : // XXX We could make this more efficient if we knew _which_
1425 : // datasource actually served up the OnAssert(): we could use
1426 : // HasAssertionN() to only search datasources _before_ the
1427 : // datasource that coughed up the assertion.
1428 : nsresult rv;
1429 :
1430 0 : if (mAllowNegativeAssertions)
1431 : {
1432 : bool hasAssertion;
1433 0 : rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
1434 0 : if (NS_FAILED(rv)) return rv;
1435 :
1436 0 : if (hasAssertion)
1437 0 : return NS_OK;
1438 : }
1439 :
1440 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1441 0 : mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget);
1442 : }
1443 0 : return NS_OK;
1444 : }
1445 :
1446 :
1447 : NS_IMETHODIMP
1448 0 : CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource,
1449 : nsIRDFResource* aSource,
1450 : nsIRDFResource* aProperty,
1451 : nsIRDFNode* aOldTarget,
1452 : nsIRDFNode* aNewTarget)
1453 : {
1454 : // Make sure that the change is actually visible, and not hidden
1455 : // by an assertion in a different datasource.
1456 : //
1457 : // XXX Because of aggregation, this could actually mutate into a
1458 : // variety of OnAssert or OnChange notifications, which we'll
1459 : // ignore for now :-/.
1460 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1461 0 : mObservers[i]->OnChange(this, aSource, aProperty,
1462 0 : aOldTarget, aNewTarget);
1463 : }
1464 0 : return NS_OK;
1465 : }
1466 :
1467 :
1468 : NS_IMETHODIMP
1469 0 : CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource,
1470 : nsIRDFResource* aOldSource,
1471 : nsIRDFResource* aNewSource,
1472 : nsIRDFResource* aProperty,
1473 : nsIRDFNode* aTarget)
1474 : {
1475 : // Make sure that the move is actually visible, and not hidden
1476 : // by an assertion in a different datasource.
1477 : //
1478 : // XXX Because of aggregation, this could actually mutate into a
1479 : // variety of OnAssert or OnMove notifications, which we'll
1480 : // ignore for now :-/.
1481 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1482 0 : mObservers[i]->OnMove(this, aOldSource, aNewSource,
1483 0 : aProperty, aTarget);
1484 : }
1485 0 : return NS_OK;
1486 : }
1487 :
1488 :
1489 : NS_IMETHODIMP
1490 0 : CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
1491 : {
1492 0 : if (mUpdateBatchNest++ == 0) {
1493 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1494 0 : mObservers[i]->OnBeginUpdateBatch(this);
1495 : }
1496 : }
1497 0 : return NS_OK;
1498 : }
1499 :
1500 :
1501 : NS_IMETHODIMP
1502 0 : CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
1503 : {
1504 0 : NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
1505 0 : if (--mUpdateBatchNest == 0) {
1506 0 : for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
1507 0 : mObservers[i]->OnEndUpdateBatch(this);
1508 : }
1509 : }
1510 0 : return NS_OK;
1511 4392 : }
|