1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This Original Code has been modified by IBM Corporation.
9 * Modifications made by IBM described herein are
10 * Copyright (c) International Business Machines
13 * Modifications to Mozilla code or documentation
14 * identified per MPL Section 3.3
16 * Date Modified by Description of modification
17 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
23 This file provides the implementation for the RDF service manager.
28 1) Implement the CreateDataBase() methods.
30 2) Cache date and int literals.
34 #include "nsRDFService.h"
36 #include "nsAutoPtr.h"
39 #include "nsIComponentManager.h"
40 #include "nsIRDFDataSource.h"
41 #include "nsIRDFNode.h"
42 #include "nsIRDFRemoteDataSource.h"
43 #include "nsIServiceManager.h"
44 #include "nsIFactory.h"
47 #include "nsXPIDLString.h"
48 #include "nsNetUtil.h"
57 #include "nsCRTGlue.h"
58 #include "mozilla/HashFunctions.h"
60 using namespace mozilla
;
62 ////////////////////////////////////////////////////////////////////////
64 static NS_DEFINE_CID(kRDFXMLDataSourceCID
, NS_RDFXMLDATASOURCE_CID
);
65 static NS_DEFINE_CID(kRDFDefaultResourceCID
, NS_RDFDEFAULTRESOURCE_CID
);
67 static NS_DEFINE_IID(kIRDFLiteralIID
, NS_IRDFLITERAL_IID
);
68 static NS_DEFINE_IID(kIRDFDateIID
, NS_IRDFDATE_IID
);
69 static NS_DEFINE_IID(kIRDFIntIID
, NS_IRDFINT_IID
);
70 static NS_DEFINE_IID(kIRDFNodeIID
, NS_IRDFNODE_IID
);
71 static NS_DEFINE_IID(kISupportsIID
, NS_ISUPPORTS_IID
);
74 static PRLogModuleInfo
* gLog
= nullptr;
79 // These functions are copied from nsprpub/lib/ds/plhash.c, with one
80 // change to free the key in DataSourceFreeEntry.
81 // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway?
84 DataSourceAllocTable(void *pool
, size_t size
)
86 return PR_MALLOC(size
);
90 DataSourceFreeTable(void *pool
, void *item
)
96 DataSourceAllocEntry(void *pool
, const void *key
)
98 return PR_NEW(PLHashEntry
);
102 DataSourceFreeEntry(void *pool
, PLHashEntry
*he
, unsigned flag
)
104 if (flag
== HT_FREE_ENTRY
) {
105 PL_strfree((char*) he
->key
);
110 static PLHashAllocOps dataSourceHashAllocOps
= {
111 DataSourceAllocTable
, DataSourceFreeTable
,
112 DataSourceAllocEntry
, DataSourceFreeEntry
115 //----------------------------------------------------------------------
117 // For the mResources hashtable.
120 struct ResourceHashEntry
: public PLDHashEntryHdr
{
122 nsIRDFResource
*mResource
;
125 HashKey(PLDHashTable
*table
, const void *key
)
127 return HashString(static_cast<const char *>(key
));
131 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
134 const ResourceHashEntry
*entry
=
135 static_cast<const ResourceHashEntry
*>(hdr
);
137 return 0 == nsCRT::strcmp(static_cast<const char *>(key
),
142 static const PLDHashTableOps gResourceTableOps
= {
145 ResourceHashEntry::HashKey
,
146 ResourceHashEntry::MatchEntry
,
147 PL_DHashMoveEntryStub
,
148 PL_DHashClearEntryStub
,
149 PL_DHashFinalizeStub
,
153 // ----------------------------------------------------------------------
155 // For the mLiterals hashtable.
158 struct LiteralHashEntry
: public PLDHashEntryHdr
{
159 nsIRDFLiteral
*mLiteral
;
160 const char16_t
*mKey
;
163 HashKey(PLDHashTable
*table
, const void *key
)
165 return HashString(static_cast<const char16_t
*>(key
));
169 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
172 const LiteralHashEntry
*entry
=
173 static_cast<const LiteralHashEntry
*>(hdr
);
175 return 0 == nsCRT::strcmp(static_cast<const char16_t
*>(key
),
180 static const PLDHashTableOps gLiteralTableOps
= {
183 LiteralHashEntry::HashKey
,
184 LiteralHashEntry::MatchEntry
,
185 PL_DHashMoveEntryStub
,
186 PL_DHashClearEntryStub
,
187 PL_DHashFinalizeStub
,
191 // ----------------------------------------------------------------------
193 // For the mInts hashtable.
196 struct IntHashEntry
: public PLDHashEntryHdr
{
201 HashKey(PLDHashTable
*table
, const void *key
)
203 return PLDHashNumber(*static_cast<const int32_t *>(key
));
207 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
210 const IntHashEntry
*entry
=
211 static_cast<const IntHashEntry
*>(hdr
);
213 return *static_cast<const int32_t *>(key
) == entry
->mKey
;
217 static const PLDHashTableOps gIntTableOps
= {
220 IntHashEntry::HashKey
,
221 IntHashEntry::MatchEntry
,
222 PL_DHashMoveEntryStub
,
223 PL_DHashClearEntryStub
,
224 PL_DHashFinalizeStub
,
228 // ----------------------------------------------------------------------
230 // For the mDates hashtable.
233 struct DateHashEntry
: public PLDHashEntryHdr
{
238 HashKey(PLDHashTable
*table
, const void *key
)
240 // xor the low 32 bits with the high 32 bits.
241 PRTime t
= *static_cast<const PRTime
*>(key
);
242 int32_t h32
= int32_t(t
>> 32);
243 int32_t l32
= int32_t(0xffffffff & t
);
244 return PLDHashNumber(l32
^ h32
);
248 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
251 const DateHashEntry
*entry
=
252 static_cast<const DateHashEntry
*>(hdr
);
254 return *static_cast<const PRTime
*>(key
) == entry
->mKey
;
258 static const PLDHashTableOps gDateTableOps
= {
261 DateHashEntry::HashKey
,
262 DateHashEntry::MatchEntry
,
263 PL_DHashMoveEntryStub
,
264 PL_DHashClearEntryStub
,
265 PL_DHashFinalizeStub
,
269 class BlobImpl
: public nsIRDFBlob
277 BlobImpl(const uint8_t *aBytes
, int32_t aLength
)
279 mData
.mLength
= aLength
;
280 mData
.mBytes
= new uint8_t[aLength
];
281 memcpy(mData
.mBytes
, aBytes
, aLength
);
282 NS_ADDREF(RDFServiceImpl::gRDFService
);
283 RDFServiceImpl::gRDFService
->RegisterBlob(this);
289 RDFServiceImpl::gRDFService
->UnregisterBlob(this);
290 // Use NS_RELEASE2() here, because we want to decrease the
291 // refcount, but not null out the gRDFService pointer (which is
292 // what a vanilla NS_RELEASE() would do).
294 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
295 delete[] mData
.mBytes
;
306 NS_IMPL_ISUPPORTS(BlobImpl
, nsIRDFNode
, nsIRDFBlob
)
309 BlobImpl::EqualsNode(nsIRDFNode
*aNode
, bool *aEquals
)
311 nsCOMPtr
<nsIRDFBlob
> blob
= do_QueryInterface(aNode
);
314 blob
->GetLength(&length
);
316 if (length
== mData
.mLength
) {
317 const uint8_t *bytes
;
318 blob
->GetValue(&bytes
);
320 if (0 == memcmp(bytes
, mData
.mBytes
, length
)) {
332 BlobImpl::GetValue(const uint8_t **aResult
)
334 *aResult
= mData
.mBytes
;
339 BlobImpl::GetLength(int32_t *aResult
)
341 *aResult
= mData
.mLength
;
345 // ----------------------------------------------------------------------
347 // For the mBlobs hashtable.
350 struct BlobHashEntry
: public PLDHashEntryHdr
{
354 HashKey(PLDHashTable
*table
, const void *key
)
356 const BlobImpl::Data
*data
=
357 static_cast<const BlobImpl::Data
*>(key
);
358 return HashBytes(data
->mBytes
, data
->mLength
);
362 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
365 const BlobHashEntry
*entry
=
366 static_cast<const BlobHashEntry
*>(hdr
);
368 const BlobImpl::Data
*left
= &entry
->mBlob
->mData
;
370 const BlobImpl::Data
*right
=
371 static_cast<const BlobImpl::Data
*>(key
);
373 return (left
->mLength
== right
->mLength
)
374 && 0 == memcmp(left
->mBytes
, right
->mBytes
, right
->mLength
);
378 static const PLDHashTableOps gBlobTableOps
= {
381 BlobHashEntry::HashKey
,
382 BlobHashEntry::MatchEntry
,
383 PL_DHashMoveEntryStub
,
384 PL_DHashClearEntryStub
,
385 PL_DHashFinalizeStub
,
389 ////////////////////////////////////////////////////////////////////////
392 // Currently, all literals are implemented exactly the same way;
393 // i.e., there is are no resource factories to allow you to generate
394 // customer resources. I doubt that makes sense, anyway.
396 class LiteralImpl
: public nsIRDFLiteral
{
399 Create(const char16_t
* aValue
, nsIRDFLiteral
** aResult
);
402 NS_DECL_THREADSAFE_ISUPPORTS
408 NS_DECL_NSIRDFLITERAL
411 explicit LiteralImpl(const char16_t
* s
);
412 virtual ~LiteralImpl();
414 const char16_t
* GetValue() const {
415 size_t objectSize
= ((sizeof(LiteralImpl
) + sizeof(char16_t
) - 1) / sizeof(char16_t
)) * sizeof(char16_t
);
416 return reinterpret_cast<const char16_t
*>(reinterpret_cast<const unsigned char*>(this) + objectSize
);
422 LiteralImpl::Create(const char16_t
* aValue
, nsIRDFLiteral
** aResult
)
424 // Goofy math to get alignment right. Copied from nsSharedString.h.
425 size_t objectSize
= ((sizeof(LiteralImpl
) + sizeof(char16_t
) - 1) / sizeof(char16_t
)) * sizeof(char16_t
);
426 size_t stringLen
= nsCharTraits
<char16_t
>::length(aValue
);
427 size_t stringSize
= (stringLen
+ 1) * sizeof(char16_t
);
429 void* objectPtr
= operator new(objectSize
+ stringSize
);
431 return NS_ERROR_NULL_POINTER
;
433 char16_t
* buf
= reinterpret_cast<char16_t
*>(static_cast<unsigned char*>(objectPtr
) + objectSize
);
434 nsCharTraits
<char16_t
>::copy(buf
, aValue
, stringLen
+ 1);
436 NS_ADDREF(*aResult
= new (objectPtr
) LiteralImpl(buf
));
441 LiteralImpl::LiteralImpl(const char16_t
* s
)
443 RDFServiceImpl::gRDFService
->RegisterLiteral(this);
444 NS_ADDREF(RDFServiceImpl::gRDFService
);
447 LiteralImpl::~LiteralImpl()
449 RDFServiceImpl::gRDFService
->UnregisterLiteral(this);
451 // Use NS_RELEASE2() here, because we want to decrease the
452 // refcount, but not null out the gRDFService pointer (which is
453 // what a vanilla NS_RELEASE() would do).
455 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
458 NS_IMPL_ADDREF(LiteralImpl
)
459 NS_IMPL_RELEASE(LiteralImpl
)
462 LiteralImpl::QueryInterface(REFNSIID iid
, void** result
)
465 return NS_ERROR_NULL_POINTER
;
468 if (iid
.Equals(kIRDFLiteralIID
) ||
469 iid
.Equals(kIRDFNodeIID
) ||
470 iid
.Equals(kISupportsIID
)) {
471 *result
= static_cast<nsIRDFLiteral
*>(this);
475 return NS_NOINTERFACE
;
479 LiteralImpl::EqualsNode(nsIRDFNode
* aNode
, bool* aResult
)
482 nsIRDFLiteral
* literal
;
483 rv
= aNode
->QueryInterface(kIRDFLiteralIID
, (void**) &literal
);
484 if (NS_SUCCEEDED(rv
)) {
485 *aResult
= (static_cast<nsIRDFLiteral
*>(this) == literal
);
489 else if (rv
== NS_NOINTERFACE
) {
499 LiteralImpl::GetValue(char16_t
* *value
)
501 NS_ASSERTION(value
, "null ptr");
503 return NS_ERROR_NULL_POINTER
;
505 const char16_t
*temp
= GetValue();
506 *value
= temp
? NS_strdup(temp
) : 0;
512 LiteralImpl::GetValueConst(const char16_t
** aValue
)
514 *aValue
= GetValue();
518 ////////////////////////////////////////////////////////////////////////
522 class DateImpl
: public nsIRDFDate
{
524 explicit DateImpl(const PRTime s
);
533 NS_IMETHOD
GetValue(PRTime
*value
);
538 nsresult
EqualsDate(nsIRDFDate
* date
, bool* result
);
543 DateImpl::DateImpl(const PRTime s
)
546 RDFServiceImpl::gRDFService
->RegisterDate(this);
547 NS_ADDREF(RDFServiceImpl::gRDFService
);
550 DateImpl::~DateImpl()
552 RDFServiceImpl::gRDFService
->UnregisterDate(this);
554 // Use NS_RELEASE2() here, because we want to decrease the
555 // refcount, but not null out the gRDFService pointer (which is
556 // what a vanilla NS_RELEASE() would do).
558 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
561 NS_IMPL_ADDREF(DateImpl
)
562 NS_IMPL_RELEASE(DateImpl
)
565 DateImpl::QueryInterface(REFNSIID iid
, void** result
)
568 return NS_ERROR_NULL_POINTER
;
571 if (iid
.Equals(kIRDFDateIID
) ||
572 iid
.Equals(kIRDFNodeIID
) ||
573 iid
.Equals(kISupportsIID
)) {
574 *result
= static_cast<nsIRDFDate
*>(this);
578 return NS_NOINTERFACE
;
582 DateImpl::EqualsNode(nsIRDFNode
* node
, bool* result
)
586 if (NS_SUCCEEDED(node
->QueryInterface(kIRDFDateIID
, (void**) &date
))) {
587 rv
= EqualsDate(date
, result
);
598 DateImpl::GetValue(PRTime
*value
)
600 NS_ASSERTION(value
, "null ptr");
602 return NS_ERROR_NULL_POINTER
;
610 DateImpl::EqualsDate(nsIRDFDate
* date
, bool* result
)
612 NS_ASSERTION(date
&& result
, "null ptr");
613 if (!date
|| !result
)
614 return NS_ERROR_NULL_POINTER
;
618 if (NS_FAILED(rv
= date
->GetValue(&p
)))
621 *result
= p
== mValue
;
625 ////////////////////////////////////////////////////////////////////////
629 class IntImpl
: public nsIRDFInt
{
631 explicit IntImpl(int32_t s
);
640 NS_IMETHOD
GetValue(int32_t *value
);
645 nsresult
EqualsInt(nsIRDFInt
* value
, bool* result
);
650 IntImpl::IntImpl(int32_t s
)
653 RDFServiceImpl::gRDFService
->RegisterInt(this);
654 NS_ADDREF(RDFServiceImpl::gRDFService
);
659 RDFServiceImpl::gRDFService
->UnregisterInt(this);
661 // Use NS_RELEASE2() here, because we want to decrease the
662 // refcount, but not null out the gRDFService pointer (which is
663 // what a vanilla NS_RELEASE() would do).
665 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
668 NS_IMPL_ADDREF(IntImpl
)
669 NS_IMPL_RELEASE(IntImpl
)
672 IntImpl::QueryInterface(REFNSIID iid
, void** result
)
675 return NS_ERROR_NULL_POINTER
;
678 if (iid
.Equals(kIRDFIntIID
) ||
679 iid
.Equals(kIRDFNodeIID
) ||
680 iid
.Equals(kISupportsIID
)) {
681 *result
= static_cast<nsIRDFInt
*>(this);
685 return NS_NOINTERFACE
;
689 IntImpl::EqualsNode(nsIRDFNode
* node
, bool* result
)
693 if (NS_SUCCEEDED(node
->QueryInterface(kIRDFIntIID
, (void**) &intValue
))) {
694 rv
= EqualsInt(intValue
, result
);
695 NS_RELEASE(intValue
);
705 IntImpl::GetValue(int32_t *value
)
707 NS_ASSERTION(value
, "null ptr");
709 return NS_ERROR_NULL_POINTER
;
717 IntImpl::EqualsInt(nsIRDFInt
* intValue
, bool* result
)
719 NS_ASSERTION(intValue
&& result
, "null ptr");
720 if (!intValue
|| !result
)
721 return NS_ERROR_NULL_POINTER
;
725 if (NS_FAILED(rv
= intValue
->GetValue(&p
)))
728 *result
= (p
== mValue
);
732 ////////////////////////////////////////////////////////////////////////
736 RDFServiceImpl::gRDFService
;
738 RDFServiceImpl::RDFServiceImpl()
739 : mNamedDataSources(nullptr)
741 mResources
.ops
= nullptr;
742 mLiterals
.ops
= nullptr;
744 mDates
.ops
= nullptr;
745 mBlobs
.ops
= nullptr;
750 RDFServiceImpl::Init()
754 mNamedDataSources
= PL_NewHashTable(23,
758 &dataSourceHashAllocOps
, nullptr);
760 if (! mNamedDataSources
)
761 return NS_ERROR_OUT_OF_MEMORY
;
763 PL_DHashTableInit(&mResources
, &gResourceTableOps
, nullptr,
764 sizeof(ResourceHashEntry
));
766 PL_DHashTableInit(&mLiterals
, &gLiteralTableOps
, nullptr,
767 sizeof(LiteralHashEntry
));
769 PL_DHashTableInit(&mInts
, &gIntTableOps
, nullptr,
770 sizeof(IntHashEntry
));
772 PL_DHashTableInit(&mDates
, &gDateTableOps
, nullptr,
773 sizeof(DateHashEntry
));
775 PL_DHashTableInit(&mBlobs
, &gBlobTableOps
, nullptr,
776 sizeof(BlobHashEntry
));
778 mDefaultResourceFactory
= do_GetClassObject(kRDFDefaultResourceCID
, &rv
);
779 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get default resource factory");
780 if (NS_FAILED(rv
)) return rv
;
784 gLog
= PR_NewLogModule("nsRDFService");
791 RDFServiceImpl::~RDFServiceImpl()
793 if (mNamedDataSources
) {
794 PL_HashTableDestroy(mNamedDataSources
);
795 mNamedDataSources
= nullptr;
798 PL_DHashTableFinish(&mResources
);
800 PL_DHashTableFinish(&mLiterals
);
802 PL_DHashTableFinish(&mInts
);
804 PL_DHashTableFinish(&mDates
);
806 PL_DHashTableFinish(&mBlobs
);
807 gRDFService
= nullptr;
813 RDFServiceImpl::CreateSingleton(nsISupports
* aOuter
,
814 const nsIID
& aIID
, void **aResult
)
816 NS_ENSURE_NO_AGGREGATION(aOuter
);
819 NS_ERROR("Trying to create RDF serviec twice.");
820 return gRDFService
->QueryInterface(aIID
, aResult
);
823 nsRefPtr
<RDFServiceImpl
> serv
= new RDFServiceImpl();
825 return NS_ERROR_OUT_OF_MEMORY
;
827 nsresult rv
= serv
->Init();
831 return serv
->QueryInterface(aIID
, aResult
);
834 NS_IMPL_ISUPPORTS(RDFServiceImpl
, nsIRDFService
, nsISupportsWeakReference
)
838 kLegalSchemeChars
[] = {
839 // ASCII Bits Ordered Hex
845 0x00, // 20-27 !"#$%&' 00000000 00000000
846 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28
847 0xff, // 30-37 01234567 11111111 11111111 0xFF
848 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03
849 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE
850 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF
851 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF
852 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87
853 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE
854 0xff, // 68-6F hijklmno 11111111 11111111 0xFF
855 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF
856 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07
857 0x00, 0x00, 0x00, 0x00, // >= 80
858 0x00, 0x00, 0x00, 0x00,
859 0x00, 0x00, 0x00, 0x00,
860 0x00, 0x00, 0x00, 0x00
864 IsLegalSchemeCharacter(const char aChar
)
866 uint8_t mask
= kLegalSchemeChars
[aChar
>> 3];
867 uint8_t bit
= 1u << (aChar
& 0x7);
868 return bool((mask
& bit
) != 0);
873 RDFServiceImpl::GetResource(const nsACString
& aURI
, nsIRDFResource
** aResource
)
876 NS_PRECONDITION(aResource
!= nullptr, "null ptr");
877 NS_PRECONDITION(!aURI
.IsEmpty(), "URI is empty");
879 return NS_ERROR_NULL_POINTER
;
881 return NS_ERROR_INVALID_ARG
;
883 const nsAFlatCString
& flatURI
= PromiseFlatCString(aURI
);
884 PR_LOG(gLog
, PR_LOG_DEBUG
, ("rdfserv get-resource %s", flatURI
.get()));
886 // First, check the cache to see if we've already created and
887 // registered this thing.
888 PLDHashEntryHdr
*hdr
=
889 PL_DHashTableLookup(&mResources
, flatURI
.get());
891 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
892 ResourceHashEntry
*entry
= static_cast<ResourceHashEntry
*>(hdr
);
893 NS_ADDREF(*aResource
= entry
->mResource
);
897 // Nope. So go to the repository to create it.
899 // Compute the scheme of the URI. Scan forward until we either:
901 // 1. Reach the end of the string
902 // 2. Encounter a non-alpha character
903 // 3. Encouter a colon.
905 // If we encounter a colon _before_ encountering a non-alpha
906 // character, then assume it's the scheme.
908 // XXX Although it's really not correct, we'll allow underscore
909 // characters ('_'), too.
910 nsACString::const_iterator p
, end
;
911 aURI
.BeginReading(p
);
912 aURI
.EndReading(end
);
913 while (p
!= end
&& IsLegalSchemeCharacter(*p
))
917 nsCOMPtr
<nsIFactory
> factory
;
919 nsACString::const_iterator begin
;
920 aURI
.BeginReading(begin
);
922 // There _was_ a scheme. First see if it's the same scheme
923 // that we just tried to use...
924 if (mLastFactory
&& mLastURIPrefix
.Equals(Substring(begin
, p
)))
925 factory
= mLastFactory
;
927 // Try to find a factory using the component manager.
928 nsACString::const_iterator begin
;
929 aURI
.BeginReading(begin
);
930 nsAutoCString contractID
;
931 contractID
= NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX
) +
934 factory
= do_GetClassObject(contractID
.get());
936 // Store the factory in our one-element cache.
938 mLastFactory
= factory
;
939 mLastURIPrefix
= Substring(begin
, p
);
946 // fall through to using the "default" resource factory if either:
948 // 1. The URI didn't have a scheme, or
949 // 2. There was no resource factory registered for the scheme.
950 factory
= mDefaultResourceFactory
;
952 // Store the factory in our one-element cache.
954 mLastFactory
= factory
;
955 mLastURIPrefix
= Substring(begin
, p
);
959 nsIRDFResource
*result
;
960 rv
= factory
->CreateInstance(nullptr, NS_GET_IID(nsIRDFResource
), (void**) &result
);
961 if (NS_FAILED(rv
)) return rv
;
963 // Now initialize it with its URI. At this point, the resource
964 // implementation should register itself with the RDF service.
965 rv
= result
->Init(flatURI
.get());
967 NS_ERROR("unable to initialize resource");
972 *aResource
= result
; // already refcounted from repository
977 RDFServiceImpl::GetUnicodeResource(const nsAString
& aURI
, nsIRDFResource
** aResource
)
979 return GetResource(NS_ConvertUTF16toUTF8(aURI
), aResource
);
984 RDFServiceImpl::GetAnonymousResource(nsIRDFResource
** aResult
)
986 static uint32_t gCounter
= 0;
987 static char gChars
[] = "0123456789abcdef"
992 static int32_t kMask
= 0x003f;
993 static int32_t kShift
= 6;
996 // Start it at a semi-unique value, just to minimize the
997 // chance that we get into a situation where
999 // 1. An anonymous resource gets serialized out in a graph
1001 // 3. The same anonymous resource gets requested, and refers
1002 // to something completely different.
1003 // 4. The serialization is read back in.
1004 gCounter
= uint32_t(PR_Now());
1011 // Ugh, this is a really sloppy way to do this; I copied the
1012 // implementation from the days when it lived outside the RDF
1013 // service. Now that it's a member we can be more cleverer.
1016 s
.AppendLiteral("rdf:#$");
1018 uint32_t id
= ++gCounter
;
1020 char ch
= gChars
[(id
& kMask
)];
1025 nsIRDFResource
* resource
;
1026 rv
= GetResource(s
, &resource
);
1027 if (NS_FAILED(rv
)) return rv
;
1029 // XXX an ugly but effective way to make sure that this
1030 // resource is really unique in the world.
1032 nsrefcnt refcnt
= resource
->Release();
1035 *aResult
= resource
;
1039 NS_RELEASE(resource
);
1047 RDFServiceImpl::GetLiteral(const char16_t
* aValue
, nsIRDFLiteral
** aLiteral
)
1049 NS_PRECONDITION(aValue
!= nullptr, "null ptr");
1051 return NS_ERROR_NULL_POINTER
;
1053 NS_PRECONDITION(aLiteral
!= nullptr, "null ptr");
1055 return NS_ERROR_NULL_POINTER
;
1057 // See if we have one already cached
1058 PLDHashEntryHdr
*hdr
=
1059 PL_DHashTableLookup(&mLiterals
, aValue
);
1061 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1062 LiteralHashEntry
*entry
= static_cast<LiteralHashEntry
*>(hdr
);
1063 NS_ADDREF(*aLiteral
= entry
->mLiteral
);
1067 // Nope. Create a new one
1068 return LiteralImpl::Create(aValue
, aLiteral
);
1072 RDFServiceImpl::GetDateLiteral(PRTime aTime
, nsIRDFDate
** aResult
)
1074 // See if we have one already cached
1075 PLDHashEntryHdr
*hdr
=
1076 PL_DHashTableLookup(&mDates
, &aTime
);
1078 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1079 DateHashEntry
*entry
= static_cast<DateHashEntry
*>(hdr
);
1080 NS_ADDREF(*aResult
= entry
->mDate
);
1084 DateImpl
* result
= new DateImpl(aTime
);
1086 return NS_ERROR_OUT_OF_MEMORY
;
1088 NS_ADDREF(*aResult
= result
);
1093 RDFServiceImpl::GetIntLiteral(int32_t aInt
, nsIRDFInt
** aResult
)
1095 // See if we have one already cached
1096 PLDHashEntryHdr
*hdr
=
1097 PL_DHashTableLookup(&mInts
, &aInt
);
1099 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1100 IntHashEntry
*entry
= static_cast<IntHashEntry
*>(hdr
);
1101 NS_ADDREF(*aResult
= entry
->mInt
);
1105 IntImpl
* result
= new IntImpl(aInt
);
1107 return NS_ERROR_OUT_OF_MEMORY
;
1109 NS_ADDREF(*aResult
= result
);
1114 RDFServiceImpl::GetBlobLiteral(const uint8_t *aBytes
, int32_t aLength
,
1115 nsIRDFBlob
**aResult
)
1117 BlobImpl::Data key
= { aLength
, const_cast<uint8_t *>(aBytes
) };
1119 PLDHashEntryHdr
*hdr
=
1120 PL_DHashTableLookup(&mBlobs
, &key
);
1122 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1123 BlobHashEntry
*entry
= static_cast<BlobHashEntry
*>(hdr
);
1124 NS_ADDREF(*aResult
= entry
->mBlob
);
1128 BlobImpl
*result
= new BlobImpl(aBytes
, aLength
);
1130 return NS_ERROR_OUT_OF_MEMORY
;
1132 NS_ADDREF(*aResult
= result
);
1137 RDFServiceImpl::IsAnonymousResource(nsIRDFResource
* aResource
, bool* _result
)
1139 NS_PRECONDITION(aResource
!= nullptr, "null ptr");
1141 return NS_ERROR_NULL_POINTER
;
1146 rv
= aResource
->GetValueConst(&uri
);
1147 if (NS_FAILED(rv
)) return rv
;
1149 if ((uri
[0] == 'r') &&
1165 RDFServiceImpl::RegisterResource(nsIRDFResource
* aResource
, bool aReplace
)
1167 NS_PRECONDITION(aResource
!= nullptr, "null ptr");
1169 return NS_ERROR_NULL_POINTER
;
1174 rv
= aResource
->GetValueConst(&uri
);
1175 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get URI from resource");
1176 if (NS_FAILED(rv
)) return rv
;
1178 NS_ASSERTION(uri
!= nullptr, "resource has no URI");
1180 return NS_ERROR_NULL_POINTER
;
1182 PLDHashEntryHdr
*hdr
=
1183 PL_DHashTableLookup(&mResources
, uri
);
1185 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1187 NS_WARNING("resource already registered, and replace not specified");
1188 return NS_ERROR_FAILURE
; // already registered
1191 // N.B., we do _not_ release the original resource because we
1192 // only ever held a weak reference to it. We simply replace
1195 PR_LOG(gLog
, PR_LOG_DEBUG
,
1196 ("rdfserv replace-resource [%p] <-- [%p] %s",
1197 static_cast<ResourceHashEntry
*>(hdr
)->mResource
,
1198 aResource
, (const char*) uri
));
1201 hdr
= PL_DHashTableAdd(&mResources
, uri
);
1203 return NS_ERROR_OUT_OF_MEMORY
;
1205 PR_LOG(gLog
, PR_LOG_DEBUG
,
1206 ("rdfserv register-resource [%p] %s",
1207 aResource
, (const char*) uri
));
1210 // N.B., we only hold a weak reference to the resource: that way,
1211 // the resource can be destroyed when the last refcount goes
1212 // away. The single addref that the CreateResource() call made
1213 // will be owned by the callee.
1214 ResourceHashEntry
*entry
= static_cast<ResourceHashEntry
*>(hdr
);
1215 entry
->mResource
= aResource
;
1222 RDFServiceImpl::UnregisterResource(nsIRDFResource
* aResource
)
1224 NS_PRECONDITION(aResource
!= nullptr, "null ptr");
1226 return NS_ERROR_NULL_POINTER
;
1231 rv
= aResource
->GetValueConst(&uri
);
1232 if (NS_FAILED(rv
)) return rv
;
1234 NS_ASSERTION(uri
!= nullptr, "resource has no URI");
1236 return NS_ERROR_UNEXPECTED
;
1238 PR_LOG(gLog
, PR_LOG_DEBUG
,
1239 ("rdfserv unregister-resource [%p] %s",
1240 aResource
, (const char*) uri
));
1243 if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mResources
, uri
)))
1244 NS_WARNING("resource was never registered");
1247 PL_DHashTableRemove(&mResources
, uri
);
1252 RDFServiceImpl::RegisterDataSource(nsIRDFDataSource
* aDataSource
, bool aReplace
)
1254 NS_PRECONDITION(aDataSource
!= nullptr, "null ptr");
1256 return NS_ERROR_NULL_POINTER
;
1261 rv
= aDataSource
->GetURI(getter_Copies(uri
));
1262 if (NS_FAILED(rv
)) return rv
;
1265 PL_HashTableRawLookup(mNamedDataSources
, (*mNamedDataSources
->keyHash
)(uri
), uri
);
1269 return NS_ERROR_FAILURE
; // already registered
1271 // N.B., we only hold a weak reference to the datasource, so
1272 // just replace the old with the new and don't touch any
1274 PR_LOG(gLog
, PR_LOG_NOTICE
,
1275 ("rdfserv replace-datasource [%p] <-- [%p] %s",
1276 (*hep
)->value
, aDataSource
, (const char*) uri
));
1278 (*hep
)->value
= aDataSource
;
1281 const char* key
= PL_strdup(uri
);
1283 return NS_ERROR_OUT_OF_MEMORY
;
1285 PL_HashTableAdd(mNamedDataSources
, key
, aDataSource
);
1287 PR_LOG(gLog
, PR_LOG_NOTICE
,
1288 ("rdfserv register-datasource [%p] %s",
1289 aDataSource
, (const char*) uri
));
1291 // N.B., we only hold a weak reference to the datasource, so don't
1299 RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource
* aDataSource
)
1301 NS_PRECONDITION(aDataSource
!= nullptr, "null ptr");
1303 return NS_ERROR_NULL_POINTER
;
1308 rv
= aDataSource
->GetURI(getter_Copies(uri
));
1309 if (NS_FAILED(rv
)) return rv
;
1311 //NS_ASSERTION(uri != nullptr, "datasource has no URI");
1313 return NS_ERROR_UNEXPECTED
;
1316 PL_HashTableRawLookup(mNamedDataSources
, (*mNamedDataSources
->keyHash
)(uri
), uri
);
1318 // It may well be that this datasource was never registered. If
1319 // so, don't unregister it.
1320 if (! *hep
|| ((*hep
)->value
!= aDataSource
))
1323 // N.B., we only held a weak reference to the datasource, so we
1324 // don't release here.
1325 PL_HashTableRawRemove(mNamedDataSources
, hep
, *hep
);
1327 PR_LOG(gLog
, PR_LOG_NOTICE
,
1328 ("rdfserv unregister-datasource [%p] %s",
1329 aDataSource
, (const char*) uri
));
1335 RDFServiceImpl::GetDataSource(const char* aURI
, nsIRDFDataSource
** aDataSource
)
1337 // Use the other GetDataSource and ask for a non-blocking Refresh.
1338 // If you wanted it loaded synchronously, then you should've tried to do it
1339 // yourself, or used GetDataSourceBlocking.
1340 return GetDataSource( aURI
, false, aDataSource
);
1344 RDFServiceImpl::GetDataSourceBlocking(const char* aURI
, nsIRDFDataSource
** aDataSource
)
1346 // Use GetDataSource and ask for a blocking Refresh.
1347 return GetDataSource( aURI
, true, aDataSource
);
1351 RDFServiceImpl::GetDataSource(const char* aURI
, bool aBlock
, nsIRDFDataSource
** aDataSource
)
1353 NS_PRECONDITION(aURI
!= nullptr, "null ptr");
1355 return NS_ERROR_NULL_POINTER
;
1359 // Attempt to canonify the URI before we look for it in the
1360 // cache. We won't bother doing this on `rdf:' URIs to avoid
1361 // useless (and expensive) protocol handler lookups.
1362 nsAutoCString
spec(aURI
);
1364 if (!StringBeginsWith(spec
, NS_LITERAL_CSTRING("rdf:"))) {
1365 nsCOMPtr
<nsIURI
> uri
;
1366 NS_NewURI(getter_AddRefs(uri
), spec
);
1371 // First, check the cache to see if we already have this
1372 // datasource loaded and initialized.
1374 nsIRDFDataSource
* cached
=
1375 static_cast<nsIRDFDataSource
*>(PL_HashTableLookup(mNamedDataSources
, spec
.get()));
1379 *aDataSource
= cached
;
1384 // Nope. So go to the repository to try to create it.
1385 nsCOMPtr
<nsIRDFDataSource
> ds
;
1386 if (StringBeginsWith(spec
, NS_LITERAL_CSTRING("rdf:"))) {
1387 // It's a built-in data source. Convert it to a contract ID.
1388 nsAutoCString
contractID(
1389 NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX
) +
1390 Substring(spec
, 4, spec
.Length() - 4));
1392 // Strip params to get ``base'' contractID for data source.
1393 int32_t p
= contractID
.FindChar(char16_t('&'));
1395 contractID
.Truncate(p
);
1397 ds
= do_GetService(contractID
.get(), &rv
);
1398 if (NS_FAILED(rv
)) return rv
;
1400 nsCOMPtr
<nsIRDFRemoteDataSource
> remote
= do_QueryInterface(ds
);
1402 rv
= remote
->Init(spec
.get());
1403 if (NS_FAILED(rv
)) return rv
;
1407 // Try to load this as an RDF/XML data source
1408 ds
= do_CreateInstance(kRDFXMLDataSourceCID
, &rv
);
1409 if (NS_FAILED(rv
)) return rv
;
1411 nsCOMPtr
<nsIRDFRemoteDataSource
> remote(do_QueryInterface(ds
));
1412 NS_ASSERTION(remote
, "not a remote RDF/XML data source!");
1413 if (! remote
) return NS_ERROR_UNEXPECTED
;
1415 rv
= remote
->Init(spec
.get());
1416 if (NS_FAILED(rv
)) return rv
;
1418 rv
= remote
->Refresh(aBlock
);
1419 if (NS_FAILED(rv
)) return rv
;
1423 NS_ADDREF(*aDataSource
);
1427 ////////////////////////////////////////////////////////////////////////
1430 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral
* aLiteral
)
1432 const char16_t
* value
;
1433 aLiteral
->GetValueConst(&value
);
1435 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mLiterals
,
1437 "literal already registered");
1439 PLDHashEntryHdr
*hdr
=
1440 PL_DHashTableAdd(&mLiterals
, value
);
1443 return NS_ERROR_OUT_OF_MEMORY
;
1445 LiteralHashEntry
*entry
= static_cast<LiteralHashEntry
*>(hdr
);
1447 // N.B., we only hold a weak reference to the literal: that
1448 // way, the literal can be destroyed when the last refcount
1449 // goes away. The single addref that the CreateLiteral() call
1450 // made will be owned by the callee.
1451 entry
->mLiteral
= aLiteral
;
1452 entry
->mKey
= value
;
1454 PR_LOG(gLog
, PR_LOG_DEBUG
,
1455 ("rdfserv register-literal [%p] %s",
1456 aLiteral
, (const char16_t
*) value
));
1463 RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral
* aLiteral
)
1465 const char16_t
* value
;
1466 aLiteral
->GetValueConst(&value
);
1468 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mLiterals
,
1470 "literal was never registered");
1472 PL_DHashTableRemove(&mLiterals
, value
);
1474 // N.B. that we _don't_ release the literal: we only held a weak
1475 // reference to it in the hashtable.
1476 PR_LOG(gLog
, PR_LOG_DEBUG
,
1477 ("rdfserv unregister-literal [%p] %s",
1478 aLiteral
, (const char16_t
*) value
));
1483 //----------------------------------------------------------------------
1486 RDFServiceImpl::RegisterInt(nsIRDFInt
* aInt
)
1489 aInt
->GetValue(&value
);
1491 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mInts
,
1493 "int already registered");
1495 PLDHashEntryHdr
*hdr
=
1496 PL_DHashTableAdd(&mInts
, &value
);
1499 return NS_ERROR_OUT_OF_MEMORY
;
1501 IntHashEntry
*entry
= static_cast<IntHashEntry
*>(hdr
);
1503 // N.B., we only hold a weak reference to the literal: that
1504 // way, the literal can be destroyed when the last refcount
1505 // goes away. The single addref that the CreateInt() call
1506 // made will be owned by the callee.
1508 entry
->mKey
= value
;
1510 PR_LOG(gLog
, PR_LOG_DEBUG
,
1511 ("rdfserv register-int [%p] %d",
1519 RDFServiceImpl::UnregisterInt(nsIRDFInt
* aInt
)
1522 aInt
->GetValue(&value
);
1524 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mInts
,
1526 "int was never registered");
1528 PL_DHashTableRemove(&mInts
, &value
);
1530 // N.B. that we _don't_ release the literal: we only held a weak
1531 // reference to it in the hashtable.
1532 PR_LOG(gLog
, PR_LOG_DEBUG
,
1533 ("rdfserv unregister-int [%p] %d",
1539 //----------------------------------------------------------------------
1542 RDFServiceImpl::RegisterDate(nsIRDFDate
* aDate
)
1545 aDate
->GetValue(&value
);
1547 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mDates
,
1549 "date already registered");
1551 PLDHashEntryHdr
*hdr
=
1552 PL_DHashTableAdd(&mDates
, &value
);
1555 return NS_ERROR_OUT_OF_MEMORY
;
1557 DateHashEntry
*entry
= static_cast<DateHashEntry
*>(hdr
);
1559 // N.B., we only hold a weak reference to the literal: that
1560 // way, the literal can be destroyed when the last refcount
1561 // goes away. The single addref that the CreateDate() call
1562 // made will be owned by the callee.
1563 entry
->mDate
= aDate
;
1564 entry
->mKey
= value
;
1566 PR_LOG(gLog
, PR_LOG_DEBUG
,
1567 ("rdfserv register-date [%p] %ld",
1575 RDFServiceImpl::UnregisterDate(nsIRDFDate
* aDate
)
1578 aDate
->GetValue(&value
);
1580 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mDates
,
1582 "date was never registered");
1584 PL_DHashTableRemove(&mDates
, &value
);
1586 // N.B. that we _don't_ release the literal: we only held a weak
1587 // reference to it in the hashtable.
1588 PR_LOG(gLog
, PR_LOG_DEBUG
,
1589 ("rdfserv unregister-date [%p] %ld",
1596 RDFServiceImpl::RegisterBlob(BlobImpl
*aBlob
)
1598 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableLookup(&mBlobs
,
1600 "blob already registered");
1602 PLDHashEntryHdr
*hdr
=
1603 PL_DHashTableAdd(&mBlobs
, &aBlob
->mData
);
1606 return NS_ERROR_OUT_OF_MEMORY
;
1608 BlobHashEntry
*entry
= static_cast<BlobHashEntry
*>(hdr
);
1610 // N.B., we only hold a weak reference to the literal: that
1611 // way, the literal can be destroyed when the last refcount
1612 // goes away. The single addref that the CreateInt() call
1613 // made will be owned by the callee.
1614 entry
->mBlob
= aBlob
;
1616 PR_LOG(gLog
, PR_LOG_DEBUG
,
1617 ("rdfserv register-blob [%p] %s",
1618 aBlob
, aBlob
->mData
.mBytes
));
1624 RDFServiceImpl::UnregisterBlob(BlobImpl
*aBlob
)
1626 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableLookup(&mBlobs
,
1628 "blob was never registered");
1630 PL_DHashTableRemove(&mBlobs
, &aBlob
->mData
);
1632 // N.B. that we _don't_ release the literal: we only held a weak
1633 // reference to it in the hashtable.
1634 PR_LOG(gLog
, PR_LOG_DEBUG
,
1635 ("rdfserv unregister-blob [%p] %s",
1636 aBlob
, aBlob
->mData
.mBytes
));