1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Benjamin Smedberg <benjamin@smedbergs.us>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK *****
41 * This Original Code has been modified by IBM Corporation.
42 * Modifications made by IBM described herein are
43 * Copyright (c) International Business Machines
46 * Modifications to Mozilla code or documentation
47 * identified per MPL Section 3.3
49 * Date Modified by Description of modification
50 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
56 This file provides the implementation for the RDF service manager.
61 1) Implement the CreateDataBase() methods.
63 2) Cache date and int literals.
67 #include "nsRDFService.h"
69 #include "nsAutoPtr.h"
72 #include "nsIComponentManager.h"
73 #include "nsIRDFDataSource.h"
74 #include "nsIRDFNode.h"
75 #include "nsIRDFRemoteDataSource.h"
76 #include "nsIServiceManager.h"
77 #include "nsIFactory.h"
80 #include "nsXPIDLString.h"
81 #include "nsNetUtil.h"
90 #include "nsCRTGlue.h"
93 ////////////////////////////////////////////////////////////////////////
95 static NS_DEFINE_CID(kRDFXMLDataSourceCID
, NS_RDFXMLDATASOURCE_CID
);
96 static NS_DEFINE_CID(kRDFDefaultResourceCID
, NS_RDFDEFAULTRESOURCE_CID
);
98 static NS_DEFINE_IID(kIRDFLiteralIID
, NS_IRDFLITERAL_IID
);
99 static NS_DEFINE_IID(kIRDFDateIID
, NS_IRDFDATE_IID
);
100 static NS_DEFINE_IID(kIRDFIntIID
, NS_IRDFINT_IID
);
101 static NS_DEFINE_IID(kIRDFNodeIID
, NS_IRDFNODE_IID
);
102 static NS_DEFINE_IID(kISupportsIID
, NS_ISUPPORTS_IID
);
105 static PRLogModuleInfo
* gLog
= nsnull
;
110 // These functions are copied from nsprpub/lib/ds/plhash.c, with one
111 // change to free the key in DataSourceFreeEntry.
112 // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway?
115 DataSourceAllocTable(void *pool
, PRSize size
)
118 #pragma unused (pool)
121 return PR_MALLOC(size
);
125 DataSourceFreeTable(void *pool
, void *item
)
128 #pragma unused (pool)
135 DataSourceAllocEntry(void *pool
, const void *key
)
138 #pragma unused (pool,key)
141 return PR_NEW(PLHashEntry
);
145 DataSourceFreeEntry(void *pool
, PLHashEntry
*he
, PRUintn flag
)
148 #pragma unused (pool)
151 if (flag
== HT_FREE_ENTRY
) {
152 PL_strfree((char*) he
->key
);
157 static PLHashAllocOps dataSourceHashAllocOps
= {
158 DataSourceAllocTable
, DataSourceFreeTable
,
159 DataSourceAllocEntry
, DataSourceFreeEntry
162 //----------------------------------------------------------------------
164 // For the mResources hashtable.
167 struct ResourceHashEntry
: public PLDHashEntryHdr
{
169 nsIRDFResource
*mResource
;
172 HashKey(PLDHashTable
*table
, const void *key
)
174 return nsCRT::HashCode(static_cast<const char *>(key
));
178 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
181 const ResourceHashEntry
*entry
=
182 static_cast<const ResourceHashEntry
*>(hdr
);
184 return 0 == nsCRT::strcmp(static_cast<const char *>(key
),
189 static PLDHashTableOps gResourceTableOps
= {
192 ResourceHashEntry::HashKey
,
193 ResourceHashEntry::MatchEntry
,
194 PL_DHashMoveEntryStub
,
195 PL_DHashClearEntryStub
,
196 PL_DHashFinalizeStub
,
200 // ----------------------------------------------------------------------
202 // For the mLiterals hashtable.
205 struct LiteralHashEntry
: public PLDHashEntryHdr
{
206 nsIRDFLiteral
*mLiteral
;
207 const PRUnichar
*mKey
;
210 HashKey(PLDHashTable
*table
, const void *key
)
212 return nsCRT::HashCode(static_cast<const PRUnichar
*>(key
));
216 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
219 const LiteralHashEntry
*entry
=
220 static_cast<const LiteralHashEntry
*>(hdr
);
222 return 0 == nsCRT::strcmp(static_cast<const PRUnichar
*>(key
),
227 static PLDHashTableOps gLiteralTableOps
= {
230 LiteralHashEntry::HashKey
,
231 LiteralHashEntry::MatchEntry
,
232 PL_DHashMoveEntryStub
,
233 PL_DHashClearEntryStub
,
234 PL_DHashFinalizeStub
,
238 // ----------------------------------------------------------------------
240 // For the mInts hashtable.
243 struct IntHashEntry
: public PLDHashEntryHdr
{
248 HashKey(PLDHashTable
*table
, const void *key
)
250 return PLDHashNumber(*static_cast<const PRInt32
*>(key
));
254 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
257 const IntHashEntry
*entry
=
258 static_cast<const IntHashEntry
*>(hdr
);
260 return *static_cast<const PRInt32
*>(key
) == entry
->mKey
;
264 static PLDHashTableOps gIntTableOps
= {
267 IntHashEntry::HashKey
,
268 IntHashEntry::MatchEntry
,
269 PL_DHashMoveEntryStub
,
270 PL_DHashClearEntryStub
,
271 PL_DHashFinalizeStub
,
275 // ----------------------------------------------------------------------
277 // For the mDates hashtable.
280 struct DateHashEntry
: public PLDHashEntryHdr
{
285 HashKey(PLDHashTable
*table
, const void *key
)
287 // xor the low 32 bits with the high 32 bits.
288 PRTime t
= *static_cast<const PRTime
*>(key
);
291 l64
= LL_INIT(0, 0xffffffff);
296 return PLDHashNumber(l32
^ h32
);
300 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
303 const DateHashEntry
*entry
=
304 static_cast<const DateHashEntry
*>(hdr
);
306 return LL_EQ(*static_cast<const PRTime
*>(key
), entry
->mKey
);
310 static PLDHashTableOps gDateTableOps
= {
313 DateHashEntry::HashKey
,
314 DateHashEntry::MatchEntry
,
315 PL_DHashMoveEntryStub
,
316 PL_DHashClearEntryStub
,
317 PL_DHashFinalizeStub
,
321 class BlobImpl
: public nsIRDFBlob
329 BlobImpl(const PRUint8
*aBytes
, PRInt32 aLength
)
331 mData
.mLength
= aLength
;
332 mData
.mBytes
= new PRUint8
[aLength
];
333 memcpy(mData
.mBytes
, aBytes
, aLength
);
334 NS_ADDREF(RDFServiceImpl::gRDFService
);
335 RDFServiceImpl::gRDFService
->RegisterBlob(this);
340 RDFServiceImpl::gRDFService
->UnregisterBlob(this);
341 // Use NS_RELEASE2() here, because we want to decrease the
342 // refcount, but not null out the gRDFService pointer (which is
343 // what a vanilla NS_RELEASE() would do).
345 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
346 delete[] mData
.mBytes
;
356 NS_IMPL_ISUPPORTS2(BlobImpl
, nsIRDFNode
, nsIRDFBlob
)
359 BlobImpl::EqualsNode(nsIRDFNode
*aNode
, PRBool
*aEquals
)
361 nsCOMPtr
<nsIRDFBlob
> blob
= do_QueryInterface(aNode
);
364 blob
->GetLength(&length
);
366 if (length
== mData
.mLength
) {
367 const PRUint8
*bytes
;
368 blob
->GetValue(&bytes
);
370 if (0 == memcmp(bytes
, mData
.mBytes
, length
)) {
382 BlobImpl::GetValue(const PRUint8
**aResult
)
384 *aResult
= mData
.mBytes
;
389 BlobImpl::GetLength(PRInt32
*aResult
)
391 *aResult
= mData
.mLength
;
395 // ----------------------------------------------------------------------
397 // For the mBlobs hashtable.
400 struct BlobHashEntry
: public PLDHashEntryHdr
{
404 HashKey(PLDHashTable
*table
, const void *key
)
406 const BlobImpl::Data
*data
=
407 static_cast<const BlobImpl::Data
*>(key
);
409 const PRUint8
*p
= data
->mBytes
, *limit
= p
+ data
->mLength
;
411 for ( ; p
< limit
; ++p
)
412 h
= PR_ROTATE_LEFT32(h
, 4) ^ *p
;
417 MatchEntry(PLDHashTable
*table
, const PLDHashEntryHdr
*hdr
,
420 const BlobHashEntry
*entry
=
421 static_cast<const BlobHashEntry
*>(hdr
);
423 const BlobImpl::Data
*left
= &entry
->mBlob
->mData
;
425 const BlobImpl::Data
*right
=
426 static_cast<const BlobImpl::Data
*>(key
);
428 return (left
->mLength
== right
->mLength
)
429 && 0 == memcmp(left
->mBytes
, right
->mBytes
, right
->mLength
);
433 static PLDHashTableOps gBlobTableOps
= {
436 BlobHashEntry::HashKey
,
437 BlobHashEntry::MatchEntry
,
438 PL_DHashMoveEntryStub
,
439 PL_DHashClearEntryStub
,
440 PL_DHashFinalizeStub
,
444 ////////////////////////////////////////////////////////////////////////
447 // Currently, all literals are implemented exactly the same way;
448 // i.e., there is are no resource factories to allow you to generate
449 // customer resources. I doubt that makes sense, anyway.
451 class LiteralImpl
: public nsIRDFLiteral
{
454 Create(const PRUnichar
* aValue
, nsIRDFLiteral
** aResult
);
463 NS_DECL_NSIRDFLITERAL
466 LiteralImpl(const PRUnichar
* s
);
467 virtual ~LiteralImpl();
469 const PRUnichar
* GetValue() const {
470 size_t objectSize
= ((sizeof(LiteralImpl
) + sizeof(PRUnichar
) - 1) / sizeof(PRUnichar
)) * sizeof(PRUnichar
);
471 return reinterpret_cast<const PRUnichar
*>(reinterpret_cast<const unsigned char*>(this) + objectSize
);
477 LiteralImpl::Create(const PRUnichar
* aValue
, nsIRDFLiteral
** aResult
)
479 // Goofy math to get alignment right. Copied from nsSharedString.h.
480 size_t objectSize
= ((sizeof(LiteralImpl
) + sizeof(PRUnichar
) - 1) / sizeof(PRUnichar
)) * sizeof(PRUnichar
);
481 size_t stringLen
= nsCharTraits
<PRUnichar
>::length(aValue
);
482 size_t stringSize
= (stringLen
+ 1) * sizeof(PRUnichar
);
484 void* objectPtr
= operator new(objectSize
+ stringSize
);
486 return NS_ERROR_NULL_POINTER
;
488 PRUnichar
* buf
= reinterpret_cast<PRUnichar
*>(static_cast<unsigned char*>(objectPtr
) + objectSize
);
489 nsCharTraits
<PRUnichar
>::copy(buf
, aValue
, stringLen
+ 1);
491 NS_ADDREF(*aResult
= new (objectPtr
) LiteralImpl(buf
));
496 LiteralImpl::LiteralImpl(const PRUnichar
* s
)
498 RDFServiceImpl::gRDFService
->RegisterLiteral(this);
499 NS_ADDREF(RDFServiceImpl::gRDFService
);
502 LiteralImpl::~LiteralImpl()
504 RDFServiceImpl::gRDFService
->UnregisterLiteral(this);
506 // Use NS_RELEASE2() here, because we want to decrease the
507 // refcount, but not null out the gRDFService pointer (which is
508 // what a vanilla NS_RELEASE() would do).
510 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
513 NS_IMPL_THREADSAFE_ADDREF(LiteralImpl
)
514 NS_IMPL_THREADSAFE_RELEASE(LiteralImpl
)
517 LiteralImpl::QueryInterface(REFNSIID iid
, void** result
)
520 return NS_ERROR_NULL_POINTER
;
523 if (iid
.Equals(kIRDFLiteralIID
) ||
524 iid
.Equals(kIRDFNodeIID
) ||
525 iid
.Equals(kISupportsIID
)) {
526 *result
= static_cast<nsIRDFLiteral
*>(this);
530 return NS_NOINTERFACE
;
534 LiteralImpl::EqualsNode(nsIRDFNode
* aNode
, PRBool
* aResult
)
537 nsIRDFLiteral
* literal
;
538 rv
= aNode
->QueryInterface(kIRDFLiteralIID
, (void**) &literal
);
539 if (NS_SUCCEEDED(rv
)) {
540 *aResult
= (static_cast<nsIRDFLiteral
*>(this) == literal
);
544 else if (rv
== NS_NOINTERFACE
) {
554 LiteralImpl::GetValue(PRUnichar
* *value
)
556 NS_ASSERTION(value
, "null ptr");
558 return NS_ERROR_NULL_POINTER
;
560 const PRUnichar
*temp
= GetValue();
561 *value
= temp
? NS_strdup(temp
) : 0;
567 LiteralImpl::GetValueConst(const PRUnichar
** aValue
)
569 *aValue
= GetValue();
573 ////////////////////////////////////////////////////////////////////////
577 class DateImpl
: public nsIRDFDate
{
579 DateImpl(const PRTime s
);
589 NS_IMETHOD
GetValue(PRTime
*value
);
592 nsresult
EqualsDate(nsIRDFDate
* date
, PRBool
* result
);
597 DateImpl::DateImpl(const PRTime s
)
600 RDFServiceImpl::gRDFService
->RegisterDate(this);
601 NS_ADDREF(RDFServiceImpl::gRDFService
);
604 DateImpl::~DateImpl()
606 RDFServiceImpl::gRDFService
->UnregisterDate(this);
608 // Use NS_RELEASE2() here, because we want to decrease the
609 // refcount, but not null out the gRDFService pointer (which is
610 // what a vanilla NS_RELEASE() would do).
612 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
615 NS_IMPL_ADDREF(DateImpl
)
616 NS_IMPL_RELEASE(DateImpl
)
619 DateImpl::QueryInterface(REFNSIID iid
, void** result
)
622 return NS_ERROR_NULL_POINTER
;
625 if (iid
.Equals(kIRDFDateIID
) ||
626 iid
.Equals(kIRDFNodeIID
) ||
627 iid
.Equals(kISupportsIID
)) {
628 *result
= static_cast<nsIRDFDate
*>(this);
632 return NS_NOINTERFACE
;
636 DateImpl::EqualsNode(nsIRDFNode
* node
, PRBool
* result
)
640 if (NS_SUCCEEDED(node
->QueryInterface(kIRDFDateIID
, (void**) &date
))) {
641 rv
= EqualsDate(date
, result
);
652 DateImpl::GetValue(PRTime
*value
)
654 NS_ASSERTION(value
, "null ptr");
656 return NS_ERROR_NULL_POINTER
;
664 DateImpl::EqualsDate(nsIRDFDate
* date
, PRBool
* result
)
666 NS_ASSERTION(date
&& result
, "null ptr");
667 if (!date
|| !result
)
668 return NS_ERROR_NULL_POINTER
;
672 if (NS_FAILED(rv
= date
->GetValue(&p
)))
675 *result
= LL_EQ(p
, mValue
);
679 ////////////////////////////////////////////////////////////////////////
683 class IntImpl
: public nsIRDFInt
{
695 NS_IMETHOD
GetValue(PRInt32
*value
);
698 nsresult
EqualsInt(nsIRDFInt
* value
, PRBool
* result
);
703 IntImpl::IntImpl(PRInt32 s
)
706 RDFServiceImpl::gRDFService
->RegisterInt(this);
707 NS_ADDREF(RDFServiceImpl::gRDFService
);
712 RDFServiceImpl::gRDFService
->UnregisterInt(this);
714 // Use NS_RELEASE2() here, because we want to decrease the
715 // refcount, but not null out the gRDFService pointer (which is
716 // what a vanilla NS_RELEASE() would do).
718 NS_RELEASE2(RDFServiceImpl::gRDFService
, refcnt
);
721 NS_IMPL_ADDREF(IntImpl
)
722 NS_IMPL_RELEASE(IntImpl
)
725 IntImpl::QueryInterface(REFNSIID iid
, void** result
)
728 return NS_ERROR_NULL_POINTER
;
731 if (iid
.Equals(kIRDFIntIID
) ||
732 iid
.Equals(kIRDFNodeIID
) ||
733 iid
.Equals(kISupportsIID
)) {
734 *result
= static_cast<nsIRDFInt
*>(this);
738 return NS_NOINTERFACE
;
742 IntImpl::EqualsNode(nsIRDFNode
* node
, PRBool
* result
)
746 if (NS_SUCCEEDED(node
->QueryInterface(kIRDFIntIID
, (void**) &intValue
))) {
747 rv
= EqualsInt(intValue
, result
);
748 NS_RELEASE(intValue
);
758 IntImpl::GetValue(PRInt32
*value
)
760 NS_ASSERTION(value
, "null ptr");
762 return NS_ERROR_NULL_POINTER
;
770 IntImpl::EqualsInt(nsIRDFInt
* intValue
, PRBool
* result
)
772 NS_ASSERTION(intValue
&& result
, "null ptr");
773 if (!intValue
|| !result
)
774 return NS_ERROR_NULL_POINTER
;
778 if (NS_FAILED(rv
= intValue
->GetValue(&p
)))
781 *result
= (p
== mValue
);
785 ////////////////////////////////////////////////////////////////////////
789 RDFServiceImpl::gRDFService
;
791 RDFServiceImpl::RDFServiceImpl()
792 : mNamedDataSources(nsnull
)
794 mResources
.ops
= nsnull
;
795 mLiterals
.ops
= nsnull
;
803 RDFServiceImpl::Init()
807 mNamedDataSources
= PL_NewHashTable(23,
811 &dataSourceHashAllocOps
, nsnull
);
813 if (! mNamedDataSources
)
814 return NS_ERROR_OUT_OF_MEMORY
;
816 if (!PL_DHashTableInit(&mResources
, &gResourceTableOps
, nsnull
,
817 sizeof(ResourceHashEntry
), PL_DHASH_MIN_SIZE
)) {
818 mResources
.ops
= nsnull
;
819 return NS_ERROR_OUT_OF_MEMORY
;
821 if (!PL_DHashTableInit(&mLiterals
, &gLiteralTableOps
, nsnull
,
822 sizeof(LiteralHashEntry
), PL_DHASH_MIN_SIZE
)) {
823 mLiterals
.ops
= nsnull
;
824 return NS_ERROR_OUT_OF_MEMORY
;
826 if (!PL_DHashTableInit(&mInts
, &gIntTableOps
, nsnull
,
827 sizeof(IntHashEntry
), PL_DHASH_MIN_SIZE
)) {
829 return NS_ERROR_OUT_OF_MEMORY
;
831 if (!PL_DHashTableInit(&mDates
, &gDateTableOps
, nsnull
,
832 sizeof(DateHashEntry
), PL_DHASH_MIN_SIZE
)) {
834 return NS_ERROR_OUT_OF_MEMORY
;
836 if (!PL_DHashTableInit(&mBlobs
, &gBlobTableOps
, nsnull
,
837 sizeof(BlobHashEntry
), PL_DHASH_MIN_SIZE
)) {
839 return NS_ERROR_OUT_OF_MEMORY
;
841 mDefaultResourceFactory
= do_GetClassObject(kRDFDefaultResourceCID
, &rv
);
842 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get default resource factory");
843 if (NS_FAILED(rv
)) return rv
;
847 gLog
= PR_NewLogModule("nsRDFService");
854 RDFServiceImpl::~RDFServiceImpl()
856 if (mNamedDataSources
) {
857 PL_HashTableDestroy(mNamedDataSources
);
858 mNamedDataSources
= nsnull
;
861 PL_DHashTableFinish(&mResources
);
863 PL_DHashTableFinish(&mLiterals
);
865 PL_DHashTableFinish(&mInts
);
867 PL_DHashTableFinish(&mDates
);
869 PL_DHashTableFinish(&mBlobs
);
870 gRDFService
= nsnull
;
876 RDFServiceImpl::CreateSingleton(nsISupports
* aOuter
,
877 const nsIID
& aIID
, void **aResult
)
879 NS_ENSURE_NO_AGGREGATION(aOuter
);
882 NS_ERROR("Trying to create RDF serviec twice.");
883 return gRDFService
->QueryInterface(aIID
, aResult
);
886 nsRefPtr
<RDFServiceImpl
> serv
= new RDFServiceImpl();
888 return NS_ERROR_OUT_OF_MEMORY
;
890 nsresult rv
= serv
->Init();
894 return serv
->QueryInterface(aIID
, aResult
);
897 NS_IMPL_THREADSAFE_ISUPPORTS2(RDFServiceImpl
, nsIRDFService
, nsISupportsWeakReference
)
901 kLegalSchemeChars
[] = {
902 // ASCII Bits Ordered Hex
908 0x00, // 20-27 !"#$%&' 00000000 00000000
909 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28
910 0xff, // 30-37 01234567 11111111 11111111 0xFF
911 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03
912 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE
913 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF
914 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF
915 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87
916 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE
917 0xff, // 68-6F hijklmno 11111111 11111111 0xFF
918 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF
919 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07
920 0x00, 0x00, 0x00, 0x00, // >= 80
921 0x00, 0x00, 0x00, 0x00,
922 0x00, 0x00, 0x00, 0x00,
923 0x00, 0x00, 0x00, 0x00
927 IsLegalSchemeCharacter(const char aChar
)
929 PRUint8 mask
= kLegalSchemeChars
[aChar
>> 3];
930 PRUint8 bit
= PR_BIT(aChar
& 0x7);
931 return PRBool((mask
& bit
) != 0);
936 RDFServiceImpl::GetResource(const nsACString
& aURI
, nsIRDFResource
** aResource
)
939 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
940 NS_PRECONDITION(!aURI
.IsEmpty(), "URI is empty");
942 return NS_ERROR_NULL_POINTER
;
944 return NS_ERROR_INVALID_ARG
;
946 const nsAFlatCString
& flatURI
= PromiseFlatCString(aURI
);
947 PR_LOG(gLog
, PR_LOG_DEBUG
, ("rdfserv get-resource %s", flatURI
.get()));
949 // First, check the cache to see if we've already created and
950 // registered this thing.
951 PLDHashEntryHdr
*hdr
=
952 PL_DHashTableOperate(&mResources
, flatURI
.get(), PL_DHASH_LOOKUP
);
954 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
955 ResourceHashEntry
*entry
= static_cast<ResourceHashEntry
*>(hdr
);
956 NS_ADDREF(*aResource
= entry
->mResource
);
960 // Nope. So go to the repository to create it.
962 // Compute the scheme of the URI. Scan forward until we either:
964 // 1. Reach the end of the string
965 // 2. Encounter a non-alpha character
966 // 3. Encouter a colon.
968 // If we encounter a colon _before_ encountering a non-alpha
969 // character, then assume it's the scheme.
971 // XXX Although it's really not correct, we'll allow underscore
972 // characters ('_'), too.
973 nsACString::const_iterator p
, end
;
974 aURI
.BeginReading(p
);
975 aURI
.EndReading(end
);
976 while (p
!= end
&& IsLegalSchemeCharacter(*p
))
980 nsCOMPtr
<nsIFactory
> factory
;
982 nsACString::const_iterator begin
;
983 aURI
.BeginReading(begin
);
985 // There _was_ a scheme. First see if it's the same scheme
986 // that we just tried to use...
987 if (mLastFactory
&& mLastURIPrefix
.Equals(Substring(begin
, p
)))
988 factory
= mLastFactory
;
990 // Try to find a factory using the component manager.
991 nsACString::const_iterator begin
;
992 aURI
.BeginReading(begin
);
993 nsCAutoString contractID
;
994 contractID
= NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX
) +
997 factory
= do_GetClassObject(contractID
.get());
999 // Store the factory in our one-element cache.
1001 mLastFactory
= factory
;
1002 mLastURIPrefix
= Substring(begin
, p
);
1009 // fall through to using the "default" resource factory if either:
1011 // 1. The URI didn't have a scheme, or
1012 // 2. There was no resource factory registered for the scheme.
1013 factory
= mDefaultResourceFactory
;
1015 // Store the factory in our one-element cache.
1017 mLastFactory
= factory
;
1018 mLastURIPrefix
= Substring(begin
, p
);
1022 nsIRDFResource
*result
;
1023 rv
= factory
->CreateInstance(nsnull
, NS_GET_IID(nsIRDFResource
), (void**) &result
);
1024 if (NS_FAILED(rv
)) return rv
;
1026 // Now initialize it with its URI. At this point, the resource
1027 // implementation should register itself with the RDF service.
1028 rv
= result
->Init(flatURI
.get());
1029 if (NS_FAILED(rv
)) {
1030 NS_ERROR("unable to initialize resource");
1035 *aResource
= result
; // already refcounted from repository
1040 RDFServiceImpl::GetUnicodeResource(const nsAString
& aURI
, nsIRDFResource
** aResource
)
1042 return GetResource(NS_ConvertUTF16toUTF8(aURI
), aResource
);
1047 RDFServiceImpl::GetAnonymousResource(nsIRDFResource
** aResult
)
1049 static PRUint32 gCounter
= 0;
1050 static char gChars
[] = "0123456789abcdef"
1055 static PRInt32 kMask
= 0x003f;
1056 static PRInt32 kShift
= 6;
1059 // Start it at a semi-unique value, just to minimize the
1060 // chance that we get into a situation where
1062 // 1. An anonymous resource gets serialized out in a graph
1064 // 3. The same anonymous resource gets requested, and refers
1065 // to something completely different.
1066 // 4. The serialization is read back in.
1067 LL_L2UI(gCounter
, PR_Now());
1074 // Ugh, this is a really sloppy way to do this; I copied the
1075 // implementation from the days when it lived outside the RDF
1076 // service. Now that it's a member we can be more cleverer.
1081 PRUint32 id
= ++gCounter
;
1083 char ch
= gChars
[(id
& kMask
)];
1088 nsIRDFResource
* resource
;
1089 rv
= GetResource(s
, &resource
);
1090 if (NS_FAILED(rv
)) return rv
;
1092 // XXX an ugly but effective way to make sure that this
1093 // resource is really unique in the world.
1095 nsrefcnt refcnt
= resource
->Release();
1098 *aResult
= resource
;
1102 NS_RELEASE(resource
);
1110 RDFServiceImpl::GetLiteral(const PRUnichar
* aValue
, nsIRDFLiteral
** aLiteral
)
1112 NS_PRECONDITION(aValue
!= nsnull
, "null ptr");
1114 return NS_ERROR_NULL_POINTER
;
1116 NS_PRECONDITION(aLiteral
!= nsnull
, "null ptr");
1118 return NS_ERROR_NULL_POINTER
;
1120 // See if we have one already cached
1121 PLDHashEntryHdr
*hdr
=
1122 PL_DHashTableOperate(&mLiterals
, aValue
, PL_DHASH_LOOKUP
);
1124 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1125 LiteralHashEntry
*entry
= static_cast<LiteralHashEntry
*>(hdr
);
1126 NS_ADDREF(*aLiteral
= entry
->mLiteral
);
1130 // Nope. Create a new one
1131 return LiteralImpl::Create(aValue
, aLiteral
);
1135 RDFServiceImpl::GetDateLiteral(PRTime aTime
, nsIRDFDate
** aResult
)
1137 // See if we have one already cached
1138 PLDHashEntryHdr
*hdr
=
1139 PL_DHashTableOperate(&mDates
, &aTime
, PL_DHASH_LOOKUP
);
1141 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1142 DateHashEntry
*entry
= static_cast<DateHashEntry
*>(hdr
);
1143 NS_ADDREF(*aResult
= entry
->mDate
);
1147 DateImpl
* result
= new DateImpl(aTime
);
1149 return NS_ERROR_OUT_OF_MEMORY
;
1151 NS_ADDREF(*aResult
= result
);
1156 RDFServiceImpl::GetIntLiteral(PRInt32 aInt
, nsIRDFInt
** aResult
)
1158 // See if we have one already cached
1159 PLDHashEntryHdr
*hdr
=
1160 PL_DHashTableOperate(&mInts
, &aInt
, PL_DHASH_LOOKUP
);
1162 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1163 IntHashEntry
*entry
= static_cast<IntHashEntry
*>(hdr
);
1164 NS_ADDREF(*aResult
= entry
->mInt
);
1168 IntImpl
* result
= new IntImpl(aInt
);
1170 return NS_ERROR_OUT_OF_MEMORY
;
1172 NS_ADDREF(*aResult
= result
);
1177 RDFServiceImpl::GetBlobLiteral(const PRUint8
*aBytes
, PRInt32 aLength
,
1178 nsIRDFBlob
**aResult
)
1180 BlobImpl::Data key
= { aLength
, const_cast<PRUint8
*>(aBytes
) };
1182 PLDHashEntryHdr
*hdr
=
1183 PL_DHashTableOperate(&mBlobs
, &key
, PL_DHASH_LOOKUP
);
1185 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1186 BlobHashEntry
*entry
= static_cast<BlobHashEntry
*>(hdr
);
1187 NS_ADDREF(*aResult
= entry
->mBlob
);
1191 BlobImpl
*result
= new BlobImpl(aBytes
, aLength
);
1193 return NS_ERROR_OUT_OF_MEMORY
;
1195 NS_ADDREF(*aResult
= result
);
1200 RDFServiceImpl::IsAnonymousResource(nsIRDFResource
* aResource
, PRBool
* _result
)
1202 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
1204 return NS_ERROR_NULL_POINTER
;
1209 rv
= aResource
->GetValueConst(&uri
);
1210 if (NS_FAILED(rv
)) return rv
;
1212 if ((uri
[0] == 'r') &&
1221 *_result
= PR_FALSE
;
1228 RDFServiceImpl::RegisterResource(nsIRDFResource
* aResource
, PRBool aReplace
)
1230 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
1232 return NS_ERROR_NULL_POINTER
;
1237 rv
= aResource
->GetValueConst(&uri
);
1238 NS_ASSERTION(NS_SUCCEEDED(rv
), "unable to get URI from resource");
1239 if (NS_FAILED(rv
)) return rv
;
1241 NS_ASSERTION(uri
!= nsnull
, "resource has no URI");
1243 return NS_ERROR_NULL_POINTER
;
1245 PLDHashEntryHdr
*hdr
=
1246 PL_DHashTableOperate(&mResources
, uri
, PL_DHASH_LOOKUP
);
1248 if (PL_DHASH_ENTRY_IS_BUSY(hdr
)) {
1250 NS_WARNING("resource already registered, and replace not specified");
1251 return NS_ERROR_FAILURE
; // already registered
1254 // N.B., we do _not_ release the original resource because we
1255 // only ever held a weak reference to it. We simply replace
1258 PR_LOG(gLog
, PR_LOG_DEBUG
,
1259 ("rdfserv replace-resource [%p] <-- [%p] %s",
1260 static_cast<ResourceHashEntry
*>(hdr
)->mResource
,
1261 aResource
, (const char*) uri
));
1264 hdr
= PL_DHashTableOperate(&mResources
, uri
, PL_DHASH_ADD
);
1266 return NS_ERROR_OUT_OF_MEMORY
;
1268 PR_LOG(gLog
, PR_LOG_DEBUG
,
1269 ("rdfserv register-resource [%p] %s",
1270 aResource
, (const char*) uri
));
1273 // N.B., we only hold a weak reference to the resource: that way,
1274 // the resource can be destroyed when the last refcount goes
1275 // away. The single addref that the CreateResource() call made
1276 // will be owned by the callee.
1277 ResourceHashEntry
*entry
= static_cast<ResourceHashEntry
*>(hdr
);
1278 entry
->mResource
= aResource
;
1285 RDFServiceImpl::UnregisterResource(nsIRDFResource
* aResource
)
1287 NS_PRECONDITION(aResource
!= nsnull
, "null ptr");
1289 return NS_ERROR_NULL_POINTER
;
1294 rv
= aResource
->GetValueConst(&uri
);
1295 if (NS_FAILED(rv
)) return rv
;
1297 NS_ASSERTION(uri
!= nsnull
, "resource has no URI");
1299 return NS_ERROR_UNEXPECTED
;
1301 PR_LOG(gLog
, PR_LOG_DEBUG
,
1302 ("rdfserv unregister-resource [%p] %s",
1303 aResource
, (const char*) uri
));
1306 if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources
, uri
, PL_DHASH_LOOKUP
)))
1307 NS_WARNING("resource was never registered");
1310 PL_DHashTableOperate(&mResources
, uri
, PL_DHASH_REMOVE
);
1315 RDFServiceImpl::RegisterDataSource(nsIRDFDataSource
* aDataSource
, PRBool aReplace
)
1317 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
1319 return NS_ERROR_NULL_POINTER
;
1324 rv
= aDataSource
->GetURI(getter_Copies(uri
));
1325 if (NS_FAILED(rv
)) return rv
;
1328 PL_HashTableRawLookup(mNamedDataSources
, (*mNamedDataSources
->keyHash
)(uri
), uri
);
1332 return NS_ERROR_FAILURE
; // already registered
1334 // N.B., we only hold a weak reference to the datasource, so
1335 // just replace the old with the new and don't touch any
1337 PR_LOG(gLog
, PR_LOG_NOTICE
,
1338 ("rdfserv replace-datasource [%p] <-- [%p] %s",
1339 (*hep
)->value
, aDataSource
, (const char*) uri
));
1341 (*hep
)->value
= aDataSource
;
1344 const char* key
= PL_strdup(uri
);
1346 return NS_ERROR_OUT_OF_MEMORY
;
1348 PL_HashTableAdd(mNamedDataSources
, key
, aDataSource
);
1350 PR_LOG(gLog
, PR_LOG_NOTICE
,
1351 ("rdfserv register-datasource [%p] %s",
1352 aDataSource
, (const char*) uri
));
1354 // N.B., we only hold a weak reference to the datasource, so don't
1362 RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource
* aDataSource
)
1364 NS_PRECONDITION(aDataSource
!= nsnull
, "null ptr");
1366 return NS_ERROR_NULL_POINTER
;
1371 rv
= aDataSource
->GetURI(getter_Copies(uri
));
1372 if (NS_FAILED(rv
)) return rv
;
1374 //NS_ASSERTION(uri != nsnull, "datasource has no URI");
1376 return NS_ERROR_UNEXPECTED
;
1379 PL_HashTableRawLookup(mNamedDataSources
, (*mNamedDataSources
->keyHash
)(uri
), uri
);
1381 // It may well be that this datasource was never registered. If
1382 // so, don't unregister it.
1383 if (! *hep
|| ((*hep
)->value
!= aDataSource
))
1386 // N.B., we only held a weak reference to the datasource, so we
1387 // don't release here.
1388 PL_HashTableRawRemove(mNamedDataSources
, hep
, *hep
);
1390 PR_LOG(gLog
, PR_LOG_NOTICE
,
1391 ("rdfserv unregister-datasource [%p] %s",
1392 aDataSource
, (const char*) uri
));
1398 RDFServiceImpl::GetDataSource(const char* aURI
, nsIRDFDataSource
** aDataSource
)
1400 // Use the other GetDataSource and ask for a non-blocking Refresh.
1401 // If you wanted it loaded synchronously, then you should've tried to do it
1402 // yourself, or used GetDataSourceBlocking.
1403 return GetDataSource( aURI
, PR_FALSE
, aDataSource
);
1407 RDFServiceImpl::GetDataSourceBlocking(const char* aURI
, nsIRDFDataSource
** aDataSource
)
1409 // Use GetDataSource and ask for a blocking Refresh.
1410 return GetDataSource( aURI
, PR_TRUE
, aDataSource
);
1414 RDFServiceImpl::GetDataSource(const char* aURI
, PRBool aBlock
, nsIRDFDataSource
** aDataSource
)
1416 NS_PRECONDITION(aURI
!= nsnull
, "null ptr");
1418 return NS_ERROR_NULL_POINTER
;
1422 // Attempt to canonify the URI before we look for it in the
1423 // cache. We won't bother doing this on `rdf:' URIs to avoid
1424 // useless (and expensive) protocol handler lookups.
1425 nsCAutoString
spec(aURI
);
1427 if (!StringBeginsWith(spec
, NS_LITERAL_CSTRING("rdf:"))) {
1428 nsCOMPtr
<nsIURI
> uri
;
1429 NS_NewURI(getter_AddRefs(uri
), spec
);
1434 // First, check the cache to see if we already have this
1435 // datasource loaded and initialized.
1437 nsIRDFDataSource
* cached
=
1438 static_cast<nsIRDFDataSource
*>(PL_HashTableLookup(mNamedDataSources
, spec
.get()));
1442 *aDataSource
= cached
;
1447 // Nope. So go to the repository to try to create it.
1448 nsCOMPtr
<nsIRDFDataSource
> ds
;
1449 if (StringBeginsWith(spec
, NS_LITERAL_CSTRING("rdf:"))) {
1450 // It's a built-in data source. Convert it to a contract ID.
1451 nsCAutoString
contractID(
1452 NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX
) +
1453 Substring(spec
, 4, spec
.Length() - 4));
1455 // Strip params to get ``base'' contractID for data source.
1456 PRInt32 p
= contractID
.FindChar(PRUnichar('&'));
1458 contractID
.Truncate(p
);
1460 ds
= do_GetService(contractID
.get(), &rv
);
1461 if (NS_FAILED(rv
)) return rv
;
1463 nsCOMPtr
<nsIRDFRemoteDataSource
> remote
= do_QueryInterface(ds
);
1465 rv
= remote
->Init(spec
.get());
1466 if (NS_FAILED(rv
)) return rv
;
1470 // Try to load this as an RDF/XML data source
1471 ds
= do_CreateInstance(kRDFXMLDataSourceCID
, &rv
);
1472 if (NS_FAILED(rv
)) return rv
;
1474 nsCOMPtr
<nsIRDFRemoteDataSource
> remote(do_QueryInterface(ds
));
1475 NS_ASSERTION(remote
, "not a remote RDF/XML data source!");
1476 if (! remote
) return NS_ERROR_UNEXPECTED
;
1478 rv
= remote
->Init(spec
.get());
1479 if (NS_FAILED(rv
)) return rv
;
1481 rv
= remote
->Refresh(aBlock
);
1482 if (NS_FAILED(rv
)) return rv
;
1486 NS_ADDREF(*aDataSource
);
1490 ////////////////////////////////////////////////////////////////////////
1493 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral
* aLiteral
)
1495 const PRUnichar
* value
;
1496 aLiteral
->GetValueConst(&value
);
1498 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals
,
1501 "literal already registered");
1503 PLDHashEntryHdr
*hdr
=
1504 PL_DHashTableOperate(&mLiterals
, value
, PL_DHASH_ADD
);
1507 return NS_ERROR_OUT_OF_MEMORY
;
1509 LiteralHashEntry
*entry
= static_cast<LiteralHashEntry
*>(hdr
);
1511 // N.B., we only hold a weak reference to the literal: that
1512 // way, the literal can be destroyed when the last refcount
1513 // goes away. The single addref that the CreateLiteral() call
1514 // made will be owned by the callee.
1515 entry
->mLiteral
= aLiteral
;
1516 entry
->mKey
= value
;
1518 PR_LOG(gLog
, PR_LOG_DEBUG
,
1519 ("rdfserv register-literal [%p] %s",
1520 aLiteral
, (const PRUnichar
*) value
));
1527 RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral
* aLiteral
)
1529 const PRUnichar
* value
;
1530 aLiteral
->GetValueConst(&value
);
1532 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals
,
1535 "literal was never registered");
1537 PL_DHashTableOperate(&mLiterals
, value
, PL_DHASH_REMOVE
);
1539 // N.B. that we _don't_ release the literal: we only held a weak
1540 // reference to it in the hashtable.
1541 PR_LOG(gLog
, PR_LOG_DEBUG
,
1542 ("rdfserv unregister-literal [%p] %s",
1543 aLiteral
, (const PRUnichar
*) value
));
1548 //----------------------------------------------------------------------
1551 RDFServiceImpl::RegisterInt(nsIRDFInt
* aInt
)
1554 aInt
->GetValue(&value
);
1556 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts
,
1559 "int already registered");
1561 PLDHashEntryHdr
*hdr
=
1562 PL_DHashTableOperate(&mInts
, &value
, PL_DHASH_ADD
);
1565 return NS_ERROR_OUT_OF_MEMORY
;
1567 IntHashEntry
*entry
= static_cast<IntHashEntry
*>(hdr
);
1569 // N.B., we only hold a weak reference to the literal: that
1570 // way, the literal can be destroyed when the last refcount
1571 // goes away. The single addref that the CreateInt() call
1572 // made will be owned by the callee.
1574 entry
->mKey
= value
;
1576 PR_LOG(gLog
, PR_LOG_DEBUG
,
1577 ("rdfserv register-int [%p] %d",
1585 RDFServiceImpl::UnregisterInt(nsIRDFInt
* aInt
)
1588 aInt
->GetValue(&value
);
1590 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts
,
1593 "int was never registered");
1595 PL_DHashTableOperate(&mInts
, &value
, PL_DHASH_REMOVE
);
1597 // N.B. that we _don't_ release the literal: we only held a weak
1598 // reference to it in the hashtable.
1599 PR_LOG(gLog
, PR_LOG_DEBUG
,
1600 ("rdfserv unregister-int [%p] %d",
1606 //----------------------------------------------------------------------
1609 RDFServiceImpl::RegisterDate(nsIRDFDate
* aDate
)
1612 aDate
->GetValue(&value
);
1614 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates
,
1617 "date already registered");
1619 PLDHashEntryHdr
*hdr
=
1620 PL_DHashTableOperate(&mDates
, &value
, PL_DHASH_ADD
);
1623 return NS_ERROR_OUT_OF_MEMORY
;
1625 DateHashEntry
*entry
= static_cast<DateHashEntry
*>(hdr
);
1627 // N.B., we only hold a weak reference to the literal: that
1628 // way, the literal can be destroyed when the last refcount
1629 // goes away. The single addref that the CreateDate() call
1630 // made will be owned by the callee.
1631 entry
->mDate
= aDate
;
1632 entry
->mKey
= value
;
1634 PR_LOG(gLog
, PR_LOG_DEBUG
,
1635 ("rdfserv register-date [%p] %ld",
1643 RDFServiceImpl::UnregisterDate(nsIRDFDate
* aDate
)
1646 aDate
->GetValue(&value
);
1648 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates
,
1651 "date was never registered");
1653 PL_DHashTableOperate(&mDates
, &value
, PL_DHASH_REMOVE
);
1655 // N.B. that we _don't_ release the literal: we only held a weak
1656 // reference to it in the hashtable.
1657 PR_LOG(gLog
, PR_LOG_DEBUG
,
1658 ("rdfserv unregister-date [%p] %ld",
1665 RDFServiceImpl::RegisterBlob(BlobImpl
*aBlob
)
1667 NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs
,
1670 "blob already registered");
1672 PLDHashEntryHdr
*hdr
=
1673 PL_DHashTableOperate(&mBlobs
, &aBlob
->mData
, PL_DHASH_ADD
);
1676 return NS_ERROR_OUT_OF_MEMORY
;
1678 BlobHashEntry
*entry
= static_cast<BlobHashEntry
*>(hdr
);
1680 // N.B., we only hold a weak reference to the literal: that
1681 // way, the literal can be destroyed when the last refcount
1682 // goes away. The single addref that the CreateInt() call
1683 // made will be owned by the callee.
1684 entry
->mBlob
= aBlob
;
1686 PR_LOG(gLog
, PR_LOG_DEBUG
,
1687 ("rdfserv register-blob [%p] %s",
1688 aBlob
, aBlob
->mData
.mBytes
));
1694 RDFServiceImpl::UnregisterBlob(BlobImpl
*aBlob
)
1696 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs
,
1699 "blob was never registered");
1701 PL_DHashTableOperate(&mBlobs
, &aBlob
->mData
, PL_DHASH_REMOVE
);
1703 // N.B. that we _don't_ release the literal: we only held a weak
1704 // reference to it in the hashtable.
1705 PR_LOG(gLog
, PR_LOG_DEBUG
,
1706 ("rdfserv unregister-blob [%p] %s",
1707 aBlob
, aBlob
->mData
.mBytes
));