Back to index

lightning-sunbird  0.9+nobinonly
nsRDFService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK *****
00038  *
00039  *
00040  * This Original Code has been modified by IBM Corporation.
00041  * Modifications made by IBM described herein are
00042  * Copyright (c) International Business Machines
00043  * Corporation, 2000
00044  *
00045  * Modifications to Mozilla code or documentation
00046  * identified per MPL Section 3.3
00047  *
00048  * Date         Modified by     Description of modification
00049  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
00050  *                               use in OS2
00051  */
00052 
00053 /*
00054 
00055   This file provides the implementation for the RDF service manager.
00056 
00057   TO DO
00058   -----
00059 
00060   1) Implement the CreateDataBase() methods.
00061 
00062   2) Cache date and int literals.
00063 
00064  */
00065 
00066 #include "nsCOMPtr.h"
00067 #include "nsMemory.h"
00068 #include "nsIAtom.h"
00069 #include "nsIComponentManager.h"
00070 #include "nsIRDFDataSource.h"
00071 #include "nsIRDFNode.h"
00072 #include "nsIRDFService.h"
00073 #include "nsIRDFRemoteDataSource.h"
00074 #include "nsIServiceManager.h"
00075 #include "nsIFactory.h"
00076 #include "nsRDFCID.h"
00077 #include "nsString.h"
00078 #include "nsWeakReference.h"
00079 #include "nsXPIDLString.h"
00080 #include "nsNetUtil.h"
00081 #include "pldhash.h"
00082 #include "plhash.h"
00083 #include "plstr.h"
00084 #include "prlog.h"
00085 #include "prprf.h"
00086 #include "prmem.h"
00087 #include "rdf.h"
00088 #include "nsCRT.h"
00089 
00091 
00092 static NS_DEFINE_CID(kRDFXMLDataSourceCID,    NS_RDFXMLDATASOURCE_CID);
00093 static NS_DEFINE_CID(kRDFDefaultResourceCID,  NS_RDFDEFAULTRESOURCE_CID);
00094 
00095 static NS_DEFINE_IID(kIRDFLiteralIID,         NS_IRDFLITERAL_IID);
00096 static NS_DEFINE_IID(kIRDFDateIID,         NS_IRDFDATE_IID);
00097 static NS_DEFINE_IID(kIRDFIntIID,         NS_IRDFINT_IID);
00098 static NS_DEFINE_IID(kIRDFNodeIID,            NS_IRDFNODE_IID);
00099 static NS_DEFINE_IID(kISupportsIID,           NS_ISUPPORTS_IID);
00100 
00101 #ifdef PR_LOGGING
00102 static PRLogModuleInfo* gLog = nsnull;
00103 #endif
00104 
00105 class BlobImpl;
00106 
00108 // RDFServiceImpl
00109 //
00110 //   This is the RDF service.
00111 //
00112 class RDFServiceImpl : public nsIRDFService,
00113                        public nsSupportsWeakReference
00114 {
00115 protected:
00116     PLHashTable* mNamedDataSources;
00117     PLDHashTable mResources;
00118     PLDHashTable mLiterals;
00119     PLDHashTable mInts;
00120     PLDHashTable mDates;
00121     PLDHashTable mBlobs;
00122 
00123     nsCAutoString mLastURIPrefix;
00124     nsCOMPtr<nsIFactory> mLastFactory;
00125     nsCOMPtr<nsIFactory> mDefaultResourceFactory;
00126 
00127     RDFServiceImpl();
00128     nsresult Init();
00129     virtual ~RDFServiceImpl();
00130 
00131 public:
00132 
00133     static nsresult GetRDFService(nsIRDFService** result);
00134 
00135     // nsISupports
00136     NS_DECL_ISUPPORTS
00137 
00138     // nsIRDFService
00139     NS_DECL_NSIRDFSERVICE
00140 
00141     // Implementation methods
00142     nsresult RegisterLiteral(nsIRDFLiteral* aLiteral);
00143     nsresult UnregisterLiteral(nsIRDFLiteral* aLiteral);
00144     nsresult RegisterInt(nsIRDFInt* aInt);
00145     nsresult UnregisterInt(nsIRDFInt* aInt);
00146     nsresult RegisterDate(nsIRDFDate* aDate);
00147     nsresult UnregisterDate(nsIRDFDate* aDate);
00148     nsresult RegisterBlob(BlobImpl* aBlob);
00149     nsresult UnregisterBlob(BlobImpl* aBlob);
00150 
00151     nsresult GetDataSource(const char *aURI, PRBool aBlock, nsIRDFDataSource **aDataSource );
00152 };
00153 
00154 static RDFServiceImpl* gRDFService; // The one-and-only RDF service
00155 
00156 
00157 // These functions are copied from nsprpub/lib/ds/plhash.c, with one
00158 // change to free the key in DataSourceFreeEntry.
00159 // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway?
00160 
00161 static void * PR_CALLBACK
00162 DataSourceAllocTable(void *pool, PRSize size)
00163 {
00164 #if defined(XP_MAC)
00165 #pragma unused (pool)
00166 #endif
00167 
00168     return PR_MALLOC(size);
00169 }
00170 
00171 static void PR_CALLBACK
00172 DataSourceFreeTable(void *pool, void *item)
00173 {
00174 #if defined(XP_MAC)
00175 #pragma unused (pool)
00176 #endif
00177 
00178     PR_Free(item);
00179 }
00180 
00181 static PLHashEntry * PR_CALLBACK
00182 DataSourceAllocEntry(void *pool, const void *key)
00183 {
00184 #if defined(XP_MAC)
00185 #pragma unused (pool,key)
00186 #endif
00187 
00188     return PR_NEW(PLHashEntry);
00189 }
00190 
00191 static void PR_CALLBACK
00192 DataSourceFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
00193 {
00194 #if defined(XP_MAC)
00195 #pragma unused (pool)
00196 #endif
00197 
00198     if (flag == HT_FREE_ENTRY) {
00199         PL_strfree((char*) he->key);
00200         PR_Free(he);
00201     }
00202 }
00203 
00204 static PLHashAllocOps dataSourceHashAllocOps = {
00205     DataSourceAllocTable, DataSourceFreeTable,
00206     DataSourceAllocEntry, DataSourceFreeEntry
00207 };
00208 
00209 //----------------------------------------------------------------------
00210 //
00211 // For the mResources hashtable.
00212 //
00213 
00214 struct ResourceHashEntry : public PLDHashEntryHdr {
00215     const char *mKey;
00216     nsIRDFResource *mResource;
00217 
00218     static const void * PR_CALLBACK
00219     GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00220     {
00221         ResourceHashEntry *entry = NS_STATIC_CAST(ResourceHashEntry *, hdr);
00222         return entry->mKey;
00223     }
00224 
00225     static PLDHashNumber PR_CALLBACK
00226     HashKey(PLDHashTable *table, const void *key)
00227     {
00228         return nsCRT::HashCode(NS_STATIC_CAST(const char *, key));
00229     }
00230 
00231     static PRBool PR_CALLBACK
00232     MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00233                const void *key)
00234     {
00235         const ResourceHashEntry *entry =
00236             NS_STATIC_CAST(const ResourceHashEntry *, hdr);
00237 
00238         return 0 == nsCRT::strcmp(NS_STATIC_CAST(const char *, key),
00239                                   entry->mKey);
00240     }
00241 };
00242 
00243 static PLDHashTableOps gResourceTableOps = {
00244     PL_DHashAllocTable,
00245     PL_DHashFreeTable,
00246     ResourceHashEntry::GetKey,
00247     ResourceHashEntry::HashKey,
00248     ResourceHashEntry::MatchEntry,
00249     PL_DHashMoveEntryStub,
00250     PL_DHashClearEntryStub,
00251     PL_DHashFinalizeStub,
00252     nsnull
00253 };
00254 
00255 // ----------------------------------------------------------------------
00256 //
00257 // For the mLiterals hashtable.
00258 //
00259 
00260 struct LiteralHashEntry : public PLDHashEntryHdr {
00261     nsIRDFLiteral *mLiteral;
00262     const PRUnichar *mKey;
00263 
00264     static const void * PR_CALLBACK
00265     GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00266     {
00267         LiteralHashEntry *entry = NS_STATIC_CAST(LiteralHashEntry *, hdr);
00268         return entry->mKey;
00269     }
00270 
00271     static PLDHashNumber PR_CALLBACK
00272     HashKey(PLDHashTable *table, const void *key)
00273     {
00274         return nsCRT::HashCode(NS_STATIC_CAST(const PRUnichar *, key));
00275     }
00276 
00277     static PRBool PR_CALLBACK
00278     MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00279                const void *key)
00280     {
00281         const LiteralHashEntry *entry =
00282             NS_STATIC_CAST(const LiteralHashEntry *, hdr);
00283 
00284         return 0 == nsCRT::strcmp(NS_STATIC_CAST(const PRUnichar *, key),
00285                                   entry->mKey);
00286     }
00287 };
00288 
00289 static PLDHashTableOps gLiteralTableOps = {
00290     PL_DHashAllocTable,
00291     PL_DHashFreeTable,
00292     LiteralHashEntry::GetKey,
00293     LiteralHashEntry::HashKey,
00294     LiteralHashEntry::MatchEntry,
00295     PL_DHashMoveEntryStub,
00296     PL_DHashClearEntryStub,
00297     PL_DHashFinalizeStub,
00298     nsnull
00299 };
00300 
00301 // ----------------------------------------------------------------------
00302 //
00303 // For the mInts hashtable.
00304 //
00305 
00306 struct IntHashEntry : public PLDHashEntryHdr {
00307     nsIRDFInt *mInt;
00308     PRInt32    mKey;
00309 
00310     static const void * PR_CALLBACK
00311     GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00312     {
00313         IntHashEntry *entry = NS_STATIC_CAST(IntHashEntry *, hdr);
00314         return &entry->mKey;
00315     }
00316 
00317     static PLDHashNumber PR_CALLBACK
00318     HashKey(PLDHashTable *table, const void *key)
00319     {
00320         return PLDHashNumber(*NS_STATIC_CAST(const PRInt32 *, key));
00321     }
00322 
00323     static PRBool PR_CALLBACK
00324     MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00325                const void *key)
00326     {
00327         const IntHashEntry *entry =
00328             NS_STATIC_CAST(const IntHashEntry *, hdr);
00329 
00330         return *NS_STATIC_CAST(const PRInt32 *, key) == entry->mKey;
00331     }
00332 };
00333 
00334 static PLDHashTableOps gIntTableOps = {
00335     PL_DHashAllocTable,
00336     PL_DHashFreeTable,
00337     IntHashEntry::GetKey,
00338     IntHashEntry::HashKey,
00339     IntHashEntry::MatchEntry,
00340     PL_DHashMoveEntryStub,
00341     PL_DHashClearEntryStub,
00342     PL_DHashFinalizeStub,
00343     nsnull
00344 };
00345 
00346 // ----------------------------------------------------------------------
00347 //
00348 // For the mDates hashtable.
00349 //
00350 
00351 struct DateHashEntry : public PLDHashEntryHdr {
00352     nsIRDFDate *mDate;
00353     PRTime      mKey;
00354 
00355     static const void * PR_CALLBACK
00356     GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00357     {
00358         DateHashEntry *entry = NS_STATIC_CAST(DateHashEntry *, hdr);
00359         return &entry->mKey;
00360     }
00361 
00362     static PLDHashNumber PR_CALLBACK
00363     HashKey(PLDHashTable *table, const void *key)
00364     {
00365         // xor the low 32 bits with the high 32 bits.
00366         PRTime t = *NS_STATIC_CAST(const PRTime *, key);
00367         PRInt64 h64, l64;
00368         LL_USHR(h64, t, 32);
00369         l64 = LL_INIT(0, 0xffffffff);
00370         LL_AND(l64, l64, t);
00371         PRInt32 h32, l32;
00372         LL_L2I(h32, h64);
00373         LL_L2I(l32, l64);
00374         return PLDHashNumber(l32 ^ h32);
00375     }
00376 
00377     static PRBool PR_CALLBACK
00378     MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00379                const void *key)
00380     {
00381         const DateHashEntry *entry =
00382             NS_STATIC_CAST(const DateHashEntry *, hdr);
00383 
00384         return LL_EQ(*NS_STATIC_CAST(const PRTime *, key), entry->mKey);
00385     }
00386 };
00387 
00388 static PLDHashTableOps gDateTableOps = {
00389     PL_DHashAllocTable,
00390     PL_DHashFreeTable,
00391     DateHashEntry::GetKey,
00392     DateHashEntry::HashKey,
00393     DateHashEntry::MatchEntry,
00394     PL_DHashMoveEntryStub,
00395     PL_DHashClearEntryStub,
00396     PL_DHashFinalizeStub,
00397     nsnull
00398 };
00399 
00400 class BlobImpl : public nsIRDFBlob
00401 {
00402 public:
00403     struct Data {
00404         PRInt32  mLength;
00405         PRUint8 *mBytes;
00406     };
00407 
00408     BlobImpl(const PRUint8 *aBytes, PRInt32 aLength)
00409     {
00410         mData.mLength = aLength;
00411         mData.mBytes = new PRUint8[aLength];
00412         memcpy(mData.mBytes, aBytes, aLength);
00413         NS_ADDREF(gRDFService);
00414         gRDFService->RegisterBlob(this);
00415     }
00416 
00417     virtual ~BlobImpl()
00418     {
00419         gRDFService->UnregisterBlob(this);
00420         // Use NS_RELEASE2() here, because we want to decrease the
00421         // refcount, but not null out the gRDFService pointer (which is
00422         // what a vanilla NS_RELEASE() would do).
00423         nsrefcnt refcnt;
00424         NS_RELEASE2(gRDFService, refcnt);
00425         delete[] mData.mBytes;
00426     }
00427 
00428     NS_DECL_ISUPPORTS
00429     NS_DECL_NSIRDFNODE
00430     NS_DECL_NSIRDFBLOB
00431 
00432     Data mData;
00433 };
00434 
00435 NS_IMPL_ISUPPORTS2(BlobImpl, nsIRDFNode, nsIRDFBlob)
00436 
00437 NS_IMETHODIMP
00438 BlobImpl::EqualsNode(nsIRDFNode *aNode, PRBool *aEquals)
00439 {
00440     nsCOMPtr<nsIRDFBlob> blob = do_QueryInterface(aNode);
00441     if (blob) {
00442         PRInt32 length;
00443         blob->GetLength(&length);
00444 
00445         if (length == mData.mLength) {
00446             const PRUint8 *bytes;
00447             blob->GetValue(&bytes);
00448 
00449             if (0 == memcmp(bytes, mData.mBytes, length)) {
00450                 *aEquals = PR_TRUE;
00451                 return NS_OK;
00452             }
00453         }
00454     }
00455 
00456     *aEquals = PR_FALSE;
00457     return NS_OK;
00458 }
00459 
00460 NS_IMETHODIMP
00461 BlobImpl::GetValue(const PRUint8 **aResult)
00462 {
00463     *aResult = mData.mBytes;
00464     return NS_OK;
00465 }
00466 
00467 NS_IMETHODIMP
00468 BlobImpl::GetLength(PRInt32 *aResult)
00469 {
00470     *aResult = mData.mLength;
00471     return NS_OK;
00472 }
00473 
00474 // ----------------------------------------------------------------------
00475 //
00476 // For the mBlobs hashtable.
00477 //
00478 
00479 struct BlobHashEntry : public PLDHashEntryHdr {
00480     BlobImpl *mBlob;
00481 
00482     static const void * PR_CALLBACK
00483     GetKey(PLDHashTable *table, PLDHashEntryHdr *hdr)
00484     {
00485         BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr);
00486         return &entry->mBlob->mData;
00487     }
00488 
00489     static PLDHashNumber PR_CALLBACK
00490     HashKey(PLDHashTable *table, const void *key)
00491     {
00492         const BlobImpl::Data *data =
00493             NS_STATIC_CAST(const BlobImpl::Data *, key);
00494 
00495         const PRUint8 *p = data->mBytes, *limit = p + data->mLength;
00496         PLDHashNumber h = 0;
00497         for ( ; p < limit; ++p)
00498             h = (h >> 28) ^ (h << 4) ^ *p;
00499         return h;
00500     }
00501 
00502     static PRBool PR_CALLBACK
00503     MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
00504                const void *key)
00505     {
00506         const BlobHashEntry *entry =
00507             NS_STATIC_CAST(const BlobHashEntry *, hdr);
00508 
00509         const BlobImpl::Data *left = &entry->mBlob->mData;
00510 
00511         const BlobImpl::Data *right =
00512             NS_STATIC_CAST(const BlobImpl::Data *, key);
00513 
00514         return (left->mLength == right->mLength)
00515             && 0 == memcmp(left->mBytes, right->mBytes, right->mLength);
00516     }
00517 };
00518 
00519 static PLDHashTableOps gBlobTableOps = {
00520     PL_DHashAllocTable,
00521     PL_DHashFreeTable,
00522     BlobHashEntry::GetKey,
00523     BlobHashEntry::HashKey,
00524     BlobHashEntry::MatchEntry,
00525     PL_DHashMoveEntryStub,
00526     PL_DHashClearEntryStub,
00527     PL_DHashFinalizeStub,
00528     nsnull
00529 };
00530 
00532 // LiteralImpl
00533 //
00534 //   Currently, all literals are implemented exactly the same way;
00535 //   i.e., there is are no resource factories to allow you to generate
00536 //   customer resources. I doubt that makes sense, anyway.
00537 //
00538 class LiteralImpl : public nsIRDFLiteral {
00539 public:
00540     static nsresult
00541     Create(const PRUnichar* aValue, nsIRDFLiteral** aResult);
00542 
00543     // nsISupports
00544     NS_DECL_ISUPPORTS
00545 
00546     // nsIRDFNode
00547     NS_DECL_NSIRDFNODE
00548 
00549     // nsIRDFLiteral
00550     NS_DECL_NSIRDFLITERAL
00551 
00552 protected:
00553     LiteralImpl(const PRUnichar* s);
00554     virtual ~LiteralImpl();
00555 
00556     const PRUnichar* GetValue() const {
00557         size_t objectSize = ((sizeof(LiteralImpl) + sizeof(PRUnichar) - 1) / sizeof(PRUnichar)) * sizeof(PRUnichar);
00558         return NS_REINTERPRET_CAST(const PRUnichar*, NS_REINTERPRET_CAST(const unsigned char*, this) + objectSize);
00559     }
00560 };
00561 
00562 
00563 nsresult
00564 LiteralImpl::Create(const PRUnichar* aValue, nsIRDFLiteral** aResult)
00565 {
00566     // Goofy math to get alignment right. Copied from nsSharedString.h.
00567     size_t objectSize = ((sizeof(LiteralImpl) + sizeof(PRUnichar) - 1) / sizeof(PRUnichar)) * sizeof(PRUnichar);
00568     size_t stringLen = nsCharTraits<PRUnichar>::length(aValue);
00569     size_t stringSize = (stringLen + 1) * sizeof(PRUnichar);
00570 
00571     void* objectPtr = operator new(objectSize + stringSize);
00572     if (! objectPtr)
00573         return NS_ERROR_NULL_POINTER;
00574 
00575     PRUnichar* buf = NS_REINTERPRET_CAST(PRUnichar*, NS_STATIC_CAST(unsigned char*, objectPtr) + objectSize);
00576     nsCharTraits<PRUnichar>::copy(buf, aValue, stringLen + 1);
00577 
00578     NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf));
00579     return NS_OK;
00580 }
00581 
00582 
00583 LiteralImpl::LiteralImpl(const PRUnichar* s)
00584 {
00585     gRDFService->RegisterLiteral(this);
00586     NS_ADDREF(gRDFService);
00587 }
00588 
00589 LiteralImpl::~LiteralImpl()
00590 {
00591     gRDFService->UnregisterLiteral(this);
00592 
00593     // Use NS_RELEASE2() here, because we want to decrease the
00594     // refcount, but not null out the gRDFService pointer (which is
00595     // what a vanilla NS_RELEASE() would do).
00596     nsrefcnt refcnt;
00597     NS_RELEASE2(gRDFService, refcnt);
00598 }
00599 
00600 NS_IMPL_THREADSAFE_ADDREF(LiteralImpl)
00601 NS_IMPL_THREADSAFE_RELEASE(LiteralImpl)
00602 
00603 nsresult
00604 LiteralImpl::QueryInterface(REFNSIID iid, void** result)
00605 {
00606     if (! result)
00607         return NS_ERROR_NULL_POINTER;
00608 
00609     *result = nsnull;
00610     if (iid.Equals(kIRDFLiteralIID) ||
00611         iid.Equals(kIRDFNodeIID) ||
00612         iid.Equals(kISupportsIID)) {
00613         *result = NS_STATIC_CAST(nsIRDFLiteral*, this);
00614         AddRef();
00615         return NS_OK;
00616     }
00617     return NS_NOINTERFACE;
00618 }
00619 
00620 NS_IMETHODIMP
00621 LiteralImpl::EqualsNode(nsIRDFNode* aNode, PRBool* aResult)
00622 {
00623     nsresult rv;
00624     nsIRDFLiteral* literal;
00625     rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal);
00626     if (NS_SUCCEEDED(rv)) {
00627         *aResult = (NS_STATIC_CAST(nsIRDFLiteral*, this) == literal);
00628         NS_RELEASE(literal);
00629         return NS_OK;
00630     }
00631     else if (rv == NS_NOINTERFACE) {
00632         *aResult = PR_FALSE;
00633         return NS_OK;
00634     }
00635     else {
00636         return rv;
00637     }
00638 }
00639 
00640 NS_IMETHODIMP
00641 LiteralImpl::GetValue(PRUnichar* *value)
00642 {
00643     NS_ASSERTION(value, "null ptr");
00644     if (! value)
00645         return NS_ERROR_NULL_POINTER;
00646 
00647     const PRUnichar *temp = GetValue();
00648     *value = temp? nsCRT::strdup(temp) : 0;
00649     return NS_OK;
00650 }
00651 
00652 
00653 NS_IMETHODIMP
00654 LiteralImpl::GetValueConst(const PRUnichar** aValue)
00655 {
00656     *aValue = GetValue();
00657     return NS_OK;
00658 }
00659 
00661 // DateImpl
00662 //
00663 
00664 class DateImpl : public nsIRDFDate {
00665 public:
00666     DateImpl(const PRTime s);
00667     virtual ~DateImpl();
00668 
00669     // nsISupports
00670     NS_DECL_ISUPPORTS
00671 
00672     // nsIRDFNode
00673     NS_DECL_NSIRDFNODE
00674 
00675     // nsIRDFDate
00676     NS_IMETHOD GetValue(PRTime *value);
00677 
00678 private:
00679     nsresult EqualsDate(nsIRDFDate* date, PRBool* result);
00680     PRTime mValue;
00681 };
00682 
00683 
00684 DateImpl::DateImpl(const PRTime s)
00685     : mValue(s)
00686 {
00687     gRDFService->RegisterDate(this);
00688     NS_ADDREF(gRDFService);
00689 }
00690 
00691 DateImpl::~DateImpl()
00692 {
00693     gRDFService->UnregisterDate(this);
00694 
00695     // Use NS_RELEASE2() here, because we want to decrease the
00696     // refcount, but not null out the gRDFService pointer (which is
00697     // what a vanilla NS_RELEASE() would do).
00698     nsrefcnt refcnt;
00699     NS_RELEASE2(gRDFService, refcnt);
00700 }
00701 
00702 NS_IMPL_ADDREF(DateImpl)
00703 NS_IMPL_RELEASE(DateImpl)
00704 
00705 nsresult
00706 DateImpl::QueryInterface(REFNSIID iid, void** result)
00707 {
00708     if (! result)
00709         return NS_ERROR_NULL_POINTER;
00710 
00711     *result = nsnull;
00712     if (iid.Equals(kIRDFDateIID) ||
00713         iid.Equals(kIRDFNodeIID) ||
00714         iid.Equals(kISupportsIID)) {
00715         *result = NS_STATIC_CAST(nsIRDFDate*, this);
00716         AddRef();
00717         return NS_OK;
00718     }
00719     return NS_NOINTERFACE;
00720 }
00721 
00722 NS_IMETHODIMP
00723 DateImpl::EqualsNode(nsIRDFNode* node, PRBool* result)
00724 {
00725     nsresult rv;
00726     nsIRDFDate* date;
00727     if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) {
00728         rv = EqualsDate(date, result);
00729         NS_RELEASE(date);
00730     }
00731     else {
00732         *result = PR_FALSE;
00733         rv = NS_OK;
00734     }
00735     return rv;
00736 }
00737 
00738 NS_IMETHODIMP
00739 DateImpl::GetValue(PRTime *value)
00740 {
00741     NS_ASSERTION(value, "null ptr");
00742     if (! value)
00743         return NS_ERROR_NULL_POINTER;
00744 
00745     *value = mValue;
00746     return NS_OK;
00747 }
00748 
00749 
00750 nsresult
00751 DateImpl::EqualsDate(nsIRDFDate* date, PRBool* result)
00752 {
00753     NS_ASSERTION(date && result, "null ptr");
00754     if (!date || !result)
00755         return NS_ERROR_NULL_POINTER;
00756 
00757     nsresult rv;
00758     PRTime p;
00759     if (NS_FAILED(rv = date->GetValue(&p)))
00760         return rv;
00761 
00762     *result = LL_EQ(p, mValue);
00763     return NS_OK;
00764 }
00765 
00767 // IntImpl
00768 //
00769 
00770 class IntImpl : public nsIRDFInt {
00771 public:
00772     IntImpl(PRInt32 s);
00773     virtual ~IntImpl();
00774 
00775     // nsISupports
00776     NS_DECL_ISUPPORTS
00777 
00778     // nsIRDFNode
00779     NS_DECL_NSIRDFNODE
00780 
00781     // nsIRDFInt
00782     NS_IMETHOD GetValue(PRInt32 *value);
00783 
00784 private:
00785     nsresult EqualsInt(nsIRDFInt* value, PRBool* result);
00786     PRInt32 mValue;
00787 };
00788 
00789 
00790 IntImpl::IntImpl(PRInt32 s)
00791     : mValue(s)
00792 {
00793     gRDFService->RegisterInt(this);
00794     NS_ADDREF(gRDFService);
00795 }
00796 
00797 IntImpl::~IntImpl()
00798 {
00799     gRDFService->UnregisterInt(this);
00800 
00801     // Use NS_RELEASE2() here, because we want to decrease the
00802     // refcount, but not null out the gRDFService pointer (which is
00803     // what a vanilla NS_RELEASE() would do).
00804     nsrefcnt refcnt;
00805     NS_RELEASE2(gRDFService, refcnt);
00806 }
00807 
00808 NS_IMPL_ADDREF(IntImpl)
00809 NS_IMPL_RELEASE(IntImpl)
00810 
00811 nsresult
00812 IntImpl::QueryInterface(REFNSIID iid, void** result)
00813 {
00814     if (! result)
00815         return NS_ERROR_NULL_POINTER;
00816 
00817     *result = nsnull;
00818     if (iid.Equals(kIRDFIntIID) ||
00819         iid.Equals(kIRDFNodeIID) ||
00820         iid.Equals(kISupportsIID)) {
00821         *result = NS_STATIC_CAST(nsIRDFInt*, this);
00822         AddRef();
00823         return NS_OK;
00824     }
00825     return NS_NOINTERFACE;
00826 }
00827 
00828 NS_IMETHODIMP
00829 IntImpl::EqualsNode(nsIRDFNode* node, PRBool* result)
00830 {
00831     nsresult rv;
00832     nsIRDFInt* intValue;
00833     if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) {
00834         rv = EqualsInt(intValue, result);
00835         NS_RELEASE(intValue);
00836     }
00837     else {
00838         *result = PR_FALSE;
00839         rv = NS_OK;
00840     }
00841     return rv;
00842 }
00843 
00844 NS_IMETHODIMP
00845 IntImpl::GetValue(PRInt32 *value)
00846 {
00847     NS_ASSERTION(value, "null ptr");
00848     if (! value)
00849         return NS_ERROR_NULL_POINTER;
00850 
00851     *value = mValue;
00852     return NS_OK;
00853 }
00854 
00855 
00856 nsresult
00857 IntImpl::EqualsInt(nsIRDFInt* intValue, PRBool* result)
00858 {
00859     NS_ASSERTION(intValue && result, "null ptr");
00860     if (!intValue || !result)
00861         return NS_ERROR_NULL_POINTER;
00862 
00863     nsresult rv;
00864     PRInt32 p;
00865     if (NS_FAILED(rv = intValue->GetValue(&p)))
00866         return rv;
00867 
00868     *result = (p == mValue);
00869     return NS_OK;
00870 }
00871 
00873 // RDFServiceImpl
00874 
00875 RDFServiceImpl::RDFServiceImpl()
00876     :  mNamedDataSources(nsnull)
00877 {
00878     mResources.ops = nsnull;
00879     mLiterals.ops = nsnull;
00880     mInts.ops = nsnull;
00881     mDates.ops = nsnull;
00882     mBlobs.ops = nsnull;
00883 }
00884 
00885 nsresult
00886 RDFServiceImpl::Init()
00887 {
00888     nsresult rv;
00889 
00890     mNamedDataSources = PL_NewHashTable(23,
00891                                         PL_HashString,
00892                                         PL_CompareStrings,
00893                                         PL_CompareValues,
00894                                         &dataSourceHashAllocOps, nsnull);
00895 
00896     if (! mNamedDataSources)
00897         return NS_ERROR_OUT_OF_MEMORY;
00898 
00899     if (!PL_DHashTableInit(&mResources, &gResourceTableOps, nsnull,
00900                            sizeof(ResourceHashEntry), PL_DHASH_MIN_SIZE)) {
00901         mResources.ops = nsnull;
00902         return NS_ERROR_OUT_OF_MEMORY;
00903     }
00904     if (!PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nsnull,
00905                            sizeof(LiteralHashEntry), PL_DHASH_MIN_SIZE)) {
00906         mLiterals.ops = nsnull;
00907         return NS_ERROR_OUT_OF_MEMORY;
00908     }
00909     if (!PL_DHashTableInit(&mInts, &gIntTableOps, nsnull,
00910                            sizeof(IntHashEntry), PL_DHASH_MIN_SIZE)) {
00911         mInts.ops = nsnull;
00912         return NS_ERROR_OUT_OF_MEMORY;
00913     }
00914     if (!PL_DHashTableInit(&mDates, &gDateTableOps, nsnull,
00915                            sizeof(DateHashEntry), PL_DHASH_MIN_SIZE)) {
00916         mDates.ops = nsnull;
00917         return NS_ERROR_OUT_OF_MEMORY;
00918     }
00919     if (!PL_DHashTableInit(&mBlobs, &gBlobTableOps, nsnull,
00920                            sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE)) {
00921         mBlobs.ops = nsnull;
00922         return NS_ERROR_OUT_OF_MEMORY;
00923     }
00924     mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv);
00925     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory");
00926     if (NS_FAILED(rv)) return rv;
00927 
00928 #ifdef PR_LOGGING
00929     if (! gLog)
00930         gLog = PR_NewLogModule("nsRDFService");
00931 #endif
00932 
00933     return NS_OK;
00934 }
00935 
00936 
00937 RDFServiceImpl::~RDFServiceImpl()
00938 {
00939     if (mNamedDataSources) {
00940         PL_HashTableDestroy(mNamedDataSources);
00941         mNamedDataSources = nsnull;
00942     }
00943     if (mResources.ops)
00944         PL_DHashTableFinish(&mResources);
00945     if (mLiterals.ops)
00946         PL_DHashTableFinish(&mLiterals);
00947     if (mInts.ops)
00948         PL_DHashTableFinish(&mInts);
00949     if (mDates.ops)
00950         PL_DHashTableFinish(&mDates);
00951     if (mBlobs.ops)
00952         PL_DHashTableFinish(&mBlobs);
00953     gRDFService = nsnull;
00954 }
00955 
00956 
00957 nsresult
00958 RDFServiceImpl::GetRDFService(nsIRDFService** mgr)
00959 {
00960     if (! gRDFService) {
00961         RDFServiceImpl* serv = new RDFServiceImpl();
00962         if (! serv)
00963             return NS_ERROR_OUT_OF_MEMORY;
00964 
00965         nsresult rv;
00966         rv = serv->Init();
00967         if (NS_FAILED(rv)) {
00968             delete serv;
00969             return rv;
00970         }
00971 
00972         gRDFService = serv;
00973     }
00974 
00975     NS_ADDREF(gRDFService);
00976     *mgr = gRDFService;
00977     return NS_OK;
00978 }
00979 
00980 NS_IMPL_THREADSAFE_ISUPPORTS2(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference)
00981 
00982 // Per RFC2396.
00983 static const PRUint8
00984 kLegalSchemeChars[] = {
00985           //        ASCII    Bits     Ordered  Hex
00986           //                 01234567 76543210
00987     0x00, // 00-07
00988     0x00, // 08-0F
00989     0x00, // 10-17
00990     0x00, // 18-1F
00991     0x00, // 20-27   !"#$%&' 00000000 00000000
00992     0x28, // 28-2F  ()*+,-./ 00010100 00101000 0x28
00993     0xff, // 30-37  01234567 11111111 11111111 0xFF
00994     0x03, // 38-3F  89:;<=>? 11000000 00000011 0x03
00995     0xfe, // 40-47  @ABCDEFG 01111111 11111110 0xFE
00996     0xff, // 48-4F  HIJKLMNO 11111111 11111111 0xFF
00997     0xff, // 50-57  PQRSTUVW 11111111 11111111 0xFF
00998     0x87, // 58-5F  XYZ[\]^_ 11100001 10000111 0x87
00999     0xfe, // 60-67  `abcdefg 01111111 11111110 0xFE
01000     0xff, // 68-6F  hijklmno 11111111 11111111 0xFF
01001     0xff, // 70-77  pqrstuvw 11111111 11111111 0xFF
01002     0x07, // 78-7F  xyz{|}~  11100000 00000111 0x07
01003     0x00, 0x00, 0x00, 0x00, // >= 80
01004     0x00, 0x00, 0x00, 0x00,
01005     0x00, 0x00, 0x00, 0x00,
01006     0x00, 0x00, 0x00, 0x00
01007 };
01008 
01009 static inline PRBool
01010 IsLegalSchemeCharacter(const char aChar)
01011 {
01012     PRUint8 mask = kLegalSchemeChars[aChar >> 3];
01013     PRUint8 bit = PR_BIT(aChar & 0x7);
01014     return PRBool((mask & bit) != 0);
01015 }
01016 
01017 
01018 NS_IMETHODIMP
01019 RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource)
01020 {
01021     // Sanity checks
01022     NS_PRECONDITION(aResource != nsnull, "null ptr");
01023     NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty");
01024     if (! aResource)
01025         return NS_ERROR_NULL_POINTER;
01026     if (aURI.IsEmpty())
01027         return NS_ERROR_INVALID_ARG;
01028 
01029     const nsAFlatCString& flatURI = PromiseFlatCString(aURI);
01030     PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get()));
01031 
01032     // First, check the cache to see if we've already created and
01033     // registered this thing.
01034     PLDHashEntryHdr *hdr =
01035         PL_DHashTableOperate(&mResources, flatURI.get(), PL_DHASH_LOOKUP);
01036 
01037     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01038         ResourceHashEntry *entry = NS_STATIC_CAST(ResourceHashEntry *, hdr);
01039         NS_ADDREF(*aResource = entry->mResource);
01040         return NS_OK;
01041     }
01042 
01043     // Nope. So go to the repository to create it.
01044 
01045     // Compute the scheme of the URI. Scan forward until we either:
01046     //
01047     // 1. Reach the end of the string
01048     // 2. Encounter a non-alpha character
01049     // 3. Encouter a colon.
01050     //
01051     // If we encounter a colon _before_ encountering a non-alpha
01052     // character, then assume it's the scheme.
01053     //
01054     // XXX Although it's really not correct, we'll allow underscore
01055     // characters ('_'), too.
01056     nsACString::const_iterator p, end;
01057     aURI.BeginReading(p);
01058     aURI.EndReading(end);
01059     while (p != end && IsLegalSchemeCharacter(*p))
01060         ++p;
01061 
01062     nsresult rv;
01063     nsCOMPtr<nsIFactory> factory;
01064 
01065     nsACString::const_iterator begin;
01066     aURI.BeginReading(begin);
01067     if (*p == ':') {
01068         // There _was_ a scheme. First see if it's the same scheme
01069         // that we just tried to use...
01070         if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p)))
01071             factory = mLastFactory;
01072         else {
01073             // Try to find a factory using the component manager.
01074             nsACString::const_iterator begin;
01075             aURI.BeginReading(begin);
01076             nsCAutoString contractID;
01077             contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) +
01078                          Substring(begin, p);
01079 
01080             factory = do_GetClassObject(contractID.get());
01081             if (factory) {
01082                 // Store the factory in our one-element cache.
01083                 if (p != begin) {
01084                     mLastFactory = factory;
01085                     mLastURIPrefix = Substring(begin, p);
01086                 }
01087             }
01088         }
01089     }
01090 
01091     if (! factory) {
01092         // fall through to using the "default" resource factory if either:
01093         //
01094         // 1. The URI didn't have a scheme, or
01095         // 2. There was no resource factory registered for the scheme.
01096         factory = mDefaultResourceFactory;
01097 
01098         // Store the factory in our one-element cache.
01099         if (p != begin) {
01100             mLastFactory = factory;
01101             mLastURIPrefix = Substring(begin, p);
01102         }
01103     }
01104 
01105     nsIRDFResource *result;
01106     rv = factory->CreateInstance(nsnull, NS_GET_IID(nsIRDFResource), (void**) &result);
01107     if (NS_FAILED(rv)) return rv;
01108 
01109     // Now initialize it with it's URI. At this point, the resource
01110     // implementation should register itself with the RDF service.
01111     rv = result->Init(flatURI.get());
01112     if (NS_FAILED(rv)) {
01113         NS_ERROR("unable to initialize resource");
01114         NS_RELEASE(result);
01115         return rv;
01116     }
01117 
01118     *aResource = result; // already refcounted from repository
01119     return rv;
01120 }
01121 
01122 NS_IMETHODIMP
01123 RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource)
01124 {
01125     return GetResource(NS_ConvertUCS2toUTF8(aURI), aResource);
01126 }
01127 
01128 
01129 NS_IMETHODIMP
01130 RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult)
01131 {
01132 static PRUint32 gCounter = 0;
01133 static char gChars[] = "0123456789abcdef"
01134                        "ghijklmnopqrstuv"
01135                        "wxyzABCDEFGHIJKL"
01136                        "MNOPQRSTUVWXYZ.+";
01137 
01138 static PRInt32 kMask  = 0x003f;
01139 static PRInt32 kShift = 6;
01140 
01141     if (! gCounter) {
01142         // Start it at a semi-unique value, just to minimize the
01143         // chance that we get into a situation where
01144         //
01145         // 1. An anonymous resource gets serialized out in a graph
01146         // 2. Reboot
01147         // 3. The same anonymous resource gets requested, and refers
01148         //    to something completely different.
01149         // 4. The serialization is read back in.
01150         LL_L2UI(gCounter, PR_Now());
01151     }
01152 
01153     nsresult rv;
01154     nsCAutoString s;
01155 
01156     do {
01157         // Ugh, this is a really sloppy way to do this; I copied the
01158         // implementation from the days when it lived outside the RDF
01159         // service. Now that it's a member we can be more cleverer.
01160 
01161         s.Truncate();
01162         s.Append("rdf:#$");
01163 
01164         PRUint32 id = ++gCounter;
01165         while (id) {
01166             char ch = gChars[(id & kMask)];
01167             s.Append(ch);
01168             id >>= kShift;
01169         }
01170 
01171         nsIRDFResource* resource;
01172         rv = GetResource(s, &resource);
01173         if (NS_FAILED(rv)) return rv;
01174 
01175         // XXX an ugly but effective way to make sure that this
01176         // resource is really unique in the world.
01177         resource->AddRef();
01178         nsrefcnt refcnt = resource->Release();
01179 
01180         if (refcnt == 1) {
01181             *aResult = resource;
01182             break;
01183         }
01184 
01185         NS_RELEASE(resource);
01186     } while (1);
01187 
01188     return NS_OK;
01189 }
01190 
01191 
01192 NS_IMETHODIMP
01193 RDFServiceImpl::GetLiteral(const PRUnichar* aValue, nsIRDFLiteral** aLiteral)
01194 {
01195     NS_PRECONDITION(aValue != nsnull, "null ptr");
01196     if (! aValue)
01197         return NS_ERROR_NULL_POINTER;
01198 
01199     NS_PRECONDITION(aLiteral != nsnull, "null ptr");
01200     if (! aLiteral)
01201         return NS_ERROR_NULL_POINTER;
01202 
01203     // See if we have one already cached
01204     PLDHashEntryHdr *hdr =
01205         PL_DHashTableOperate(&mLiterals, aValue, PL_DHASH_LOOKUP);
01206 
01207     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01208         LiteralHashEntry *entry = NS_STATIC_CAST(LiteralHashEntry *, hdr);
01209         NS_ADDREF(*aLiteral = entry->mLiteral);
01210         return NS_OK;
01211     }
01212 
01213     // Nope. Create a new one
01214     return LiteralImpl::Create(aValue, aLiteral);
01215 }
01216 
01217 NS_IMETHODIMP
01218 RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult)
01219 {
01220     // See if we have one already cached
01221     PLDHashEntryHdr *hdr =
01222         PL_DHashTableOperate(&mDates, &aTime, PL_DHASH_LOOKUP);
01223 
01224     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01225         DateHashEntry *entry = NS_STATIC_CAST(DateHashEntry *, hdr);
01226         NS_ADDREF(*aResult = entry->mDate);
01227         return NS_OK;
01228     }
01229 
01230     DateImpl* result = new DateImpl(aTime);
01231     if (! result)
01232         return NS_ERROR_OUT_OF_MEMORY;
01233 
01234     NS_ADDREF(*aResult = result);
01235     return NS_OK;
01236 }
01237 
01238 NS_IMETHODIMP
01239 RDFServiceImpl::GetIntLiteral(PRInt32 aInt, nsIRDFInt** aResult)
01240 {
01241     // See if we have one already cached
01242     PLDHashEntryHdr *hdr =
01243         PL_DHashTableOperate(&mInts, &aInt, PL_DHASH_LOOKUP);
01244 
01245     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01246         IntHashEntry *entry = NS_STATIC_CAST(IntHashEntry *, hdr);
01247         NS_ADDREF(*aResult = entry->mInt);
01248         return NS_OK;
01249     }
01250 
01251     IntImpl* result = new IntImpl(aInt);
01252     if (! result)
01253         return NS_ERROR_OUT_OF_MEMORY;
01254 
01255     NS_ADDREF(*aResult = result);
01256     return NS_OK;
01257 }
01258 
01259 NS_IMETHODIMP
01260 RDFServiceImpl::GetBlobLiteral(const PRUint8 *aBytes, PRInt32 aLength,
01261                                nsIRDFBlob **aResult)
01262 {
01263     BlobImpl::Data key = { aLength, NS_CONST_CAST(PRUint8 *, aBytes) };
01264 
01265     PLDHashEntryHdr *hdr =
01266         PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP);
01267 
01268     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01269         BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr);
01270         NS_ADDREF(*aResult = entry->mBlob);
01271         return NS_OK;
01272     }
01273 
01274     BlobImpl *result = new BlobImpl(aBytes, aLength);
01275     if (! result)
01276         return NS_ERROR_OUT_OF_MEMORY;
01277 
01278     NS_ADDREF(*aResult = result);
01279     return NS_OK;
01280 }
01281 
01282 NS_IMETHODIMP
01283 RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, PRBool* _result)
01284 {
01285     NS_PRECONDITION(aResource != nsnull, "null ptr");
01286     if (! aResource)
01287         return NS_ERROR_NULL_POINTER;
01288 
01289     nsresult rv;
01290 
01291     const char* uri;
01292     rv = aResource->GetValueConst(&uri);
01293     if (NS_FAILED(rv)) return rv;
01294 
01295     if ((uri[0] == 'r') &&
01296         (uri[1] == 'd') &&
01297         (uri[2] == 'f') &&
01298         (uri[3] == ':') &&
01299         (uri[4] == '#') &&
01300         (uri[5] == '$')) {
01301         *_result = PR_TRUE;
01302     }
01303     else {
01304         *_result = PR_FALSE;
01305     }
01306 
01307     return NS_OK;
01308 }
01309 
01310 NS_IMETHODIMP
01311 RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, PRBool aReplace)
01312 {
01313     NS_PRECONDITION(aResource != nsnull, "null ptr");
01314     if (! aResource)
01315         return NS_ERROR_NULL_POINTER;
01316 
01317     nsresult rv;
01318 
01319     const char* uri;
01320     rv = aResource->GetValueConst(&uri);
01321     NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource");
01322     if (NS_FAILED(rv)) return rv;
01323 
01324     NS_ASSERTION(uri != nsnull, "resource has no URI");
01325     if (! uri)
01326         return NS_ERROR_NULL_POINTER;
01327 
01328     PLDHashEntryHdr *hdr =
01329         PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP);
01330 
01331     if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
01332         if (!aReplace) {
01333             NS_WARNING("resource already registered, and replace not specified");
01334             return NS_ERROR_FAILURE;    // already registered
01335         }
01336 
01337         // N.B., we do _not_ release the original resource because we
01338         // only ever held a weak reference to it. We simply replace
01339         // it.
01340 
01341         PR_LOG(gLog, PR_LOG_DEBUG,
01342                ("rdfserv   replace-resource [%p] <-- [%p] %s",
01343                 NS_STATIC_CAST(ResourceHashEntry *, hdr)->mResource,
01344                 aResource, (const char*) uri));
01345     }
01346     else {
01347         hdr = PL_DHashTableOperate(&mResources, uri, PL_DHASH_ADD);
01348         if (! hdr)
01349             return NS_ERROR_OUT_OF_MEMORY;
01350 
01351         PR_LOG(gLog, PR_LOG_DEBUG,
01352                ("rdfserv   register-resource [%p] %s",
01353                 aResource, (const char*) uri));
01354     }
01355 
01356     // N.B., we only hold a weak reference to the resource: that way,
01357     // the resource can be destroyed when the last refcount goes
01358     // away. The single addref that the CreateResource() call made
01359     // will be owned by the callee.
01360     ResourceHashEntry *entry = NS_STATIC_CAST(ResourceHashEntry *, hdr);
01361     entry->mResource = aResource;
01362     entry->mKey = uri;
01363 
01364     return NS_OK;
01365 }
01366 
01367 NS_IMETHODIMP
01368 RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource)
01369 {
01370     NS_PRECONDITION(aResource != nsnull, "null ptr");
01371     if (! aResource)
01372         return NS_ERROR_NULL_POINTER;
01373 
01374     nsresult rv;
01375 
01376     const char* uri;
01377     rv = aResource->GetValueConst(&uri);
01378     if (NS_FAILED(rv)) return rv;
01379 
01380     NS_ASSERTION(uri != nsnull, "resource has no URI");
01381     if (! uri)
01382         return NS_ERROR_UNEXPECTED;
01383 
01384     PR_LOG(gLog, PR_LOG_DEBUG,
01385            ("rdfserv unregister-resource [%p] %s",
01386             aResource, (const char*) uri));
01387 
01388 #ifdef DEBUG
01389     if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP)))
01390         NS_WARNING("resource was never registered");
01391 #endif
01392 
01393     PL_DHashTableOperate(&mResources, uri, PL_DHASH_REMOVE);
01394     return NS_OK;
01395 }
01396 
01397 NS_IMETHODIMP
01398 RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, PRBool aReplace)
01399 {
01400     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
01401     if (! aDataSource)
01402         return NS_ERROR_NULL_POINTER;
01403 
01404     nsresult rv;
01405 
01406     nsXPIDLCString uri;
01407     rv = aDataSource->GetURI(getter_Copies(uri));
01408     if (NS_FAILED(rv)) return rv;
01409 
01410     PLHashEntry** hep =
01411         PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
01412 
01413     if (*hep) {
01414         if (! aReplace)
01415             return NS_ERROR_FAILURE; // already registered
01416 
01417         // N.B., we only hold a weak reference to the datasource, so
01418         // just replace the old with the new and don't touch any
01419         // refcounts.
01420         PR_LOG(gLog, PR_LOG_NOTICE,
01421                ("rdfserv    replace-datasource [%p] <-- [%p] %s",
01422                 (*hep)->value, aDataSource, (const char*) uri));
01423 
01424         (*hep)->value = aDataSource;
01425     }
01426     else {
01427         const char* key = PL_strdup(uri);
01428         if (! key)
01429             return NS_ERROR_OUT_OF_MEMORY;
01430 
01431         PL_HashTableAdd(mNamedDataSources, key, aDataSource);
01432 
01433         PR_LOG(gLog, PR_LOG_NOTICE,
01434                ("rdfserv   register-datasource [%p] %s",
01435                 aDataSource, (const char*) uri));
01436 
01437         // N.B., we only hold a weak reference to the datasource, so don't
01438         // addref.
01439     }
01440 
01441     return NS_OK;
01442 }
01443 
01444 NS_IMETHODIMP
01445 RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource)
01446 {
01447     NS_PRECONDITION(aDataSource != nsnull, "null ptr");
01448     if (! aDataSource)
01449         return NS_ERROR_NULL_POINTER;
01450 
01451     nsresult rv;
01452 
01453     nsXPIDLCString uri;
01454     rv = aDataSource->GetURI(getter_Copies(uri));
01455     if (NS_FAILED(rv)) return rv;
01456 
01457     //NS_ASSERTION(uri != nsnull, "datasource has no URI");
01458     if (! uri)
01459         return NS_ERROR_UNEXPECTED;
01460 
01461     PLHashEntry** hep =
01462         PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
01463 
01464     // It may well be that this datasource was never registered. If
01465     // so, don't unregister it.
01466     if (! *hep || ((*hep)->value != aDataSource))
01467         return NS_OK;
01468 
01469     // N.B., we only held a weak reference to the datasource, so we
01470     // don't release here.
01471     PL_HashTableRawRemove(mNamedDataSources, hep, *hep);
01472 
01473     PR_LOG(gLog, PR_LOG_NOTICE,
01474            ("rdfserv unregister-datasource [%p] %s",
01475             aDataSource, (const char*) uri));
01476 
01477     return NS_OK;
01478 }
01479 
01480 NS_IMETHODIMP
01481 RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource)
01482 {
01483     // Use the other GetDataSource and ask for a non-blocking Refresh.
01484     // If you wanted it loaded synchronously, then you should've tried to do it
01485     // yourself, or used GetDataSourceBlocking.
01486     return GetDataSource( aURI, PR_FALSE, aDataSource );
01487 }
01488 
01489 NS_IMETHODIMP
01490 RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource)
01491 {
01492     // Use GetDataSource and ask for a blocking Refresh.
01493     return GetDataSource( aURI, PR_TRUE, aDataSource );
01494 }
01495 
01496 nsresult
01497 RDFServiceImpl::GetDataSource(const char* aURI, PRBool aBlock, nsIRDFDataSource** aDataSource)
01498 {
01499     NS_PRECONDITION(aURI != nsnull, "null ptr");
01500     if (! aURI)
01501         return NS_ERROR_NULL_POINTER;
01502 
01503     nsresult rv;
01504 
01505     // Attempt to canonify the URI before we look for it in the
01506     // cache. We won't bother doing this on `rdf:' URIs to avoid
01507     // useless (and expensive) protocol handler lookups.
01508     nsCAutoString spec(aURI);
01509 
01510     if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
01511         nsCOMPtr<nsIURI> uri;
01512         NS_NewURI(getter_AddRefs(uri), spec);
01513         if (uri)
01514             uri->GetSpec(spec);
01515     }
01516 
01517     // First, check the cache to see if we already have this
01518     // datasource loaded and initialized.
01519     {
01520         nsIRDFDataSource* cached =
01521             NS_STATIC_CAST(nsIRDFDataSource*, PL_HashTableLookup(mNamedDataSources, spec.get()));
01522 
01523         if (cached) {
01524             NS_ADDREF(cached);
01525             *aDataSource = cached;
01526             return NS_OK;
01527         }
01528     }
01529 
01530     // Nope. So go to the repository to try to create it.
01531     nsCOMPtr<nsIRDFDataSource> ds;
01532     if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
01533         // It's a built-in data source. Convert it to a contract ID.
01534         nsCAutoString contractID(
01535                 NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) +
01536                 Substring(spec, 4, spec.Length() - 4));
01537 
01538         // Strip params to get ``base'' contractID for data source.
01539         PRInt32 p = contractID.FindChar(PRUnichar('&'));
01540         if (p >= 0)
01541             contractID.Truncate(p);
01542 
01543         ds = do_GetService(contractID.get(), &rv);
01544         if (NS_FAILED(rv)) return rv;
01545 
01546         nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(ds);
01547         if (remote) {
01548             rv = remote->Init(spec.get());
01549             if (NS_FAILED(rv)) return rv;
01550         }
01551     }
01552     else {
01553         // Try to load this as an RDF/XML data source
01554         ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv);
01555         if (NS_FAILED(rv)) return rv;
01556 
01557         nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(ds));
01558         NS_ASSERTION(remote, "not a remote RDF/XML data source!");
01559         if (! remote) return NS_ERROR_UNEXPECTED;
01560 
01561         rv = remote->Init(spec.get());
01562         if (NS_FAILED(rv)) return rv;
01563 
01564         rv = remote->Refresh(aBlock);
01565         if (NS_FAILED(rv)) return rv;
01566     }
01567 
01568     *aDataSource = ds;
01569     NS_ADDREF(*aDataSource);
01570     return NS_OK;
01571 }
01572 
01574 
01575 nsresult
01576 RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral)
01577 {
01578     const PRUnichar* value;
01579     aLiteral->GetValueConst(&value);
01580 
01581     NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals,
01582                                                              value,
01583                                                              PL_DHASH_LOOKUP)),
01584                  "literal already registered");
01585 
01586     PLDHashEntryHdr *hdr =
01587         PL_DHashTableOperate(&mLiterals, value, PL_DHASH_ADD);
01588 
01589     if (! hdr)
01590         return NS_ERROR_OUT_OF_MEMORY;
01591 
01592     LiteralHashEntry *entry = NS_STATIC_CAST(LiteralHashEntry *, hdr);
01593 
01594     // N.B., we only hold a weak reference to the literal: that
01595     // way, the literal can be destroyed when the last refcount
01596     // goes away. The single addref that the CreateLiteral() call
01597     // made will be owned by the callee.
01598     entry->mLiteral = aLiteral;
01599     entry->mKey = value;
01600 
01601     PR_LOG(gLog, PR_LOG_DEBUG,
01602            ("rdfserv   register-literal [%p] %s",
01603             aLiteral, (const PRUnichar*) value));
01604 
01605     return NS_OK;
01606 }
01607 
01608 
01609 nsresult
01610 RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral)
01611 {
01612     const PRUnichar* value;
01613     aLiteral->GetValueConst(&value);
01614 
01615     NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals,
01616                                                              value,
01617                                                              PL_DHASH_LOOKUP)),
01618                  "literal was never registered");
01619 
01620     PL_DHashTableOperate(&mLiterals, value, PL_DHASH_REMOVE);
01621 
01622     // N.B. that we _don't_ release the literal: we only held a weak
01623     // reference to it in the hashtable.
01624     PR_LOG(gLog, PR_LOG_DEBUG,
01625            ("rdfserv unregister-literal [%p] %s",
01626             aLiteral, (const PRUnichar*) value));
01627 
01628     return NS_OK;
01629 }
01630 
01631 //----------------------------------------------------------------------
01632 
01633 nsresult
01634 RDFServiceImpl::RegisterInt(nsIRDFInt* aInt)
01635 {
01636     PRInt32 value;
01637     aInt->GetValue(&value);
01638 
01639     NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts,
01640                                                              &value,
01641                                                              PL_DHASH_LOOKUP)),
01642                  "int already registered");
01643 
01644     PLDHashEntryHdr *hdr =
01645         PL_DHashTableOperate(&mInts, &value, PL_DHASH_ADD);
01646 
01647     if (! hdr)
01648         return NS_ERROR_OUT_OF_MEMORY;
01649 
01650     IntHashEntry *entry = NS_STATIC_CAST(IntHashEntry *, hdr);
01651 
01652     // N.B., we only hold a weak reference to the literal: that
01653     // way, the literal can be destroyed when the last refcount
01654     // goes away. The single addref that the CreateInt() call
01655     // made will be owned by the callee.
01656     entry->mInt = aInt;
01657     entry->mKey = value;
01658 
01659     PR_LOG(gLog, PR_LOG_DEBUG,
01660            ("rdfserv   register-int [%p] %d",
01661             aInt, value));
01662 
01663     return NS_OK;
01664 }
01665 
01666 
01667 nsresult
01668 RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt)
01669 {
01670     PRInt32 value;
01671     aInt->GetValue(&value);
01672 
01673     NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts,
01674                                                              &value,
01675                                                              PL_DHASH_LOOKUP)),
01676                  "int was never registered");
01677 
01678     PL_DHashTableOperate(&mInts, &value, PL_DHASH_REMOVE);
01679 
01680     // N.B. that we _don't_ release the literal: we only held a weak
01681     // reference to it in the hashtable.
01682     PR_LOG(gLog, PR_LOG_DEBUG,
01683            ("rdfserv unregister-int [%p] %d",
01684             aInt, value));
01685 
01686     return NS_OK;
01687 }
01688 
01689 //----------------------------------------------------------------------
01690 
01691 nsresult
01692 RDFServiceImpl::RegisterDate(nsIRDFDate* aDate)
01693 {
01694     PRTime value;
01695     aDate->GetValue(&value);
01696 
01697     NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates,
01698                                                              &value,
01699                                                              PL_DHASH_LOOKUP)),
01700                  "date already registered");
01701 
01702     PLDHashEntryHdr *hdr =
01703         PL_DHashTableOperate(&mDates, &value, PL_DHASH_ADD);
01704 
01705     if (! hdr)
01706         return NS_ERROR_OUT_OF_MEMORY;
01707 
01708     DateHashEntry *entry = NS_STATIC_CAST(DateHashEntry *, hdr);
01709 
01710     // N.B., we only hold a weak reference to the literal: that
01711     // way, the literal can be destroyed when the last refcount
01712     // goes away. The single addref that the CreateDate() call
01713     // made will be owned by the callee.
01714     entry->mDate = aDate;
01715     entry->mKey = value;
01716 
01717     PR_LOG(gLog, PR_LOG_DEBUG,
01718            ("rdfserv   register-date [%p] %ld",
01719             aDate, value));
01720 
01721     return NS_OK;
01722 }
01723 
01724 
01725 nsresult
01726 RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate)
01727 {
01728     PRTime value;
01729     aDate->GetValue(&value);
01730 
01731     NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates,
01732                                                              &value,
01733                                                              PL_DHASH_LOOKUP)),
01734                  "date was never registered");
01735 
01736     PL_DHashTableOperate(&mDates, &value, PL_DHASH_REMOVE);
01737 
01738     // N.B. that we _don't_ release the literal: we only held a weak
01739     // reference to it in the hashtable.
01740     PR_LOG(gLog, PR_LOG_DEBUG,
01741            ("rdfserv unregister-date [%p] %ld",
01742             aDate, value));
01743 
01744     return NS_OK;
01745 }
01746 
01747 nsresult
01748 RDFServiceImpl::RegisterBlob(BlobImpl *aBlob)
01749 {
01750     NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs,
01751                                                              &aBlob->mData,
01752                                                              PL_DHASH_LOOKUP)),
01753                  "blob already registered");
01754 
01755     PLDHashEntryHdr *hdr = 
01756         PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD);
01757 
01758     if (! hdr)
01759         return NS_ERROR_OUT_OF_MEMORY;
01760 
01761     BlobHashEntry *entry = NS_STATIC_CAST(BlobHashEntry *, hdr);
01762 
01763     // N.B., we only hold a weak reference to the literal: that
01764     // way, the literal can be destroyed when the last refcount
01765     // goes away. The single addref that the CreateInt() call
01766     // made will be owned by the callee.
01767     entry->mBlob = aBlob;
01768 
01769     PR_LOG(gLog, PR_LOG_DEBUG,
01770            ("rdfserv   register-blob [%p] %s",
01771             aBlob, aBlob->mData.mBytes));
01772 
01773     return NS_OK;
01774 }
01775 
01776 nsresult
01777 RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob)
01778 {
01779     NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs,
01780                                                              &aBlob->mData,
01781                                                              PL_DHASH_LOOKUP)),
01782                  "blob was never registered");
01783 
01784     PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE);
01785  
01786      // N.B. that we _don't_ release the literal: we only held a weak
01787      // reference to it in the hashtable.
01788     PR_LOG(gLog, PR_LOG_DEBUG,
01789            ("rdfserv unregister-blob [%p] %s",
01790             aBlob, aBlob->mData.mBytes));
01791 
01792     return NS_OK;
01793 }
01794 
01796 
01797 nsresult
01798 NS_NewRDFService(nsIRDFService** mgr)
01799 {
01800     return RDFServiceImpl::GetRDFService(mgr);
01801 }