nsLocalStore.cpp 14 KB

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