1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
23 : * Contributor(s):
24 : * Benjamin Smedberg <benjamin@smedbergs.us>
25 : *
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.
37 : *
38 : * ***** END LICENSE BLOCK *****
39 : *
40 : *
41 : * This Original Code has been modified by IBM Corporation.
42 : * Modifications made by IBM described herein are
43 : * Copyright (c) International Business Machines
44 : * Corporation, 2000
45 : *
46 : * Modifications to Mozilla code or documentation
47 : * identified per MPL Section 3.3
48 : *
49 : * Date Modified by Description of modification
50 : * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
51 : * use in OS2
52 : */
53 :
54 : /*
55 :
56 : This file provides the implementation for the RDF service manager.
57 :
58 : TO DO
59 : -----
60 :
61 : 1) Implement the CreateDataBase() methods.
62 :
63 : 2) Cache date and int literals.
64 :
65 : */
66 :
67 : #include "nsRDFService.h"
68 : #include "nsCOMPtr.h"
69 : #include "nsAutoPtr.h"
70 : #include "nsMemory.h"
71 : #include "nsIAtom.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"
78 : #include "nsRDFCID.h"
79 : #include "nsString.h"
80 : #include "nsXPIDLString.h"
81 : #include "nsNetUtil.h"
82 : #include "pldhash.h"
83 : #include "plhash.h"
84 : #include "plstr.h"
85 : #include "prlog.h"
86 : #include "prprf.h"
87 : #include "prmem.h"
88 : #include "rdf.h"
89 : #include "nsCRT.h"
90 : #include "nsCRTGlue.h"
91 : #include "prbit.h"
92 : #include "mozilla/HashFunctions.h"
93 :
94 : using namespace mozilla;
95 :
96 : ////////////////////////////////////////////////////////////////////////
97 :
98 : static NS_DEFINE_CID(kRDFXMLDataSourceCID, NS_RDFXMLDATASOURCE_CID);
99 : static NS_DEFINE_CID(kRDFDefaultResourceCID, NS_RDFDEFAULTRESOURCE_CID);
100 :
101 : static NS_DEFINE_IID(kIRDFLiteralIID, NS_IRDFLITERAL_IID);
102 : static NS_DEFINE_IID(kIRDFDateIID, NS_IRDFDATE_IID);
103 : static NS_DEFINE_IID(kIRDFIntIID, NS_IRDFINT_IID);
104 : static NS_DEFINE_IID(kIRDFNodeIID, NS_IRDFNODE_IID);
105 : static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
106 :
107 : #ifdef PR_LOGGING
108 : static PRLogModuleInfo* gLog = nsnull;
109 : #endif
110 :
111 : class BlobImpl;
112 :
113 : // These functions are copied from nsprpub/lib/ds/plhash.c, with one
114 : // change to free the key in DataSourceFreeEntry.
115 : // XXX sigh, why were DefaultAllocTable et. al. declared static, anyway?
116 :
117 : static void *
118 2815 : DataSourceAllocTable(void *pool, PRSize size)
119 : {
120 2815 : return PR_MALLOC(size);
121 : }
122 :
123 : static void
124 2813 : DataSourceFreeTable(void *pool, void *item)
125 : {
126 2813 : PR_Free(item);
127 2813 : }
128 :
129 : static PLHashEntry *
130 10 : DataSourceAllocEntry(void *pool, const void *key)
131 : {
132 10 : return PR_NEW(PLHashEntry);
133 : }
134 :
135 : static void
136 10 : DataSourceFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
137 : {
138 10 : if (flag == HT_FREE_ENTRY) {
139 10 : PL_strfree((char*) he->key);
140 10 : PR_Free(he);
141 : }
142 10 : }
143 :
144 : static PLHashAllocOps dataSourceHashAllocOps = {
145 : DataSourceAllocTable, DataSourceFreeTable,
146 : DataSourceAllocEntry, DataSourceFreeEntry
147 : };
148 :
149 : //----------------------------------------------------------------------
150 : //
151 : // For the mResources hashtable.
152 : //
153 :
154 : struct ResourceHashEntry : public PLDHashEntryHdr {
155 : const char *mKey;
156 : nsIRDFResource *mResource;
157 :
158 : static PLDHashNumber
159 364509 : HashKey(PLDHashTable *table, const void *key)
160 : {
161 364509 : return HashString(static_cast<const char *>(key));
162 : }
163 :
164 : static bool
165 195237 : MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
166 : const void *key)
167 : {
168 : const ResourceHashEntry *entry =
169 195237 : static_cast<const ResourceHashEntry *>(hdr);
170 :
171 : return 0 == nsCRT::strcmp(static_cast<const char *>(key),
172 195237 : entry->mKey);
173 : }
174 : };
175 :
176 : static PLDHashTableOps gResourceTableOps = {
177 : PL_DHashAllocTable,
178 : PL_DHashFreeTable,
179 : ResourceHashEntry::HashKey,
180 : ResourceHashEntry::MatchEntry,
181 : PL_DHashMoveEntryStub,
182 : PL_DHashClearEntryStub,
183 : PL_DHashFinalizeStub,
184 : nsnull
185 : };
186 :
187 : // ----------------------------------------------------------------------
188 : //
189 : // For the mLiterals hashtable.
190 : //
191 :
192 : struct LiteralHashEntry : public PLDHashEntryHdr {
193 : nsIRDFLiteral *mLiteral;
194 : const PRUnichar *mKey;
195 :
196 : static PLDHashNumber
197 65008 : HashKey(PLDHashTable *table, const void *key)
198 : {
199 65008 : return HashString(static_cast<const PRUnichar *>(key));
200 : }
201 :
202 : static bool
203 36976 : MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
204 : const void *key)
205 : {
206 : const LiteralHashEntry *entry =
207 36976 : static_cast<const LiteralHashEntry *>(hdr);
208 :
209 : return 0 == nsCRT::strcmp(static_cast<const PRUnichar *>(key),
210 36976 : entry->mKey);
211 : }
212 : };
213 :
214 : static PLDHashTableOps gLiteralTableOps = {
215 : PL_DHashAllocTable,
216 : PL_DHashFreeTable,
217 : LiteralHashEntry::HashKey,
218 : LiteralHashEntry::MatchEntry,
219 : PL_DHashMoveEntryStub,
220 : PL_DHashClearEntryStub,
221 : PL_DHashFinalizeStub,
222 : nsnull
223 : };
224 :
225 : // ----------------------------------------------------------------------
226 : //
227 : // For the mInts hashtable.
228 : //
229 :
230 : struct IntHashEntry : public PLDHashEntryHdr {
231 : nsIRDFInt *mInt;
232 : PRInt32 mKey;
233 :
234 : static PLDHashNumber
235 64 : HashKey(PLDHashTable *table, const void *key)
236 : {
237 64 : return PLDHashNumber(*static_cast<const PRInt32 *>(key));
238 : }
239 :
240 : static bool
241 40 : MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
242 : const void *key)
243 : {
244 : const IntHashEntry *entry =
245 40 : static_cast<const IntHashEntry *>(hdr);
246 :
247 40 : return *static_cast<const PRInt32 *>(key) == entry->mKey;
248 : }
249 : };
250 :
251 : static PLDHashTableOps gIntTableOps = {
252 : PL_DHashAllocTable,
253 : PL_DHashFreeTable,
254 : IntHashEntry::HashKey,
255 : IntHashEntry::MatchEntry,
256 : PL_DHashMoveEntryStub,
257 : PL_DHashClearEntryStub,
258 : PL_DHashFinalizeStub,
259 : nsnull
260 : };
261 :
262 : // ----------------------------------------------------------------------
263 : //
264 : // For the mDates hashtable.
265 : //
266 :
267 : struct DateHashEntry : public PLDHashEntryHdr {
268 : nsIRDFDate *mDate;
269 : PRTime mKey;
270 :
271 : static PLDHashNumber
272 0 : HashKey(PLDHashTable *table, const void *key)
273 : {
274 : // xor the low 32 bits with the high 32 bits.
275 0 : PRTime t = *static_cast<const PRTime *>(key);
276 : PRInt64 h64, l64;
277 0 : LL_USHR(h64, t, 32);
278 0 : l64 = LL_INIT(0, 0xffffffff);
279 0 : LL_AND(l64, l64, t);
280 : PRInt32 h32, l32;
281 0 : LL_L2I(h32, h64);
282 0 : LL_L2I(l32, l64);
283 0 : return PLDHashNumber(l32 ^ h32);
284 : }
285 :
286 : static bool
287 0 : MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
288 : const void *key)
289 : {
290 : const DateHashEntry *entry =
291 0 : static_cast<const DateHashEntry *>(hdr);
292 :
293 0 : return LL_EQ(*static_cast<const PRTime *>(key), entry->mKey);
294 : }
295 : };
296 :
297 : static PLDHashTableOps gDateTableOps = {
298 : PL_DHashAllocTable,
299 : PL_DHashFreeTable,
300 : DateHashEntry::HashKey,
301 : DateHashEntry::MatchEntry,
302 : PL_DHashMoveEntryStub,
303 : PL_DHashClearEntryStub,
304 : PL_DHashFinalizeStub,
305 : nsnull
306 : };
307 :
308 : class BlobImpl : public nsIRDFBlob
309 : {
310 : public:
311 : struct Data {
312 : PRInt32 mLength;
313 : PRUint8 *mBytes;
314 : };
315 :
316 0 : BlobImpl(const PRUint8 *aBytes, PRInt32 aLength)
317 0 : {
318 0 : mData.mLength = aLength;
319 0 : mData.mBytes = new PRUint8[aLength];
320 0 : memcpy(mData.mBytes, aBytes, aLength);
321 0 : NS_ADDREF(RDFServiceImpl::gRDFService);
322 0 : RDFServiceImpl::gRDFService->RegisterBlob(this);
323 0 : }
324 :
325 0 : virtual ~BlobImpl()
326 0 : {
327 0 : RDFServiceImpl::gRDFService->UnregisterBlob(this);
328 : // Use NS_RELEASE2() here, because we want to decrease the
329 : // refcount, but not null out the gRDFService pointer (which is
330 : // what a vanilla NS_RELEASE() would do).
331 : nsrefcnt refcnt;
332 0 : NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
333 0 : delete[] mData.mBytes;
334 0 : }
335 :
336 : NS_DECL_ISUPPORTS
337 : NS_DECL_NSIRDFNODE
338 : NS_DECL_NSIRDFBLOB
339 :
340 : Data mData;
341 : };
342 :
343 0 : NS_IMPL_ISUPPORTS2(BlobImpl, nsIRDFNode, nsIRDFBlob)
344 :
345 : NS_IMETHODIMP
346 0 : BlobImpl::EqualsNode(nsIRDFNode *aNode, bool *aEquals)
347 : {
348 0 : nsCOMPtr<nsIRDFBlob> blob = do_QueryInterface(aNode);
349 0 : if (blob) {
350 : PRInt32 length;
351 0 : blob->GetLength(&length);
352 :
353 0 : if (length == mData.mLength) {
354 : const PRUint8 *bytes;
355 0 : blob->GetValue(&bytes);
356 :
357 0 : if (0 == memcmp(bytes, mData.mBytes, length)) {
358 0 : *aEquals = true;
359 0 : return NS_OK;
360 : }
361 : }
362 : }
363 :
364 0 : *aEquals = false;
365 0 : return NS_OK;
366 : }
367 :
368 : NS_IMETHODIMP
369 0 : BlobImpl::GetValue(const PRUint8 **aResult)
370 : {
371 0 : *aResult = mData.mBytes;
372 0 : return NS_OK;
373 : }
374 :
375 : NS_IMETHODIMP
376 0 : BlobImpl::GetLength(PRInt32 *aResult)
377 : {
378 0 : *aResult = mData.mLength;
379 0 : return NS_OK;
380 : }
381 :
382 : // ----------------------------------------------------------------------
383 : //
384 : // For the mBlobs hashtable.
385 : //
386 :
387 : struct BlobHashEntry : public PLDHashEntryHdr {
388 : BlobImpl *mBlob;
389 :
390 : static PLDHashNumber
391 0 : HashKey(PLDHashTable *table, const void *key)
392 : {
393 : const BlobImpl::Data *data =
394 0 : static_cast<const BlobImpl::Data *>(key);
395 0 : return HashBytes(data->mBytes, data->mLength);
396 : }
397 :
398 : static bool
399 0 : MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
400 : const void *key)
401 : {
402 : const BlobHashEntry *entry =
403 0 : static_cast<const BlobHashEntry *>(hdr);
404 :
405 0 : const BlobImpl::Data *left = &entry->mBlob->mData;
406 :
407 : const BlobImpl::Data *right =
408 0 : static_cast<const BlobImpl::Data *>(key);
409 :
410 : return (left->mLength == right->mLength)
411 0 : && 0 == memcmp(left->mBytes, right->mBytes, right->mLength);
412 : }
413 : };
414 :
415 : static PLDHashTableOps gBlobTableOps = {
416 : PL_DHashAllocTable,
417 : PL_DHashFreeTable,
418 : BlobHashEntry::HashKey,
419 : BlobHashEntry::MatchEntry,
420 : PL_DHashMoveEntryStub,
421 : PL_DHashClearEntryStub,
422 : PL_DHashFinalizeStub,
423 : nsnull
424 : };
425 :
426 : ////////////////////////////////////////////////////////////////////////
427 : // LiteralImpl
428 : //
429 : // Currently, all literals are implemented exactly the same way;
430 : // i.e., there is are no resource factories to allow you to generate
431 : // customer resources. I doubt that makes sense, anyway.
432 : //
433 : class LiteralImpl : public nsIRDFLiteral {
434 : public:
435 : static nsresult
436 : Create(const PRUnichar* aValue, nsIRDFLiteral** aResult);
437 :
438 : // nsISupports
439 : NS_DECL_ISUPPORTS
440 :
441 : // nsIRDFNode
442 : NS_DECL_NSIRDFNODE
443 :
444 : // nsIRDFLiteral
445 : NS_DECL_NSIRDFLITERAL
446 :
447 : protected:
448 : LiteralImpl(const PRUnichar* s);
449 : virtual ~LiteralImpl();
450 :
451 37607 : const PRUnichar* GetValue() const {
452 37607 : size_t objectSize = ((sizeof(LiteralImpl) + sizeof(PRUnichar) - 1) / sizeof(PRUnichar)) * sizeof(PRUnichar);
453 37607 : return reinterpret_cast<const PRUnichar*>(reinterpret_cast<const unsigned char*>(this) + objectSize);
454 : }
455 : };
456 :
457 :
458 : nsresult
459 9344 : LiteralImpl::Create(const PRUnichar* aValue, nsIRDFLiteral** aResult)
460 : {
461 : // Goofy math to get alignment right. Copied from nsSharedString.h.
462 9344 : size_t objectSize = ((sizeof(LiteralImpl) + sizeof(PRUnichar) - 1) / sizeof(PRUnichar)) * sizeof(PRUnichar);
463 9344 : size_t stringLen = nsCharTraits<PRUnichar>::length(aValue);
464 9344 : size_t stringSize = (stringLen + 1) * sizeof(PRUnichar);
465 :
466 18688 : void* objectPtr = operator new(objectSize + stringSize);
467 9344 : if (! objectPtr)
468 0 : return NS_ERROR_NULL_POINTER;
469 :
470 9344 : PRUnichar* buf = reinterpret_cast<PRUnichar*>(static_cast<unsigned char*>(objectPtr) + objectSize);
471 9344 : nsCharTraits<PRUnichar>::copy(buf, aValue, stringLen + 1);
472 :
473 9344 : NS_ADDREF(*aResult = new (objectPtr) LiteralImpl(buf));
474 9344 : return NS_OK;
475 : }
476 :
477 :
478 9344 : LiteralImpl::LiteralImpl(const PRUnichar* s)
479 : {
480 9344 : RDFServiceImpl::gRDFService->RegisterLiteral(this);
481 9344 : NS_ADDREF(RDFServiceImpl::gRDFService);
482 9344 : }
483 :
484 18686 : LiteralImpl::~LiteralImpl()
485 : {
486 9343 : RDFServiceImpl::gRDFService->UnregisterLiteral(this);
487 :
488 : // Use NS_RELEASE2() here, because we want to decrease the
489 : // refcount, but not null out the gRDFService pointer (which is
490 : // what a vanilla NS_RELEASE() would do).
491 : nsrefcnt refcnt;
492 9343 : NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
493 37372 : }
494 :
495 140354 : NS_IMPL_THREADSAFE_ADDREF(LiteralImpl)
496 140353 : NS_IMPL_THREADSAFE_RELEASE(LiteralImpl)
497 :
498 : nsresult
499 148000 : LiteralImpl::QueryInterface(REFNSIID iid, void** result)
500 : {
501 148000 : if (! result)
502 0 : return NS_ERROR_NULL_POINTER;
503 :
504 148000 : *result = nsnull;
505 376029 : if (iid.Equals(kIRDFLiteralIID) ||
506 131165 : iid.Equals(kIRDFNodeIID) ||
507 96864 : iid.Equals(kISupportsIID)) {
508 66782 : *result = static_cast<nsIRDFLiteral*>(this);
509 66782 : AddRef();
510 66782 : return NS_OK;
511 : }
512 81218 : return NS_NOINTERFACE;
513 : }
514 :
515 : NS_IMETHODIMP
516 0 : LiteralImpl::EqualsNode(nsIRDFNode* aNode, bool* aResult)
517 : {
518 : nsresult rv;
519 : nsIRDFLiteral* literal;
520 0 : rv = aNode->QueryInterface(kIRDFLiteralIID, (void**) &literal);
521 0 : if (NS_SUCCEEDED(rv)) {
522 0 : *aResult = (static_cast<nsIRDFLiteral*>(this) == literal);
523 0 : NS_RELEASE(literal);
524 0 : return NS_OK;
525 : }
526 0 : else if (rv == NS_NOINTERFACE) {
527 0 : *aResult = false;
528 0 : return NS_OK;
529 : }
530 : else {
531 0 : return rv;
532 : }
533 : }
534 :
535 : NS_IMETHODIMP
536 15130 : LiteralImpl::GetValue(PRUnichar* *value)
537 : {
538 15130 : NS_ASSERTION(value, "null ptr");
539 15130 : if (! value)
540 0 : return NS_ERROR_NULL_POINTER;
541 :
542 15130 : const PRUnichar *temp = GetValue();
543 15130 : *value = temp? NS_strdup(temp) : 0;
544 15130 : return NS_OK;
545 : }
546 :
547 :
548 : NS_IMETHODIMP
549 22477 : LiteralImpl::GetValueConst(const PRUnichar** aValue)
550 : {
551 22477 : *aValue = GetValue();
552 22477 : return NS_OK;
553 : }
554 :
555 : ////////////////////////////////////////////////////////////////////////
556 : // DateImpl
557 : //
558 :
559 : class DateImpl : public nsIRDFDate {
560 : public:
561 : DateImpl(const PRTime s);
562 : virtual ~DateImpl();
563 :
564 : // nsISupports
565 : NS_DECL_ISUPPORTS
566 :
567 : // nsIRDFNode
568 : NS_DECL_NSIRDFNODE
569 :
570 : // nsIRDFDate
571 : NS_IMETHOD GetValue(PRTime *value);
572 :
573 : private:
574 : nsresult EqualsDate(nsIRDFDate* date, bool* result);
575 : PRTime mValue;
576 : };
577 :
578 :
579 0 : DateImpl::DateImpl(const PRTime s)
580 0 : : mValue(s)
581 : {
582 0 : RDFServiceImpl::gRDFService->RegisterDate(this);
583 0 : NS_ADDREF(RDFServiceImpl::gRDFService);
584 0 : }
585 :
586 0 : DateImpl::~DateImpl()
587 : {
588 0 : RDFServiceImpl::gRDFService->UnregisterDate(this);
589 :
590 : // Use NS_RELEASE2() here, because we want to decrease the
591 : // refcount, but not null out the gRDFService pointer (which is
592 : // what a vanilla NS_RELEASE() would do).
593 : nsrefcnt refcnt;
594 0 : NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
595 0 : }
596 :
597 0 : NS_IMPL_ADDREF(DateImpl)
598 0 : NS_IMPL_RELEASE(DateImpl)
599 :
600 : nsresult
601 0 : DateImpl::QueryInterface(REFNSIID iid, void** result)
602 : {
603 0 : if (! result)
604 0 : return NS_ERROR_NULL_POINTER;
605 :
606 0 : *result = nsnull;
607 0 : if (iid.Equals(kIRDFDateIID) ||
608 0 : iid.Equals(kIRDFNodeIID) ||
609 0 : iid.Equals(kISupportsIID)) {
610 0 : *result = static_cast<nsIRDFDate*>(this);
611 0 : AddRef();
612 0 : return NS_OK;
613 : }
614 0 : return NS_NOINTERFACE;
615 : }
616 :
617 : NS_IMETHODIMP
618 0 : DateImpl::EqualsNode(nsIRDFNode* node, bool* result)
619 : {
620 : nsresult rv;
621 : nsIRDFDate* date;
622 0 : if (NS_SUCCEEDED(node->QueryInterface(kIRDFDateIID, (void**) &date))) {
623 0 : rv = EqualsDate(date, result);
624 0 : NS_RELEASE(date);
625 : }
626 : else {
627 0 : *result = false;
628 0 : rv = NS_OK;
629 : }
630 0 : return rv;
631 : }
632 :
633 : NS_IMETHODIMP
634 0 : DateImpl::GetValue(PRTime *value)
635 : {
636 0 : NS_ASSERTION(value, "null ptr");
637 0 : if (! value)
638 0 : return NS_ERROR_NULL_POINTER;
639 :
640 0 : *value = mValue;
641 0 : return NS_OK;
642 : }
643 :
644 :
645 : nsresult
646 0 : DateImpl::EqualsDate(nsIRDFDate* date, bool* result)
647 : {
648 0 : NS_ASSERTION(date && result, "null ptr");
649 0 : if (!date || !result)
650 0 : return NS_ERROR_NULL_POINTER;
651 :
652 : nsresult rv;
653 : PRTime p;
654 0 : if (NS_FAILED(rv = date->GetValue(&p)))
655 0 : return rv;
656 :
657 0 : *result = LL_EQ(p, mValue);
658 0 : return NS_OK;
659 : }
660 :
661 : ////////////////////////////////////////////////////////////////////////
662 : // IntImpl
663 : //
664 :
665 : class IntImpl : public nsIRDFInt {
666 : public:
667 : IntImpl(PRInt32 s);
668 : virtual ~IntImpl();
669 :
670 : // nsISupports
671 : NS_DECL_ISUPPORTS
672 :
673 : // nsIRDFNode
674 : NS_DECL_NSIRDFNODE
675 :
676 : // nsIRDFInt
677 : NS_IMETHOD GetValue(PRInt32 *value);
678 :
679 : private:
680 : nsresult EqualsInt(nsIRDFInt* value, bool* result);
681 : PRInt32 mValue;
682 : };
683 :
684 :
685 8 : IntImpl::IntImpl(PRInt32 s)
686 8 : : mValue(s)
687 : {
688 8 : RDFServiceImpl::gRDFService->RegisterInt(this);
689 8 : NS_ADDREF(RDFServiceImpl::gRDFService);
690 8 : }
691 :
692 16 : IntImpl::~IntImpl()
693 : {
694 8 : RDFServiceImpl::gRDFService->UnregisterInt(this);
695 :
696 : // Use NS_RELEASE2() here, because we want to decrease the
697 : // refcount, but not null out the gRDFService pointer (which is
698 : // what a vanilla NS_RELEASE() would do).
699 : nsrefcnt refcnt;
700 8 : NS_RELEASE2(RDFServiceImpl::gRDFService, refcnt);
701 32 : }
702 :
703 96 : NS_IMPL_ADDREF(IntImpl)
704 96 : NS_IMPL_RELEASE(IntImpl)
705 :
706 : nsresult
707 32 : IntImpl::QueryInterface(REFNSIID iid, void** result)
708 : {
709 32 : if (! result)
710 0 : return NS_ERROR_NULL_POINTER;
711 :
712 32 : *result = nsnull;
713 64 : if (iid.Equals(kIRDFIntIID) ||
714 32 : iid.Equals(kIRDFNodeIID) ||
715 0 : iid.Equals(kISupportsIID)) {
716 32 : *result = static_cast<nsIRDFInt*>(this);
717 32 : AddRef();
718 32 : return NS_OK;
719 : }
720 0 : return NS_NOINTERFACE;
721 : }
722 :
723 : NS_IMETHODIMP
724 0 : IntImpl::EqualsNode(nsIRDFNode* node, bool* result)
725 : {
726 : nsresult rv;
727 : nsIRDFInt* intValue;
728 0 : if (NS_SUCCEEDED(node->QueryInterface(kIRDFIntIID, (void**) &intValue))) {
729 0 : rv = EqualsInt(intValue, result);
730 0 : NS_RELEASE(intValue);
731 : }
732 : else {
733 0 : *result = false;
734 0 : rv = NS_OK;
735 : }
736 0 : return rv;
737 : }
738 :
739 : NS_IMETHODIMP
740 16 : IntImpl::GetValue(PRInt32 *value)
741 : {
742 16 : NS_ASSERTION(value, "null ptr");
743 16 : if (! value)
744 0 : return NS_ERROR_NULL_POINTER;
745 :
746 16 : *value = mValue;
747 16 : return NS_OK;
748 : }
749 :
750 :
751 : nsresult
752 0 : IntImpl::EqualsInt(nsIRDFInt* intValue, bool* result)
753 : {
754 0 : NS_ASSERTION(intValue && result, "null ptr");
755 0 : if (!intValue || !result)
756 0 : return NS_ERROR_NULL_POINTER;
757 :
758 : nsresult rv;
759 : PRInt32 p;
760 0 : if (NS_FAILED(rv = intValue->GetValue(&p)))
761 0 : return rv;
762 :
763 0 : *result = (p == mValue);
764 0 : return NS_OK;
765 : }
766 :
767 : ////////////////////////////////////////////////////////////////////////
768 : // RDFServiceImpl
769 :
770 : RDFServiceImpl*
771 : RDFServiceImpl::gRDFService;
772 :
773 1404 : RDFServiceImpl::RDFServiceImpl()
774 1404 : : mNamedDataSources(nsnull)
775 : {
776 1404 : mResources.ops = nsnull;
777 1404 : mLiterals.ops = nsnull;
778 1404 : mInts.ops = nsnull;
779 1404 : mDates.ops = nsnull;
780 1404 : mBlobs.ops = nsnull;
781 1404 : gRDFService = this;
782 1404 : }
783 :
784 : nsresult
785 1404 : RDFServiceImpl::Init()
786 : {
787 : nsresult rv;
788 :
789 : mNamedDataSources = PL_NewHashTable(23,
790 : PL_HashString,
791 : PL_CompareStrings,
792 : PL_CompareValues,
793 1404 : &dataSourceHashAllocOps, nsnull);
794 :
795 1404 : if (! mNamedDataSources)
796 0 : return NS_ERROR_OUT_OF_MEMORY;
797 :
798 1404 : if (!PL_DHashTableInit(&mResources, &gResourceTableOps, nsnull,
799 1404 : sizeof(ResourceHashEntry), PL_DHASH_MIN_SIZE)) {
800 0 : mResources.ops = nsnull;
801 0 : return NS_ERROR_OUT_OF_MEMORY;
802 : }
803 1404 : if (!PL_DHashTableInit(&mLiterals, &gLiteralTableOps, nsnull,
804 1404 : sizeof(LiteralHashEntry), PL_DHASH_MIN_SIZE)) {
805 0 : mLiterals.ops = nsnull;
806 0 : return NS_ERROR_OUT_OF_MEMORY;
807 : }
808 1404 : if (!PL_DHashTableInit(&mInts, &gIntTableOps, nsnull,
809 1404 : sizeof(IntHashEntry), PL_DHASH_MIN_SIZE)) {
810 0 : mInts.ops = nsnull;
811 0 : return NS_ERROR_OUT_OF_MEMORY;
812 : }
813 1404 : if (!PL_DHashTableInit(&mDates, &gDateTableOps, nsnull,
814 1404 : sizeof(DateHashEntry), PL_DHASH_MIN_SIZE)) {
815 0 : mDates.ops = nsnull;
816 0 : return NS_ERROR_OUT_OF_MEMORY;
817 : }
818 1404 : if (!PL_DHashTableInit(&mBlobs, &gBlobTableOps, nsnull,
819 1404 : sizeof(BlobHashEntry), PL_DHASH_MIN_SIZE)) {
820 0 : mBlobs.ops = nsnull;
821 0 : return NS_ERROR_OUT_OF_MEMORY;
822 : }
823 1404 : mDefaultResourceFactory = do_GetClassObject(kRDFDefaultResourceCID, &rv);
824 1404 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get default resource factory");
825 1404 : if (NS_FAILED(rv)) return rv;
826 :
827 : #ifdef PR_LOGGING
828 1404 : if (! gLog)
829 1404 : gLog = PR_NewLogModule("nsRDFService");
830 : #endif
831 :
832 1404 : return NS_OK;
833 : }
834 :
835 :
836 4209 : RDFServiceImpl::~RDFServiceImpl()
837 : {
838 1403 : if (mNamedDataSources) {
839 1403 : PL_HashTableDestroy(mNamedDataSources);
840 1403 : mNamedDataSources = nsnull;
841 : }
842 1403 : if (mResources.ops)
843 1403 : PL_DHashTableFinish(&mResources);
844 1403 : if (mLiterals.ops)
845 1403 : PL_DHashTableFinish(&mLiterals);
846 1403 : if (mInts.ops)
847 1403 : PL_DHashTableFinish(&mInts);
848 1403 : if (mDates.ops)
849 1403 : PL_DHashTableFinish(&mDates);
850 1403 : if (mBlobs.ops)
851 1403 : PL_DHashTableFinish(&mBlobs);
852 1403 : gRDFService = nsnull;
853 5612 : }
854 :
855 :
856 : // static
857 : nsresult
858 1404 : RDFServiceImpl::CreateSingleton(nsISupports* aOuter,
859 : const nsIID& aIID, void **aResult)
860 : {
861 1404 : NS_ENSURE_NO_AGGREGATION(aOuter);
862 :
863 1404 : if (gRDFService) {
864 0 : NS_ERROR("Trying to create RDF serviec twice.");
865 0 : return gRDFService->QueryInterface(aIID, aResult);
866 : }
867 :
868 2808 : nsRefPtr<RDFServiceImpl> serv = new RDFServiceImpl();
869 1404 : if (!serv)
870 0 : return NS_ERROR_OUT_OF_MEMORY;
871 :
872 1404 : nsresult rv = serv->Init();
873 1404 : if (NS_FAILED(rv))
874 0 : return rv;
875 :
876 1404 : return serv->QueryInterface(aIID, aResult);
877 : }
878 :
879 68912 : NS_IMPL_THREADSAFE_ISUPPORTS2(RDFServiceImpl, nsIRDFService, nsISupportsWeakReference)
880 :
881 : // Per RFC2396.
882 : static const PRUint8
883 : kLegalSchemeChars[] = {
884 : // ASCII Bits Ordered Hex
885 : // 01234567 76543210
886 : 0x00, // 00-07
887 : 0x00, // 08-0F
888 : 0x00, // 10-17
889 : 0x00, // 18-1F
890 : 0x00, // 20-27 !"#$%&' 00000000 00000000
891 : 0x28, // 28-2F ()*+,-./ 00010100 00101000 0x28
892 : 0xff, // 30-37 01234567 11111111 11111111 0xFF
893 : 0x03, // 38-3F 89:;<=>? 11000000 00000011 0x03
894 : 0xfe, // 40-47 @ABCDEFG 01111111 11111110 0xFE
895 : 0xff, // 48-4F HIJKLMNO 11111111 11111111 0xFF
896 : 0xff, // 50-57 PQRSTUVW 11111111 11111111 0xFF
897 : 0x87, // 58-5F XYZ[\]^_ 11100001 10000111 0x87
898 : 0xfe, // 60-67 `abcdefg 01111111 11111110 0xFE
899 : 0xff, // 68-6F hijklmno 11111111 11111111 0xFF
900 : 0xff, // 70-77 pqrstuvw 11111111 11111111 0xFF
901 : 0x07, // 78-7F xyz{|}~ 11100000 00000111 0x07
902 : 0x00, 0x00, 0x00, 0x00, // >= 80
903 : 0x00, 0x00, 0x00, 0x00,
904 : 0x00, 0x00, 0x00, 0x00,
905 : 0x00, 0x00, 0x00, 0x00
906 : };
907 :
908 : static inline bool
909 243780 : IsLegalSchemeCharacter(const char aChar)
910 : {
911 243780 : PRUint8 mask = kLegalSchemeChars[aChar >> 3];
912 243780 : PRUint8 bit = PR_BIT(aChar & 0x7);
913 243780 : return bool((mask & bit) != 0);
914 : }
915 :
916 :
917 : NS_IMETHODIMP
918 138819 : RDFServiceImpl::GetResource(const nsACString& aURI, nsIRDFResource** aResource)
919 : {
920 : // Sanity checks
921 138819 : NS_PRECONDITION(aResource != nsnull, "null ptr");
922 138819 : NS_PRECONDITION(!aURI.IsEmpty(), "URI is empty");
923 138819 : if (! aResource)
924 0 : return NS_ERROR_NULL_POINTER;
925 138819 : if (aURI.IsEmpty())
926 0 : return NS_ERROR_INVALID_ARG;
927 :
928 277638 : const nsAFlatCString& flatURI = PromiseFlatCString(aURI);
929 138819 : PR_LOG(gLog, PR_LOG_DEBUG, ("rdfserv get-resource %s", flatURI.get()));
930 :
931 : // First, check the cache to see if we've already created and
932 : // registered this thing.
933 : PLDHashEntryHdr *hdr =
934 138819 : PL_DHashTableOperate(&mResources, flatURI.get(), PL_DHASH_LOOKUP);
935 :
936 138819 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
937 82395 : ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
938 82395 : NS_ADDREF(*aResource = entry->mResource);
939 82395 : return NS_OK;
940 : }
941 :
942 : // Nope. So go to the repository to create it.
943 :
944 : // Compute the scheme of the URI. Scan forward until we either:
945 : //
946 : // 1. Reach the end of the string
947 : // 2. Encounter a non-alpha character
948 : // 3. Encouter a colon.
949 : //
950 : // If we encounter a colon _before_ encountering a non-alpha
951 : // character, then assume it's the scheme.
952 : //
953 : // XXX Although it's really not correct, we'll allow underscore
954 : // characters ('_'), too.
955 56424 : nsACString::const_iterator p, end;
956 56424 : aURI.BeginReading(p);
957 56424 : aURI.EndReading(end);
958 300204 : while (p != end && IsLegalSchemeCharacter(*p))
959 187356 : ++p;
960 :
961 : nsresult rv;
962 112848 : nsCOMPtr<nsIFactory> factory;
963 :
964 56424 : nsACString::const_iterator begin;
965 56424 : aURI.BeginReading(begin);
966 56424 : if (*p == ':') {
967 : // There _was_ a scheme. First see if it's the same scheme
968 : // that we just tried to use...
969 56424 : if (mLastFactory && mLastURIPrefix.Equals(Substring(begin, p)))
970 41801 : factory = mLastFactory;
971 : else {
972 : // Try to find a factory using the component manager.
973 14623 : nsACString::const_iterator begin;
974 14623 : aURI.BeginReading(begin);
975 29246 : nsCAutoString contractID;
976 14623 : contractID = NS_LITERAL_CSTRING(NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX) +
977 29246 : Substring(begin, p);
978 :
979 14623 : factory = do_GetClassObject(contractID.get());
980 14623 : if (factory) {
981 : // Store the factory in our one-element cache.
982 0 : if (p != begin) {
983 0 : mLastFactory = factory;
984 0 : mLastURIPrefix = Substring(begin, p);
985 : }
986 : }
987 : }
988 : }
989 :
990 56424 : if (! factory) {
991 : // fall through to using the "default" resource factory if either:
992 : //
993 : // 1. The URI didn't have a scheme, or
994 : // 2. There was no resource factory registered for the scheme.
995 14623 : factory = mDefaultResourceFactory;
996 :
997 : // Store the factory in our one-element cache.
998 14623 : if (p != begin) {
999 14623 : mLastFactory = factory;
1000 14623 : mLastURIPrefix = Substring(begin, p);
1001 : }
1002 : }
1003 :
1004 : nsIRDFResource *result;
1005 56424 : rv = factory->CreateInstance(nsnull, NS_GET_IID(nsIRDFResource), (void**) &result);
1006 56424 : if (NS_FAILED(rv)) return rv;
1007 :
1008 : // Now initialize it with its URI. At this point, the resource
1009 : // implementation should register itself with the RDF service.
1010 56424 : rv = result->Init(flatURI.get());
1011 56424 : if (NS_FAILED(rv)) {
1012 0 : NS_ERROR("unable to initialize resource");
1013 0 : NS_RELEASE(result);
1014 0 : return rv;
1015 : }
1016 :
1017 56424 : *aResource = result; // already refcounted from repository
1018 56424 : return rv;
1019 : }
1020 :
1021 : NS_IMETHODIMP
1022 2 : RDFServiceImpl::GetUnicodeResource(const nsAString& aURI, nsIRDFResource** aResource)
1023 : {
1024 2 : return GetResource(NS_ConvertUTF16toUTF8(aURI), aResource);
1025 : }
1026 :
1027 :
1028 : NS_IMETHODIMP
1029 36222 : RDFServiceImpl::GetAnonymousResource(nsIRDFResource** aResult)
1030 : {
1031 : static PRUint32 gCounter = 0;
1032 : static char gChars[] = "0123456789abcdef"
1033 : "ghijklmnopqrstuv"
1034 : "wxyzABCDEFGHIJKL"
1035 : "MNOPQRSTUVWXYZ.+";
1036 :
1037 : static PRInt32 kMask = 0x003f;
1038 : static PRInt32 kShift = 6;
1039 :
1040 36222 : if (! gCounter) {
1041 : // Start it at a semi-unique value, just to minimize the
1042 : // chance that we get into a situation where
1043 : //
1044 : // 1. An anonymous resource gets serialized out in a graph
1045 : // 2. Reboot
1046 : // 3. The same anonymous resource gets requested, and refers
1047 : // to something completely different.
1048 : // 4. The serialization is read back in.
1049 169 : LL_L2UI(gCounter, PR_Now());
1050 : }
1051 :
1052 : nsresult rv;
1053 72444 : nsCAutoString s;
1054 :
1055 0 : do {
1056 : // Ugh, this is a really sloppy way to do this; I copied the
1057 : // implementation from the days when it lived outside the RDF
1058 : // service. Now that it's a member we can be more cleverer.
1059 :
1060 36222 : s.Truncate();
1061 36222 : s.Append("rdf:#$");
1062 :
1063 36222 : PRUint32 id = ++gCounter;
1064 289776 : while (id) {
1065 217332 : char ch = gChars[(id & kMask)];
1066 217332 : s.Append(ch);
1067 217332 : id >>= kShift;
1068 : }
1069 :
1070 : nsIRDFResource* resource;
1071 36222 : rv = GetResource(s, &resource);
1072 36222 : if (NS_FAILED(rv)) return rv;
1073 :
1074 : // XXX an ugly but effective way to make sure that this
1075 : // resource is really unique in the world.
1076 36222 : resource->AddRef();
1077 36222 : nsrefcnt refcnt = resource->Release();
1078 :
1079 36222 : if (refcnt == 1) {
1080 36222 : *aResult = resource;
1081 : break;
1082 : }
1083 :
1084 0 : NS_RELEASE(resource);
1085 : } while (1);
1086 :
1087 36222 : return NS_OK;
1088 : }
1089 :
1090 :
1091 : NS_IMETHODIMP
1092 27634 : RDFServiceImpl::GetLiteral(const PRUnichar* aValue, nsIRDFLiteral** aLiteral)
1093 : {
1094 27634 : NS_PRECONDITION(aValue != nsnull, "null ptr");
1095 27634 : if (! aValue)
1096 0 : return NS_ERROR_NULL_POINTER;
1097 :
1098 27634 : NS_PRECONDITION(aLiteral != nsnull, "null ptr");
1099 27634 : if (! aLiteral)
1100 0 : return NS_ERROR_NULL_POINTER;
1101 :
1102 : // See if we have one already cached
1103 : PLDHashEntryHdr *hdr =
1104 27634 : PL_DHashTableOperate(&mLiterals, aValue, PL_DHASH_LOOKUP);
1105 :
1106 27634 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1107 18290 : LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1108 18290 : NS_ADDREF(*aLiteral = entry->mLiteral);
1109 18290 : return NS_OK;
1110 : }
1111 :
1112 : // Nope. Create a new one
1113 9344 : return LiteralImpl::Create(aValue, aLiteral);
1114 : }
1115 :
1116 : NS_IMETHODIMP
1117 0 : RDFServiceImpl::GetDateLiteral(PRTime aTime, nsIRDFDate** aResult)
1118 : {
1119 : // See if we have one already cached
1120 : PLDHashEntryHdr *hdr =
1121 0 : PL_DHashTableOperate(&mDates, &aTime, PL_DHASH_LOOKUP);
1122 :
1123 0 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1124 0 : DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1125 0 : NS_ADDREF(*aResult = entry->mDate);
1126 0 : return NS_OK;
1127 : }
1128 :
1129 0 : DateImpl* result = new DateImpl(aTime);
1130 0 : if (! result)
1131 0 : return NS_ERROR_OUT_OF_MEMORY;
1132 :
1133 0 : NS_ADDREF(*aResult = result);
1134 0 : return NS_OK;
1135 : }
1136 :
1137 : NS_IMETHODIMP
1138 32 : RDFServiceImpl::GetIntLiteral(PRInt32 aInt, nsIRDFInt** aResult)
1139 : {
1140 : // See if we have one already cached
1141 : PLDHashEntryHdr *hdr =
1142 32 : PL_DHashTableOperate(&mInts, &aInt, PL_DHASH_LOOKUP);
1143 :
1144 32 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1145 24 : IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1146 24 : NS_ADDREF(*aResult = entry->mInt);
1147 24 : return NS_OK;
1148 : }
1149 :
1150 8 : IntImpl* result = new IntImpl(aInt);
1151 8 : if (! result)
1152 0 : return NS_ERROR_OUT_OF_MEMORY;
1153 :
1154 8 : NS_ADDREF(*aResult = result);
1155 8 : return NS_OK;
1156 : }
1157 :
1158 : NS_IMETHODIMP
1159 0 : RDFServiceImpl::GetBlobLiteral(const PRUint8 *aBytes, PRInt32 aLength,
1160 : nsIRDFBlob **aResult)
1161 : {
1162 0 : BlobImpl::Data key = { aLength, const_cast<PRUint8 *>(aBytes) };
1163 :
1164 : PLDHashEntryHdr *hdr =
1165 0 : PL_DHashTableOperate(&mBlobs, &key, PL_DHASH_LOOKUP);
1166 :
1167 0 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1168 0 : BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1169 0 : NS_ADDREF(*aResult = entry->mBlob);
1170 0 : return NS_OK;
1171 : }
1172 :
1173 0 : BlobImpl *result = new BlobImpl(aBytes, aLength);
1174 0 : if (! result)
1175 0 : return NS_ERROR_OUT_OF_MEMORY;
1176 :
1177 0 : NS_ADDREF(*aResult = result);
1178 0 : return NS_OK;
1179 : }
1180 :
1181 : NS_IMETHODIMP
1182 56 : RDFServiceImpl::IsAnonymousResource(nsIRDFResource* aResource, bool* _result)
1183 : {
1184 56 : NS_PRECONDITION(aResource != nsnull, "null ptr");
1185 56 : if (! aResource)
1186 0 : return NS_ERROR_NULL_POINTER;
1187 :
1188 : nsresult rv;
1189 :
1190 : const char* uri;
1191 56 : rv = aResource->GetValueConst(&uri);
1192 56 : if (NS_FAILED(rv)) return rv;
1193 :
1194 266 : if ((uri[0] == 'r') &&
1195 42 : (uri[1] == 'd') &&
1196 42 : (uri[2] == 'f') &&
1197 42 : (uri[3] == ':') &&
1198 42 : (uri[4] == '#') &&
1199 42 : (uri[5] == '$')) {
1200 42 : *_result = true;
1201 : }
1202 : else {
1203 14 : *_result = false;
1204 : }
1205 :
1206 56 : return NS_OK;
1207 : }
1208 :
1209 : NS_IMETHODIMP
1210 56424 : RDFServiceImpl::RegisterResource(nsIRDFResource* aResource, bool aReplace)
1211 : {
1212 56424 : NS_PRECONDITION(aResource != nsnull, "null ptr");
1213 56424 : if (! aResource)
1214 0 : return NS_ERROR_NULL_POINTER;
1215 :
1216 : nsresult rv;
1217 :
1218 : const char* uri;
1219 56424 : rv = aResource->GetValueConst(&uri);
1220 56424 : NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get URI from resource");
1221 56424 : if (NS_FAILED(rv)) return rv;
1222 :
1223 56424 : NS_ASSERTION(uri != nsnull, "resource has no URI");
1224 56424 : if (! uri)
1225 0 : return NS_ERROR_NULL_POINTER;
1226 :
1227 : PLDHashEntryHdr *hdr =
1228 56424 : PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP);
1229 :
1230 56424 : if (PL_DHASH_ENTRY_IS_BUSY(hdr)) {
1231 0 : if (!aReplace) {
1232 0 : NS_WARNING("resource already registered, and replace not specified");
1233 0 : return NS_ERROR_FAILURE; // already registered
1234 : }
1235 :
1236 : // N.B., we do _not_ release the original resource because we
1237 : // only ever held a weak reference to it. We simply replace
1238 : // it.
1239 :
1240 0 : PR_LOG(gLog, PR_LOG_DEBUG,
1241 : ("rdfserv replace-resource [%p] <-- [%p] %s",
1242 : static_cast<ResourceHashEntry *>(hdr)->mResource,
1243 : aResource, (const char*) uri));
1244 : }
1245 : else {
1246 56424 : hdr = PL_DHashTableOperate(&mResources, uri, PL_DHASH_ADD);
1247 56424 : if (! hdr)
1248 0 : return NS_ERROR_OUT_OF_MEMORY;
1249 :
1250 56424 : PR_LOG(gLog, PR_LOG_DEBUG,
1251 : ("rdfserv register-resource [%p] %s",
1252 : aResource, (const char*) uri));
1253 : }
1254 :
1255 : // N.B., we only hold a weak reference to the resource: that way,
1256 : // the resource can be destroyed when the last refcount goes
1257 : // away. The single addref that the CreateResource() call made
1258 : // will be owned by the callee.
1259 56424 : ResourceHashEntry *entry = static_cast<ResourceHashEntry *>(hdr);
1260 56424 : entry->mResource = aResource;
1261 56424 : entry->mKey = uri;
1262 :
1263 56424 : return NS_OK;
1264 : }
1265 :
1266 : NS_IMETHODIMP
1267 56421 : RDFServiceImpl::UnregisterResource(nsIRDFResource* aResource)
1268 : {
1269 56421 : NS_PRECONDITION(aResource != nsnull, "null ptr");
1270 56421 : if (! aResource)
1271 0 : return NS_ERROR_NULL_POINTER;
1272 :
1273 : nsresult rv;
1274 :
1275 : const char* uri;
1276 56421 : rv = aResource->GetValueConst(&uri);
1277 56421 : if (NS_FAILED(rv)) return rv;
1278 :
1279 56421 : NS_ASSERTION(uri != nsnull, "resource has no URI");
1280 56421 : if (! uri)
1281 0 : return NS_ERROR_UNEXPECTED;
1282 :
1283 56421 : PR_LOG(gLog, PR_LOG_DEBUG,
1284 : ("rdfserv unregister-resource [%p] %s",
1285 : aResource, (const char*) uri));
1286 :
1287 : #ifdef DEBUG
1288 56421 : if (PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mResources, uri, PL_DHASH_LOOKUP)))
1289 0 : NS_WARNING("resource was never registered");
1290 : #endif
1291 :
1292 56421 : PL_DHashTableOperate(&mResources, uri, PL_DHASH_REMOVE);
1293 56421 : return NS_OK;
1294 : }
1295 :
1296 : NS_IMETHODIMP
1297 10 : RDFServiceImpl::RegisterDataSource(nsIRDFDataSource* aDataSource, bool aReplace)
1298 : {
1299 10 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
1300 10 : if (! aDataSource)
1301 0 : return NS_ERROR_NULL_POINTER;
1302 :
1303 : nsresult rv;
1304 :
1305 20 : nsXPIDLCString uri;
1306 10 : rv = aDataSource->GetURI(getter_Copies(uri));
1307 10 : if (NS_FAILED(rv)) return rv;
1308 :
1309 : PLHashEntry** hep =
1310 10 : PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1311 :
1312 10 : if (*hep) {
1313 0 : if (! aReplace)
1314 0 : return NS_ERROR_FAILURE; // already registered
1315 :
1316 : // N.B., we only hold a weak reference to the datasource, so
1317 : // just replace the old with the new and don't touch any
1318 : // refcounts.
1319 0 : PR_LOG(gLog, PR_LOG_NOTICE,
1320 : ("rdfserv replace-datasource [%p] <-- [%p] %s",
1321 : (*hep)->value, aDataSource, (const char*) uri));
1322 :
1323 0 : (*hep)->value = aDataSource;
1324 : }
1325 : else {
1326 10 : const char* key = PL_strdup(uri);
1327 10 : if (! key)
1328 0 : return NS_ERROR_OUT_OF_MEMORY;
1329 :
1330 10 : PL_HashTableAdd(mNamedDataSources, key, aDataSource);
1331 :
1332 10 : PR_LOG(gLog, PR_LOG_NOTICE,
1333 : ("rdfserv register-datasource [%p] %s",
1334 : aDataSource, (const char*) uri));
1335 :
1336 : // N.B., we only hold a weak reference to the datasource, so don't
1337 : // addref.
1338 : }
1339 :
1340 10 : return NS_OK;
1341 : }
1342 :
1343 : NS_IMETHODIMP
1344 10 : RDFServiceImpl::UnregisterDataSource(nsIRDFDataSource* aDataSource)
1345 : {
1346 10 : NS_PRECONDITION(aDataSource != nsnull, "null ptr");
1347 10 : if (! aDataSource)
1348 0 : return NS_ERROR_NULL_POINTER;
1349 :
1350 : nsresult rv;
1351 :
1352 20 : nsXPIDLCString uri;
1353 10 : rv = aDataSource->GetURI(getter_Copies(uri));
1354 10 : if (NS_FAILED(rv)) return rv;
1355 :
1356 : //NS_ASSERTION(uri != nsnull, "datasource has no URI");
1357 10 : if (! uri)
1358 0 : return NS_ERROR_UNEXPECTED;
1359 :
1360 : PLHashEntry** hep =
1361 10 : PL_HashTableRawLookup(mNamedDataSources, (*mNamedDataSources->keyHash)(uri), uri);
1362 :
1363 : // It may well be that this datasource was never registered. If
1364 : // so, don't unregister it.
1365 10 : if (! *hep || ((*hep)->value != aDataSource))
1366 0 : return NS_OK;
1367 :
1368 : // N.B., we only held a weak reference to the datasource, so we
1369 : // don't release here.
1370 10 : PL_HashTableRawRemove(mNamedDataSources, hep, *hep);
1371 :
1372 10 : PR_LOG(gLog, PR_LOG_NOTICE,
1373 : ("rdfserv unregister-datasource [%p] %s",
1374 : aDataSource, (const char*) uri));
1375 :
1376 10 : return NS_OK;
1377 : }
1378 :
1379 : NS_IMETHODIMP
1380 4 : RDFServiceImpl::GetDataSource(const char* aURI, nsIRDFDataSource** aDataSource)
1381 : {
1382 : // Use the other GetDataSource and ask for a non-blocking Refresh.
1383 : // If you wanted it loaded synchronously, then you should've tried to do it
1384 : // yourself, or used GetDataSourceBlocking.
1385 4 : return GetDataSource( aURI, false, aDataSource );
1386 : }
1387 :
1388 : NS_IMETHODIMP
1389 7 : RDFServiceImpl::GetDataSourceBlocking(const char* aURI, nsIRDFDataSource** aDataSource)
1390 : {
1391 : // Use GetDataSource and ask for a blocking Refresh.
1392 7 : return GetDataSource( aURI, true, aDataSource );
1393 : }
1394 :
1395 : nsresult
1396 11 : RDFServiceImpl::GetDataSource(const char* aURI, bool aBlock, nsIRDFDataSource** aDataSource)
1397 : {
1398 11 : NS_PRECONDITION(aURI != nsnull, "null ptr");
1399 11 : if (! aURI)
1400 0 : return NS_ERROR_NULL_POINTER;
1401 :
1402 : nsresult rv;
1403 :
1404 : // Attempt to canonify the URI before we look for it in the
1405 : // cache. We won't bother doing this on `rdf:' URIs to avoid
1406 : // useless (and expensive) protocol handler lookups.
1407 22 : nsCAutoString spec(aURI);
1408 :
1409 11 : if (!StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1410 22 : nsCOMPtr<nsIURI> uri;
1411 11 : NS_NewURI(getter_AddRefs(uri), spec);
1412 11 : if (uri)
1413 11 : uri->GetSpec(spec);
1414 : }
1415 :
1416 : // First, check the cache to see if we already have this
1417 : // datasource loaded and initialized.
1418 : {
1419 : nsIRDFDataSource* cached =
1420 11 : static_cast<nsIRDFDataSource*>(PL_HashTableLookup(mNamedDataSources, spec.get()));
1421 :
1422 11 : if (cached) {
1423 1 : NS_ADDREF(cached);
1424 1 : *aDataSource = cached;
1425 1 : return NS_OK;
1426 : }
1427 : }
1428 :
1429 : // Nope. So go to the repository to try to create it.
1430 20 : nsCOMPtr<nsIRDFDataSource> ds;
1431 10 : if (StringBeginsWith(spec, NS_LITERAL_CSTRING("rdf:"))) {
1432 : // It's a built-in data source. Convert it to a contract ID.
1433 : nsCAutoString contractID(
1434 0 : NS_LITERAL_CSTRING(NS_RDF_DATASOURCE_CONTRACTID_PREFIX) +
1435 0 : Substring(spec, 4, spec.Length() - 4));
1436 :
1437 : // Strip params to get ``base'' contractID for data source.
1438 0 : PRInt32 p = contractID.FindChar(PRUnichar('&'));
1439 0 : if (p >= 0)
1440 0 : contractID.Truncate(p);
1441 :
1442 0 : ds = do_GetService(contractID.get(), &rv);
1443 0 : if (NS_FAILED(rv)) return rv;
1444 :
1445 0 : nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(ds);
1446 0 : if (remote) {
1447 0 : rv = remote->Init(spec.get());
1448 0 : if (NS_FAILED(rv)) return rv;
1449 : }
1450 : }
1451 : else {
1452 : // Try to load this as an RDF/XML data source
1453 10 : ds = do_CreateInstance(kRDFXMLDataSourceCID, &rv);
1454 10 : if (NS_FAILED(rv)) return rv;
1455 :
1456 20 : nsCOMPtr<nsIRDFRemoteDataSource> remote(do_QueryInterface(ds));
1457 10 : NS_ASSERTION(remote, "not a remote RDF/XML data source!");
1458 10 : if (! remote) return NS_ERROR_UNEXPECTED;
1459 :
1460 10 : rv = remote->Init(spec.get());
1461 10 : if (NS_FAILED(rv)) return rv;
1462 :
1463 10 : rv = remote->Refresh(aBlock);
1464 10 : if (NS_FAILED(rv)) return rv;
1465 : }
1466 :
1467 10 : *aDataSource = ds;
1468 10 : NS_ADDREF(*aDataSource);
1469 10 : return NS_OK;
1470 : }
1471 :
1472 : ////////////////////////////////////////////////////////////////////////
1473 :
1474 : nsresult
1475 9344 : RDFServiceImpl::RegisterLiteral(nsIRDFLiteral* aLiteral)
1476 : {
1477 : const PRUnichar* value;
1478 9344 : aLiteral->GetValueConst(&value);
1479 :
1480 9344 : NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mLiterals,
1481 : value,
1482 : PL_DHASH_LOOKUP)),
1483 : "literal already registered");
1484 :
1485 : PLDHashEntryHdr *hdr =
1486 9344 : PL_DHashTableOperate(&mLiterals, value, PL_DHASH_ADD);
1487 :
1488 9344 : if (! hdr)
1489 0 : return NS_ERROR_OUT_OF_MEMORY;
1490 :
1491 9344 : LiteralHashEntry *entry = static_cast<LiteralHashEntry *>(hdr);
1492 :
1493 : // N.B., we only hold a weak reference to the literal: that
1494 : // way, the literal can be destroyed when the last refcount
1495 : // goes away. The single addref that the CreateLiteral() call
1496 : // made will be owned by the callee.
1497 9344 : entry->mLiteral = aLiteral;
1498 9344 : entry->mKey = value;
1499 :
1500 9344 : PR_LOG(gLog, PR_LOG_DEBUG,
1501 : ("rdfserv register-literal [%p] %s",
1502 : aLiteral, (const PRUnichar*) value));
1503 :
1504 9344 : return NS_OK;
1505 : }
1506 :
1507 :
1508 : nsresult
1509 9343 : RDFServiceImpl::UnregisterLiteral(nsIRDFLiteral* aLiteral)
1510 : {
1511 : const PRUnichar* value;
1512 9343 : aLiteral->GetValueConst(&value);
1513 :
1514 9343 : NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mLiterals,
1515 : value,
1516 : PL_DHASH_LOOKUP)),
1517 : "literal was never registered");
1518 :
1519 9343 : PL_DHashTableOperate(&mLiterals, value, PL_DHASH_REMOVE);
1520 :
1521 : // N.B. that we _don't_ release the literal: we only held a weak
1522 : // reference to it in the hashtable.
1523 9343 : PR_LOG(gLog, PR_LOG_DEBUG,
1524 : ("rdfserv unregister-literal [%p] %s",
1525 : aLiteral, (const PRUnichar*) value));
1526 :
1527 9343 : return NS_OK;
1528 : }
1529 :
1530 : //----------------------------------------------------------------------
1531 :
1532 : nsresult
1533 8 : RDFServiceImpl::RegisterInt(nsIRDFInt* aInt)
1534 : {
1535 : PRInt32 value;
1536 8 : aInt->GetValue(&value);
1537 :
1538 8 : NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mInts,
1539 : &value,
1540 : PL_DHASH_LOOKUP)),
1541 : "int already registered");
1542 :
1543 : PLDHashEntryHdr *hdr =
1544 8 : PL_DHashTableOperate(&mInts, &value, PL_DHASH_ADD);
1545 :
1546 8 : if (! hdr)
1547 0 : return NS_ERROR_OUT_OF_MEMORY;
1548 :
1549 8 : IntHashEntry *entry = static_cast<IntHashEntry *>(hdr);
1550 :
1551 : // N.B., we only hold a weak reference to the literal: that
1552 : // way, the literal can be destroyed when the last refcount
1553 : // goes away. The single addref that the CreateInt() call
1554 : // made will be owned by the callee.
1555 8 : entry->mInt = aInt;
1556 8 : entry->mKey = value;
1557 :
1558 8 : PR_LOG(gLog, PR_LOG_DEBUG,
1559 : ("rdfserv register-int [%p] %d",
1560 : aInt, value));
1561 :
1562 8 : return NS_OK;
1563 : }
1564 :
1565 :
1566 : nsresult
1567 8 : RDFServiceImpl::UnregisterInt(nsIRDFInt* aInt)
1568 : {
1569 : PRInt32 value;
1570 8 : aInt->GetValue(&value);
1571 :
1572 8 : NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mInts,
1573 : &value,
1574 : PL_DHASH_LOOKUP)),
1575 : "int was never registered");
1576 :
1577 8 : PL_DHashTableOperate(&mInts, &value, PL_DHASH_REMOVE);
1578 :
1579 : // N.B. that we _don't_ release the literal: we only held a weak
1580 : // reference to it in the hashtable.
1581 8 : PR_LOG(gLog, PR_LOG_DEBUG,
1582 : ("rdfserv unregister-int [%p] %d",
1583 : aInt, value));
1584 :
1585 8 : return NS_OK;
1586 : }
1587 :
1588 : //----------------------------------------------------------------------
1589 :
1590 : nsresult
1591 0 : RDFServiceImpl::RegisterDate(nsIRDFDate* aDate)
1592 : {
1593 : PRTime value;
1594 0 : aDate->GetValue(&value);
1595 :
1596 0 : NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mDates,
1597 : &value,
1598 : PL_DHASH_LOOKUP)),
1599 : "date already registered");
1600 :
1601 : PLDHashEntryHdr *hdr =
1602 0 : PL_DHashTableOperate(&mDates, &value, PL_DHASH_ADD);
1603 :
1604 0 : if (! hdr)
1605 0 : return NS_ERROR_OUT_OF_MEMORY;
1606 :
1607 0 : DateHashEntry *entry = static_cast<DateHashEntry *>(hdr);
1608 :
1609 : // N.B., we only hold a weak reference to the literal: that
1610 : // way, the literal can be destroyed when the last refcount
1611 : // goes away. The single addref that the CreateDate() call
1612 : // made will be owned by the callee.
1613 0 : entry->mDate = aDate;
1614 0 : entry->mKey = value;
1615 :
1616 0 : PR_LOG(gLog, PR_LOG_DEBUG,
1617 : ("rdfserv register-date [%p] %ld",
1618 : aDate, value));
1619 :
1620 0 : return NS_OK;
1621 : }
1622 :
1623 :
1624 : nsresult
1625 0 : RDFServiceImpl::UnregisterDate(nsIRDFDate* aDate)
1626 : {
1627 : PRTime value;
1628 0 : aDate->GetValue(&value);
1629 :
1630 0 : NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mDates,
1631 : &value,
1632 : PL_DHASH_LOOKUP)),
1633 : "date was never registered");
1634 :
1635 0 : PL_DHashTableOperate(&mDates, &value, PL_DHASH_REMOVE);
1636 :
1637 : // N.B. that we _don't_ release the literal: we only held a weak
1638 : // reference to it in the hashtable.
1639 0 : PR_LOG(gLog, PR_LOG_DEBUG,
1640 : ("rdfserv unregister-date [%p] %ld",
1641 : aDate, value));
1642 :
1643 0 : return NS_OK;
1644 : }
1645 :
1646 : nsresult
1647 0 : RDFServiceImpl::RegisterBlob(BlobImpl *aBlob)
1648 : {
1649 0 : NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(PL_DHashTableOperate(&mBlobs,
1650 : &aBlob->mData,
1651 : PL_DHASH_LOOKUP)),
1652 : "blob already registered");
1653 :
1654 : PLDHashEntryHdr *hdr =
1655 0 : PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_ADD);
1656 :
1657 0 : if (! hdr)
1658 0 : return NS_ERROR_OUT_OF_MEMORY;
1659 :
1660 0 : BlobHashEntry *entry = static_cast<BlobHashEntry *>(hdr);
1661 :
1662 : // N.B., we only hold a weak reference to the literal: that
1663 : // way, the literal can be destroyed when the last refcount
1664 : // goes away. The single addref that the CreateInt() call
1665 : // made will be owned by the callee.
1666 0 : entry->mBlob = aBlob;
1667 :
1668 0 : PR_LOG(gLog, PR_LOG_DEBUG,
1669 : ("rdfserv register-blob [%p] %s",
1670 : aBlob, aBlob->mData.mBytes));
1671 :
1672 0 : return NS_OK;
1673 : }
1674 :
1675 : nsresult
1676 0 : RDFServiceImpl::UnregisterBlob(BlobImpl *aBlob)
1677 : {
1678 0 : NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(PL_DHashTableOperate(&mBlobs,
1679 : &aBlob->mData,
1680 : PL_DHASH_LOOKUP)),
1681 : "blob was never registered");
1682 :
1683 0 : PL_DHashTableOperate(&mBlobs, &aBlob->mData, PL_DHASH_REMOVE);
1684 :
1685 : // N.B. that we _don't_ release the literal: we only held a weak
1686 : // reference to it in the hashtable.
1687 0 : PR_LOG(gLog, PR_LOG_DEBUG,
1688 : ("rdfserv unregister-blob [%p] %s",
1689 : aBlob, aBlob->mData.mBytes));
1690 :
1691 0 : return NS_OK;
1692 : }
|