rdf/datasource/src/nsLocalStore.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:9261884399eb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set cindent tabstop=4 expandtab shiftwidth=4: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /*
8
9 Implementation for the local store
10
11 */
12
13 #include "nsNetUtil.h"
14 #include "nsIURI.h"
15 #include "nsIIOService.h"
16 #include "nsIOutputStream.h"
17 #include "nsIComponentManager.h"
18 #include "nsILocalStore.h"
19 #include "nsIRDFDataSource.h"
20 #include "nsIRDFRemoteDataSource.h"
21 #include "nsIRDFService.h"
22 #include "nsIServiceManager.h"
23 #include "nsRDFCID.h"
24 #include "nsXPIDLString.h"
25 #include "plstr.h"
26 #include "rdf.h"
27 #include "nsCOMPtr.h"
28 #include "nsWeakPtr.h"
29 #include "nsAppDirectoryServiceDefs.h"
30 #include "nsIObserver.h"
31 #include "nsIObserverService.h"
32 #include "nsWeakReference.h"
33 #include "nsCRTGlue.h"
34 #include "nsCRT.h"
35 #include "nsEnumeratorUtils.h"
36 #include "nsCycleCollectionParticipant.h"
37
38 ////////////////////////////////////////////////////////////////////////
39
40 class LocalStoreImpl : public nsILocalStore,
41 public nsIRDFDataSource,
42 public nsIRDFRemoteDataSource,
43 public nsIObserver,
44 public nsSupportsWeakReference
45 {
46 protected:
47 nsCOMPtr<nsIRDFDataSource> mInner;
48
49 LocalStoreImpl();
50 virtual ~LocalStoreImpl();
51 nsresult Init();
52 nsresult CreateLocalStore(nsIFile* aFile);
53 nsresult LoadData();
54
55 friend nsresult
56 NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult);
57
58 nsCOMPtr<nsIRDFService> mRDFService;
59
60 public:
61 // nsISupports interface
62 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
63 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(LocalStoreImpl, nsILocalStore)
64
65 // nsILocalStore interface
66
67 // nsIRDFDataSource interface. Most of these are just delegated to
68 // the inner, in-memory datasource.
69 NS_IMETHOD GetURI(char* *aURI);
70
71 NS_IMETHOD GetSource(nsIRDFResource* aProperty,
72 nsIRDFNode* aTarget,
73 bool aTruthValue,
74 nsIRDFResource** aSource) {
75 return mInner->GetSource(aProperty, aTarget, aTruthValue, aSource);
76 }
77
78 NS_IMETHOD GetSources(nsIRDFResource* aProperty,
79 nsIRDFNode* aTarget,
80 bool aTruthValue,
81 nsISimpleEnumerator** aSources) {
82 return mInner->GetSources(aProperty, aTarget, aTruthValue, aSources);
83 }
84
85 NS_IMETHOD GetTarget(nsIRDFResource* aSource,
86 nsIRDFResource* aProperty,
87 bool aTruthValue,
88 nsIRDFNode** aTarget) {
89 return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget);
90 }
91
92 NS_IMETHOD GetTargets(nsIRDFResource* aSource,
93 nsIRDFResource* aProperty,
94 bool aTruthValue,
95 nsISimpleEnumerator** aTargets) {
96 return mInner->GetTargets(aSource, aProperty, aTruthValue, aTargets);
97 }
98
99 NS_IMETHOD Assert(nsIRDFResource* aSource,
100 nsIRDFResource* aProperty,
101 nsIRDFNode* aTarget,
102 bool aTruthValue) {
103 return mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
104 }
105
106 NS_IMETHOD Unassert(nsIRDFResource* aSource,
107 nsIRDFResource* aProperty,
108 nsIRDFNode* aTarget) {
109 return mInner->Unassert(aSource, aProperty, aTarget);
110 }
111
112 NS_IMETHOD Change(nsIRDFResource* aSource,
113 nsIRDFResource* aProperty,
114 nsIRDFNode* aOldTarget,
115 nsIRDFNode* aNewTarget) {
116 return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
117 }
118
119 NS_IMETHOD Move(nsIRDFResource* aOldSource,
120 nsIRDFResource* aNewSource,
121 nsIRDFResource* aProperty,
122 nsIRDFNode* aTarget) {
123 return mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
124 }
125
126 NS_IMETHOD HasAssertion(nsIRDFResource* aSource,
127 nsIRDFResource* aProperty,
128 nsIRDFNode* aTarget,
129 bool aTruthValue,
130 bool* hasAssertion) {
131 return mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, hasAssertion);
132 }
133
134 NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) {
135 return NS_ERROR_NOT_IMPLEMENTED;
136 }
137
138 NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) {
139 return NS_ERROR_NOT_IMPLEMENTED;
140 }
141
142 NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) {
143 return mInner->HasArcIn(aNode, aArc, _retval);
144 }
145
146 NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) {
147 return mInner->HasArcOut(aSource, aArc, _retval);
148 }
149
150 NS_IMETHOD ArcLabelsIn(nsIRDFNode* aNode,
151 nsISimpleEnumerator** aLabels) {
152 return mInner->ArcLabelsIn(aNode, aLabels);
153 }
154
155 NS_IMETHOD ArcLabelsOut(nsIRDFResource* aSource,
156 nsISimpleEnumerator** aLabels) {
157 return mInner->ArcLabelsOut(aSource, aLabels);
158 }
159
160 NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) {
161 return mInner->GetAllResources(aResult);
162 }
163
164 NS_IMETHOD GetAllCmds(nsIRDFResource* aSource,
165 nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands);
166
167 NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
168 nsIRDFResource* aCommand,
169 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
170 bool* aResult);
171
172 NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
173 nsIRDFResource* aCommand,
174 nsISupportsArray/*<nsIRDFResource>*/* aArguments);
175
176 NS_IMETHOD BeginUpdateBatch() {
177 return mInner->BeginUpdateBatch();
178 }
179
180 NS_IMETHOD EndUpdateBatch() {
181 return mInner->EndUpdateBatch();
182 }
183
184 NS_IMETHOD GetLoaded(bool* _result);
185 NS_IMETHOD Init(const char *uri);
186 NS_IMETHOD Flush();
187 NS_IMETHOD FlushTo(const char *aURI);
188 NS_IMETHOD Refresh(bool sync);
189
190 // nsIObserver
191 NS_DECL_NSIOBSERVER
192 };
193
194 ////////////////////////////////////////////////////////////////////////
195
196
197 LocalStoreImpl::LocalStoreImpl(void)
198 {
199 }
200
201 LocalStoreImpl::~LocalStoreImpl(void)
202 {
203 if (mRDFService)
204 mRDFService->UnregisterDataSource(this);
205 }
206
207
208 nsresult
209 NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult)
210 {
211 NS_PRECONDITION(aOuter == nullptr, "no aggregation");
212 if (aOuter)
213 return NS_ERROR_NO_AGGREGATION;
214
215 NS_PRECONDITION(aResult != nullptr, "null ptr");
216 if (! aResult)
217 return NS_ERROR_NULL_POINTER;
218
219 LocalStoreImpl* impl = new LocalStoreImpl();
220 if (! impl)
221 return NS_ERROR_OUT_OF_MEMORY;
222
223 NS_ADDREF(impl);
224
225 nsresult rv;
226 rv = impl->Init();
227 if (NS_SUCCEEDED(rv)) {
228 // Set up the result pointer
229 rv = impl->QueryInterface(aIID, aResult);
230 }
231
232 NS_RELEASE(impl);
233 return rv;
234 }
235
236 NS_IMPL_CYCLE_COLLECTION(LocalStoreImpl, mInner)
237 NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalStoreImpl)
238 NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalStoreImpl)
239
240 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStoreImpl)
241 NS_INTERFACE_MAP_ENTRY(nsILocalStore)
242 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
243 NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource)
244 NS_INTERFACE_MAP_ENTRY(nsIObserver)
245 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
246 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILocalStore)
247 NS_INTERFACE_MAP_END
248
249 // nsILocalStore interface
250
251 // nsIRDFDataSource interface
252
253 NS_IMETHODIMP
254 LocalStoreImpl::GetLoaded(bool* _result)
255 {
256 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
257 NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource");
258 if (! remote)
259 return NS_ERROR_UNEXPECTED;
260
261 return remote->GetLoaded(_result);
262 }
263
264
265 NS_IMETHODIMP
266 LocalStoreImpl::Init(const char *uri)
267 {
268 return(NS_OK);
269 }
270
271 NS_IMETHODIMP
272 LocalStoreImpl::Flush()
273 {
274 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
275 // FIXME Bug 340242: Temporarily make this a warning rather than an
276 // assertion until we sort out the ordering of how we write
277 // everything to the localstore, flush it, and disconnect it when
278 // we're getting profile-change notifications.
279 NS_WARN_IF_FALSE(remote != nullptr, "not an nsIRDFRemoteDataSource");
280 if (! remote)
281 return NS_ERROR_UNEXPECTED;
282
283 return remote->Flush();
284 }
285
286 NS_IMETHODIMP
287 LocalStoreImpl::FlushTo(const char *aURI)
288 {
289 // Do not ever implement this (security)
290 return NS_ERROR_NOT_IMPLEMENTED;
291 }
292
293 NS_IMETHODIMP
294 LocalStoreImpl::Refresh(bool sync)
295 {
296 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
297 NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource");
298 if (! remote)
299 return NS_ERROR_UNEXPECTED;
300
301 return remote->Refresh(sync);
302 }
303
304 nsresult
305 LocalStoreImpl::Init()
306 {
307 nsresult rv;
308
309 rv = LoadData();
310 if (NS_FAILED(rv)) return rv;
311
312 // register this as a named data source with the RDF service
313 mRDFService = do_GetService(NS_RDF_CONTRACTID "/rdf-service;1", &rv);
314 if (NS_FAILED(rv)) return rv;
315
316 mRDFService->RegisterDataSource(this, false);
317
318 // Register as an observer of profile changes
319 nsCOMPtr<nsIObserverService> obs =
320 do_GetService("@mozilla.org/observer-service;1");
321
322 if (obs) {
323 obs->AddObserver(this, "profile-before-change", true);
324 obs->AddObserver(this, "profile-do-change", true);
325 }
326
327 return NS_OK;
328 }
329
330 nsresult
331 LocalStoreImpl::CreateLocalStore(nsIFile* aFile)
332 {
333 nsresult rv;
334
335 rv = aFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
336 if (NS_FAILED(rv)) return rv;
337
338 nsCOMPtr<nsIOutputStream> outStream;
339 rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aFile);
340 if (NS_FAILED(rv)) return rv;
341
342 const char defaultRDF[] =
343 "<?xml version=\"1.0\"?>\n" \
344 "<RDF:RDF xmlns:RDF=\"" RDF_NAMESPACE_URI "\"\n" \
345 " xmlns:NC=\"" NC_NAMESPACE_URI "\">\n" \
346 " <!-- Empty -->\n" \
347 "</RDF:RDF>\n";
348
349 uint32_t count;
350 rv = outStream->Write(defaultRDF, sizeof(defaultRDF)-1, &count);
351 if (NS_FAILED(rv)) return rv;
352
353 if (count != sizeof(defaultRDF)-1)
354 return NS_ERROR_UNEXPECTED;
355
356 // Okay, now see if the file exists _for real_. If it's still
357 // not there, it could be that the profile service gave us
358 // back a read-only directory. Whatever.
359 bool fileExistsFlag = false;
360 aFile->Exists(&fileExistsFlag);
361 if (!fileExistsFlag)
362 return NS_ERROR_UNEXPECTED;
363
364 return NS_OK;
365 }
366
367 nsresult
368 LocalStoreImpl::LoadData()
369 {
370 nsresult rv;
371
372 // Look for localstore.rdf in the current profile
373 // directory. Bomb if we can't find it.
374
375 nsCOMPtr<nsIFile> aFile;
376 rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile));
377 if (NS_FAILED(rv)) return rv;
378
379 bool fileExistsFlag = false;
380 (void)aFile->Exists(&fileExistsFlag);
381 if (!fileExistsFlag) {
382 // if file doesn't exist, create it
383 rv = CreateLocalStore(aFile);
384 if (NS_FAILED(rv)) return rv;
385 }
386
387 mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", &rv);
388 if (NS_FAILED(rv)) return rv;
389
390 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner, &rv);
391 if (NS_FAILED(rv)) return rv;
392
393 nsCOMPtr<nsIURI> aURI;
394 rv = NS_NewFileURI(getter_AddRefs(aURI), aFile);
395 if (NS_FAILED(rv)) return rv;
396
397 nsAutoCString spec;
398 rv = aURI->GetSpec(spec);
399 if (NS_FAILED(rv)) return rv;
400
401 rv = remote->Init(spec.get());
402 if (NS_FAILED(rv)) return rv;
403
404 // Read the datasource synchronously.
405 rv = remote->Refresh(true);
406
407 if (NS_FAILED(rv)) {
408 // Load failed, delete and recreate a fresh localstore
409 aFile->Remove(true);
410 rv = CreateLocalStore(aFile);
411 if (NS_FAILED(rv)) return rv;
412
413 rv = remote->Refresh(true);
414 }
415
416 return rv;
417 }
418
419
420 NS_IMETHODIMP
421 LocalStoreImpl::GetURI(char* *aURI)
422 {
423 NS_PRECONDITION(aURI != nullptr, "null ptr");
424 if (! aURI)
425 return NS_ERROR_NULL_POINTER;
426
427 *aURI = NS_strdup("rdf:local-store");
428 if (! *aURI)
429 return NS_ERROR_OUT_OF_MEMORY;
430
431 return NS_OK;
432 }
433
434
435 NS_IMETHODIMP
436 LocalStoreImpl::GetAllCmds(nsIRDFResource* aSource,
437 nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands)
438 {
439 return(NS_NewEmptyEnumerator(aCommands));
440 }
441
442 NS_IMETHODIMP
443 LocalStoreImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
444 nsIRDFResource* aCommand,
445 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
446 bool* aResult)
447 {
448 *aResult = true;
449 return NS_OK;
450 }
451
452 NS_IMETHODIMP
453 LocalStoreImpl::DoCommand(nsISupportsArray* aSources,
454 nsIRDFResource* aCommand,
455 nsISupportsArray* aArguments)
456 {
457 // no-op
458 return NS_OK;
459 }
460
461 NS_IMETHODIMP
462 LocalStoreImpl::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
463 {
464 nsresult rv = NS_OK;
465
466 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
467 // Write out the old datasource's contents.
468 if (mInner) {
469 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
470 if (remote)
471 remote->Flush();
472 }
473
474 // Create an in-memory datasource for use while we're
475 // profile-less.
476 mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "in-memory-datasource");
477
478 if (!nsCRT::strcmp(NS_ConvertUTF16toUTF8(someData).get(), "shutdown-cleanse")) {
479 nsCOMPtr<nsIFile> aFile;
480 rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile));
481 if (NS_SUCCEEDED(rv))
482 rv = aFile->Remove(false);
483 }
484 }
485 else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
486 rv = LoadData();
487 }
488 return rv;
489 }

mercurial