1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const Ci = Components.interfaces;
8 const Cu = Components.utils;
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
11 Cu.import("resource://gre/modules/Services.jsm");
12 Cu.import('resource://gre/modules/SettingsRequestManager.jsm');
14 /* static functions */
20 Services.prefs.getBoolPref("dom.mozSettings.SettingsService.debug.enabled");
22 Services.prefs.getBoolPref("dom.mozSettings.SettingsService.verbose.enabled");
26 dump("-*- SettingsService: " + s + "\n");
29 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
30 "@mozilla.org/uuid-generator;1",
32 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
33 "@mozilla.org/childprocessmessagemanager;1",
36 const nsIClassInfo = Ci.nsIClassInfo;
38 const SETTINGSSERVICELOCK_CONTRACTID = "@mozilla.org/settingsServiceLock;1";
39 const SETTINGSSERVICELOCK_CID = Components.ID("{d7a395a0-e292-11e1-834e-1761d57f5f99}");
40 const nsISettingsServiceLock = Ci.nsISettingsServiceLock;
42 function makeSettingsServiceRequest(aCallback, aName, aValue) {
50 function SettingsServiceLock(aSettingsService, aTransactionCallback) {
51 if (VERBOSE) debug("settingsServiceLock constr!");
53 this._settingsService = aSettingsService;
54 this._id = uuidgen.generateUUID().toString();
55 this._transactionCallback = aTransactionCallback;
57 let closeHelper = function() {
58 if (VERBOSE) debug("closing lock " + this._id);
60 this.runOrFinalizeQueries();
63 let msgs = ["Settings:Get:OK", "Settings:Get:KO",
64 "Settings:Clear:OK", "Settings:Clear:KO",
65 "Settings:Set:OK", "Settings:Set:KO",
66 "Settings:Finalize:OK", "Settings:Finalize:KO"];
68 for (let msg in msgs) {
69 cpmm.addMessageListener(msgs[msg], this);
72 cpmm.sendAsyncMessage("Settings:CreateLock", {lockID: this._id, isServiceLock: true}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
73 Services.tm.currentThread.dispatch(closeHelper, Ci.nsIThread.DISPATCH_NORMAL);
76 SettingsServiceLock.prototype = {
81 runOrFinalizeQueries: function() {
82 if (!this._requests || Object.keys(this._requests).length == 0) {
83 cpmm.sendAsyncMessage("Settings:Finalize", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
85 cpmm.sendAsyncMessage("Settings:Run", {lockID: this._id}, undefined, Services.scriptSecurityManager.getSystemPrincipal());
89 receiveMessage: function(aMessage) {
91 let msg = aMessage.data;
92 // SettingsRequestManager broadcasts changes to all locks in the child. If
93 // our lock isn't being addressed, just return.
94 if(msg.lockID != this._id) {
97 if (VERBOSE) debug("receiveMessage (" + this._id + "): " + aMessage.name);
98 // Finalizing a transaction does not return a request ID since we are
99 // supposed to fire callbacks.
100 if (!msg.requestID) {
101 switch (aMessage.name) {
102 case "Settings:Finalize:OK":
103 if (VERBOSE) debug("Lock finalize ok!");
104 this.callTransactionHandle();
106 case "Settings:Finalize:KO":
107 if (DEBUG) debug("Lock finalize failed!");
111 if (DEBUG) debug("Message type " + aMessage.name + " is missing a requestID");
116 let req = this._requests[msg.requestID];
118 if (DEBUG) debug("Matching request not found.");
121 delete this._requests[msg.requestID];
122 switch (aMessage.name) {
123 case "Settings:Get:OK":
125 let settings_names = Object.keys(msg.settings);
126 if (settings_names.length > 0) {
127 let name = settings_names[0];
128 if (DEBUG && settings_names.length > 1) {
129 debug("Warning: overloaded setting:" + name);
131 let result = msg.settings[name];
132 this.callHandle(req.callback, name, result);
134 this.callHandle(req.callback, req.name, null);
138 case "Settings:Set:OK":
140 // We don't pass values back from sets in SettingsManager...
141 this.callHandle(req.callback, req.name, req.value);
144 case "Settings:Get:KO":
145 case "Settings:Set:KO":
146 if (DEBUG) debug("error:" + msg.errorMsg);
147 this.callError(req.callback, msg.error);
150 if (DEBUG) debug("Wrong message: " + aMessage.name);
152 this.runOrFinalizeQueries();
155 get: function get(aName, aCallback) {
156 if (VERBOSE) debug("get (" + this._id + "): " + aName);
158 dump("Settings lock not open!\n");
159 throw Components.results.NS_ERROR_ABORT;
161 let reqID = uuidgen.generateUUID().toString();
162 this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName);
163 cpmm.sendAsyncMessage("Settings:Get", {requestID: reqID,
167 Services.scriptSecurityManager.getSystemPrincipal());
170 set: function set(aName, aValue, aCallback) {
171 if (VERBOSE) debug("set: " + aName + " " + aValue);
173 throw "Settings lock not open";
175 let reqID = uuidgen.generateUUID().toString();
176 this._requests[reqID] = makeSettingsServiceRequest(aCallback, aName, aValue);
178 settings[aName] = aValue;
179 cpmm.sendAsyncMessage("Settings:Set", {requestID: reqID,
183 Services.scriptSecurityManager.getSystemPrincipal());
186 callHandle: function callHandle(aCallback, aName, aValue) {
188 aCallback ? aCallback.handle(aName, aValue) : null;
190 dump("settings 'handle' callback threw an exception, dropping: " + e + "\n");
194 callAbort: function callAbort(aCallback, aMessage) {
196 aCallback ? aCallback.handleAbort(aMessage) : null;
198 dump("settings 'abort' callback threw an exception, dropping: " + e + "\n");
202 callError: function callError(aCallback, aMessage) {
204 aCallback ? aCallback.handleError(aMessage) : null;
206 dump("settings 'error' callback threw an exception, dropping: " + e + "\n");
210 callTransactionHandle: function callTransactionHandle() {
212 this._transactionCallback ? this._transactionCallback.handle() : null;
214 dump("settings 'Transaction handle' callback threw an exception, dropping: " + e + "\n");
218 classID : SETTINGSSERVICELOCK_CID,
219 QueryInterface : XPCOMUtils.generateQI([nsISettingsServiceLock])
222 const SETTINGSSERVICE_CID = Components.ID("{f656f0c0-f776-11e1-a21f-0800200c9a66}");
224 function SettingsService()
226 if (VERBOSE) debug("settingsService Constructor");
229 SettingsService.prototype = {
231 createLock: function createLock(aCallback) {
232 var lock = new SettingsServiceLock(this, aCallback);
236 classID : SETTINGSSERVICE_CID,
237 QueryInterface : XPCOMUtils.generateQI([Ci.nsISettingsService])
240 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsService, SettingsServiceLock]);