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