Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
8 A simple composite data source implementation. A composit data
9 source is just a strategy for combining individual data sources into
10 a collective graph.
13 1) A composite data source holds a sequence of data sources. The set
14 of data sources can be specified during creation of the
15 database. Data sources can also be added/deleted from a database
16 later.
18 2) The aggregation mechanism is based on simple super-positioning of
19 the graphs from the datasources. If there is a conflict (i.e.,
20 data source A has a true arc from foo to bar while data source B
21 has a false arc from foo to bar), the data source that it earlier
22 in the sequence wins.
24 The implementation below doesn't really do this and needs to be
25 fixed.
27 */
29 #include "xpcom-config.h"
30 #include "nsCOMPtr.h"
31 #include "nsIComponentManager.h"
32 #include "nsIRDFCompositeDataSource.h"
33 #include "nsIRDFNode.h"
34 #include "nsIRDFObserver.h"
35 #include "nsIRDFRemoteDataSource.h"
36 #include "nsTArray.h"
37 #include "nsCOMArray.h"
38 #include "nsArrayEnumerator.h"
39 #include "nsXPIDLString.h"
40 #include "rdf.h"
41 #include "nsCycleCollectionParticipant.h"
43 #include "nsEnumeratorUtils.h"
45 #ifdef PR_LOGGING
46 #include "prlog.h"
47 #include "prprf.h"
48 #include <stdio.h>
49 PRLogModuleInfo* nsRDFLog = nullptr;
50 #endif
52 //----------------------------------------------------------------------
53 //
54 // CompositeDataSourceImpl
55 //
57 class CompositeEnumeratorImpl;
58 class CompositeArcsInOutEnumeratorImpl;
59 class CompositeAssertionEnumeratorImpl;
61 class CompositeDataSourceImpl : public nsIRDFCompositeDataSource,
62 public nsIRDFObserver
63 {
64 public:
65 CompositeDataSourceImpl(void);
66 CompositeDataSourceImpl(char** dataSources);
68 // nsISupports interface
69 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
70 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(CompositeDataSourceImpl,
71 nsIRDFCompositeDataSource)
73 // nsIRDFDataSource interface
74 NS_DECL_NSIRDFDATASOURCE
76 // nsIRDFCompositeDataSource interface
77 NS_DECL_NSIRDFCOMPOSITEDATASOURCE
79 // nsIRDFObserver interface
80 NS_DECL_NSIRDFOBSERVER
82 bool HasAssertionN(int n, nsIRDFResource* source,
83 nsIRDFResource* property,
84 nsIRDFNode* target,
85 bool tv);
87 protected:
88 nsCOMArray<nsIRDFObserver> mObservers;
89 nsCOMArray<nsIRDFDataSource> mDataSources;
91 bool mAllowNegativeAssertions;
92 bool mCoalesceDuplicateArcs;
93 int32_t mUpdateBatchNest;
95 virtual ~CompositeDataSourceImpl() {}
97 friend class CompositeEnumeratorImpl;
98 friend class CompositeArcsInOutEnumeratorImpl;
99 friend class CompositeAssertionEnumeratorImpl;
100 };
102 //----------------------------------------------------------------------
103 //
104 // CompositeEnumeratorImpl
105 //
107 class CompositeEnumeratorImpl : public nsISimpleEnumerator
108 {
109 // nsISupports
110 NS_DECL_ISUPPORTS
112 // nsISimpleEnumerator interface
113 NS_DECL_NSISIMPLEENUMERATOR
115 // pure abstract methods to be overridden
116 virtual nsresult
117 GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult) = 0;
119 virtual nsresult
120 HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult) = 0;
122 protected:
123 CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
124 bool aAllowNegativeAssertions,
125 bool aCoalesceDuplicateArcs);
127 virtual ~CompositeEnumeratorImpl();
129 CompositeDataSourceImpl* mCompositeDataSource;
131 nsISimpleEnumerator* mCurrent;
132 nsIRDFNode* mResult;
133 int32_t mNext;
134 nsAutoTArray<nsCOMPtr<nsIRDFNode>, 8> mAlreadyReturned;
135 bool mAllowNegativeAssertions;
136 bool mCoalesceDuplicateArcs;
137 };
140 CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
141 bool aAllowNegativeAssertions,
142 bool aCoalesceDuplicateArcs)
143 : mCompositeDataSource(aCompositeDataSource),
144 mCurrent(nullptr),
145 mResult(nullptr),
146 mNext(0),
147 mAllowNegativeAssertions(aAllowNegativeAssertions),
148 mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
149 {
150 NS_ADDREF(mCompositeDataSource);
151 }
154 CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void)
155 {
156 NS_IF_RELEASE(mCurrent);
157 NS_IF_RELEASE(mResult);
158 NS_RELEASE(mCompositeDataSource);
159 }
161 NS_IMPL_ADDREF(CompositeEnumeratorImpl)
162 NS_IMPL_RELEASE(CompositeEnumeratorImpl)
163 NS_IMPL_QUERY_INTERFACE(CompositeEnumeratorImpl, nsISimpleEnumerator)
165 NS_IMETHODIMP
166 CompositeEnumeratorImpl::HasMoreElements(bool* aResult)
167 {
168 NS_PRECONDITION(aResult != nullptr, "null ptr");
169 if (! aResult)
170 return NS_ERROR_NULL_POINTER;
172 nsresult rv;
174 // If we've already queued up a next target, then yep, there are
175 // more elements.
176 if (mResult) {
177 *aResult = true;
178 return NS_OK;
179 }
181 // Otherwise, we'll need to find a next target, switching cursors
182 // if necessary.
183 for ( ; mNext < mCompositeDataSource->mDataSources.Count(); ++mNext) {
184 if (! mCurrent) {
185 // We don't have a current enumerator, so create a new one on
186 // the next data source.
187 nsIRDFDataSource* datasource =
188 mCompositeDataSource->mDataSources[mNext];
190 rv = GetEnumerator(datasource, &mCurrent);
191 if (NS_FAILED(rv)) return rv;
192 if (rv == NS_RDF_NO_VALUE)
193 continue;
195 NS_ASSERTION(mCurrent != nullptr, "you're always supposed to return an enumerator from GetEnumerator, punk.");
196 if (! mCurrent)
197 continue;
198 }
200 do {
201 int32_t i;
203 bool hasMore;
204 rv = mCurrent->HasMoreElements(&hasMore);
205 if (NS_FAILED(rv)) return rv;
207 // Is the current enumerator depleted?
208 if (! hasMore) {
209 NS_RELEASE(mCurrent);
210 break;
211 }
213 // Even if the current enumerator has more elements, we still
214 // need to check that the current element isn't masked by
215 // a negation in an earlier data source.
217 // "Peek" ahead and pull out the next target.
218 nsCOMPtr<nsISupports> result;
219 rv = mCurrent->GetNext(getter_AddRefs(result));
220 if (NS_FAILED(rv)) return rv;
222 rv = result->QueryInterface(NS_GET_IID(nsIRDFNode), (void**) &mResult);
223 if (NS_FAILED(rv)) return rv;
225 if (mAllowNegativeAssertions)
226 {
227 // See if any previous data source negates this
228 bool hasNegation = false;
229 for (i = mNext - 1; i >= 0; --i)
230 {
231 nsIRDFDataSource* datasource =
232 mCompositeDataSource->mDataSources[i];
234 rv = HasNegation(datasource, mResult, &hasNegation);
235 if (NS_FAILED(rv)) return rv;
237 if (hasNegation)
238 break;
239 }
241 // if so, we've gotta keep looking
242 if (hasNegation)
243 {
244 NS_RELEASE(mResult);
245 continue;
246 }
247 }
249 if (mCoalesceDuplicateArcs)
250 {
251 // Now see if we've returned it once already.
252 // XXX N.B. performance here...may want to hash if things get large?
253 bool alreadyReturned = false;
254 for (i = mAlreadyReturned.Length() - 1; i >= 0; --i)
255 {
256 if (mAlreadyReturned[i] == mResult)
257 {
258 alreadyReturned = true;
259 break;
260 }
261 }
262 if (alreadyReturned)
263 {
264 NS_RELEASE(mResult);
265 continue;
266 }
267 }
269 // If we get here, then we've really found one. It'll
270 // remain cached in mResult until GetNext() sucks it out.
271 *aResult = true;
273 // Remember that we returned it, so we don't return duplicates.
275 // XXX I wonder if we should make unique-checking be
276 // optional. This could get to be pretty expensive (this
277 // implementation turns iteration into O(n^2)).
279 if (mCoalesceDuplicateArcs)
280 {
281 mAlreadyReturned.AppendElement(mResult);
282 }
284 return NS_OK;
285 } while (1);
286 }
288 // if we get here, there aren't any elements left.
289 *aResult = false;
290 return NS_OK;
291 }
294 NS_IMETHODIMP
295 CompositeEnumeratorImpl::GetNext(nsISupports** aResult)
296 {
297 nsresult rv;
299 bool hasMore;
300 rv = HasMoreElements(&hasMore);
301 if (NS_FAILED(rv)) return rv;
303 if (! hasMore)
304 return NS_ERROR_UNEXPECTED;
306 // Don't AddRef: we "transfer" ownership to the caller
307 *aResult = mResult;
308 mResult = nullptr;
310 return NS_OK;
311 }
313 //----------------------------------------------------------------------
314 //
315 // CompositeArcsInOutEnumeratorImpl
316 //
317 //
319 class CompositeArcsInOutEnumeratorImpl : public CompositeEnumeratorImpl
320 {
321 public:
322 enum Type { eArcsIn, eArcsOut };
324 virtual ~CompositeArcsInOutEnumeratorImpl();
326 virtual nsresult
327 GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
329 virtual nsresult
330 HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
332 CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
333 nsIRDFNode* aNode,
334 Type aType,
335 bool aAllowNegativeAssertions,
336 bool aCoalesceDuplicateArcs);
338 private:
339 nsIRDFNode* mNode;
340 Type mType;
341 };
344 CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl(
345 CompositeDataSourceImpl* aCompositeDataSource,
346 nsIRDFNode* aNode,
347 Type aType,
348 bool aAllowNegativeAssertions,
349 bool aCoalesceDuplicateArcs)
350 : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
351 mNode(aNode),
352 mType(aType)
353 {
354 NS_ADDREF(mNode);
355 }
357 CompositeArcsInOutEnumeratorImpl::~CompositeArcsInOutEnumeratorImpl()
358 {
359 NS_RELEASE(mNode);
360 }
363 nsresult
364 CompositeArcsInOutEnumeratorImpl::GetEnumerator(
365 nsIRDFDataSource* aDataSource,
366 nsISimpleEnumerator** aResult)
367 {
368 if (mType == eArcsIn) {
369 return aDataSource->ArcLabelsIn(mNode, aResult);
370 }
371 else {
372 nsCOMPtr<nsIRDFResource> resource( do_QueryInterface(mNode) );
373 return aDataSource->ArcLabelsOut(resource, aResult);
374 }
375 }
377 nsresult
378 CompositeArcsInOutEnumeratorImpl::HasNegation(
379 nsIRDFDataSource* aDataSource,
380 nsIRDFNode* aNode,
381 bool* aResult)
382 {
383 *aResult = false;
384 return NS_OK;
385 }
388 //----------------------------------------------------------------------
389 //
390 // CompositeAssertionEnumeratorImpl
391 //
393 class CompositeAssertionEnumeratorImpl : public CompositeEnumeratorImpl
394 {
395 public:
396 virtual nsresult
397 GetEnumerator(nsIRDFDataSource* aDataSource, nsISimpleEnumerator** aResult);
399 virtual nsresult
400 HasNegation(nsIRDFDataSource* aDataSource, nsIRDFNode* aNode, bool* aResult);
402 CompositeAssertionEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
403 nsIRDFResource* aSource,
404 nsIRDFResource* aProperty,
405 nsIRDFNode* aTarget,
406 bool aTruthValue,
407 bool aAllowNegativeAssertions,
408 bool aCoalesceDuplicateArcs);
410 virtual ~CompositeAssertionEnumeratorImpl();
412 private:
413 nsIRDFResource* mSource;
414 nsIRDFResource* mProperty;
415 nsIRDFNode* mTarget;
416 bool mTruthValue;
417 };
420 CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl(
421 CompositeDataSourceImpl* aCompositeDataSource,
422 nsIRDFResource* aSource,
423 nsIRDFResource* aProperty,
424 nsIRDFNode* aTarget,
425 bool aTruthValue,
426 bool aAllowNegativeAssertions,
427 bool aCoalesceDuplicateArcs)
428 : CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
429 mSource(aSource),
430 mProperty(aProperty),
431 mTarget(aTarget),
432 mTruthValue(aTruthValue)
433 {
434 NS_IF_ADDREF(mSource);
435 NS_ADDREF(mProperty); // always must be specified
436 NS_IF_ADDREF(mTarget);
437 }
439 CompositeAssertionEnumeratorImpl::~CompositeAssertionEnumeratorImpl()
440 {
441 NS_IF_RELEASE(mSource);
442 NS_RELEASE(mProperty);
443 NS_IF_RELEASE(mTarget);
444 }
447 nsresult
448 CompositeAssertionEnumeratorImpl::GetEnumerator(
449 nsIRDFDataSource* aDataSource,
450 nsISimpleEnumerator** aResult)
451 {
452 if (mSource) {
453 return aDataSource->GetTargets(mSource, mProperty, mTruthValue, aResult);
454 }
455 else {
456 return aDataSource->GetSources(mProperty, mTarget, mTruthValue, aResult);
457 }
458 }
460 nsresult
461 CompositeAssertionEnumeratorImpl::HasNegation(
462 nsIRDFDataSource* aDataSource,
463 nsIRDFNode* aNode,
464 bool* aResult)
465 {
466 if (mSource) {
467 return aDataSource->HasAssertion(mSource, mProperty, aNode, !mTruthValue, aResult);
468 }
469 else {
470 nsCOMPtr<nsIRDFResource> source( do_QueryInterface(aNode) );
471 return aDataSource->HasAssertion(source, mProperty, mTarget, !mTruthValue, aResult);
472 }
473 }
475 ////////////////////////////////////////////////////////////////////////
477 nsresult
478 NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result)
479 {
480 CompositeDataSourceImpl* db = new CompositeDataSourceImpl();
481 if (! db)
482 return NS_ERROR_OUT_OF_MEMORY;
484 *result = db;
485 NS_ADDREF(*result);
486 return NS_OK;
487 }
490 CompositeDataSourceImpl::CompositeDataSourceImpl(void)
491 : mAllowNegativeAssertions(true),
492 mCoalesceDuplicateArcs(true),
493 mUpdateBatchNest(0)
494 {
495 #ifdef PR_LOGGING
496 if (nsRDFLog == nullptr)
497 nsRDFLog = PR_NewLogModule("RDF");
498 #endif
499 }
501 //----------------------------------------------------------------------
502 //
503 // nsISupports interface
504 //
506 NS_IMPL_CYCLE_COLLECTION_CLASS(CompositeDataSourceImpl)
508 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CompositeDataSourceImpl)
509 uint32_t i, count = tmp->mDataSources.Count();
510 for (i = count; i > 0; --i) {
511 tmp->mDataSources[i - 1]->RemoveObserver(tmp);
512 tmp->mDataSources.RemoveObjectAt(i - 1);
513 }
514 NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers);
515 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
516 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CompositeDataSourceImpl)
517 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
518 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataSources)
519 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
522 NS_IMPL_CYCLE_COLLECTING_ADDREF(CompositeDataSourceImpl)
523 NS_IMPL_CYCLE_COLLECTING_RELEASE(CompositeDataSourceImpl)
525 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CompositeDataSourceImpl)
526 NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
527 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
528 NS_INTERFACE_MAP_ENTRY(nsIRDFObserver)
529 NS_INTERFACE_MAP_ENTRY(nsIRDFCompositeDataSource)
530 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFCompositeDataSource)
531 NS_INTERFACE_MAP_END
534 //----------------------------------------------------------------------
535 //
536 // nsIRDFDataSource interface
537 //
539 NS_IMETHODIMP
540 CompositeDataSourceImpl::GetURI(char* *uri)
541 {
542 *uri = nullptr;
543 return NS_OK;
544 }
546 NS_IMETHODIMP
547 CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
548 nsIRDFNode* target,
549 bool tv,
550 nsIRDFResource** source)
551 {
552 if (!mAllowNegativeAssertions && !tv)
553 return(NS_RDF_NO_VALUE);
555 int32_t count = mDataSources.Count();
556 for (int32_t i = 0; i < count; ++i) {
557 nsresult rv;
558 rv = mDataSources[i]->GetSource(property, target, tv, source);
559 if (NS_FAILED(rv)) return rv;
561 if (rv == NS_RDF_NO_VALUE)
562 continue;
564 if (!mAllowNegativeAssertions) return(NS_OK);
566 // okay, found it. make sure we don't have the opposite
567 // asserted in a more local data source
568 if (!HasAssertionN(count-1, *source, property, target, !tv))
569 return NS_OK;
571 NS_RELEASE(*source);
572 return NS_RDF_NO_VALUE;
573 }
574 return NS_RDF_NO_VALUE;
575 }
577 NS_IMETHODIMP
578 CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty,
579 nsIRDFNode* aTarget,
580 bool aTruthValue,
581 nsISimpleEnumerator** aResult)
582 {
583 NS_PRECONDITION(aProperty != nullptr, "null ptr");
584 if (! aProperty)
585 return NS_ERROR_NULL_POINTER;
587 NS_PRECONDITION(aTarget != nullptr, "null ptr");
588 if (! aTarget)
589 return NS_ERROR_NULL_POINTER;
591 NS_PRECONDITION(aResult != nullptr, "null ptr");
592 if (! aResult)
593 return NS_ERROR_NULL_POINTER;
595 if (! mAllowNegativeAssertions && ! aTruthValue)
596 return(NS_RDF_NO_VALUE);
598 *aResult = new CompositeAssertionEnumeratorImpl(this, nullptr, aProperty,
599 aTarget, aTruthValue,
600 mAllowNegativeAssertions,
601 mCoalesceDuplicateArcs);
603 if (! *aResult)
604 return NS_ERROR_OUT_OF_MEMORY;
606 NS_ADDREF(*aResult);
607 return NS_OK;
608 }
610 NS_IMETHODIMP
611 CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
612 nsIRDFResource* aProperty,
613 bool aTruthValue,
614 nsIRDFNode** aResult)
615 {
616 NS_PRECONDITION(aSource != nullptr, "null ptr");
617 if (! aSource)
618 return NS_ERROR_NULL_POINTER;
620 NS_PRECONDITION(aProperty != nullptr, "null ptr");
621 if (! aProperty)
622 return NS_ERROR_NULL_POINTER;
624 NS_PRECONDITION(aResult != nullptr, "null ptr");
625 if (! aResult)
626 return NS_ERROR_NULL_POINTER;
628 if (! mAllowNegativeAssertions && ! aTruthValue)
629 return(NS_RDF_NO_VALUE);
631 int32_t count = mDataSources.Count();
632 for (int32_t i = 0; i < count; ++i) {
633 nsresult rv;
634 rv = mDataSources[i]->GetTarget(aSource, aProperty, aTruthValue,
635 aResult);
636 if (NS_FAILED(rv))
637 return rv;
639 if (rv == NS_OK) {
640 // okay, found it. make sure we don't have the opposite
641 // asserted in an earlier data source
643 if (mAllowNegativeAssertions) {
644 if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
645 // whoops, it's been negated.
646 NS_RELEASE(*aResult);
647 return NS_RDF_NO_VALUE;
648 }
649 }
650 return NS_OK;
651 }
652 }
654 // Otherwise, we couldn't find it at all.
655 return NS_RDF_NO_VALUE;
656 }
658 bool
659 CompositeDataSourceImpl::HasAssertionN(int n,
660 nsIRDFResource* aSource,
661 nsIRDFResource* aProperty,
662 nsIRDFNode* aTarget,
663 bool aTruthValue)
664 {
665 nsresult rv;
666 for (int32_t m = 0; m < n; ++m) {
667 bool result;
668 rv = mDataSources[m]->HasAssertion(aSource, aProperty, aTarget,
669 aTruthValue, &result);
670 if (NS_FAILED(rv))
671 return false;
673 // found it!
674 if (result)
675 return true;
676 }
677 return false;
678 }
682 NS_IMETHODIMP
683 CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource,
684 nsIRDFResource* aProperty,
685 bool aTruthValue,
686 nsISimpleEnumerator** aResult)
687 {
688 NS_PRECONDITION(aSource != nullptr, "null ptr");
689 if (! aSource)
690 return NS_ERROR_NULL_POINTER;
692 NS_PRECONDITION(aProperty != nullptr, "null ptr");
693 if (! aProperty)
694 return NS_ERROR_NULL_POINTER;
696 NS_PRECONDITION(aResult != nullptr, "null ptr");
697 if (! aResult)
698 return NS_ERROR_NULL_POINTER;
700 if (! mAllowNegativeAssertions && ! aTruthValue)
701 return(NS_RDF_NO_VALUE);
703 *aResult =
704 new CompositeAssertionEnumeratorImpl(this,
705 aSource, aProperty, nullptr,
706 aTruthValue,
707 mAllowNegativeAssertions,
708 mCoalesceDuplicateArcs);
710 if (! *aResult)
711 return NS_ERROR_OUT_OF_MEMORY;
713 NS_ADDREF(*aResult);
714 return NS_OK;
715 }
717 NS_IMETHODIMP
718 CompositeDataSourceImpl::Assert(nsIRDFResource* aSource,
719 nsIRDFResource* aProperty,
720 nsIRDFNode* aTarget,
721 bool aTruthValue)
722 {
723 NS_PRECONDITION(aSource != nullptr, "null ptr");
724 if (! aSource)
725 return NS_ERROR_NULL_POINTER;
727 NS_PRECONDITION(aProperty != nullptr, "null ptr");
728 if (! aProperty)
729 return NS_ERROR_NULL_POINTER;
731 NS_PRECONDITION(aTarget != nullptr, "null ptr");
732 if (! aTarget)
733 return NS_ERROR_NULL_POINTER;
735 if (! mAllowNegativeAssertions && ! aTruthValue)
736 return(NS_RDF_ASSERTION_REJECTED);
738 nsresult rv;
740 // XXX Need to add back the stuff for unblocking ...
742 // We iterate backwards from the last data source which was added
743 // ("the most remote") to the first ("the most local"), trying to
744 // apply the assertion in each.
745 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
746 rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, aTruthValue);
747 if (NS_RDF_ASSERTION_ACCEPTED == rv)
748 return rv;
750 if (NS_FAILED(rv))
751 return rv;
752 }
754 // nobody wanted to accept it
755 return NS_RDF_ASSERTION_REJECTED;
756 }
758 NS_IMETHODIMP
759 CompositeDataSourceImpl::Unassert(nsIRDFResource* aSource,
760 nsIRDFResource* aProperty,
761 nsIRDFNode* aTarget)
762 {
763 NS_PRECONDITION(aSource != nullptr, "null ptr");
764 if (! aSource)
765 return NS_ERROR_NULL_POINTER;
767 NS_PRECONDITION(aProperty != nullptr, "null ptr");
768 if (! aProperty)
769 return NS_ERROR_NULL_POINTER;
771 NS_PRECONDITION(aTarget != nullptr, "null ptr");
772 if (! aTarget)
773 return NS_ERROR_NULL_POINTER;
775 nsresult rv;
777 // Iterate through each of the datasources, starting with "the
778 // most local" and moving to "the most remote". If _any_ of the
779 // datasources have the assertion, attempt to unassert it.
780 bool unasserted = true;
781 int32_t i;
782 int32_t count = mDataSources.Count();
783 for (i = 0; i < count; ++i) {
784 nsIRDFDataSource* ds = mDataSources[i];
786 bool hasAssertion;
787 rv = ds->HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
788 if (NS_FAILED(rv)) return rv;
790 if (hasAssertion) {
791 rv = ds->Unassert(aSource, aProperty, aTarget);
792 if (NS_FAILED(rv)) return rv;
794 if (rv != NS_RDF_ASSERTION_ACCEPTED) {
795 unasserted = false;
796 break;
797 }
798 }
799 }
801 // Either none of the datasources had it, or they were all willing
802 // to let it be unasserted.
803 if (unasserted)
804 return NS_RDF_ASSERTION_ACCEPTED;
806 // If we get here, one of the datasources already had the
807 // assertion, and was adamant about not letting us remove
808 // it. Iterate from the "most local" to the "most remote"
809 // attempting to assert the negation...
810 for (i = 0; i < count; ++i) {
811 rv = mDataSources[i]->Assert(aSource, aProperty, aTarget, false);
812 if (NS_FAILED(rv)) return rv;
814 // Did it take?
815 if (rv == NS_RDF_ASSERTION_ACCEPTED)
816 return rv;
817 }
819 // Couln't get anyone to accept the negation, either.
820 return NS_RDF_ASSERTION_REJECTED;
821 }
823 NS_IMETHODIMP
824 CompositeDataSourceImpl::Change(nsIRDFResource* aSource,
825 nsIRDFResource* aProperty,
826 nsIRDFNode* aOldTarget,
827 nsIRDFNode* aNewTarget)
828 {
829 NS_PRECONDITION(aSource != nullptr, "null ptr");
830 if (! aSource)
831 return NS_ERROR_NULL_POINTER;
833 NS_PRECONDITION(aProperty != nullptr, "null ptr");
834 if (! aProperty)
835 return NS_ERROR_NULL_POINTER;
837 NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
838 if (! aOldTarget)
839 return NS_ERROR_NULL_POINTER;
841 NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
842 if (! aNewTarget)
843 return NS_ERROR_NULL_POINTER;
845 nsresult rv;
847 // XXX So we're assuming that a datasource _must_ accept the
848 // atomic change; i.e., we can't split it up across two
849 // datasources. That sucks.
851 // We iterate backwards from the last data source which was added
852 // ("the most remote") to the first ("the most local"), trying to
853 // apply the change in each.
854 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
855 rv = mDataSources[i]->Change(aSource, aProperty, aOldTarget, aNewTarget);
856 if (NS_RDF_ASSERTION_ACCEPTED == rv)
857 return rv;
859 if (NS_FAILED(rv))
860 return rv;
861 }
863 // nobody wanted to accept it
864 return NS_RDF_ASSERTION_REJECTED;
865 }
867 NS_IMETHODIMP
868 CompositeDataSourceImpl::Move(nsIRDFResource* aOldSource,
869 nsIRDFResource* aNewSource,
870 nsIRDFResource* aProperty,
871 nsIRDFNode* aTarget)
872 {
873 NS_PRECONDITION(aOldSource != nullptr, "null ptr");
874 if (! aOldSource)
875 return NS_ERROR_NULL_POINTER;
877 NS_PRECONDITION(aNewSource != nullptr, "null ptr");
878 if (! aNewSource)
879 return NS_ERROR_NULL_POINTER;
881 NS_PRECONDITION(aProperty != nullptr, "null ptr");
882 if (! aProperty)
883 return NS_ERROR_NULL_POINTER;
885 NS_PRECONDITION(aTarget != nullptr, "null ptr");
886 if (! aTarget)
887 return NS_ERROR_NULL_POINTER;
889 nsresult rv;
891 // XXX So we're assuming that a datasource _must_ accept the
892 // atomic move; i.e., we can't split it up across two
893 // datasources. That sucks.
895 // We iterate backwards from the last data source which was added
896 // ("the most remote") to the first ("the most local"), trying to
897 // apply the assertion in each.
898 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
899 rv = mDataSources[i]->Move(aOldSource, aNewSource, aProperty, aTarget);
900 if (NS_RDF_ASSERTION_ACCEPTED == rv)
901 return rv;
903 if (NS_FAILED(rv))
904 return rv;
905 }
907 // nobody wanted to accept it
908 return NS_RDF_ASSERTION_REJECTED;
909 }
912 NS_IMETHODIMP
913 CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
914 nsIRDFResource* aProperty,
915 nsIRDFNode* aTarget,
916 bool aTruthValue,
917 bool* aResult)
918 {
919 NS_PRECONDITION(aSource != nullptr, "null ptr");
920 if (! aSource)
921 return NS_ERROR_NULL_POINTER;
923 NS_PRECONDITION(aProperty != nullptr, "null ptr");
924 if (! aProperty)
925 return NS_ERROR_NULL_POINTER;
927 NS_PRECONDITION(aResult != nullptr, "null ptr");
928 if (! aResult)
929 return NS_ERROR_NULL_POINTER;
931 if (! mAllowNegativeAssertions && ! aTruthValue)
932 {
933 *aResult = false;
934 return(NS_OK);
935 }
937 nsresult rv;
939 // Otherwise, look through all the data sources to see if anyone
940 // has the positive...
941 int32_t count = mDataSources.Count();
942 for (int32_t i = 0; i < count; ++i) {
943 nsIRDFDataSource* datasource = mDataSources[i];
944 rv = datasource->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult);
945 if (NS_FAILED(rv)) return rv;
947 if (*aResult)
948 return NS_OK;
950 if (mAllowNegativeAssertions)
951 {
952 bool hasNegation;
953 rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
954 if (NS_FAILED(rv)) return rv;
956 if (hasNegation)
957 {
958 *aResult = false;
959 return NS_OK;
960 }
961 }
962 }
964 // If we get here, nobody had the assertion at all
965 *aResult = false;
966 return NS_OK;
967 }
969 NS_IMETHODIMP
970 CompositeDataSourceImpl::AddObserver(nsIRDFObserver* aObserver)
971 {
972 NS_PRECONDITION(aObserver != nullptr, "null ptr");
973 if (! aObserver)
974 return NS_ERROR_NULL_POINTER;
976 // XXX ensure uniqueness?
977 mObservers.AppendObject(aObserver);
979 return NS_OK;
980 }
982 NS_IMETHODIMP
983 CompositeDataSourceImpl::RemoveObserver(nsIRDFObserver* aObserver)
984 {
985 NS_PRECONDITION(aObserver != nullptr, "null ptr");
986 if (! aObserver)
987 return NS_ERROR_NULL_POINTER;
989 mObservers.RemoveObject(aObserver);
991 return NS_OK;
992 }
994 NS_IMETHODIMP
995 CompositeDataSourceImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
996 {
997 nsresult rv;
998 *result = false;
999 int32_t count = mDataSources.Count();
1000 for (int32_t i = 0; i < count; ++i) {
1001 rv = mDataSources[i]->HasArcIn(aNode, aArc, result);
1002 if (NS_FAILED(rv)) return rv;
1003 if (*result)
1004 return NS_OK;
1005 }
1006 return NS_OK;
1007 }
1009 NS_IMETHODIMP
1010 CompositeDataSourceImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
1011 {
1012 nsresult rv;
1013 *result = false;
1014 int32_t count = mDataSources.Count();
1015 for (int32_t i = 0; i < count; ++i) {
1016 rv = mDataSources[i]->HasArcOut(aSource, aArc, result);
1017 if (NS_FAILED(rv)) return rv;
1018 if (*result)
1019 return NS_OK;
1020 }
1021 return NS_OK;
1022 }
1024 NS_IMETHODIMP
1025 CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
1026 {
1027 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1028 if (! aTarget)
1029 return NS_ERROR_NULL_POINTER;
1031 NS_PRECONDITION(aResult != nullptr, "null ptr");
1032 if (! aResult)
1033 return NS_ERROR_NULL_POINTER;
1035 nsISimpleEnumerator* result =
1036 new CompositeArcsInOutEnumeratorImpl(this, aTarget,
1037 CompositeArcsInOutEnumeratorImpl::eArcsIn,
1038 mAllowNegativeAssertions,
1039 mCoalesceDuplicateArcs);
1041 if (! result)
1042 return NS_ERROR_OUT_OF_MEMORY;
1044 NS_ADDREF(result);
1045 *aResult = result;
1046 return NS_OK;
1047 }
1049 NS_IMETHODIMP
1050 CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource,
1051 nsISimpleEnumerator** aResult)
1052 {
1053 NS_PRECONDITION(aSource != nullptr, "null ptr");
1054 if (! aSource)
1055 return NS_ERROR_NULL_POINTER;
1057 NS_PRECONDITION(aResult != nullptr, "null ptr");
1058 if (! aResult)
1059 return NS_ERROR_NULL_POINTER;
1061 nsISimpleEnumerator* result =
1062 new CompositeArcsInOutEnumeratorImpl(this, aSource,
1063 CompositeArcsInOutEnumeratorImpl::eArcsOut,
1064 mAllowNegativeAssertions,
1065 mCoalesceDuplicateArcs);
1067 if (! result)
1068 return NS_ERROR_OUT_OF_MEMORY;
1070 NS_ADDREF(result);
1071 *aResult = result;
1072 return NS_OK;
1073 }
1075 NS_IMETHODIMP
1076 CompositeDataSourceImpl::GetAllResources(nsISimpleEnumerator** aResult)
1077 {
1078 NS_NOTYETIMPLEMENTED("CompositeDataSourceImpl::GetAllResources");
1079 return NS_ERROR_NOT_IMPLEMENTED;
1080 }
1082 NS_IMETHODIMP
1083 CompositeDataSourceImpl::GetAllCmds(nsIRDFResource* source,
1084 nsISimpleEnumerator/*<nsIRDFResource>*/** result)
1085 {
1086 nsresult rv;
1087 nsCOMPtr<nsISimpleEnumerator> set;
1089 for (int32_t i = 0; i < mDataSources.Count(); i++)
1090 {
1091 nsCOMPtr<nsISimpleEnumerator> dsCmds;
1093 rv = mDataSources[i]->GetAllCmds(source, getter_AddRefs(dsCmds));
1094 if (NS_SUCCEEDED(rv))
1095 {
1096 nsCOMPtr<nsISimpleEnumerator> tmp;
1097 rv = NS_NewUnionEnumerator(getter_AddRefs(tmp), set, dsCmds);
1098 set.swap(tmp);
1099 if (NS_FAILED(rv)) return(rv);
1100 }
1101 }
1103 set.forget(result);
1104 return NS_OK;
1105 }
1107 NS_IMETHODIMP
1108 CompositeDataSourceImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1109 nsIRDFResource* aCommand,
1110 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
1111 bool* aResult)
1112 {
1113 nsresult rv;
1114 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
1115 bool enabled = true;
1116 rv = mDataSources[i]->IsCommandEnabled(aSources, aCommand, aArguments, &enabled);
1117 if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
1118 {
1119 return(rv);
1120 }
1122 if (! enabled) {
1123 *aResult = false;
1124 return(NS_OK);
1125 }
1126 }
1127 *aResult = true;
1128 return(NS_OK);
1129 }
1131 NS_IMETHODIMP
1132 CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1133 nsIRDFResource* aCommand,
1134 nsISupportsArray/*<nsIRDFResource>*/* aArguments)
1135 {
1136 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
1137 nsresult rv = mDataSources[i]->DoCommand(aSources, aCommand, aArguments);
1138 if (NS_FAILED(rv) && (rv != NS_ERROR_NOT_IMPLEMENTED))
1139 {
1140 return(rv); // all datasources must succeed
1141 }
1142 }
1143 return(NS_OK);
1144 }
1146 NS_IMETHODIMP
1147 CompositeDataSourceImpl::BeginUpdateBatch()
1148 {
1149 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
1150 mDataSources[i]->BeginUpdateBatch();
1151 }
1152 return NS_OK;
1153 }
1155 NS_IMETHODIMP
1156 CompositeDataSourceImpl::EndUpdateBatch()
1157 {
1158 for (int32_t i = mDataSources.Count() - 1; i >= 0; --i) {
1159 mDataSources[i]->EndUpdateBatch();
1160 }
1161 return NS_OK;
1162 }
1164 ////////////////////////////////////////////////////////////////////////
1165 // nsIRDFCompositeDataSource methods
1166 // XXX rvg We should make this take an additional argument specifying where
1167 // in the sequence of data sources (of the db), the new data source should
1168 // fit in. Right now, the new datasource gets stuck at the end.
1169 // need to add the observers of the CompositeDataSourceImpl to the new data source.
1171 NS_IMETHODIMP
1172 CompositeDataSourceImpl::GetAllowNegativeAssertions(bool *aAllowNegativeAssertions)
1173 {
1174 *aAllowNegativeAssertions = mAllowNegativeAssertions;
1175 return(NS_OK);
1176 }
1178 NS_IMETHODIMP
1179 CompositeDataSourceImpl::SetAllowNegativeAssertions(bool aAllowNegativeAssertions)
1180 {
1181 mAllowNegativeAssertions = aAllowNegativeAssertions;
1182 return(NS_OK);
1183 }
1185 NS_IMETHODIMP
1186 CompositeDataSourceImpl::GetCoalesceDuplicateArcs(bool *aCoalesceDuplicateArcs)
1187 {
1188 *aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
1189 return(NS_OK);
1190 }
1192 NS_IMETHODIMP
1193 CompositeDataSourceImpl::SetCoalesceDuplicateArcs(bool aCoalesceDuplicateArcs)
1194 {
1195 mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
1196 return(NS_OK);
1197 }
1199 NS_IMETHODIMP
1200 CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource)
1201 {
1202 NS_ASSERTION(aDataSource != nullptr, "null ptr");
1203 if (! aDataSource)
1204 return NS_ERROR_NULL_POINTER;
1206 mDataSources.AppendObject(aDataSource);
1207 aDataSource->AddObserver(this);
1208 return NS_OK;
1209 }
1213 NS_IMETHODIMP
1214 CompositeDataSourceImpl::RemoveDataSource(nsIRDFDataSource* aDataSource)
1215 {
1216 NS_ASSERTION(aDataSource != nullptr, "null ptr");
1217 if (! aDataSource)
1218 return NS_ERROR_NULL_POINTER;
1221 if (mDataSources.IndexOf(aDataSource) >= 0) {
1222 aDataSource->RemoveObserver(this);
1223 mDataSources.RemoveObject(aDataSource);
1224 }
1225 return NS_OK;
1226 }
1229 NS_IMETHODIMP
1230 CompositeDataSourceImpl::GetDataSources(nsISimpleEnumerator** _result)
1231 {
1232 // NS_NewArrayEnumerator for an nsCOMArray takes a snapshot of the
1233 // current state.
1234 return NS_NewArrayEnumerator(_result, mDataSources);
1235 }
1237 NS_IMETHODIMP
1238 CompositeDataSourceImpl::OnAssert(nsIRDFDataSource* aDataSource,
1239 nsIRDFResource* aSource,
1240 nsIRDFResource* aProperty,
1241 nsIRDFNode* aTarget)
1242 {
1243 // Make sure that the assertion isn't masked by another
1244 // datasource.
1245 //
1246 // XXX We could make this more efficient if we knew _which_
1247 // datasource actually served up the OnAssert(): we could use
1248 // HasAssertionN() to only search datasources _before_ the
1249 // datasource that coughed up the assertion.
1250 nsresult rv = NS_OK;
1252 if (mAllowNegativeAssertions)
1253 {
1254 bool hasAssertion;
1255 rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
1256 if (NS_FAILED(rv)) return rv;
1258 if (! hasAssertion)
1259 return(NS_OK);
1260 }
1262 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1263 mObservers[i]->OnAssert(this, aSource, aProperty, aTarget);
1264 }
1265 return NS_OK;
1266 }
1268 NS_IMETHODIMP
1269 CompositeDataSourceImpl::OnUnassert(nsIRDFDataSource* aDataSource,
1270 nsIRDFResource* aSource,
1271 nsIRDFResource* aProperty,
1272 nsIRDFNode* aTarget)
1273 {
1274 // Make sure that the un-assertion doesn't just unmask the
1275 // same assertion in a different datasource.
1276 //
1277 // XXX We could make this more efficient if we knew _which_
1278 // datasource actually served up the OnAssert(): we could use
1279 // HasAssertionN() to only search datasources _before_ the
1280 // datasource that coughed up the assertion.
1281 nsresult rv;
1283 if (mAllowNegativeAssertions)
1284 {
1285 bool hasAssertion;
1286 rv = HasAssertion(aSource, aProperty, aTarget, true, &hasAssertion);
1287 if (NS_FAILED(rv)) return rv;
1289 if (hasAssertion)
1290 return NS_OK;
1291 }
1293 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1294 mObservers[i]->OnUnassert(this, aSource, aProperty, aTarget);
1295 }
1296 return NS_OK;
1297 }
1300 NS_IMETHODIMP
1301 CompositeDataSourceImpl::OnChange(nsIRDFDataSource* aDataSource,
1302 nsIRDFResource* aSource,
1303 nsIRDFResource* aProperty,
1304 nsIRDFNode* aOldTarget,
1305 nsIRDFNode* aNewTarget)
1306 {
1307 // Make sure that the change is actually visible, and not hidden
1308 // by an assertion in a different datasource.
1309 //
1310 // XXX Because of aggregation, this could actually mutate into a
1311 // variety of OnAssert or OnChange notifications, which we'll
1312 // ignore for now :-/.
1313 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1314 mObservers[i]->OnChange(this, aSource, aProperty,
1315 aOldTarget, aNewTarget);
1316 }
1317 return NS_OK;
1318 }
1321 NS_IMETHODIMP
1322 CompositeDataSourceImpl::OnMove(nsIRDFDataSource* aDataSource,
1323 nsIRDFResource* aOldSource,
1324 nsIRDFResource* aNewSource,
1325 nsIRDFResource* aProperty,
1326 nsIRDFNode* aTarget)
1327 {
1328 // Make sure that the move is actually visible, and not hidden
1329 // by an assertion in a different datasource.
1330 //
1331 // XXX Because of aggregation, this could actually mutate into a
1332 // variety of OnAssert or OnMove notifications, which we'll
1333 // ignore for now :-/.
1334 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1335 mObservers[i]->OnMove(this, aOldSource, aNewSource,
1336 aProperty, aTarget);
1337 }
1338 return NS_OK;
1339 }
1342 NS_IMETHODIMP
1343 CompositeDataSourceImpl::OnBeginUpdateBatch(nsIRDFDataSource* aDataSource)
1344 {
1345 if (mUpdateBatchNest++ == 0) {
1346 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1347 mObservers[i]->OnBeginUpdateBatch(this);
1348 }
1349 }
1350 return NS_OK;
1351 }
1354 NS_IMETHODIMP
1355 CompositeDataSourceImpl::OnEndUpdateBatch(nsIRDFDataSource* aDataSource)
1356 {
1357 NS_ASSERTION(mUpdateBatchNest > 0, "badly nested update batch");
1358 if (--mUpdateBatchNest == 0) {
1359 for (int32_t i = mObservers.Count() - 1; i >= 0; --i) {
1360 mObservers[i]->OnEndUpdateBatch(this);
1361 }
1362 }
1363 return NS_OK;
1364 }