!import
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Content Preferences (cpref).
15 *
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2006
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Myk Melez <myk@mozilla.org>
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 const Ci = Components.interfaces;
38 const Cc = Components.classes;
39 const Cr = Components.results;
40 const Cu = Components.utils;
41
42 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
43
ContentPrefService
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
44 function ContentPrefService() {
45 // If this throws an exception, it causes the getService call to fail,
46 // but the next time a consumer tries to retrieve the service, we'll try
47 // to initialize the database again, which might work if the failure
48 // was due to a temporary condition (like being out of disk space).
49 this._dbInit();
50
51 // Observe shutdown so we can shut down the database connection.
52 this._observerSvc.addObserver(this, "xpcom-shutdown", false);
53 }
54
55 ContentPrefService.prototype = {
56 //**************************************************************************//
57 // XPCOM Plumbing
58
59 classDescription: "Content Pref Service",
60 classID: Components.ID("{e6a3f533-4ffa-4615-8eb4-d4e72d883fa7}"),
61 contractID: "@mozilla.org/content-pref/service;1",
62 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPrefService]),
63
64
65 //**************************************************************************//
66 // Convenience Getters
67
68 // Observer Service
69 __observerSvc: null,
ContentPrefService_get__observerSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
70 get _observerSvc ContentPrefService_get__observerSvc() {
71 if (!this.__observerSvc)
72 this.__observerSvc = Cc["@mozilla.org/observer-service;1"].
73 getService(Ci.nsIObserverService);
74 return this.__observerSvc;
75 },
76
77 // Console Service
78 __consoleSvc: null,
ContentPrefService_get__consoleSvc
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
79 get _consoleSvc ContentPrefService_get__consoleSvc() {
80 if (!this.__consoleSvc)
81 this.__consoleSvc = Cc["@mozilla.org/consoleservice;1"].
82 getService(Ci.nsIConsoleService);
83 return this.__consoleSvc;
84 },
85
86
87 //**************************************************************************//
88 // Destruction
89
ContentPrefService__destroy
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
90 _destroy: function ContentPrefService__destroy() {
91 this._observerSvc.removeObserver(this, "xpcom-shutdown");
92
93 // Delete references to XPCOM components to make sure we don't leak them
94 // (although we haven't observed leakage in tests). Also delete references
95 // in _observers and _genericObservers to avoid cycles with those that
96 // refer to us and don't remove themselves from those observer pools.
97 for (var i in this) {
98 try { this[i] = null }
99 // Ignore "setting a property that has only a getter" exceptions.
100 catch(ex) {}
101 }
102 },
103
104
105 //**************************************************************************//
106 // nsIObserver
107
ContentPrefService_observe
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
108 observe: function ContentPrefService_observe(subject, topic, data) {
109 switch (topic) {
110 case "xpcom-shutdown":
111 this._destroy();
112 break;
113 }
114 },
115
116
117 //**************************************************************************//
118 // nsIContentPrefService
119
ContentPrefService_getPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
120 getPref: function ContentPrefService_getPref(aURI, aName) {
121 if (aURI) {
122 var group = this.grouper.group(aURI);
123 return this._selectPref(group, aName);
124 }
125
126 return this._selectGlobalPref(aName);
127 },
128
ContentPrefService_setPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
129 setPref: function ContentPrefService_setPref(aURI, aName, aValue) {
130 // If the pref is already set to the value, there's nothing more to do.
131 var currentValue = this.getPref(aURI, aName);
132 if (typeof currentValue != "undefined" && currentValue == aValue)
133 return;
134
135 var settingID = this._selectSettingID(aName) || this._insertSetting(aName);
136 var group, groupID, prefID;
137 if (aURI) {
138 group = this.grouper.group(aURI);
139 groupID = this._selectGroupID(group) || this._insertGroup(group);
140 prefID = this._selectPrefID(groupID, settingID);
141 }
142 else {
143 group = null;
144 groupID = null;
145 prefID = this._selectGlobalPrefID(settingID);
146 }
147
148 // Update the existing record, if any, or create a new one.
149 if (prefID)
150 this._updatePref(prefID, aValue);
151 else
152 this._insertPref(groupID, settingID, aValue);
153
154 for each (var observer in this._getObservers(aName)) {
155 try {
156 observer.onContentPrefSet(group, aName, aValue);
157 }
158 catch(ex) {
159 Cu.reportError(ex);
160 }
161 }
162 },
163
ContentPrefService_hasPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
164 hasPref: function ContentPrefService_hasPref(aURI, aName) {
165 // XXX If consumers end up calling this method regularly, then we should
166 // optimize this to query the database directly.
167 return (typeof this.getPref(aURI, aName) != "undefined");
168 },
169
ContentPrefService_removePref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
170 removePref: function ContentPrefService_removePref(aURI, aName) {
171 // If there's no old value, then there's nothing to remove.
172 if (!this.hasPref(aURI, aName))
173 return;
174
175 var settingID = this._selectSettingID(aName);
176 var group, groupID, prefID;
177 if (aURI) {
178 group = this.grouper.group(aURI);
179 groupID = this._selectGroupID(group);
180 prefID = this._selectPrefID(groupID, settingID);
181 }
182 else {
183 group = null;
184 groupID = null;
185 prefID = this._selectGlobalPrefID(settingID);
186 }
187
188 this._deletePref(prefID);
189
190 // Get rid of extraneous records that are no longer being used.
191 this._deleteSettingIfUnused(settingID);
192 if (groupID)
193 this._deleteGroupIfUnused(groupID);
194
195 for each (var observer in this._getObservers(aName)) {
196 try {
197 observer.onContentPrefRemoved(group, aName);
198 }
199 catch(ex) {
200 Cu.reportError(ex);
201 }
202 }
203 },
204
ContentPrefService_getPrefs
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
205 getPrefs: function ContentPrefService_getPrefs(aURI) {
206 if (aURI) {
207 var group = this.grouper.group(aURI);
208 return this._selectPrefs(group);
209 }
210
211 return this._selectGlobalPrefs();
212 },
213
214 // A hash of arrays of observers, indexed by setting name.
215 _observers: {},
216
217 // An array of generic observers, which observe all settings.
218 _genericObservers: [],
219
ContentPrefService_addObserver
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
220 addObserver: function ContentPrefService_addObserver(aName, aObserver) {
221 var observers;
222 if (aName) {
223 if (!this._observers[aName])
224 this._observers[aName] = [];
225 observers = this._observers[aName];
226 }
227 else
228 observers = this._genericObservers;
229
230 if (observers.indexOf(aObserver) == -1)
231 observers.push(aObserver);
232 },
233
ContentPrefService_removeObserver
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
234 removeObserver: function ContentPrefService_removeObserver(aName, aObserver) {
235 var observers;
236 if (aName) {
237 if (!this._observers[aName])
238 return;
239 observers = this._observers[aName];
240 }
241 else
242 observers = this._genericObservers;
243
244 if (observers.indexOf(aObserver) != -1)
245 observers.splice(observers.indexOf(aObserver), 1);
246 },
247
248 /**
249 * Construct a list of observers to notify about a change to some setting,
250 * putting setting-specific observers before before generic ones, so observers
251 * that initialize individual settings (like the page style controller)
252 * execute before observers that display multiple settings and depend on them
253 * being initialized first (like the content prefs sidebar).
254 */
ContentPrefService__getObservers
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
255 _getObservers: function ContentPrefService__getObservers(aName) {
256 var observers = [];
257
258 if (aName && this._observers[aName])
259 observers = observers.concat(this._observers[aName]);
260 observers = observers.concat(this._genericObservers);
261
262 return observers;
263 },
264
265 _grouper: null,
ContentPrefService_get_grouper
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
266 get grouper ContentPrefService_get_grouper() {
267 if (!this._grouper)
268 this._grouper = Cc["@mozilla.org/content-pref/hostname-grouper;1"].
269 getService(Ci.nsIContentURIGrouper);
270 return this._grouper;
271 },
272
ContentPrefService_get_DBConnection
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
273 get DBConnection ContentPrefService_get_DBConnection() {
274 return this._dbConnection;
275 },
276
277
278 //**************************************************************************//
279 // Data Retrieval & Modification
280
281 __stmtSelectPref: null,
ContentPrefService_get__stmtSelectPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
282 get _stmtSelectPref ContentPrefService_get__stmtSelectPref() {
283 if (!this.__stmtSelectPref)
284 this.__stmtSelectPref = this._dbCreateStatement(
285 "SELECT prefs.value AS value " +
286 "FROM prefs " +
287 "JOIN groups ON prefs.groupID = groups.id " +
288 "JOIN settings ON prefs.settingID = settings.id " +
289 "WHERE groups.name = :group " +
290 "AND settings.name = :setting"
291 );
292
293 return this.__stmtSelectPref;
294 },
295
ContentPrefService__selectPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
296 _selectPref: function ContentPrefService__selectPref(aGroup, aSetting) {
297 var value;
298
299 try {
300 this._stmtSelectPref.params.group = aGroup;
301 this._stmtSelectPref.params.setting = aSetting;
302
303 if (this._stmtSelectPref.step())
304 value = this._stmtSelectPref.row["value"];
305 }
306 finally {
307 this._stmtSelectPref.reset();
308 }
309
310 return value;
311 },
312
313 __stmtSelectGlobalPref: null,
ContentPrefService_get__stmtSelectGlobalPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
314 get _stmtSelectGlobalPref ContentPrefService_get__stmtSelectGlobalPref() {
315 if (!this.__stmtSelectGlobalPref)
316 this.__stmtSelectGlobalPref = this._dbCreateStatement(
317 "SELECT prefs.value AS value " +
318 "FROM prefs " +
319 "JOIN settings ON prefs.settingID = settings.id " +
320 "WHERE prefs.groupID IS NULL " +
321 "AND settings.name = :name"
322 );
323
324 return this.__stmtSelectGlobalPref;
325 },
326
ContentPrefService__selectGlobalPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
327 _selectGlobalPref: function ContentPrefService__selectGlobalPref(aName) {
328 var value;
329
330 try {
331 this._stmtSelectGlobalPref.params.name = aName;
332
333 if (this._stmtSelectGlobalPref.step())
334 value = this._stmtSelectGlobalPref.row["value"];
335 }
336 finally {
337 this._stmtSelectGlobalPref.reset();
338 }
339
340 return value;
341 },
342
343 __stmtSelectGroupID: null,
ContentPrefService_get__stmtSelectGroupID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
344 get _stmtSelectGroupID ContentPrefService_get__stmtSelectGroupID() {
345 if (!this.__stmtSelectGroupID)
346 this.__stmtSelectGroupID = this._dbCreateStatement(
347 "SELECT groups.id AS id " +
348 "FROM groups " +
349 "WHERE groups.name = :name "
350 );
351
352 return this.__stmtSelectGroupID;
353 },
354
ContentPrefService__selectGroupID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
355 _selectGroupID: function ContentPrefService__selectGroupID(aName) {
356 var id;
357
358 try {
359 this._stmtSelectGroupID.params.name = aName;
360
361 if (this._stmtSelectGroupID.step())
362 id = this._stmtSelectGroupID.row["id"];
363 }
364 finally {
365 this._stmtSelectGroupID.reset();
366 }
367
368 return id;
369 },
370
371 __stmtInsertGroup: null,
ContentPrefService_get__stmtInsertGroup
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
372 get _stmtInsertGroup ContentPrefService_get__stmtInsertGroup() {
373 if (!this.__stmtInsertGroup)
374 this.__stmtInsertGroup = this._dbCreateStatement(
375 "INSERT INTO groups (name) VALUES (:name)"
376 );
377
378 return this.__stmtInsertGroup;
379 },
380
ContentPrefService__insertGroup
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
381 _insertGroup: function ContentPrefService__insertGroup(aName) {
382 this._stmtInsertGroup.params.name = aName;
383 this._stmtInsertGroup.execute();
384 return this._dbConnection.lastInsertRowID;
385 },
386
387 __stmtSelectSettingID: null,
ContentPrefService_get__stmtSelectSettingID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
388 get _stmtSelectSettingID ContentPrefService_get__stmtSelectSettingID() {
389 if (!this.__stmtSelectSettingID)
390 this.__stmtSelectSettingID = this._dbCreateStatement(
391 "SELECT id FROM settings WHERE name = :name"
392 );
393
394 return this.__stmtSelectSettingID;
395 },
396
ContentPrefService__selectSettingID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
397 _selectSettingID: function ContentPrefService__selectSettingID(aName) {
398 var id;
399
400 try {
401 this._stmtSelectSettingID.params.name = aName;
402
403 if (this._stmtSelectSettingID.step())
404 id = this._stmtSelectSettingID.row["id"];
405 }
406 finally {
407 this._stmtSelectSettingID.reset();
408 }
409
410 return id;
411 },
412
413 __stmtInsertSetting: null,
ContentPrefService_get__stmtInsertSetting
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
414 get _stmtInsertSetting ContentPrefService_get__stmtInsertSetting() {
415 if (!this.__stmtInsertSetting)
416 this.__stmtInsertSetting = this._dbCreateStatement(
417 "INSERT INTO settings (name) VALUES (:name)"
418 );
419
420 return this.__stmtInsertSetting;
421 },
422
ContentPrefService__insertSetting
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
423 _insertSetting: function ContentPrefService__insertSetting(aName) {
424 this._stmtInsertSetting.params.name = aName;
425 this._stmtInsertSetting.execute();
426 return this._dbConnection.lastInsertRowID;
427 },
428
429 __stmtSelectPrefID: null,
ContentPrefService_get__stmtSelectPrefID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
430 get _stmtSelectPrefID ContentPrefService_get__stmtSelectPrefID() {
431 if (!this.__stmtSelectPrefID)
432 this.__stmtSelectPrefID = this._dbCreateStatement(
433 "SELECT id FROM prefs WHERE groupID = :groupID AND settingID = :settingID"
434 );
435
436 return this.__stmtSelectPrefID;
437 },
438
ContentPrefService__selectPrefID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
439 _selectPrefID: function ContentPrefService__selectPrefID(aGroupID, aSettingID) {
440 var id;
441
442 try {
443 this._stmtSelectPrefID.params.groupID = aGroupID;
444 this._stmtSelectPrefID.params.settingID = aSettingID;
445
446 if (this._stmtSelectPrefID.step())
447 id = this._stmtSelectPrefID.row["id"];
448 }
449 finally {
450 this._stmtSelectPrefID.reset();
451 }
452
453 return id;
454 },
455
456 __stmtSelectGlobalPrefID: null,
ContentPrefService_get__stmtSelectGlobalPrefID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
457 get _stmtSelectGlobalPrefID ContentPrefService_get__stmtSelectGlobalPrefID() {
458 if (!this.__stmtSelectGlobalPrefID)
459 this.__stmtSelectGlobalPrefID = this._dbCreateStatement(
460 "SELECT id FROM prefs WHERE groupID IS NULL AND settingID = :settingID"
461 );
462
463 return this.__stmtSelectGlobalPrefID;
464 },
465
ContentPrefService__selectGlobalPrefID
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
466 _selectGlobalPrefID: function ContentPrefService__selectGlobalPrefID(aSettingID) {
467 var id;
468
469 try {
470 this._stmtSelectGlobalPrefID.params.settingID = aSettingID;
471
472 if (this._stmtSelectGlobalPrefID.step())
473 id = this._stmtSelectGlobalPrefID.row["id"];
474 }
475 finally {
476 this._stmtSelectGlobalPrefID.reset();
477 }
478
479 return id;
480 },
481
482 __stmtInsertPref: null,
ContentPrefService_get__stmtInsertPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
483 get _stmtInsertPref ContentPrefService_get__stmtInsertPref() {
484 if (!this.__stmtInsertPref)
485 this.__stmtInsertPref = this._dbCreateStatement(
486 "INSERT INTO prefs (groupID, settingID, value) " +
487 "VALUES (:groupID, :settingID, :value)"
488 );
489
490 return this.__stmtInsertPref;
491 },
492
ContentPrefService__insertPref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
493 _insertPref: function ContentPrefService__insertPref(aGroupID, aSettingID, aValue) {
494 this._stmtInsertPref.params.groupID = aGroupID;
495 this._stmtInsertPref.params.settingID = aSettingID;
496 this._stmtInsertPref.params.value = aValue;
497 this._stmtInsertPref.execute();
498 return this._dbConnection.lastInsertRowID;
499 },
500
501 __stmtUpdatePref: null,
ContentPrefService_get__stmtUpdatePref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
502 get _stmtUpdatePref ContentPrefService_get__stmtUpdatePref() {
503 if (!this.__stmtUpdatePref)
504 this.__stmtUpdatePref = this._dbCreateStatement(
505 "UPDATE prefs SET value = :value WHERE id = :id"
506 );
507
508 return this.__stmtUpdatePref;
509 },
510
ContentPrefService__updatePref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
511 _updatePref: function ContentPrefService__updatePref(aPrefID, aValue) {
512 this._stmtUpdatePref.params.id = aPrefID;
513 this._stmtUpdatePref.params.value = aValue;
514 this._stmtUpdatePref.execute();
515 },
516
517 __stmtDeletePref: null,
ContentPrefService_get__stmtDeletePref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
518 get _stmtDeletePref ContentPrefService_get__stmtDeletePref() {
519 if (!this.__stmtDeletePref)
520 this.__stmtDeletePref = this._dbCreateStatement(
521 "DELETE FROM prefs WHERE id = :id"
522 );
523
524 return this.__stmtDeletePref;
525 },
526
ContentPrefService__deletePref
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
527 _deletePref: function ContentPrefService__deletePref(aPrefID) {
528 this._stmtDeletePref.params.id = aPrefID;
529 this._stmtDeletePref.execute();
530 },
531
532 __stmtDeleteSettingIfUnused: null,
ContentPrefService_get__stmtDeleteSettingIfUnused
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
533 get _stmtDeleteSettingIfUnused ContentPrefService_get__stmtDeleteSettingIfUnused() {
534 if (!this.__stmtDeleteSettingIfUnused)
535 this.__stmtDeleteSettingIfUnused = this._dbCreateStatement(
536 "DELETE FROM settings WHERE id = :id " +
537 "AND id NOT IN (SELECT DISTINCT settingID FROM prefs)"
538 );
539
540 return this.__stmtDeleteSettingIfUnused;
541 },
542
ContentPrefService__deleteSettingIfUnused
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
543 _deleteSettingIfUnused: function ContentPrefService__deleteSettingIfUnused(aSettingID) {
544 this._stmtDeleteSettingIfUnused.params.id = aSettingID;
545 this._stmtDeleteSettingIfUnused.execute();
546 },
547
548 __stmtDeleteGroupIfUnused: null,
ContentPrefService_get__stmtDeleteGroupIfUnused
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
549 get _stmtDeleteGroupIfUnused ContentPrefService_get__stmtDeleteGroupIfUnused() {
550 if (!this.__stmtDeleteGroupIfUnused)
551 this.__stmtDeleteGroupIfUnused = this._dbCreateStatement(
552 "DELETE FROM groups WHERE id = :id " +
553 "AND id NOT IN (SELECT DISTINCT groupID FROM prefs)"
554 );
555
556 return this.__stmtDeleteGroupIfUnused;
557 },
558
ContentPrefService__deleteGroupIfUnused
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
559 _deleteGroupIfUnused: function ContentPrefService__deleteGroupIfUnused(aGroupID) {
560 this._stmtDeleteGroupIfUnused.params.id = aGroupID;
561 this._stmtDeleteGroupIfUnused.execute();
562 },
563
564 __stmtSelectPrefs: null,
ContentPrefService_get__stmtSelectPrefs
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
565 get _stmtSelectPrefs ContentPrefService_get__stmtSelectPrefs() {
566 if (!this.__stmtSelectPrefs)
567 this.__stmtSelectPrefs = this._dbCreateStatement(
568 "SELECT settings.name AS name, prefs.value AS value " +
569 "FROM prefs " +
570 "JOIN groups ON prefs.groupID = groups.id " +
571 "JOIN settings ON prefs.settingID = settings.id " +
572 "WHERE groups.name = :group "
573 );
574
575 return this.__stmtSelectPrefs;
576 },
577
ContentPrefService__selectPrefs
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
578 _selectPrefs: function ContentPrefService__selectPrefs(aGroup) {
579 var prefs = Cc["@mozilla.org/hash-property-bag;1"].
580 createInstance(Ci.nsIWritablePropertyBag);
581
582 try {
583 this._stmtSelectPrefs.params.group = aGroup;
584
585 while (this._stmtSelectPrefs.step())
586 prefs.setProperty(this._stmtSelectPrefs.row["name"],
587 this._stmtSelectPrefs.row["value"]);
588 }
589 finally {
590 this._stmtSelectPrefs.reset();
591 }
592
593 return prefs;
594 },
595
596 __stmtSelectGlobalPrefs: null,
ContentPrefService_get__stmtSelectGlobalPrefs
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
597 get _stmtSelectGlobalPrefs ContentPrefService_get__stmtSelectGlobalPrefs() {
598 if (!this.__stmtSelectGlobalPrefs)
599 this.__stmtSelectGlobalPrefs = this._dbCreateStatement(
600 "SELECT settings.name AS name, prefs.value AS value " +
601 "FROM prefs " +
602 "JOIN settings ON prefs.settingID = settings.id " +
603 "WHERE prefs.groupID IS NULL"
604 );
605
606 return this.__stmtSelectGlobalPrefs;
607 },
608
ContentPrefService__selectGlobalPrefs
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
609 _selectGlobalPrefs: function ContentPrefService__selectGlobalPrefs() {
610 var prefs = Cc["@mozilla.org/hash-property-bag;1"].
611 createInstance(Ci.nsIWritablePropertyBag);
612
613 try {
614 while (this._stmtSelectGlobalPrefs.step())
615 prefs.setProperty(this._stmtSelectGlobalPrefs.row["name"],
616 this._stmtSelectGlobalPrefs.row["value"]);
617 }
618 finally {
619 this._stmtSelectGlobalPrefs.reset();
620 }
621
622 return prefs;
623 },
624
625
626 //**************************************************************************//
627 // Database Creation & Access
628
629 _dbVersion: 3,
630
631 _dbSchema: {
632 tables: {
633 groups: "id INTEGER PRIMARY KEY, \
634 name TEXT NOT NULL",
635
636 settings: "id INTEGER PRIMARY KEY, \
637 name TEXT NOT NULL",
638
639 prefs: "id INTEGER PRIMARY KEY, \
640 groupID INTEGER REFERENCES groups(id), \
641 settingID INTEGER NOT NULL REFERENCES settings(id), \
642 value BLOB"
643 },
644 indices: {
645 groups_idx: {
646 table: "groups",
647 columns: ["name"]
648 },
649 settings_idx: {
650 table: "settings",
651 columns: ["name"]
652 },
653 prefs_idx: {
654 table: "prefs",
655 columns: ["groupID", "settingID"]
656 }
657 }
658 },
659
660 _dbConnection: null,
661
ContentPrefService__dbCreateStatement
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
662 _dbCreateStatement: function ContentPrefService__dbCreateStatement(aSQLString) {
663 try {
664 var statement = this._dbConnection.createStatement(aSQLString);
665 }
666 catch(ex) {
667 Cu.reportError("error creating statement " + aSQLString + ": " +
668 this._dbConnection.lastError + " - " +
669 this._dbConnection.lastErrorString);
670 throw ex;
671 }
672
673 var wrappedStatement = Cc["@mozilla.org/storage/statement-wrapper;1"].
674 createInstance(Ci.mozIStorageStatementWrapper);
675 wrappedStatement.initialize(statement);
676 return wrappedStatement;
677 },
678
679 // _dbInit and the methods it calls (_dbCreate, _dbMigrate, and version-
680 // specific migration methods) must be careful not to call any method
681 // of the service that assumes the database connection has already been
682 // initialized, since it won't be initialized until at the end of _dbInit.
683
ContentPrefService__dbInit
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
684 _dbInit: function ContentPrefService__dbInit() {
685 var dirService = Cc["@mozilla.org/file/directory_service;1"].
686 getService(Ci.nsIProperties);
687 var dbFile = dirService.get("ProfD", Ci.nsIFile);
688 dbFile.append("content-prefs.sqlite");
689
690 var dbService = Cc["@mozilla.org/storage/service;1"].
691 getService(Ci.mozIStorageService);
692
693 var dbConnection;
694
695 if (!dbFile.exists())
696 dbConnection = this._dbCreate(dbService, dbFile);
697 else {
698 try {
699 dbConnection = dbService.openDatabase(dbFile);
700 }
701 // If the connection isn't ready after we open the database, that means
702 // the database has been corrupted, so we back it up and then recreate it.
703 catch (e if e.result == Cr.NS_ERROR_FILE_CORRUPTED) {
704 dbConnection = this._dbBackUpAndRecreate(dbService, dbFile,
705 dbConnection);
706 }
707
708 // Get the version of the schema in the file.
709 var version = dbConnection.schemaVersion;
710
711 // Try to migrate the schema in the database to the current schema used by
712 // the service. If migration fails, back up the database and recreate it.
713 if (version != this._dbVersion) {
714 try {
715 this._dbMigrate(dbConnection, version, this._dbVersion);
716 }
717 catch(ex) {
718 Cu.reportError("error migrating DB: " + ex + "; backing up and recreating");
719 dbConnection = this._dbBackUpAndRecreate(dbService, dbFile, dbConnection);
720 }
721 }
722 }
723
724 this._dbConnection = dbConnection;
725 },
726
ContentPrefService__dbCreate
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
727 _dbCreate: function ContentPrefService__dbCreate(aDBService, aDBFile) {
728 var dbConnection = aDBService.openDatabase(aDBFile);
729
730 try {
731 this._dbCreateSchema(dbConnection);
732 dbConnection.schemaVersion = this._dbVersion;
733 }
734 catch(ex) {
735 // If we failed to create the database (perhaps because the disk ran out
736 // of space), then remove the database file so we don't leave it in some
737 // half-created state from which we won't know how to recover.
738 dbConnection.close();
739 aDBFile.remove(false);
740 throw ex;
741 }
742
743 return dbConnection;
744 },
745
ContentPrefService__dbCreateSchema
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
746 _dbCreateSchema: function ContentPrefService__dbCreateSchema(aDBConnection) {
747 this._dbCreateTables(aDBConnection);
748 this._dbCreateIndices(aDBConnection);
749 },
750
ContentPrefService__dbCreateTables
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
751 _dbCreateTables: function ContentPrefService__dbCreateTables(aDBConnection) {
752 for (let name in this._dbSchema.tables)
753 aDBConnection.createTable(name, this._dbSchema.tables[name]);
754 },
755
ContentPrefService__dbCreateIndices
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
756 _dbCreateIndices: function ContentPrefService__dbCreateIndices(aDBConnection) {
757 for (let name in this._dbSchema.indices) {
758 let index = this._dbSchema.indices[name];
759 let statement = "CREATE INDEX IF NOT EXISTS " + name + " ON " + index.table +
760 "(" + index.columns.join(", ") + ")";
761 aDBConnection.executeSimpleSQL(statement);
762 }
763 },
764
ContentPrefService__dbBackUpAndRecreate
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
765 _dbBackUpAndRecreate: function ContentPrefService__dbBackUpAndRecreate(aDBService,
766 aDBFile,
767 aDBConnection) {
768 aDBService.backupDatabaseFile(aDBFile, "content-prefs.sqlite.corrupt");
769
770 // Close the database, ignoring the "already closed" exception, if any.
771 // It'll be open if we're here because of a migration failure but closed
772 // if we're here because of database corruption.
773 try { aDBConnection.close() } catch(ex) {}
774
775 aDBFile.remove(false);
776
777 let dbConnection = this._dbCreate(aDBService, aDBFile);
778
779 return dbConnection;
780 },
781
ContentPrefService__dbMigrate
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
782 _dbMigrate: function ContentPrefService__dbMigrate(aDBConnection, aOldVersion, aNewVersion) {
783 if (this["_dbMigrate" + aOldVersion + "To" + aNewVersion]) {
784 aDBConnection.beginTransaction();
785 try {
786 this["_dbMigrate" + aOldVersion + "To" + aNewVersion](aDBConnection);
787 aDBConnection.schemaVersion = aNewVersion;
788 aDBConnection.commitTransaction();
789 }
790 catch(ex) {
791 aDBConnection.rollbackTransaction();
792 throw ex;
793 }
794 }
795 else
796 throw("no migrator function from version " + aOldVersion +
797 " to version " + aNewVersion);
798 },
799
800 /**
801 * If the schema version is 0, that means it was never set, which means
802 * the database was somehow created without the schema being applied, perhaps
803 * because the system ran out of disk space (although we check for this
804 * in _createDB) or because some other code created the database file without
805 * applying the schema. In any case, recover by simply reapplying the schema.
806 */
ContentPrefService___dbMigrate0To3
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
807 _dbMigrate0To3: function ContentPrefService___dbMigrate0To3(aDBConnection) {
808 this._dbCreateSchema(aDBConnection);
809 },
810
ContentPrefService___dbMigrate1To3
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
811 _dbMigrate1To3: function ContentPrefService___dbMigrate1To3(aDBConnection) {
812 aDBConnection.executeSimpleSQL("ALTER TABLE groups RENAME TO groupsOld");
813 aDBConnection.createTable("groups", this._dbSchema.tables.groups);
814 aDBConnection.executeSimpleSQL(
815 "INSERT INTO groups (id, name) " +
816 "SELECT id, name FROM groupsOld"
817 );
818
819 aDBConnection.executeSimpleSQL("DROP TABLE groupers");
820 aDBConnection.executeSimpleSQL("DROP TABLE groupsOld");
821
822 this._dbCreateIndices(aDBConnection);
823 },
824
ContentPrefService__dbMigrate2To3
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
825 _dbMigrate2To3: function ContentPrefService__dbMigrate2To3(aDBConnection) {
826 this._dbCreateIndices(aDBConnection);
827 }
828
829 };
830
831
HostnameGrouper
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
832 function HostnameGrouper() {}
833
834 HostnameGrouper.prototype = {
835 //**************************************************************************//
836 // XPCOM Plumbing
837
838 classDescription: "Hostname Grouper",
839 classID: Components.ID("{8df290ae-dcaa-4c11-98a5-2429a4dc97bb}"),
840 contractID: "@mozilla.org/content-pref/hostname-grouper;1",
841 QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentURIGrouper]),
842
843
844 //**************************************************************************//
845 // nsIContentURIGrouper
846
HostnameGrouper_group
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
847 group: function HostnameGrouper_group(aURI) {
848 var group;
849
850 try {
851 // Accessing the host property of the URI will throw an exception
852 // if the URI is of a type that doesn't have a host property.
853 // Otherwise, we manually throw an exception if the host is empty,
854 // since the effect is the same (we can't derive a group from it).
855
856 group = aURI.host;
857 if (!group)
858 throw("can't derive group from host; no host in URI");
859 }
860 catch(ex) {
861 // If we don't have a host, then use the entire URI (minus the query,
862 // reference, and hash, if possible) as the group. This means that URIs
863 // like about:mozilla and about:blank will be considered separate groups,
864 // but at least they'll be grouped somehow.
865
866 // This also means that each individual file: URL will be considered
867 // its own group. This seems suboptimal, but so does treating the entire
868 // file: URL space as a single group (especially if folks start setting
869 // group-specific capabilities prefs).
870
871 // XXX Is there something better we can do here?
872
873 try {
874 var url = aURI.QueryInterface(Ci.nsIURL);
875 group = aURI.prePath + url.filePath;
876 }
877 catch(ex) {
878 group = aURI.spec;
879 }
880 }
881
882 return group;
883 }
884 };
885
886
887 //****************************************************************************//
888 // XPCOM Plumbing
889
890 var components = [ContentPrefService, HostnameGrouper];
ContentPrefService_NSGetModule
(0 calls, 0 incl. v-uS, 0 excl. v-uS)
891 var NSGetModule = function ContentPrefService_NSGetModule(compMgr, fileSpec) {
892 return XPCOMUtils.generateModule(components);
893 }