1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/datasource/src/nsLocalStore.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,489 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set cindent tabstop=4 expandtab shiftwidth=4: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + 1.12 + Implementation for the local store 1.13 + 1.14 + */ 1.15 + 1.16 +#include "nsNetUtil.h" 1.17 +#include "nsIURI.h" 1.18 +#include "nsIIOService.h" 1.19 +#include "nsIOutputStream.h" 1.20 +#include "nsIComponentManager.h" 1.21 +#include "nsILocalStore.h" 1.22 +#include "nsIRDFDataSource.h" 1.23 +#include "nsIRDFRemoteDataSource.h" 1.24 +#include "nsIRDFService.h" 1.25 +#include "nsIServiceManager.h" 1.26 +#include "nsRDFCID.h" 1.27 +#include "nsXPIDLString.h" 1.28 +#include "plstr.h" 1.29 +#include "rdf.h" 1.30 +#include "nsCOMPtr.h" 1.31 +#include "nsWeakPtr.h" 1.32 +#include "nsAppDirectoryServiceDefs.h" 1.33 +#include "nsIObserver.h" 1.34 +#include "nsIObserverService.h" 1.35 +#include "nsWeakReference.h" 1.36 +#include "nsCRTGlue.h" 1.37 +#include "nsCRT.h" 1.38 +#include "nsEnumeratorUtils.h" 1.39 +#include "nsCycleCollectionParticipant.h" 1.40 + 1.41 +//////////////////////////////////////////////////////////////////////// 1.42 + 1.43 +class LocalStoreImpl : public nsILocalStore, 1.44 + public nsIRDFDataSource, 1.45 + public nsIRDFRemoteDataSource, 1.46 + public nsIObserver, 1.47 + public nsSupportsWeakReference 1.48 +{ 1.49 +protected: 1.50 + nsCOMPtr<nsIRDFDataSource> mInner; 1.51 + 1.52 + LocalStoreImpl(); 1.53 + virtual ~LocalStoreImpl(); 1.54 + nsresult Init(); 1.55 + nsresult CreateLocalStore(nsIFile* aFile); 1.56 + nsresult LoadData(); 1.57 + 1.58 + friend nsresult 1.59 + NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult); 1.60 + 1.61 + nsCOMPtr<nsIRDFService> mRDFService; 1.62 + 1.63 +public: 1.64 + // nsISupports interface 1.65 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.66 + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(LocalStoreImpl, nsILocalStore) 1.67 + 1.68 + // nsILocalStore interface 1.69 + 1.70 + // nsIRDFDataSource interface. Most of these are just delegated to 1.71 + // the inner, in-memory datasource. 1.72 + NS_IMETHOD GetURI(char* *aURI); 1.73 + 1.74 + NS_IMETHOD GetSource(nsIRDFResource* aProperty, 1.75 + nsIRDFNode* aTarget, 1.76 + bool aTruthValue, 1.77 + nsIRDFResource** aSource) { 1.78 + return mInner->GetSource(aProperty, aTarget, aTruthValue, aSource); 1.79 + } 1.80 + 1.81 + NS_IMETHOD GetSources(nsIRDFResource* aProperty, 1.82 + nsIRDFNode* aTarget, 1.83 + bool aTruthValue, 1.84 + nsISimpleEnumerator** aSources) { 1.85 + return mInner->GetSources(aProperty, aTarget, aTruthValue, aSources); 1.86 + } 1.87 + 1.88 + NS_IMETHOD GetTarget(nsIRDFResource* aSource, 1.89 + nsIRDFResource* aProperty, 1.90 + bool aTruthValue, 1.91 + nsIRDFNode** aTarget) { 1.92 + return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget); 1.93 + } 1.94 + 1.95 + NS_IMETHOD GetTargets(nsIRDFResource* aSource, 1.96 + nsIRDFResource* aProperty, 1.97 + bool aTruthValue, 1.98 + nsISimpleEnumerator** aTargets) { 1.99 + return mInner->GetTargets(aSource, aProperty, aTruthValue, aTargets); 1.100 + } 1.101 + 1.102 + NS_IMETHOD Assert(nsIRDFResource* aSource, 1.103 + nsIRDFResource* aProperty, 1.104 + nsIRDFNode* aTarget, 1.105 + bool aTruthValue) { 1.106 + return mInner->Assert(aSource, aProperty, aTarget, aTruthValue); 1.107 + } 1.108 + 1.109 + NS_IMETHOD Unassert(nsIRDFResource* aSource, 1.110 + nsIRDFResource* aProperty, 1.111 + nsIRDFNode* aTarget) { 1.112 + return mInner->Unassert(aSource, aProperty, aTarget); 1.113 + } 1.114 + 1.115 + NS_IMETHOD Change(nsIRDFResource* aSource, 1.116 + nsIRDFResource* aProperty, 1.117 + nsIRDFNode* aOldTarget, 1.118 + nsIRDFNode* aNewTarget) { 1.119 + return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); 1.120 + } 1.121 + 1.122 + NS_IMETHOD Move(nsIRDFResource* aOldSource, 1.123 + nsIRDFResource* aNewSource, 1.124 + nsIRDFResource* aProperty, 1.125 + nsIRDFNode* aTarget) { 1.126 + return mInner->Move(aOldSource, aNewSource, aProperty, aTarget); 1.127 + } 1.128 + 1.129 + NS_IMETHOD HasAssertion(nsIRDFResource* aSource, 1.130 + nsIRDFResource* aProperty, 1.131 + nsIRDFNode* aTarget, 1.132 + bool aTruthValue, 1.133 + bool* hasAssertion) { 1.134 + return mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, hasAssertion); 1.135 + } 1.136 + 1.137 + NS_IMETHOD AddObserver(nsIRDFObserver* aObserver) { 1.138 + return NS_ERROR_NOT_IMPLEMENTED; 1.139 + } 1.140 + 1.141 + NS_IMETHOD RemoveObserver(nsIRDFObserver* aObserver) { 1.142 + return NS_ERROR_NOT_IMPLEMENTED; 1.143 + } 1.144 + 1.145 + NS_IMETHOD HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *_retval) { 1.146 + return mInner->HasArcIn(aNode, aArc, _retval); 1.147 + } 1.148 + 1.149 + NS_IMETHOD HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *_retval) { 1.150 + return mInner->HasArcOut(aSource, aArc, _retval); 1.151 + } 1.152 + 1.153 + NS_IMETHOD ArcLabelsIn(nsIRDFNode* aNode, 1.154 + nsISimpleEnumerator** aLabels) { 1.155 + return mInner->ArcLabelsIn(aNode, aLabels); 1.156 + } 1.157 + 1.158 + NS_IMETHOD ArcLabelsOut(nsIRDFResource* aSource, 1.159 + nsISimpleEnumerator** aLabels) { 1.160 + return mInner->ArcLabelsOut(aSource, aLabels); 1.161 + } 1.162 + 1.163 + NS_IMETHOD GetAllResources(nsISimpleEnumerator** aResult) { 1.164 + return mInner->GetAllResources(aResult); 1.165 + } 1.166 + 1.167 + NS_IMETHOD GetAllCmds(nsIRDFResource* aSource, 1.168 + nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands); 1.169 + 1.170 + NS_IMETHOD IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.171 + nsIRDFResource* aCommand, 1.172 + nsISupportsArray/*<nsIRDFResource>*/* aArguments, 1.173 + bool* aResult); 1.174 + 1.175 + NS_IMETHOD DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.176 + nsIRDFResource* aCommand, 1.177 + nsISupportsArray/*<nsIRDFResource>*/* aArguments); 1.178 + 1.179 + NS_IMETHOD BeginUpdateBatch() { 1.180 + return mInner->BeginUpdateBatch(); 1.181 + } 1.182 + 1.183 + NS_IMETHOD EndUpdateBatch() { 1.184 + return mInner->EndUpdateBatch(); 1.185 + } 1.186 + 1.187 + NS_IMETHOD GetLoaded(bool* _result); 1.188 + NS_IMETHOD Init(const char *uri); 1.189 + NS_IMETHOD Flush(); 1.190 + NS_IMETHOD FlushTo(const char *aURI); 1.191 + NS_IMETHOD Refresh(bool sync); 1.192 + 1.193 + // nsIObserver 1.194 + NS_DECL_NSIOBSERVER 1.195 +}; 1.196 + 1.197 +//////////////////////////////////////////////////////////////////////// 1.198 + 1.199 + 1.200 +LocalStoreImpl::LocalStoreImpl(void) 1.201 +{ 1.202 +} 1.203 + 1.204 +LocalStoreImpl::~LocalStoreImpl(void) 1.205 +{ 1.206 + if (mRDFService) 1.207 + mRDFService->UnregisterDataSource(this); 1.208 +} 1.209 + 1.210 + 1.211 +nsresult 1.212 +NS_NewLocalStore(nsISupports* aOuter, REFNSIID aIID, void** aResult) 1.213 +{ 1.214 + NS_PRECONDITION(aOuter == nullptr, "no aggregation"); 1.215 + if (aOuter) 1.216 + return NS_ERROR_NO_AGGREGATION; 1.217 + 1.218 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.219 + if (! aResult) 1.220 + return NS_ERROR_NULL_POINTER; 1.221 + 1.222 + LocalStoreImpl* impl = new LocalStoreImpl(); 1.223 + if (! impl) 1.224 + return NS_ERROR_OUT_OF_MEMORY; 1.225 + 1.226 + NS_ADDREF(impl); 1.227 + 1.228 + nsresult rv; 1.229 + rv = impl->Init(); 1.230 + if (NS_SUCCEEDED(rv)) { 1.231 + // Set up the result pointer 1.232 + rv = impl->QueryInterface(aIID, aResult); 1.233 + } 1.234 + 1.235 + NS_RELEASE(impl); 1.236 + return rv; 1.237 +} 1.238 + 1.239 +NS_IMPL_CYCLE_COLLECTION(LocalStoreImpl, mInner) 1.240 +NS_IMPL_CYCLE_COLLECTING_ADDREF(LocalStoreImpl) 1.241 +NS_IMPL_CYCLE_COLLECTING_RELEASE(LocalStoreImpl) 1.242 + 1.243 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LocalStoreImpl) 1.244 + NS_INTERFACE_MAP_ENTRY(nsILocalStore) 1.245 + NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) 1.246 + NS_INTERFACE_MAP_ENTRY(nsIRDFRemoteDataSource) 1.247 + NS_INTERFACE_MAP_ENTRY(nsIObserver) 1.248 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.249 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsILocalStore) 1.250 +NS_INTERFACE_MAP_END 1.251 + 1.252 +// nsILocalStore interface 1.253 + 1.254 +// nsIRDFDataSource interface 1.255 + 1.256 +NS_IMETHODIMP 1.257 +LocalStoreImpl::GetLoaded(bool* _result) 1.258 +{ 1.259 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); 1.260 + NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource"); 1.261 + if (! remote) 1.262 + return NS_ERROR_UNEXPECTED; 1.263 + 1.264 + return remote->GetLoaded(_result); 1.265 +} 1.266 + 1.267 + 1.268 +NS_IMETHODIMP 1.269 +LocalStoreImpl::Init(const char *uri) 1.270 +{ 1.271 + return(NS_OK); 1.272 +} 1.273 + 1.274 +NS_IMETHODIMP 1.275 +LocalStoreImpl::Flush() 1.276 +{ 1.277 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); 1.278 + // FIXME Bug 340242: Temporarily make this a warning rather than an 1.279 + // assertion until we sort out the ordering of how we write 1.280 + // everything to the localstore, flush it, and disconnect it when 1.281 + // we're getting profile-change notifications. 1.282 + NS_WARN_IF_FALSE(remote != nullptr, "not an nsIRDFRemoteDataSource"); 1.283 + if (! remote) 1.284 + return NS_ERROR_UNEXPECTED; 1.285 + 1.286 + return remote->Flush(); 1.287 +} 1.288 + 1.289 +NS_IMETHODIMP 1.290 +LocalStoreImpl::FlushTo(const char *aURI) 1.291 +{ 1.292 + // Do not ever implement this (security) 1.293 + return NS_ERROR_NOT_IMPLEMENTED; 1.294 +} 1.295 + 1.296 +NS_IMETHODIMP 1.297 +LocalStoreImpl::Refresh(bool sync) 1.298 +{ 1.299 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); 1.300 + NS_ASSERTION(remote != nullptr, "not an nsIRDFRemoteDataSource"); 1.301 + if (! remote) 1.302 + return NS_ERROR_UNEXPECTED; 1.303 + 1.304 + return remote->Refresh(sync); 1.305 +} 1.306 + 1.307 +nsresult 1.308 +LocalStoreImpl::Init() 1.309 +{ 1.310 + nsresult rv; 1.311 + 1.312 + rv = LoadData(); 1.313 + if (NS_FAILED(rv)) return rv; 1.314 + 1.315 + // register this as a named data source with the RDF service 1.316 + mRDFService = do_GetService(NS_RDF_CONTRACTID "/rdf-service;1", &rv); 1.317 + if (NS_FAILED(rv)) return rv; 1.318 + 1.319 + mRDFService->RegisterDataSource(this, false); 1.320 + 1.321 + // Register as an observer of profile changes 1.322 + nsCOMPtr<nsIObserverService> obs = 1.323 + do_GetService("@mozilla.org/observer-service;1"); 1.324 + 1.325 + if (obs) { 1.326 + obs->AddObserver(this, "profile-before-change", true); 1.327 + obs->AddObserver(this, "profile-do-change", true); 1.328 + } 1.329 + 1.330 + return NS_OK; 1.331 +} 1.332 + 1.333 +nsresult 1.334 +LocalStoreImpl::CreateLocalStore(nsIFile* aFile) 1.335 +{ 1.336 + nsresult rv; 1.337 + 1.338 + rv = aFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666); 1.339 + if (NS_FAILED(rv)) return rv; 1.340 + 1.341 + nsCOMPtr<nsIOutputStream> outStream; 1.342 + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), aFile); 1.343 + if (NS_FAILED(rv)) return rv; 1.344 + 1.345 + const char defaultRDF[] = 1.346 + "<?xml version=\"1.0\"?>\n" \ 1.347 + "<RDF:RDF xmlns:RDF=\"" RDF_NAMESPACE_URI "\"\n" \ 1.348 + " xmlns:NC=\"" NC_NAMESPACE_URI "\">\n" \ 1.349 + " <!-- Empty -->\n" \ 1.350 + "</RDF:RDF>\n"; 1.351 + 1.352 + uint32_t count; 1.353 + rv = outStream->Write(defaultRDF, sizeof(defaultRDF)-1, &count); 1.354 + if (NS_FAILED(rv)) return rv; 1.355 + 1.356 + if (count != sizeof(defaultRDF)-1) 1.357 + return NS_ERROR_UNEXPECTED; 1.358 + 1.359 + // Okay, now see if the file exists _for real_. If it's still 1.360 + // not there, it could be that the profile service gave us 1.361 + // back a read-only directory. Whatever. 1.362 + bool fileExistsFlag = false; 1.363 + aFile->Exists(&fileExistsFlag); 1.364 + if (!fileExistsFlag) 1.365 + return NS_ERROR_UNEXPECTED; 1.366 + 1.367 + return NS_OK; 1.368 +} 1.369 + 1.370 +nsresult 1.371 +LocalStoreImpl::LoadData() 1.372 +{ 1.373 + nsresult rv; 1.374 + 1.375 + // Look for localstore.rdf in the current profile 1.376 + // directory. Bomb if we can't find it. 1.377 + 1.378 + nsCOMPtr<nsIFile> aFile; 1.379 + rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile)); 1.380 + if (NS_FAILED(rv)) return rv; 1.381 + 1.382 + bool fileExistsFlag = false; 1.383 + (void)aFile->Exists(&fileExistsFlag); 1.384 + if (!fileExistsFlag) { 1.385 + // if file doesn't exist, create it 1.386 + rv = CreateLocalStore(aFile); 1.387 + if (NS_FAILED(rv)) return rv; 1.388 + } 1.389 + 1.390 + mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", &rv); 1.391 + if (NS_FAILED(rv)) return rv; 1.392 + 1.393 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner, &rv); 1.394 + if (NS_FAILED(rv)) return rv; 1.395 + 1.396 + nsCOMPtr<nsIURI> aURI; 1.397 + rv = NS_NewFileURI(getter_AddRefs(aURI), aFile); 1.398 + if (NS_FAILED(rv)) return rv; 1.399 + 1.400 + nsAutoCString spec; 1.401 + rv = aURI->GetSpec(spec); 1.402 + if (NS_FAILED(rv)) return rv; 1.403 + 1.404 + rv = remote->Init(spec.get()); 1.405 + if (NS_FAILED(rv)) return rv; 1.406 + 1.407 + // Read the datasource synchronously. 1.408 + rv = remote->Refresh(true); 1.409 + 1.410 + if (NS_FAILED(rv)) { 1.411 + // Load failed, delete and recreate a fresh localstore 1.412 + aFile->Remove(true); 1.413 + rv = CreateLocalStore(aFile); 1.414 + if (NS_FAILED(rv)) return rv; 1.415 + 1.416 + rv = remote->Refresh(true); 1.417 + } 1.418 + 1.419 + return rv; 1.420 +} 1.421 + 1.422 + 1.423 +NS_IMETHODIMP 1.424 +LocalStoreImpl::GetURI(char* *aURI) 1.425 +{ 1.426 + NS_PRECONDITION(aURI != nullptr, "null ptr"); 1.427 + if (! aURI) 1.428 + return NS_ERROR_NULL_POINTER; 1.429 + 1.430 + *aURI = NS_strdup("rdf:local-store"); 1.431 + if (! *aURI) 1.432 + return NS_ERROR_OUT_OF_MEMORY; 1.433 + 1.434 + return NS_OK; 1.435 +} 1.436 + 1.437 + 1.438 +NS_IMETHODIMP 1.439 +LocalStoreImpl::GetAllCmds(nsIRDFResource* aSource, 1.440 + nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands) 1.441 +{ 1.442 + return(NS_NewEmptyEnumerator(aCommands)); 1.443 +} 1.444 + 1.445 +NS_IMETHODIMP 1.446 +LocalStoreImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources, 1.447 + nsIRDFResource* aCommand, 1.448 + nsISupportsArray/*<nsIRDFResource>*/* aArguments, 1.449 + bool* aResult) 1.450 +{ 1.451 + *aResult = true; 1.452 + return NS_OK; 1.453 +} 1.454 + 1.455 +NS_IMETHODIMP 1.456 +LocalStoreImpl::DoCommand(nsISupportsArray* aSources, 1.457 + nsIRDFResource* aCommand, 1.458 + nsISupportsArray* aArguments) 1.459 +{ 1.460 + // no-op 1.461 + return NS_OK; 1.462 +} 1.463 + 1.464 +NS_IMETHODIMP 1.465 +LocalStoreImpl::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) 1.466 +{ 1.467 + nsresult rv = NS_OK; 1.468 + 1.469 + if (!nsCRT::strcmp(aTopic, "profile-before-change")) { 1.470 + // Write out the old datasource's contents. 1.471 + if (mInner) { 1.472 + nsCOMPtr<nsIRDFRemoteDataSource> remote = do_QueryInterface(mInner); 1.473 + if (remote) 1.474 + remote->Flush(); 1.475 + } 1.476 + 1.477 + // Create an in-memory datasource for use while we're 1.478 + // profile-less. 1.479 + mInner = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "in-memory-datasource"); 1.480 + 1.481 + if (!nsCRT::strcmp(NS_ConvertUTF16toUTF8(someData).get(), "shutdown-cleanse")) { 1.482 + nsCOMPtr<nsIFile> aFile; 1.483 + rv = NS_GetSpecialDirectory(NS_APP_LOCALSTORE_50_FILE, getter_AddRefs(aFile)); 1.484 + if (NS_SUCCEEDED(rv)) 1.485 + rv = aFile->Remove(false); 1.486 + } 1.487 + } 1.488 + else if (!nsCRT::strcmp(aTopic, "profile-do-change")) { 1.489 + rv = LoadData(); 1.490 + } 1.491 + return rv; 1.492 +}