1998-12-24 05:07:14 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
Implementation for an in-memory RDF data store.
|
|
|
|
|
1999-01-05 21:06:54 +00:00
|
|
|
TO DO
|
|
|
|
|
|
|
|
1) Instrument this code to gather space and time performance
|
|
|
|
characteristics.
|
|
|
|
|
|
|
|
2) If/when RDF containers become commonplace, consider implementing
|
|
|
|
a special case for them to improve access time to individual
|
|
|
|
elements.
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
3) Complete implementation of thread-safety; specifically, make
|
|
|
|
assertions be reference counted objects (so that a cursor can
|
|
|
|
still refer to an assertion that gets removed from the graph).
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
*/
|
|
|
|
|
1999-08-24 04:59:58 +00:00
|
|
|
#include "nsAgg.h"
|
1999-04-01 08:28:12 +00:00
|
|
|
#include "nsCOMPtr.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "nscore.h"
|
1999-01-05 03:53:15 +00:00
|
|
|
#include "nsIOutputStream.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "nsIRDFDataSource.h"
|
1999-05-05 03:09:12 +00:00
|
|
|
#include "nsIRDFLiteral.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "nsIRDFNode.h"
|
|
|
|
#include "nsIRDFObserver.h"
|
1999-05-05 03:09:12 +00:00
|
|
|
#include "nsIRDFPurgeableDataSource.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "nsIServiceManager.h"
|
1999-04-24 02:41:02 +00:00
|
|
|
#include "nsISupportsArray.h"
|
1999-04-01 08:28:12 +00:00
|
|
|
#include "nsAutoLock.h"
|
1999-04-24 02:41:02 +00:00
|
|
|
#include "nsEnumeratorUtils.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "nsVoidArray.h" // XXX introduces dependency on raptorbase
|
|
|
|
#include "nsRDFCID.h"
|
1999-06-24 00:22:58 +00:00
|
|
|
#include "nsRDFBaseDataSources.h"
|
1999-01-05 03:53:15 +00:00
|
|
|
#include "nsString.h"
|
1999-03-29 19:52:54 +00:00
|
|
|
#include "nsXPIDLString.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
#include "rdfutil.h"
|
|
|
|
#include "plhash.h"
|
|
|
|
#include "plstr.h"
|
1999-04-01 08:28:12 +00:00
|
|
|
#include "prlog.h"
|
1999-03-29 19:52:54 +00:00
|
|
|
#include "rdf.h"
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-09-07 02:44:43 +00:00
|
|
|
#if defined(MOZ_THREADSAFE_RDF)
|
|
|
|
#define NS_AUTOLOCK(_lock) nsAutoLock _autolock(_lock)
|
1999-02-04 10:42:21 +00:00
|
|
|
#else
|
1999-09-07 02:44:43 +00:00
|
|
|
#define NS_AUTOLOCK(_lock)
|
1999-02-04 10:42:21 +00:00
|
|
|
#endif
|
|
|
|
|
1999-04-01 08:28:12 +00:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
static PRLogModuleInfo* gLog = nsnull;
|
|
|
|
#endif
|
|
|
|
|
1999-01-05 21:06:54 +00:00
|
|
|
// This struct is used as the slot value in the forward and reverse
|
|
|
|
// arcs hash tables.
|
1999-05-05 03:09:12 +00:00
|
|
|
class Assertion
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-05-05 03:09:12 +00:00
|
|
|
public:
|
|
|
|
Assertion(nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue);
|
|
|
|
|
|
|
|
~Assertion();
|
|
|
|
|
|
|
|
// public for now, because I'm too lazy to go thru and clean this up.
|
|
|
|
nsIRDFResource* mSource; // OWNER
|
|
|
|
nsIRDFResource* mProperty; // OWNER
|
|
|
|
nsIRDFNode* mTarget; // OWNER
|
1998-12-24 05:07:14 +00:00
|
|
|
Assertion* mNext;
|
|
|
|
Assertion* mInvNext;
|
1999-05-05 03:09:12 +00:00
|
|
|
PRBool mTruthValue;
|
|
|
|
|
|
|
|
// For nsIRDFPurgeableDataSource
|
|
|
|
void Mark() { mMarked = PR_TRUE; }
|
|
|
|
PRBool IsMarked() { return mMarked; }
|
|
|
|
void Unmark() { mMarked = PR_FALSE; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
PRBool mMarked;
|
|
|
|
PRInt16 mRefCnt; // XXX not used yet: to be used for threadsafety
|
1998-12-27 20:35:46 +00:00
|
|
|
};
|
1999-05-05 03:09:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
Assertion::Assertion(nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue)
|
|
|
|
: mSource(aSource),
|
|
|
|
mProperty(aProperty),
|
|
|
|
mTarget(aTarget),
|
|
|
|
mNext(nsnull),
|
|
|
|
mInvNext(nsnull),
|
|
|
|
mTruthValue(aTruthValue),
|
|
|
|
mMarked(PR_FALSE),
|
|
|
|
mRefCnt(0)
|
|
|
|
{
|
|
|
|
NS_ADDREF(mSource);
|
|
|
|
NS_ADDREF(mProperty);
|
|
|
|
NS_ADDREF(mTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
Assertion::~Assertion()
|
|
|
|
{
|
|
|
|
NS_RELEASE(mSource);
|
|
|
|
NS_RELEASE(mProperty);
|
|
|
|
NS_RELEASE(mTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
1999-01-05 21:06:54 +00:00
|
|
|
// Utility routines
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-09-07 02:44:43 +00:00
|
|
|
static inline PLHashNumber
|
1998-12-24 05:07:14 +00:00
|
|
|
rdf_HashPointer(const void* key)
|
|
|
|
{
|
1999-09-07 02:44:43 +00:00
|
|
|
return NS_REINTERPRET_CAST(PLHashNumber, key) >> 2;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// InMemoryDataSource
|
1999-04-24 02:41:02 +00:00
|
|
|
class InMemoryResourceEnumeratorImpl;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
class InMemoryDataSource : public nsIRDFDataSource,
|
|
|
|
public nsIRDFPurgeableDataSource
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
|
|
|
protected:
|
1999-01-05 21:06:54 +00:00
|
|
|
// These hash tables are keyed on pointers to nsIRDFResource
|
|
|
|
// objects (the nsIRDFService ensures that there is only ever one
|
|
|
|
// nsIRDFResource object per unique URI). The value of an entry is
|
|
|
|
// an Assertion struct, which is a linked list of (subject
|
|
|
|
// predicate object) triples.
|
1998-12-24 05:07:14 +00:00
|
|
|
PLHashTable* mForwardArcs;
|
|
|
|
PLHashTable* mReverseArcs;
|
|
|
|
|
1999-06-24 00:22:58 +00:00
|
|
|
nsCOMPtr<nsISupportsArray> mObservers;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
static const PRInt32 kInitialTableSize;
|
|
|
|
|
1999-05-06 06:33:47 +00:00
|
|
|
static PRIntn DeleteForwardArcsEntry(PLHashEntry* he, PRIntn i, void* arg);
|
1999-02-02 08:06:38 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
// Thread-safe writer implementation methods.
|
|
|
|
nsresult
|
1999-07-02 03:40:32 +00:00
|
|
|
LockedAssert(nsIRDFResource* source,
|
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target,
|
|
|
|
PRBool tv);
|
1999-02-04 10:42:21 +00:00
|
|
|
|
|
|
|
nsresult
|
1999-07-02 03:40:32 +00:00
|
|
|
LockedUnassert(nsIRDFResource* source,
|
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target);
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
InMemoryDataSource(nsISupports* aOuter);
|
|
|
|
virtual ~InMemoryDataSource();
|
|
|
|
nsresult Init();
|
|
|
|
|
|
|
|
friend NS_IMETHODIMP
|
|
|
|
NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
public:
|
|
|
|
|
1999-08-24 04:59:58 +00:00
|
|
|
NS_DECL_AGGREGATED
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
// nsIRDFDataSource methods
|
1999-08-24 09:11:48 +00:00
|
|
|
NS_DECL_NSIRDFDATASOURCE
|
1999-01-12 19:41:06 +00:00
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
// nsIRDFPurgeableDataSource methods
|
1999-08-24 09:11:48 +00:00
|
|
|
NS_DECL_NSIRDFPURGEABLEDATASOURCE
|
1999-05-05 03:09:12 +00:00
|
|
|
|
|
|
|
protected:
|
1999-05-06 06:33:47 +00:00
|
|
|
static PRIntn SweepForwardArcsEntries(PLHashEntry* he, PRIntn i, void* arg);
|
1999-05-05 03:09:12 +00:00
|
|
|
|
|
|
|
public:
|
1999-08-24 09:11:48 +00:00
|
|
|
// Implementation methods
|
1999-09-07 02:44:43 +00:00
|
|
|
Assertion* GetForwardArcs(nsIRDFResource* u)
|
|
|
|
{
|
|
|
|
// Use PL_HashTableRawLookup() so we can inline the hash
|
|
|
|
PLHashEntry** hep = PL_HashTableRawLookup(mForwardArcs, rdf_HashPointer(u), u);
|
|
|
|
return NS_REINTERPRET_CAST(Assertion*, *hep ? ((*hep)->value) : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Assertion* GetReverseArcs(nsIRDFNode* v)
|
|
|
|
{
|
|
|
|
// Use PL_HashTableRawLookup() so we can inline the hash
|
|
|
|
PLHashEntry** hep = PL_HashTableRawLookup(mReverseArcs, rdf_HashPointer(v), v);
|
|
|
|
return NS_REINTERPRET_CAST(Assertion*, *hep ? ((*hep)->value) : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetForwardArcs(nsIRDFResource* u, Assertion* as)
|
|
|
|
{
|
|
|
|
if (as) {
|
|
|
|
PL_HashTableAdd(mForwardArcs, u, as);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PL_HashTableRemove(mForwardArcs, u);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetReverseArcs(nsIRDFNode* v, Assertion* as)
|
|
|
|
{
|
|
|
|
if (as) {
|
|
|
|
PL_HashTableAdd(mReverseArcs, v, as);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PL_HashTableRemove(mReverseArcs, v);
|
|
|
|
}
|
|
|
|
}
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
void
|
|
|
|
LogOperation(const char* aOperation,
|
|
|
|
nsIRDFResource* asource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue = PR_TRUE);
|
|
|
|
#endif
|
1999-02-04 10:42:21 +00:00
|
|
|
|
|
|
|
// This datasource's monitor object.
|
|
|
|
PRLock* mLock;
|
1998-12-24 05:07:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const PRInt32 InMemoryDataSource::kInitialTableSize = 500;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
1999-04-24 02:41:02 +00:00
|
|
|
// InMemoryAssertionEnumeratorImpl
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
/**
|
1999-04-24 02:41:02 +00:00
|
|
|
* InMemoryAssertionEnumeratorImpl
|
1999-01-05 03:53:15 +00:00
|
|
|
*/
|
1999-04-24 02:41:02 +00:00
|
|
|
class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
InMemoryDataSource* mDataSource;
|
|
|
|
nsIRDFResource* mSource;
|
1999-04-24 02:41:02 +00:00
|
|
|
nsIRDFResource* mProperty;
|
1998-12-24 05:07:14 +00:00
|
|
|
nsIRDFNode* mTarget;
|
|
|
|
nsIRDFNode* mValue;
|
|
|
|
PRInt32 mCount;
|
|
|
|
PRBool mTruthValue;
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
// XXX this implementation is a race condition waiting to
|
|
|
|
// happen. Hopefully, no one will blow away this assertion while
|
|
|
|
// we're iterating, but...
|
1998-12-24 05:07:14 +00:00
|
|
|
Assertion* mNextAssertion;
|
|
|
|
|
|
|
|
public:
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
|
|
|
|
nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue);
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
virtual ~InMemoryAssertionEnumeratorImpl();
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
// nsISupports interface
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
// nsISimpleEnumerator interface
|
1999-08-24 09:11:48 +00:00
|
|
|
NS_DECL_NSISIMPLEENUMERATOR
|
1998-12-24 05:07:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
|
|
|
|
InMemoryDataSource* aDataSource,
|
|
|
|
nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue)
|
|
|
|
: mDataSource(aDataSource),
|
|
|
|
mSource(aSource),
|
|
|
|
mProperty(aProperty),
|
|
|
|
mTarget(aTarget),
|
1999-05-06 06:33:47 +00:00
|
|
|
mValue(nsnull),
|
1998-12-24 05:07:14 +00:00
|
|
|
mCount(0),
|
1999-05-06 06:33:47 +00:00
|
|
|
mTruthValue(aTruthValue),
|
|
|
|
mNextAssertion(nsnull)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
|
|
|
NS_INIT_REFCNT();
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_ADDREF(mDataSource);
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IF_ADDREF(mSource);
|
|
|
|
NS_ADDREF(mProperty);
|
|
|
|
NS_IF_ADDREF(mTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (mSource) {
|
1999-01-05 03:53:15 +00:00
|
|
|
mNextAssertion = mDataSource->GetForwardArcs(mSource);
|
1999-04-24 02:41:02 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
mNextAssertion = mDataSource->GetReverseArcs(mTarget);
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_IF_RELEASE(mDataSource);
|
|
|
|
NS_IF_RELEASE(mSource);
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IF_RELEASE(mProperty);
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_IF_RELEASE(mTarget);
|
1998-12-24 05:07:14 +00:00
|
|
|
NS_IF_RELEASE(mValue);
|
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IMPL_ISUPPORTS(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator::GetIID());
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl::HasMoreElements(PRBool* aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mDataSource->mLock);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (mValue) {
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
|
|
|
|
while (mNextAssertion) {
|
1999-01-05 03:53:15 +00:00
|
|
|
PRBool foundIt = PR_FALSE;
|
1999-04-24 02:41:02 +00:00
|
|
|
if ((mProperty == mNextAssertion->mProperty) && (mTruthValue == mNextAssertion->mTruthValue)) {
|
|
|
|
if (mSource) {
|
1999-01-05 03:53:15 +00:00
|
|
|
mValue = mNextAssertion->mTarget;
|
1998-12-24 05:07:14 +00:00
|
|
|
NS_ADDREF(mValue);
|
1999-04-24 02:41:02 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-01-05 03:53:15 +00:00
|
|
|
mValue = mNextAssertion->mSource;
|
1998-12-24 05:07:14 +00:00
|
|
|
NS_ADDREF(mValue);
|
|
|
|
}
|
1999-01-05 03:53:15 +00:00
|
|
|
foundIt = PR_TRUE;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->mInvNext;
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (foundIt) {
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = PR_FALSE;
|
1998-12-24 05:07:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
nsresult rv;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
PRBool hasMore;
|
|
|
|
rv = HasMoreElements(&hasMore);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (! hasMore)
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
// Don't AddRef: we "transfer" ownership to the caller
|
|
|
|
*aResult = mValue;
|
|
|
|
mValue = nsnull;
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class is a little bit bizarre in that it implements both the
|
|
|
|
* <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
|
|
|
|
* Because the structure of the in-memory graph is pretty flexible, it's
|
|
|
|
* fairly easy to parameterize this class. The only funky thing to watch
|
1999-01-05 21:06:54 +00:00
|
|
|
* out for is the mutliple inheiritance clashes.
|
1999-01-05 03:53:15 +00:00
|
|
|
*/
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
|
|
|
private:
|
|
|
|
InMemoryDataSource* mDataSource;
|
1999-04-24 02:41:02 +00:00
|
|
|
nsIRDFResource* mSource;
|
|
|
|
nsIRDFNode* mTarget;
|
|
|
|
nsVoidArray mAlreadyReturned;
|
1999-01-05 03:53:15 +00:00
|
|
|
nsIRDFResource* mCurrent;
|
1999-04-24 02:41:02 +00:00
|
|
|
Assertion* mAssertion;
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
public:
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
|
|
|
|
nsIRDFResource* aSource,
|
|
|
|
nsIRDFNode* aTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
virtual ~InMemoryArcsEnumeratorImpl();
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
// nsISupports interface
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
// nsISimpleEnumerator interface
|
1999-08-24 09:11:48 +00:00
|
|
|
NS_DECL_NSISIMPLEENUMERATOR
|
1999-01-05 03:53:15 +00:00
|
|
|
};
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
|
|
|
|
nsIRDFResource* aSource,
|
|
|
|
nsIRDFNode* aTarget)
|
|
|
|
: mDataSource(aDataSource),
|
|
|
|
mSource(aSource),
|
|
|
|
mTarget(aTarget),
|
|
|
|
mCurrent(nsnull)
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
1999-01-12 19:41:06 +00:00
|
|
|
NS_INIT_REFCNT();
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_ADDREF(mDataSource);
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IF_ADDREF(mSource);
|
|
|
|
NS_IF_ADDREF(mTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (mSource) {
|
1999-01-05 03:53:15 +00:00
|
|
|
// cast okay because it's a closed system
|
1999-04-24 02:41:02 +00:00
|
|
|
mAssertion = mDataSource->GetForwardArcs(mSource);
|
1999-01-05 03:53:15 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-04-24 02:41:02 +00:00
|
|
|
mAssertion = mDataSource->GetReverseArcs(mTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
|
|
|
NS_RELEASE(mDataSource);
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IF_RELEASE(mSource);
|
|
|
|
NS_IF_RELEASE(mTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_IF_RELEASE(mCurrent);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
for (PRInt32 i = mAlreadyReturned.Count() - 1; i >= 0; --i) {
|
|
|
|
nsIRDFResource* resource = (nsIRDFResource*) mAlreadyReturned[i];
|
1999-01-05 03:53:15 +00:00
|
|
|
NS_RELEASE(resource);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_IMPL_ISUPPORTS(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator::GetIID());
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl::HasMoreElements(PRBool* aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (mCurrent) {
|
|
|
|
*aResult = PR_TRUE;
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_AUTOLOCK(mDataSource->mLock);
|
|
|
|
while (mAssertion) {
|
|
|
|
nsIRDFResource* next = mAssertion->mProperty;
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
PRBool alreadyReturned = PR_FALSE;
|
|
|
|
for (PRInt32 i = mAlreadyReturned.Count() - 1; i >= 0; --i) {
|
|
|
|
if (mAlreadyReturned[i] == mCurrent) {
|
|
|
|
alreadyReturned = PR_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
mAssertion = (mSource ? mAssertion->mNext : mAssertion->mInvNext);
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (! alreadyReturned) {
|
|
|
|
mCurrent = next;
|
|
|
|
NS_ADDREF(mCurrent);
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1999-01-21 22:24:32 +00:00
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = PR_FALSE;
|
1999-01-21 22:24:32 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
|
1999-01-21 22:24:32 +00:00
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
PRBool hasMore;
|
|
|
|
rv = HasMoreElements(&hasMore);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
if (! hasMore)
|
1999-01-21 22:24:32 +00:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
// Add this to the set of things we've already returned so that we
|
|
|
|
// can ensure uniqueness
|
|
|
|
NS_ADDREF(mCurrent);
|
|
|
|
mAlreadyReturned.AppendElement(mCurrent);
|
|
|
|
|
|
|
|
// Don't AddRef: we "transfer" ownership to the caller
|
|
|
|
*aResult = mCurrent;
|
|
|
|
mCurrent = nsnull;
|
1999-01-21 22:24:32 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
1999-01-05 03:53:15 +00:00
|
|
|
// InMemoryDataSource
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-06-10 06:47:28 +00:00
|
|
|
NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
1999-06-10 06:47:28 +00:00
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
1999-08-24 04:59:58 +00:00
|
|
|
if (! aResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
if (aOuter && !aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
|
|
|
NS_ERROR("aggregation requires nsISupports");
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
|
|
|
|
if (! datasource)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1999-05-06 06:33:47 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
rv = datasource->Init();
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
1999-08-24 04:59:58 +00:00
|
|
|
datasource->fAggregated.AddRef();
|
|
|
|
rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
|
|
|
|
datasource->fAggregated.Release();
|
1999-06-10 06:47:28 +00:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
return rv;
|
1999-01-05 03:53:15 +00:00
|
|
|
}
|
1999-05-05 03:09:12 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
delete datasource;
|
|
|
|
*aResult = nsnull;
|
|
|
|
return rv;
|
1999-01-05 03:53:15 +00:00
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
|
1999-06-24 00:22:58 +00:00
|
|
|
: mForwardArcs(nsnull),
|
1998-12-24 05:07:14 +00:00
|
|
|
mReverseArcs(nsnull),
|
1999-06-24 00:22:58 +00:00
|
|
|
mLock(nsnull)
|
1999-06-10 06:47:28 +00:00
|
|
|
{
|
1999-08-24 04:59:58 +00:00
|
|
|
NS_INIT_AGGREGATED(aOuter);
|
1999-06-10 06:47:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
InMemoryDataSource::Init()
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
|
|
|
mForwardArcs = PL_NewHashTable(kInitialTableSize,
|
1999-03-08 08:27:53 +00:00
|
|
|
rdf_HashPointer,
|
|
|
|
PL_CompareValues,
|
|
|
|
PL_CompareValues,
|
|
|
|
nsnull,
|
|
|
|
nsnull);
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
if (! mForwardArcs)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
mReverseArcs = PL_NewHashTable(kInitialTableSize,
|
1999-03-08 08:27:53 +00:00
|
|
|
rdf_HashPointer,
|
1999-06-24 21:19:54 +00:00
|
|
|
PL_CompareValues,
|
1999-03-08 08:27:53 +00:00
|
|
|
PL_CompareValues,
|
|
|
|
nsnull,
|
|
|
|
nsnull);
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
if (! mReverseArcs)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
mLock = PR_NewLock();
|
|
|
|
if (! mLock)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
1999-04-01 08:28:12 +00:00
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (! gLog)
|
|
|
|
gLog = PR_NewLogModule("InMemoryDataSource");
|
|
|
|
#endif
|
1999-06-10 06:47:28 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
|
|
|
|
InMemoryDataSource::~InMemoryDataSource()
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
|
|
|
if (mForwardArcs) {
|
1999-02-02 08:06:38 +00:00
|
|
|
// This'll release all of the Assertion objects that are
|
|
|
|
// associated with this data source. We only need to do this
|
|
|
|
// for the forward arcs, because the reverse arcs table
|
|
|
|
// indexes the exact same set of resources.
|
|
|
|
PL_HashTableEnumerateEntries(mForwardArcs, DeleteForwardArcsEntry, nsnull);
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
PL_HashTableDestroy(mForwardArcs);
|
|
|
|
mForwardArcs = nsnull;
|
|
|
|
}
|
|
|
|
if (mReverseArcs) {
|
|
|
|
PL_HashTableDestroy(mReverseArcs);
|
|
|
|
mReverseArcs = nsnull;
|
|
|
|
}
|
1999-04-29 04:20:14 +00:00
|
|
|
|
1999-04-01 08:28:12 +00:00
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
1999-06-24 00:22:58 +00:00
|
|
|
("InMemoryDataSource(%p): destroyed.", this));
|
1999-04-01 08:28:12 +00:00
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
PR_DestroyLock(mLock);
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-02-02 08:06:38 +00:00
|
|
|
PRIntn
|
1999-05-06 06:33:47 +00:00
|
|
|
InMemoryDataSource::DeleteForwardArcsEntry(PLHashEntry* he, PRIntn i, void* arg)
|
1999-02-02 08:06:38 +00:00
|
|
|
{
|
|
|
|
Assertion* as = (Assertion*) he->value;
|
|
|
|
while (as) {
|
|
|
|
Assertion* doomed = as;
|
|
|
|
as = as->mNext;
|
|
|
|
delete doomed;
|
|
|
|
}
|
|
|
|
return HT_ENUMERATE_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-06-10 06:47:28 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
1999-08-24 04:59:58 +00:00
|
|
|
NS_IMPL_AGGREGATED(InMemoryDataSource)
|
1999-06-10 06:47:28 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-08-24 04:59:58 +00:00
|
|
|
InMemoryDataSource::AggregatedQueryInterface(REFNSIID aIID, void** aResult)
|
1999-06-10 06:47:28 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-08-24 04:59:58 +00:00
|
|
|
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
|
|
|
*aResult = NS_STATIC_CAST(nsISupports*, &fAggregated);
|
|
|
|
}
|
|
|
|
else if (aIID.Equals(nsCOMTypeInfo<nsIRDFDataSource>::GetIID())) {
|
1999-06-10 06:47:28 +00:00
|
|
|
*aResult = NS_STATIC_CAST(nsIRDFDataSource*, this);
|
|
|
|
}
|
1999-08-24 04:59:58 +00:00
|
|
|
else if (aIID.Equals(nsCOMTypeInfo<nsIRDFPurgeableDataSource>::GetIID())) {
|
1999-06-10 06:47:28 +00:00
|
|
|
*aResult = NS_STATIC_CAST(nsIRDFPurgeableDataSource*, this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*aResult = nsnull;
|
|
|
|
return NS_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
1999-08-24 04:59:58 +00:00
|
|
|
NS_ADDREF(NS_STATIC_CAST(nsISupports*, *aResult));
|
1999-06-10 06:47:28 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
#ifdef PR_LOGGING
|
|
|
|
void
|
|
|
|
InMemoryDataSource::LogOperation(const char* aOperation,
|
|
|
|
nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue)
|
|
|
|
{
|
|
|
|
if (! PR_LOG_TEST(gLog, PR_LOG_ALWAYS))
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsXPIDLCString uri;
|
|
|
|
aSource->GetValue(getter_Copies(uri));
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
1999-06-24 00:22:58 +00:00
|
|
|
("InMemoryDataSource(%p): %s", this, aOperation));
|
1999-05-05 03:09:12 +00:00
|
|
|
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
|
|
|
(" [(%p)%s]--", aSource, (const char*) uri));
|
|
|
|
|
|
|
|
aProperty->GetValue(getter_Copies(uri));
|
|
|
|
|
|
|
|
char tv = (aTruthValue ? '-' : '!');
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
|
|
|
(" --%c[(%p)%s]--", tv, aProperty, (const char*) uri));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIRDFResource> resource;
|
|
|
|
nsCOMPtr<nsIRDFLiteral> literal;
|
|
|
|
|
|
|
|
if ((resource = do_QueryInterface(aTarget)) != nsnull) {
|
|
|
|
resource->GetValue(getter_Copies(uri));
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
|
|
|
(" -->[(%p)%s]", aTarget, (const char*) uri));
|
|
|
|
}
|
|
|
|
else if ((literal = do_QueryInterface(aTarget)) != nsnull) {
|
|
|
|
nsXPIDLString value;
|
|
|
|
literal->GetValue(getter_Copies(value));
|
|
|
|
nsAutoString valueStr(value);
|
|
|
|
char* valueCStr = valueStr.ToNewCString();
|
|
|
|
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
|
|
|
(" -->(\"%s\")\n", valueCStr));
|
|
|
|
|
1999-09-04 13:42:15 +00:00
|
|
|
nsCRT::free(valueCStr);
|
1999-05-05 03:09:12 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
PR_LOG(gLog, PR_LOG_ALWAYS,
|
|
|
|
(" -->(unknown-type)\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
NS_IMETHODIMP
|
1999-03-29 19:52:54 +00:00
|
|
|
InMemoryDataSource::GetURI(char* *uri)
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
|
|
|
NS_PRECONDITION(uri != nsnull, "null ptr");
|
|
|
|
if (! uri)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-06-24 00:22:58 +00:00
|
|
|
*uri = nsnull;
|
|
|
|
return NS_OK;
|
1999-01-05 03:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::GetSource(nsIRDFResource* property,
|
1999-02-02 08:06:38 +00:00
|
|
|
nsIRDFNode* target,
|
|
|
|
PRBool tv,
|
|
|
|
nsIRDFResource** source)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_PRECONDITION(source != nsnull, "null ptr");
|
|
|
|
if (! source)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(property != nsnull, "null ptr");
|
|
|
|
if (! property)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(target != nsnull, "null ptr");
|
|
|
|
if (! target)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
for (Assertion* as = GetReverseArcs(target); as != nsnull; as = as->mNext) {
|
1999-05-05 03:09:12 +00:00
|
|
|
if ((property == as->mProperty) && (as->mTruthValue == tv)) {
|
|
|
|
*source = as->mSource;
|
|
|
|
NS_ADDREF(as->mSource);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
*source = nsnull;
|
1999-03-30 02:30:16 +00:00
|
|
|
return NS_RDF_NO_VALUE;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-01-05 03:53:15 +00:00
|
|
|
InMemoryDataSource::GetTarget(nsIRDFResource* source,
|
1999-02-02 08:06:38 +00:00
|
|
|
nsIRDFResource* property,
|
|
|
|
PRBool tv,
|
|
|
|
nsIRDFNode** target)
|
1999-01-05 03:53:15 +00:00
|
|
|
{
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_PRECONDITION(source != nsnull, "null ptr");
|
|
|
|
if (! source)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(property != nsnull, "null ptr");
|
|
|
|
if (! property)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(target != nsnull, "null ptr");
|
|
|
|
if (! target)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
for (Assertion* as = GetForwardArcs(source); as != nsnull; as = as->mNext) {
|
1999-05-05 03:09:12 +00:00
|
|
|
if ((property == as->mProperty) && (as->mTruthValue == tv)) {
|
|
|
|
*target = as->mTarget;
|
|
|
|
NS_ADDREF(as->mTarget);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, then there was no target with for the specified
|
|
|
|
// property & truth value.
|
|
|
|
*target = nsnull;
|
1999-03-30 02:30:16 +00:00
|
|
|
return NS_RDF_NO_VALUE;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-01-05 03:53:15 +00:00
|
|
|
InMemoryDataSource::HasAssertion(nsIRDFResource* source,
|
1999-02-02 08:06:38 +00:00
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target,
|
|
|
|
PRBool tv,
|
|
|
|
PRBool* hasAssertion)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_PRECONDITION(source != nsnull, "null ptr");
|
|
|
|
if (! source)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(property != nsnull, "null ptr");
|
|
|
|
if (! property)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(target != nsnull, "null ptr");
|
|
|
|
if (! target)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
for (Assertion* as = GetForwardArcs(source); as != nsnull; as = as->mNext) {
|
1999-05-05 03:09:12 +00:00
|
|
|
if (property != as->mProperty)
|
1998-12-24 05:07:14 +00:00
|
|
|
continue;
|
|
|
|
|
1999-06-24 21:19:54 +00:00
|
|
|
if (target != as->mTarget)
|
1998-12-24 05:07:14 +00:00
|
|
|
continue;
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
if (as->mTruthValue != tv)
|
1998-12-24 05:07:14 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// found it!
|
|
|
|
*hasAssertion = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, we couldn't find the assertion
|
|
|
|
*hasAssertion = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue,
|
|
|
|
nsISimpleEnumerator** aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aProperty != nsnull, "null ptr");
|
|
|
|
if (! aProperty)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aTarget != nsnull, "null ptr");
|
|
|
|
if (! aTarget)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl* result
|
|
|
|
= new InMemoryAssertionEnumeratorImpl(this, nsnull, aProperty, aTarget, aTruthValue);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(result);
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = result;
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
PRBool aTruthValue,
|
|
|
|
nsISimpleEnumerator** aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aSource != nsnull, "null ptr");
|
|
|
|
if (! aSource)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aProperty != nsnull, "null ptr");
|
|
|
|
if (! aProperty)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryAssertionEnumeratorImpl* result
|
|
|
|
= new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty, nsnull, aTruthValue);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(result);
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = result;
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
|
|
|
|
nsresult
|
1999-07-02 03:40:32 +00:00
|
|
|
InMemoryDataSource::LockedAssert(nsIRDFResource* source,
|
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target,
|
|
|
|
PRBool tv)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-01 08:28:12 +00:00
|
|
|
#ifdef PR_LOGGING
|
1999-05-05 03:09:12 +00:00
|
|
|
LogOperation("ASSERT", source, property, target, tv);
|
1999-04-01 08:28:12 +00:00
|
|
|
#endif
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
Assertion* next = GetForwardArcs(source);
|
1998-12-24 05:07:14 +00:00
|
|
|
Assertion* prev = next;
|
|
|
|
Assertion* as = nsnull;
|
|
|
|
|
|
|
|
// Walk to the end of the linked list.
|
|
|
|
// XXX shouldn't we just keep a pointer to the end, or insert at the front???
|
|
|
|
while (next) {
|
1999-05-05 03:09:12 +00:00
|
|
|
if (property == next->mProperty) {
|
1999-06-24 21:19:54 +00:00
|
|
|
if (target == next->mTarget) {
|
1998-12-24 05:07:14 +00:00
|
|
|
// Wow, we already had the assertion. Make sure that the
|
|
|
|
// truth values are correct and bail.
|
1999-01-05 03:53:15 +00:00
|
|
|
next->mTruthValue = tv;
|
1998-12-24 05:07:14 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = next;
|
1999-01-05 03:53:15 +00:00
|
|
|
next = next->mNext;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
as = new Assertion(source, property, target, tv);
|
1998-12-24 05:07:14 +00:00
|
|
|
if (! as)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
// Link it in to the "forward arcs" table
|
|
|
|
if (!prev) {
|
1999-01-05 03:53:15 +00:00
|
|
|
SetForwardArcs(source, as);
|
1998-12-24 05:07:14 +00:00
|
|
|
} else {
|
|
|
|
prev->mNext = as;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link it in to the "reverse arcs" table
|
|
|
|
|
|
|
|
// XXX Shouldn't we keep a pointer to the end of the list to make
|
|
|
|
// sure this is O(1)?
|
1999-03-08 08:27:53 +00:00
|
|
|
prev = nsnull;
|
|
|
|
next = GetReverseArcs(target);
|
|
|
|
while (next) {
|
|
|
|
prev = next;
|
|
|
|
next = next->mInvNext;
|
|
|
|
}
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
if (!prev) {
|
1999-01-05 03:53:15 +00:00
|
|
|
SetReverseArcs(target, as);
|
1998-12-24 05:07:14 +00:00
|
|
|
} else {
|
|
|
|
prev->mInvNext = as;
|
|
|
|
}
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Assert(nsIRDFResource* source,
|
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target,
|
|
|
|
PRBool tv)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
1999-07-02 03:40:32 +00:00
|
|
|
{
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
rv = LockedAssert(source, property, target, tv);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
// notify observers
|
|
|
|
if (mObservers) {
|
1999-06-24 00:22:58 +00:00
|
|
|
PRUint32 count;
|
|
|
|
rv = mObservers->Count(&count);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
|
1998-12-24 05:07:14 +00:00
|
|
|
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
|
|
|
|
obs->OnAssert(source, property, target);
|
1999-06-24 00:22:58 +00:00
|
|
|
NS_RELEASE(obs);
|
1998-12-24 05:07:14 +00:00
|
|
|
// XXX ignore return value?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-07 06:29:41 +00:00
|
|
|
return NS_RDF_ASSERTION_ACCEPTED;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
|
|
|
|
nsresult
|
1999-07-02 03:40:32 +00:00
|
|
|
InMemoryDataSource::LockedUnassert(nsIRDFResource* source,
|
1999-02-04 10:42:21 +00:00
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-01 08:28:12 +00:00
|
|
|
#ifdef PR_LOGGING
|
1999-05-05 03:09:12 +00:00
|
|
|
LogOperation("UNASSERT", source, property, target);
|
1999-04-01 08:28:12 +00:00
|
|
|
#endif
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
Assertion* next = GetForwardArcs(source);
|
1998-12-24 05:07:14 +00:00
|
|
|
Assertion* prev = next;
|
|
|
|
Assertion* as = nsnull;
|
|
|
|
|
|
|
|
while (next) {
|
1999-05-05 03:09:12 +00:00
|
|
|
if (property == next->mProperty) {
|
1999-06-24 21:19:54 +00:00
|
|
|
if (target == next->mTarget) {
|
1998-12-24 05:07:14 +00:00
|
|
|
if (prev == next) {
|
1999-01-05 03:53:15 +00:00
|
|
|
SetForwardArcs(source, next->mNext);
|
1998-12-24 05:07:14 +00:00
|
|
|
} else {
|
|
|
|
prev->mNext = next->mNext;
|
|
|
|
}
|
|
|
|
as = next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prev = next;
|
1999-01-05 03:53:15 +00:00
|
|
|
next = next->mNext;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// We don't even have the assertion, so just bail.
|
|
|
|
if (!as)
|
|
|
|
return NS_OK;
|
|
|
|
|
1999-03-08 08:27:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
PRBool foundReverseArc = PR_FALSE;
|
|
|
|
#endif
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
next = prev = GetReverseArcs(target);
|
1998-12-24 05:07:14 +00:00
|
|
|
while (next) {
|
|
|
|
if (next == as) {
|
|
|
|
if (prev == next) {
|
1999-01-05 03:53:15 +00:00
|
|
|
SetReverseArcs(target, next->mInvNext);
|
1998-12-24 05:07:14 +00:00
|
|
|
} else {
|
|
|
|
prev->mInvNext = next->mInvNext;
|
|
|
|
}
|
1999-03-08 08:27:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
foundReverseArc = PR_TRUE;
|
|
|
|
#endif
|
1998-12-24 05:07:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = next;
|
1999-01-05 03:53:15 +00:00
|
|
|
next = next->mInvNext;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-03-08 08:27:53 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
|
|
|
|
#endif
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
// Delete the assertion struct & release resources
|
|
|
|
delete as;
|
1998-12-24 05:07:14 +00:00
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Unassert(nsIRDFResource* source,
|
|
|
|
nsIRDFResource* property,
|
|
|
|
nsIRDFNode* target)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
|
1999-07-02 03:40:32 +00:00
|
|
|
{
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
|
|
|
rv = LockedUnassert(source, property, target);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
1999-02-04 10:42:21 +00:00
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
// Notify the world
|
1998-12-24 05:07:14 +00:00
|
|
|
if (mObservers) {
|
1999-06-24 00:22:58 +00:00
|
|
|
PRUint32 count;
|
|
|
|
rv = mObservers->Count(&count);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
|
1998-12-24 05:07:14 +00:00
|
|
|
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
|
|
|
|
obs->OnUnassert(source, property, target);
|
1999-06-24 00:22:58 +00:00
|
|
|
NS_RELEASE(obs);
|
1998-12-24 05:07:14 +00:00
|
|
|
// XXX ignore return value?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-07 06:29:41 +00:00
|
|
|
return NS_RDF_ASSERTION_ACCEPTED;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-06-24 00:22:58 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Change(nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aOldTarget,
|
|
|
|
nsIRDFNode* aNewTarget)
|
|
|
|
{
|
1999-07-02 03:40:32 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
{
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
|
|
|
// XXX We can implement LockedChange() if we decide that this
|
|
|
|
// is a performance bottleneck.
|
|
|
|
|
|
|
|
rv = LockedUnassert(aSource, aProperty, aOldTarget);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
rv = LockedAssert(aSource, aProperty, aNewTarget, PR_TRUE);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify the world
|
|
|
|
if (mObservers) {
|
|
|
|
PRUint32 count;
|
|
|
|
rv = mObservers->Count(&count);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
|
|
|
|
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
|
|
|
|
obs->OnChange(aSource, aProperty, aOldTarget, aNewTarget);
|
|
|
|
NS_RELEASE(obs);
|
|
|
|
// XXX ignore return value?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_RDF_ASSERTION_ACCEPTED;
|
1999-06-24 00:22:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Move(nsIRDFResource* aOldSource,
|
|
|
|
nsIRDFResource* aNewSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget)
|
|
|
|
{
|
1999-07-02 03:40:32 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
{
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
|
|
|
// XXX We can implement LockedMove() if we decide that this
|
|
|
|
// is a performance bottleneck.
|
|
|
|
|
|
|
|
rv = LockedUnassert(aOldSource, aProperty, aTarget);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
rv = LockedAssert(aNewSource, aProperty, aTarget, PR_TRUE);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify the world
|
|
|
|
if (mObservers) {
|
|
|
|
PRUint32 count;
|
|
|
|
rv = mObservers->Count(&count);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
|
|
|
|
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
|
|
|
|
obs->OnMove(aOldSource, aNewSource, aProperty, aTarget);
|
|
|
|
NS_RELEASE(obs);
|
|
|
|
// XXX ignore return value?
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_RDF_ASSERTION_ACCEPTED;
|
1999-06-24 00:22:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::AddObserver(nsIRDFObserver* observer)
|
|
|
|
{
|
1999-01-12 19:41:06 +00:00
|
|
|
NS_ASSERTION(observer != nsnull, "null ptr");
|
|
|
|
if (! observer)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
if (! mObservers) {
|
1999-06-24 00:22:58 +00:00
|
|
|
nsresult rv;
|
|
|
|
rv = NS_NewISupportsArray(getter_AddRefs(mObservers));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mObservers->AppendElement(observer);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::RemoveObserver(nsIRDFObserver* observer)
|
|
|
|
{
|
1999-01-12 19:41:06 +00:00
|
|
|
NS_ASSERTION(observer != nsnull, "null ptr");
|
|
|
|
if (! observer)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
if (! mObservers)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
mObservers->RemoveElement(observer);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aTarget != nsnull, "null ptr");
|
|
|
|
if (! aTarget)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl* result =
|
|
|
|
new InMemoryArcsEnumeratorImpl(this, nsnull, aTarget);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(result);
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = result;
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_OK;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
|
1998-12-24 05:07:14 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aSource != nsnull, "null ptr");
|
|
|
|
if (! aSource)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryArcsEnumeratorImpl* result =
|
|
|
|
new InMemoryArcsEnumeratorImpl(this, aSource, nsnull);
|
1999-01-05 03:53:15 +00:00
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
NS_ADDREF(result);
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = result;
|
|
|
|
|
1999-01-05 03:53:15 +00:00
|
|
|
return NS_OK;
|
1998-12-24 05:07:14 +00:00
|
|
|
}
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
static PRIntn
|
1999-05-06 06:33:47 +00:00
|
|
|
rdf_ResourceEnumerator(PLHashEntry* he, PRIntn i, void* closure)
|
1999-04-24 02:41:02 +00:00
|
|
|
{
|
|
|
|
nsISupportsArray* resources = NS_STATIC_CAST(nsISupportsArray*, closure);
|
|
|
|
|
|
|
|
nsIRDFResource* resource =
|
|
|
|
NS_CONST_CAST(nsIRDFResource*, NS_STATIC_CAST(const nsIRDFResource*, he->key));
|
|
|
|
|
|
|
|
NS_ADDREF(resource);
|
|
|
|
resources->AppendElement(resource);
|
|
|
|
return HT_ENUMERATE_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-01-21 22:24:32 +00:00
|
|
|
NS_IMETHODIMP
|
1999-04-24 02:41:02 +00:00
|
|
|
InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
|
1999-01-21 22:24:32 +00:00
|
|
|
{
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_PRECONDITION(aResult != nsnull, "null ptr");
|
|
|
|
if (! aResult)
|
1999-01-21 22:24:32 +00:00
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISupportsArray> values;
|
|
|
|
rv = NS_NewISupportsArray(getter_AddRefs(values));
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
|
1999-02-04 10:42:21 +00:00
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
// Enumerate all of our entries into an nsISupportsArray.
|
|
|
|
PL_HashTableEnumerateEntries(mForwardArcs, rdf_ResourceEnumerator, values.get());
|
1999-01-21 22:24:32 +00:00
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
*aResult = new nsArrayEnumerator(values);
|
|
|
|
if (! *aResult)
|
1999-01-21 22:24:32 +00:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
1999-04-24 02:41:02 +00:00
|
|
|
NS_ADDREF(*aResult);
|
1999-01-21 22:24:32 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
1999-01-12 19:41:06 +00:00
|
|
|
NS_IMETHODIMP
|
1999-03-12 21:28:34 +00:00
|
|
|
InMemoryDataSource::GetAllCommands(nsIRDFResource* source,
|
|
|
|
nsIEnumerator/*<nsIRDFResource>*/** commands)
|
|
|
|
{
|
|
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
1999-06-26 01:09:02 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
|
|
|
|
nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
|
|
|
|
{
|
1999-06-26 04:58:22 +00:00
|
|
|
return(NS_NewEmptyEnumerator(commands));
|
1999-06-26 01:09:02 +00:00
|
|
|
}
|
|
|
|
|
1999-03-12 21:28:34 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
|
|
|
|
nsIRDFResource* aCommand,
|
1999-03-29 19:52:54 +00:00
|
|
|
nsISupportsArray/*<nsIRDFResource>*/* aArguments,
|
|
|
|
PRBool* aResult)
|
1999-01-12 19:41:06 +00:00
|
|
|
{
|
1999-03-11 10:01:25 +00:00
|
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
1999-01-12 19:41:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
1999-03-12 21:28:34 +00:00
|
|
|
InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
|
1999-03-11 10:01:25 +00:00
|
|
|
nsIRDFResource* aCommand,
|
1999-03-12 21:28:34 +00:00
|
|
|
nsISupportsArray/*<nsIRDFResource>*/* aArguments)
|
1999-01-12 19:41:06 +00:00
|
|
|
{
|
1999-03-11 10:01:25 +00:00
|
|
|
NS_NOTYETIMPLEMENTED("write me!");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
1999-01-12 19:41:06 +00:00
|
|
|
}
|
1999-01-05 08:44:40 +00:00
|
|
|
|
1999-05-05 03:09:12 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
// nsIRDFPurgeableDataSource methods
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Mark(nsIRDFResource* aSource,
|
|
|
|
nsIRDFResource* aProperty,
|
|
|
|
nsIRDFNode* aTarget,
|
|
|
|
PRBool aTruthValue,
|
|
|
|
PRBool* aDidMark)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aSource != nsnull, "null ptr");
|
|
|
|
if (! aSource)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aProperty != nsnull, "null ptr");
|
|
|
|
if (! aProperty)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_PRECONDITION(aTarget != nsnull, "null ptr");
|
|
|
|
if (! aTarget)
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
|
|
|
|
for (Assertion* as = GetForwardArcs(aSource); as != nsnull; as = as->mNext) {
|
|
|
|
if (aProperty != as->mProperty)
|
|
|
|
continue;
|
|
|
|
|
1999-06-24 21:19:54 +00:00
|
|
|
if (aTarget != as->mTarget)
|
1999-05-05 03:09:12 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (as->mTruthValue != aTruthValue)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// found it! so mark it.
|
|
|
|
as->Mark();
|
|
|
|
*aDidMark = PR_TRUE;
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we get here, we couldn't find the assertion
|
|
|
|
*aDidMark = PR_FALSE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct SweepInfo {
|
|
|
|
Assertion* mUnassertList;
|
|
|
|
PLHashTable* mReverseArcs;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
InMemoryDataSource::Sweep()
|
|
|
|
{
|
|
|
|
SweepInfo info = { nsnull, mReverseArcs };
|
|
|
|
|
|
|
|
{
|
|
|
|
// Remove all the assertions while holding the lock, but don't notify anyone.
|
|
|
|
NS_AUTOLOCK(mLock);
|
|
|
|
PL_HashTableEnumerateEntries(mForwardArcs, SweepForwardArcsEntries, &info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we've left the autolock. Do the notification.
|
|
|
|
Assertion* as = info.mUnassertList;
|
|
|
|
while (as) {
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
LogOperation("SWEEP", as->mSource, as->mProperty, as->mTarget, as->mTruthValue);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (mObservers) {
|
1999-06-24 00:22:58 +00:00
|
|
|
nsresult rv;
|
|
|
|
PRUint32 count;
|
|
|
|
rv = mObservers->Count(&count);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; --i) {
|
|
|
|
nsIRDFObserver* obs = (nsIRDFObserver*) mObservers->ElementAt(i);
|
|
|
|
obs->OnUnassert(as->mSource, as->mProperty, as->mTarget);
|
|
|
|
// XXX ignore return value?
|
|
|
|
}
|
1999-05-05 03:09:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Assertion* doomed = as;
|
|
|
|
as = as->mNext;
|
|
|
|
delete doomed;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PRIntn
|
1999-05-06 06:33:47 +00:00
|
|
|
InMemoryDataSource::SweepForwardArcsEntries(PLHashEntry* he, PRIntn i, void* arg)
|
1999-05-05 03:09:12 +00:00
|
|
|
{
|
|
|
|
SweepInfo* info = (SweepInfo*) arg;
|
|
|
|
|
|
|
|
Assertion* as = (Assertion*) he->value;
|
|
|
|
Assertion* prev = nsnull;
|
|
|
|
while (as) {
|
|
|
|
if (as->IsMarked()) {
|
|
|
|
prev = as;
|
|
|
|
as->Unmark();
|
|
|
|
as = as->mNext;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// remove from the list of assertions in the datasource
|
|
|
|
Assertion* next = as->mNext;
|
|
|
|
if (prev) {
|
|
|
|
prev->mNext = next;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// it's the first one. update the hashtable entry.
|
|
|
|
he->value = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove from the reverse arcs
|
|
|
|
PLHashEntry** hep =
|
|
|
|
PL_HashTableRawLookup(info->mReverseArcs,
|
1999-09-07 02:44:43 +00:00
|
|
|
rdf_HashPointer(as->mTarget),
|
1999-05-05 03:09:12 +00:00
|
|
|
as->mTarget);
|
|
|
|
|
|
|
|
Assertion* ras = (Assertion*) ((*hep)->value);
|
|
|
|
NS_ASSERTION(ras != nsnull, "no assertion in reverse arcs");
|
|
|
|
Assertion* rprev = nsnull;
|
|
|
|
while (ras) {
|
|
|
|
if (ras == as) {
|
|
|
|
if (rprev) {
|
|
|
|
rprev->mInvNext = ras->mInvNext;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// it's the first one. update the hashtable entry.
|
|
|
|
(*hep)->value = ras->mInvNext;
|
|
|
|
}
|
|
|
|
as->mInvNext = nsnull; // for my sanity.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rprev = ras;
|
|
|
|
ras = ras->mInvNext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wow, it was the _only_ one. Unhash it.
|
|
|
|
if (! (*hep)->value)
|
|
|
|
PL_HashTableRawRemove(info->mReverseArcs, hep, *hep);
|
|
|
|
|
|
|
|
|
|
|
|
// add to the list of assertions to unassert
|
|
|
|
as->mNext = info->mUnassertList;
|
|
|
|
info->mUnassertList = as;
|
|
|
|
|
|
|
|
// Advance to the next assertion
|
|
|
|
as = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRIntn result = HT_ENUMERATE_NEXT;
|
|
|
|
|
|
|
|
// if no more assertions exist for this resource, then unhash it.
|
|
|
|
if (! he->value)
|
|
|
|
result |= HT_ENUMERATE_REMOVE;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1998-12-24 05:07:14 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|