Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / notification / NotificationStorage.js
blobcbf94cb6c7dd12dd4c0a6f3ab67c6f1eb4c2d505
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/. */
5 "use strict";
7 const DEBUG = false;
8 function debug(s) { dump("-*- NotificationStorage.js: " + s + "\n"); }
10 const Cc = Components.classes;
11 const Ci = Components.interfaces;
12 const Cu = Components.utils;
14 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
16 const NOTIFICATIONSTORAGE_CID = "{37f819b0-0b5c-11e3-8ffd-0800200c9a66}";
17 const NOTIFICATIONSTORAGE_CONTRACTID = "@mozilla.org/notificationStorage;1";
19 XPCOMUtils.defineLazyModuleGetter(this, "Services",
20                                   "resource://gre/modules/Services.jsm");
22 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
23                                    "@mozilla.org/childprocessmessagemanager;1",
24                                    "nsIMessageSender");
26 const kMessageNotificationGetAllOk = "Notification:GetAll:Return:OK";
27 const kMessageNotificationGetAllKo = "Notification:GetAll:Return:KO";
28 const kMessageNotificationSaveKo   = "Notification:Save:Return:KO";
29 const kMessageNotificationDeleteKo = "Notification:Delete:Return:KO";
31 const kMessages = [
32   kMessageNotificationGetAllOk,
33   kMessageNotificationGetAllKo,
34   kMessageNotificationSaveKo,
35   kMessageNotificationDeleteKo
38 function NotificationStorage() {
39   // cache objects
40   this._notifications = {};
41   this._byTag = {};
42   this._cached = false;
44   this._requests = {};
45   this._requestCount = 0;
47   Services.obs.addObserver(this, "xpcom-shutdown", false);
48   // Register for message listeners.
49   this.registerListeners();
52 NotificationStorage.prototype = {
54   registerListeners: function() {
55     for (let message of kMessages) {
56       cpmm.addMessageListener(message, this);
57     }
58   },
60   unregisterListeners: function() {
61     for (let message of kMessages) {
62       cpmm.removeMessageListener(message, this);
63     }
64   },
66   observe: function(aSubject, aTopic, aData) {
67     if (DEBUG) debug("Topic: " + aTopic);
68     if (aTopic == "xpcom-shutdown") {
69       Services.obs.removeObserver(this, "xpcom-shutdown");
70       this.unregisterListeners();
71     }
72   },
74   put: function(origin, id, title, dir, lang, body, tag, icon, alertName,
75                 data) {
76     if (DEBUG) { debug("PUT: " + id + ": " + title); }
77     var notification = {
78       id: id,
79       title: title,
80       dir: dir,
81       lang: lang,
82       body: body,
83       tag: tag,
84       icon: icon,
85       alertName: alertName,
86       timestamp: new Date().getTime(),
87       origin: origin,
88       data: data
89     };
91     this._notifications[id] = notification;
92     if (tag) {
93       if (!this._byTag[origin]) {
94         this._byTag[origin] = {};
95       }
97       // We might have existing notification with this tag,
98       // if so we need to remove it from our cache.
99       if (this._byTag[origin][tag]) {
100         var oldNotification = this._byTag[origin][tag];
101         delete this._notifications[oldNotification.id];
102       }
104       this._byTag[origin][tag] = notification;
105     };
107     cpmm.sendAsyncMessage("Notification:Save", {
108       origin: origin,
109       notification: notification
110     });
111   },
113   get: function(origin, tag, callback) {
114     if (DEBUG) { debug("GET: " + origin + " " + tag); }
115     if (this._cached) {
116       this._fetchFromCache(origin, tag, callback);
117     } else {
118       this._fetchFromDB(origin, tag, callback);
119     }
120   },
122   delete: function(origin, id) {
123     if (DEBUG) { debug("DELETE: " + id); }
124     var notification = this._notifications[id];
125     if (notification) {
126       if (notification.tag) {
127         delete this._byTag[origin][notification.tag];
128       }
129       delete this._notifications[id];
130     }
132     cpmm.sendAsyncMessage("Notification:Delete", {
133       origin: origin,
134       id: id
135     });
136   },
138   receiveMessage: function(message) {
139     var request = this._requests[message.data.requestID];
141     switch (message.name) {
142       case kMessageNotificationGetAllOk:
143         delete this._requests[message.data.requestID];
144         this._populateCache(message.data.notifications);
145         this._fetchFromCache(request.origin, request.tag, request.callback);
146         break;
148       case kMessageNotificationGetAllKo:
149         delete this._requests[message.data.requestID];
150         try {
151           request.callback.done();
152         } catch (e) {
153           debug("Error calling callback done: " + e);
154         }
155       case kMessageNotificationSaveKo:
156       case kMessageNotificationDeleteKo:
157         if (DEBUG) {
158           debug("Error received when treating: '" + message.name +
159                 "': " + message.data.errorMsg);
160         }
161         break;
163       default:
164         if (DEBUG) debug("Unrecognized message: " + message.name);
165         break;
166     }
167   },
169   _fetchFromDB: function(origin, tag, callback) {
170     var request = {
171       origin: origin,
172       tag: tag,
173       callback: callback
174     };
175     var requestID = this._requestCount++;
176     this._requests[requestID] = request;
177     cpmm.sendAsyncMessage("Notification:GetAll", {
178       origin: origin,
179       requestID: requestID
180     });
181   },
183   _fetchFromCache: function(origin, tag, callback) {
184     var notifications = [];
185     // If a tag was specified and we have a notification
186     // with this tag, return that. If no tag was specified
187     // simple return all stored notifications.
188     if (tag && this._byTag[origin] && this._byTag[origin][tag]) {
189       notifications.push(this._byTag[origin][tag]);
190     } else if (!tag) {
191       for (var id in this._notifications) {
192         if (this._notifications[id].origin === origin) {
193           notifications.push(this._notifications[id]);
194         }
195       }
196     }
198     // Pass each notification back separately.
199     notifications.forEach(function(notification) {
200       try {
201         callback.handle(notification.id,
202                         notification.title,
203                         notification.dir,
204                         notification.lang,
205                         notification.body,
206                         notification.tag,
207                         notification.icon,
208                         notification.data);
209       } catch (e) {
210         if (DEBUG) { debug("Error calling callback handle: " + e); }
211       }
212     });
213     try {
214       callback.done();
215     } catch (e) {
216       if (DEBUG) { debug("Error calling callback done: " + e); }
217     }
218   },
220   _populateCache: function(notifications) {
221     notifications.forEach(function(notification) {
222       this._notifications[notification.id] = notification;
223       if (notification.tag && notification.origin) {
224         let tag = notification.tag;
225         let origin = notification.origin;
226         if (!this._byTag[origin]) {
227           this._byTag[origin] = {};
228         }
229         this._byTag[origin][tag] = notification;
230       }
231     }.bind(this));
232     this._cached = true;
233   },
235   classID : Components.ID(NOTIFICATIONSTORAGE_CID),
236   contractID : NOTIFICATIONSTORAGE_CONTRACTID,
237   QueryInterface: XPCOMUtils.generateQI([Ci.nsINotificationStorage,
238                                          Ci.nsIMessageListener]),
242 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NotificationStorage]);