Bumping manifests a=b2g-bump
[gecko.git] / rdf / datasource / nsLocalStore.cpp
blobc4622937ebe9feb22556f128f39a461127ddead5
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/. */
7 /*
9 Implementation for the local store
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"
38 ////////////////////////////////////////////////////////////////////////
40 class LocalStoreImpl : public nsILocalStore,
41 public nsIRDFDataSource,
42 public nsIRDFRemoteDataSource,
43 public nsIObserver,
44 public nsSupportsWeakReference
46 protected:
47 nsCOMPtr<nsIRDFDataSource> mInner;
49 LocalStoreImpl();
50 virtual ~LocalStoreImpl();
51 nsresult Init();
52 nsresult CreateLocalStore(nsIFile* aFile);
53 nsresult LoadData();
55 friend nsresult
56 NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult);
58 nsCOMPtr<nsIRDFService> mRDFService;
60 public:
61 // nsISupports interface
62 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
63 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(LocalStoreImpl, nsILocalStore)
65 // nsILocalStore interface
67 // nsIRDFDataSource interface. Most of these are just delegated to
68 // the inner, in-memory datasource.
69 NS_IMETHOD GetURI(char* *aURI);
71 NS_IMETHOD GetSource(nsIRDFResource* aProperty,
72 nsIRDFNode* aTarget,
73 bool aTruthValue,
74 nsIRDFResource** aSource) {
75 return mInner->GetSource(aProperty, aTarget, aTruthValue, aSource);
78 NS_IMETHOD GetSources(nsIRDFResource* aProperty,
79 nsIRDFNode* aTarget,
80 bool aTruthValue,
81 nsISimpleEnumerator** aSources) {
82 return mInner->GetSources(aProperty, aTarget, aTruthValue, aSources);
85 NS_IMETHOD GetTarget(nsIRDFResource* aSource,
86 nsIRDFResource* aProperty,
87 bool aTruthValue,
88 nsIRDFNode** aTarget) {
89 return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget);
92 NS_IMETHOD GetTargets(nsIRDFResource* aSource,
93 nsIRDFResource* aProperty,
94 bool aTruthValue,
95 nsISimpleEnumerator** aTargets) {
96 return mInner->GetTargets(aSource, aProperty, aTruthValue, aTargets);
99 NS_IMETHOD Assert(nsIRDFResource* aSource,
100 nsIRDFResource* aProperty,
101 nsIRDFNode* aTarget,
102 bool aTruthValue) {
103 return mInner->Assert(aSource, aProperty, aTarget, aTruthValue);
106 NS_IMETHOD Unassert(nsIRDFResource* aSource,
107 nsIRDFResource* aProperty,
108 nsIRDFNode* aTarget) {
109 return mInner->Unassert(aSource, aProperty, aTarget);
112 NS_IMETHOD Change(nsIRDFResource* aSource,
113 nsIRDFResource* aProperty,
114 nsIRDFNode* aOldTarget,
115 nsIRDFNode* aNewTarget) {
116 return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget);
119 NS_IMETHOD Move(nsIRDFResource* aOldSource,
120 nsIRDFResource* aNewSource,
121 nsIRDFResource* aProperty,
122 nsIRDFNode* aTarget) {
123 return mInner->Move(aOldSource, aNewSource, aProperty, aTarget);
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);
134 NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) {
135 return NS_ERROR_NOT_IMPLEMENTED;
138 NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) {
139 return NS_ERROR_NOT_IMPLEMENTED;
142 NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) {
143 return mInner->HasArcIn(aNode, aArc, _retval);
146 NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) {
147 return mInner->HasArcOut(aSource, aArc, _retval);
150 NS_IMETHOD ArcLabelsIn(nsIRDFNode* aNode,
151 nsISimpleEnumerator** aLabels) {
152 return mInner->ArcLabelsIn(aNode, aLabels);
155 NS_IMETHOD ArcLabelsOut(nsIRDFResource* aSource,
156 nsISimpleEnumerator** aLabels) {
157 return mInner->ArcLabelsOut(aSource, aLabels);
160 NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) {
161 return mInner->GetAllResources(aResult);
164 NS_IMETHOD GetAllCmds(nsIRDFResource* aSource,
165 nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands);
167 NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
168 nsIRDFResource* aCommand,
169 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
170 bool* aResult);
172 NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
173 nsIRDFResource* aCommand,
174 nsISupportsArray/*<nsIRDFResource>*/* aArguments);
176 NS_IMETHOD BeginUpdateBatch() {
177 return mInner->BeginUpdateBatch();
180 NS_IMETHOD EndUpdateBatch() {
181 return mInner->EndUpdateBatch();
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);
190 // nsIObserver
191 NS_DECL_NSIOBSERVER
194 ////////////////////////////////////////////////////////////////////////
197 LocalStoreImpl::LocalStoreImpl(void)
201 LocalStoreImpl::~LocalStoreImpl(void)
203 if (mRDFService)
204 mRDFService->UnregisterDataSource(this);
208 nsresult
209 NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult)
211 NS_PRECONDITION(aOuter == nullptr, "no aggregation");
212 if (aOuter)
213 return NS_ERROR_NO_AGGREGATION;
215 NS_PRECONDITION(aResult != nullptr, "null ptr");
216 if (! aResult)
217 return NS_ERROR_NULL_POINTER;
219 LocalStoreImpl* impl = new LocalStoreImpl();
220 if (! impl)
221 return NS_ERROR_OUT_OF_MEMORY;
223 NS_ADDREF(impl);
225 nsresult rv;
226 rv = impl->Init();
227 if (NS_SUCCEEDED(rv)) {
228 // Set up the result pointer
229 rv = impl->QueryInterface(aIID, aResult);
232 NS_RELEASE(impl);
233 return rv;
236 NS_IMPL_CYCLE_COLLECTION(LocalStoreImpl, mInner)
237 NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalStoreImpl)
238 NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalStoreImpl)
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
249 // nsILocalStore interface
251 // nsIRDFDataSource interface
253 NS_IMETHODIMP
254 LocalStoreImpl::GetLoaded(bool* _result)
256 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
257 NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource");
258 if (! remote)
259 return NS_ERROR_UNEXPECTED;
261 return remote->GetLoaded(_result);
265 NS_IMETHODIMP
266 LocalStoreImpl::Init(const char *uri)
268 return(NS_OK);
271 NS_IMETHODIMP
272 LocalStoreImpl::Flush()
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;
283 return remote->Flush();
286 NS_IMETHODIMP
287 LocalStoreImpl::FlushTo(const char *aURI)
289 // Do not ever implement this (security)
290 return NS_ERROR_NOT_IMPLEMENTED;
293 NS_IMETHODIMP
294 LocalStoreImpl::Refresh(bool sync)
296 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner);
297 NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource");
298 if (! remote)
299 return NS_ERROR_UNEXPECTED;
301 return remote->Refresh(sync);
304 nsresult
305 LocalStoreImpl::Init()
307 nsresult rv;
309 rv = LoadData();
310 if (NS_FAILED(rv)) return rv;
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;
316 mRDFService->RegisterDataSource(this, false);
318 // Register as an observer of profile changes
319 nsCOMPtr<nsIObserverService> obs =
320 do_GetService("@mozilla.org/observer-service;1");
322 if (obs) {
323 obs->AddObserver(this, "profile-before-change", true);
324 obs->AddObserver(this, "profile-do-change", true);
327 return NS_OK;
330 nsresult
331 LocalStoreImpl::CreateLocalStore(nsIFile* aFile)
333 nsresult rv;
335 rv = aFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
336 if (NS_FAILED(rv)) return rv;
338 nsCOMPtr<nsIOutputStream> outStream;
339 rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aFile);
340 if (NS_FAILED(rv)) return rv;
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";
349 uint32_t count;
350 rv = outStream->Write(defaultRDF, sizeof(defaultRDF)-1, &count);
351 if (NS_FAILED(rv)) return rv;
353 if (count != sizeof(defaultRDF)-1)
354 return NS_ERROR_UNEXPECTED;
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;
364 return NS_OK;
367 nsresult
368 LocalStoreImpl::LoadData()
370 nsresult rv;
372 // Look for localstore.rdf in the current profile
373 // directory. Bomb if we can't find it.
375 nsCOMPtr<nsIFile> aFile;
376 rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile));
377 if (NS_FAILED(rv)) return rv;
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;
387 mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", &rv);
388 if (NS_FAILED(rv)) return rv;
390 nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner, &rv);
391 if (NS_FAILED(rv)) return rv;
393 nsCOMPtr<nsIURI> aURI;
394 rv = NS_NewFileURI(getter_AddRefs(aURI), aFile);
395 if (NS_FAILED(rv)) return rv;
397 nsAutoCString spec;
398 rv = aURI->GetSpec(spec);
399 if (NS_FAILED(rv)) return rv;
401 rv = remote->Init(spec.get());
402 if (NS_FAILED(rv)) return rv;
404 // Read the datasource synchronously.
405 rv = remote->Refresh(true);
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;
413 rv = remote->Refresh(true);
416 return rv;
420 NS_IMETHODIMP
421 LocalStoreImpl::GetURI(char* *aURI)
423 NS_PRECONDITION(aURI != nullptr, "null ptr");
424 if (! aURI)
425 return NS_ERROR_NULL_POINTER;
427 *aURI = NS_strdup("rdf:local-store");
428 if (! *aURI)
429 return NS_ERROR_OUT_OF_MEMORY;
431 return NS_OK;
435 NS_IMETHODIMP
436 LocalStoreImpl::GetAllCmds(nsIRDFResource* aSource,
437 nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands)
439 return(NS_NewEmptyEnumerator(aCommands));
442 NS_IMETHODIMP
443 LocalStoreImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
444 nsIRDFResource* aCommand,
445 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
446 bool* aResult)
448 *aResult = true;
449 return NS_OK;
452 NS_IMETHODIMP
453 LocalStoreImpl::DoCommand(nsISupportsArray* aSources,
454 nsIRDFResource* aCommand,
455 nsISupportsArray* aArguments)
457 // no-op
458 return NS_OK;
461 NS_IMETHODIMP
462 LocalStoreImpl::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData)
464 nsresult rv = NS_OK;
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();
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");
478 if (!NS_strcmp(someData, MOZ_UTF16("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);
485 else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
486 rv = LoadData();
488 return rv;