Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / uriloader / exthandler / nsHandlerService.js
blobe5c21f04b76c3e921eb617eb5a78e2ee570499d2
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
14 * The Original Code is the Mozilla browser.
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2007
18 * the Initial Developer. All Rights Reserved.
20 * Contributor(s):
21 * Myk Melez <myk@mozilla.org>
22 * Dan Mosedale <dmose@mozilla.org>
23 * Florian Queze <florian@queze.net>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 const Ci = Components.interfaces;
40 const Cc = Components.classes;
41 const Cu = Components.utils;
42 const Cr = Components.results;
45 const CLASS_MIMEINFO = "mimetype";
46 const CLASS_PROTOCOLINFO = "scheme";
49 // namespace prefix
50 const NC_NS = "http://home.netscape.com/NC-rdf#";
52 // the most recent default handlers that have been injected. Note that
53 // this is used to construct an RDF resource, which needs to have NC_NS
54 // prepended, since that hasn't been done yet
55 const DEFAULT_HANDLERS_VERSION = "defaultHandlersVersion";
57 // type list properties
59 const NC_MIME_TYPES = NC_NS + "MIME-types";
60 const NC_PROTOCOL_SCHEMES = NC_NS + "Protocol-Schemes";
62 // content type ("type") properties
64 // nsIHandlerInfo::type
65 const NC_VALUE = NC_NS + "value";
66 const NC_DESCRIPTION = NC_NS + "description";
68 // additional extensions
69 const NC_FILE_EXTENSIONS = NC_NS + "fileExtensions";
71 // references nsIHandlerInfo record
72 const NC_HANDLER_INFO = NC_NS + "handlerProp";
74 // handler info ("info") properties
76 // nsIHandlerInfo::preferredAction
77 const NC_SAVE_TO_DISK = NC_NS + "saveToDisk";
78 const NC_HANDLE_INTERNALLY = NC_NS + "handleInternal";
79 const NC_USE_SYSTEM_DEFAULT = NC_NS + "useSystemDefault";
81 // nsIHandlerInfo::alwaysAskBeforeHandling
82 const NC_ALWAYS_ASK = NC_NS + "alwaysAsk";
84 // references nsIHandlerApp records
85 const NC_PREFERRED_APP = NC_NS + "externalApplication";
86 const NC_POSSIBLE_APP = NC_NS + "possibleApplication";
88 // handler app ("handler") properties
90 // nsIHandlerApp::name
91 const NC_PRETTY_NAME = NC_NS + "prettyName";
93 // nsILocalHandlerApp::executable
94 const NC_PATH = NC_NS + "path";
96 // nsIWebHandlerApp::uriTemplate
97 const NC_URI_TEMPLATE = NC_NS + "uriTemplate";
99 // nsIDBusHandlerApp::service
100 const NC_SERVICE = NC_NS + "service";
102 // nsIDBusHandlerApp::method
103 const NC_METHOD = NC_NS + "method";
105 // nsIDBusHandlerApp::objectPath
106 const NC_OBJPATH = NC_NS + "objectPath";
108 // nsIDBusHandlerApp::dbusInterface
109 const NC_INTERFACE = NC_NS + "dBusInterface";
111 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
114 function HandlerService() {
115 this._init();
118 HandlerService.prototype = {
119 //**************************************************************************//
120 // XPCOM Plumbing
122 classDescription: "Handler Service",
123 classID: Components.ID("{32314cc8-22f7-4f7f-a645-1a45453ba6a6}"),
124 contractID: "@mozilla.org/uriloader/handler-service;1",
125 QueryInterface: XPCOMUtils.generateQI([Ci.nsIHandlerService]),
128 //**************************************************************************//
129 // Initialization & Destruction
131 _init: function HS__init() {
132 // Observe profile-before-change so we can switch to the datasource
133 // in the new profile when the user changes profiles.
134 this._observerSvc.addObserver(this, "profile-before-change", false);
136 // Observe xpcom-shutdown so we can remove these observers
137 // when the application shuts down.
138 this._observerSvc.addObserver(this, "xpcom-shutdown", false);
140 // Observe profile-do-change so that non-default profiles get upgraded too
141 this._observerSvc.addObserver(this, "profile-do-change", false);
143 // do any necessary updating of the datastore
144 this._updateDB();
147 _updateDB: function HS__updateDB() {
148 try {
149 var defaultHandlersVersion = this._datastoreDefaultHandlersVersion;
150 } catch(ex) {
151 // accessing the datastore failed, we can't update anything
152 return;
155 try {
156 // if we don't have the current version of the default prefs for
157 // this locale, inject any new default handers into the datastore
158 if (defaultHandlersVersion < this._prefsDefaultHandlersVersion) {
160 // set the new version first so that if we recurse we don't
161 // call _injectNewDefaults several times
162 this._datastoreDefaultHandlersVersion =
163 this._prefsDefaultHandlersVersion;
164 this._injectNewDefaults();
166 } catch (ex) {
167 // if injecting the defaults failed, set the version back to the
168 // previous value
169 this._datastoreDefaultHandlersVersion = defaultHandlersVersion;
173 get _currentLocale() {
174 var chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"].
175 getService(Ci.nsIXULChromeRegistry);
176 var currentLocale = chromeRegistry.getSelectedLocale("global");
177 return currentLocale;
180 _destroy: function HS__destroy() {
181 this._observerSvc.removeObserver(this, "profile-before-change");
182 this._observerSvc.removeObserver(this, "xpcom-shutdown");
183 this._observerSvc.removeObserver(this, "profile-do-change");
185 // XXX Should we also null references to all the services that get stored
186 // by our memoizing getters in the Convenience Getters section?
189 _onProfileChange: function HS__onProfileChange() {
190 // Lose our reference to the datasource so we reacquire it
191 // from the new profile the next time we need it.
192 this.__ds = null;
195 _isInHandlerArray: function HS__isInHandlerArray(aArray, aHandler) {
196 var enumerator = aArray.enumerate();
197 while (enumerator.hasMoreElements()) {
198 let handler = enumerator.getNext();
199 handler.QueryInterface(Ci.nsIHandlerApp);
200 if (handler.equals(aHandler))
201 return true;
204 return false;
207 // note that this applies to the current locale only
208 get _datastoreDefaultHandlersVersion() {
209 var version = this._getValue("urn:root", NC_NS + this._currentLocale +
210 "_" + DEFAULT_HANDLERS_VERSION);
212 return version ? version : -1;
215 set _datastoreDefaultHandlersVersion(aNewVersion) {
216 return this._setLiteral("urn:root", NC_NS + this._currentLocale + "_" +
217 DEFAULT_HANDLERS_VERSION, aNewVersion);
220 get _prefsDefaultHandlersVersion() {
221 // get handler service pref branch
222 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
223 getService(Ci.nsIPrefService);
224 var handlerSvcBranch = prefSvc.getBranch("gecko.handlerService.");
226 // get the version of the preferences for this locale
227 return Number(handlerSvcBranch.
228 getComplexValue("defaultHandlersVersion",
229 Ci.nsIPrefLocalizedString).data);
232 _injectNewDefaults: function HS__injectNewDefaults() {
233 // get handler service pref branch
234 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
235 getService(Ci.nsIPrefService);
237 let schemesPrefBranch = prefSvc.getBranch("gecko.handlerService.schemes.");
238 let schemePrefList = schemesPrefBranch.getChildList("", {});
240 var schemes = {};
242 // read all the scheme prefs into a hash
243 for each (var schemePrefName in schemePrefList) {
245 let [scheme, handlerNumber, attribute] = schemePrefName.split(".");
247 try {
248 var attrData =
249 schemesPrefBranch.getComplexValue(schemePrefName,
250 Ci.nsIPrefLocalizedString).data;
251 if (!(scheme in schemes))
252 schemes[scheme] = {};
254 if (!(handlerNumber in schemes[scheme]))
255 schemes[scheme][handlerNumber] = {};
257 schemes[scheme][handlerNumber][attribute] = attrData;
258 } catch (ex) {}
261 let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
262 getService(Ci.nsIExternalProtocolService);
263 for (var scheme in schemes) {
265 // This clause is essentially a reimplementation of
266 // nsIExternalProtocolHandlerService.getProtocolHandlerInfo().
267 // Necessary because calling that from here would make XPConnect barf
268 // when getService tried to re-enter the constructor for this
269 // service.
270 let osDefaultHandlerFound = {};
271 let protoInfo = protoSvc.getProtocolHandlerInfoFromOS(scheme,
272 osDefaultHandlerFound);
274 if (this.exists(protoInfo))
275 this.fillHandlerInfo(protoInfo, null);
276 else
277 protoSvc.setProtocolHandlerDefaults(protoInfo,
278 osDefaultHandlerFound.value);
280 // cache the possible handlers to avoid extra xpconnect traversals.
281 let possibleHandlers = protoInfo.possibleApplicationHandlers;
283 for each (var handlerPrefs in schemes[scheme]) {
285 let handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"].
286 createInstance(Ci.nsIWebHandlerApp);
288 handlerApp.uriTemplate = handlerPrefs.uriTemplate;
289 handlerApp.name = handlerPrefs.name;
291 if (!this._isInHandlerArray(possibleHandlers, handlerApp)) {
292 possibleHandlers.appendElement(handlerApp, false);
296 this.store(protoInfo);
300 //**************************************************************************//
301 // nsIObserver
303 observe: function HS__observe(subject, topic, data) {
304 switch(topic) {
305 case "profile-before-change":
306 this._onProfileChange();
307 break;
308 case "xpcom-shutdown":
309 this._destroy();
310 break;
311 case "profile-do-change":
312 this._updateDB();
313 break;
318 //**************************************************************************//
319 // nsIHandlerService
321 enumerate: function HS_enumerate() {
322 var handlers = Cc["@mozilla.org/array;1"].
323 createInstance(Ci.nsIMutableArray);
324 this._appendHandlers(handlers, CLASS_MIMEINFO);
325 this._appendHandlers(handlers, CLASS_PROTOCOLINFO);
326 return handlers.enumerate();
329 fillHandlerInfo: function HS_fillHandlerInfo(aHandlerInfo, aOverrideType) {
330 var type = aOverrideType || aHandlerInfo.type;
331 var typeID = this._getTypeID(this._getClass(aHandlerInfo), type);
333 // Determine whether or not information about this handler is available
334 // in the datastore by looking for its "value" property, which stores its
335 // type and should always be present.
336 if (!this._hasValue(typeID, NC_VALUE))
337 throw Cr.NS_ERROR_NOT_AVAILABLE;
339 // Retrieve the human-readable description of the type.
340 if (this._hasValue(typeID, NC_DESCRIPTION))
341 aHandlerInfo.description = this._getValue(typeID, NC_DESCRIPTION);
343 // Note: for historical reasons, we don't actually check that the type
344 // record has a "handlerProp" property referencing the info record. It's
345 // unclear whether or not we should start doing this check; perhaps some
346 // legacy datasources don't have such references.
347 var infoID = this._getInfoID(this._getClass(aHandlerInfo), type);
349 aHandlerInfo.preferredAction = this._retrievePreferredAction(infoID);
351 var preferredHandlerID =
352 this._getPreferredHandlerID(this._getClass(aHandlerInfo), type);
354 // Retrieve the preferred handler.
355 // Note: for historical reasons, we don't actually check that the info
356 // record has an "externalApplication" property referencing the preferred
357 // handler record. It's unclear whether or not we should start doing
358 // this check; perhaps some legacy datasources don't have such references.
359 aHandlerInfo.preferredApplicationHandler =
360 this._retrieveHandlerApp(preferredHandlerID);
362 // Fill the array of possible handlers with the ones in the datastore.
363 this._fillPossibleHandlers(infoID,
364 aHandlerInfo.possibleApplicationHandlers,
365 aHandlerInfo.preferredApplicationHandler);
367 // If we have an "always ask" flag stored in the RDF, always use its
368 // value. Otherwise, use the default value stored in the pref service.
369 var alwaysAsk;
370 if (this._hasValue(infoID, NC_ALWAYS_ASK)) {
371 alwaysAsk = (this._getValue(infoID, NC_ALWAYS_ASK) != "false");
372 } else {
373 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
374 getService(Ci.nsIPrefService);
375 var prefBranch = prefSvc.getBranch("network.protocol-handler.");
376 try {
377 alwaysAsk = prefBranch.getBoolPref("warn-external." + type);
378 } catch (e) {
379 // will throw if pref didn't exist.
380 try {
381 alwaysAsk = prefBranch.getBoolPref("warn-external-default");
382 } catch (e) {
383 // Nothing to tell us what to do, so be paranoid and prompt.
384 alwaysAsk = true;
388 aHandlerInfo.alwaysAskBeforeHandling = alwaysAsk;
390 // If the object represents a MIME type handler, then also retrieve
391 // any file extensions.
392 if (aHandlerInfo instanceof Ci.nsIMIMEInfo)
393 for each (let fileExtension in this._retrieveFileExtensions(typeID))
394 aHandlerInfo.appendExtension(fileExtension);
397 store: function HS_store(aHandlerInfo) {
398 // FIXME: when we switch from RDF to something with transactions (like
399 // SQLite), enclose the following changes in a transaction so they all
400 // get rolled back if any of them fail and we don't leave the datastore
401 // in an inconsistent state.
403 this._ensureRecordsForType(aHandlerInfo);
404 this._storePreferredAction(aHandlerInfo);
405 this._storePreferredHandler(aHandlerInfo);
406 this._storePossibleHandlers(aHandlerInfo);
407 this._storeAlwaysAsk(aHandlerInfo);
409 // Write the changes to the database immediately so we don't lose them
410 // if the application crashes.
411 if (this._ds instanceof Ci.nsIRDFRemoteDataSource)
412 this._ds.Flush();
415 exists: function HS_exists(aHandlerInfo) {
416 var found;
418 try {
419 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
420 found = this._hasLiteralAssertion(typeID, NC_VALUE, aHandlerInfo.type);
421 } catch (e) {
422 // If the RDF threw (eg, corrupt file), treat as non-existent.
423 found = false;
426 return found;
429 remove: function HS_remove(aHandlerInfo) {
430 var preferredHandlerID =
431 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
432 this._removeAssertions(preferredHandlerID);
434 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
436 // Get a list of possible handlers. After we have removed the info record,
437 // we'll check if any other info records reference these handlers, and we'll
438 // remove the handler records that aren't referenced by other info records.
439 var possibleHandlerIDs = [];
440 var possibleHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP);
441 while (possibleHandlerTargets.hasMoreElements()) {
442 let possibleHandlerTarget = possibleHandlerTargets.getNext();
443 // Note: possibleHandlerTarget should always be an nsIRDFResource.
444 // The conditional is just here in case of a corrupt RDF datasource.
445 if (possibleHandlerTarget instanceof Ci.nsIRDFResource)
446 possibleHandlerIDs.push(possibleHandlerTarget.ValueUTF8);
449 // Remove the info record.
450 this._removeAssertions(infoID);
452 // Now that we've removed the info record, remove any possible handlers
453 // that aren't referenced by other info records.
454 for each (let possibleHandlerID in possibleHandlerIDs)
455 if (!this._existsResourceTarget(NC_POSSIBLE_APP, possibleHandlerID))
456 this._removeAssertions(possibleHandlerID);
458 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
459 this._removeAssertions(typeID);
461 // Now that there's no longer a handler for this type, remove the type
462 // from the list of types for which there are known handlers.
463 var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo));
464 var type = this._rdf.GetResource(typeID);
465 var typeIndex = typeList.IndexOf(type);
466 if (typeIndex != -1)
467 typeList.RemoveElementAt(typeIndex, true);
469 // Write the changes to the database immediately so we don't lose them
470 // if the application crashes.
471 // XXX If we're removing a bunch of handlers at once, will flushing
472 // after every removal cause a significant performance hit?
473 if (this._ds instanceof Ci.nsIRDFRemoteDataSource)
474 this._ds.Flush();
477 getTypeFromExtension: function HS_getTypeFromExtension(aFileExtension) {
478 var fileExtension = aFileExtension.toLowerCase();
479 var typeID;
481 if (this._existsLiteralTarget(NC_FILE_EXTENSIONS, fileExtension))
482 typeID = this._getSourceForLiteral(NC_FILE_EXTENSIONS, fileExtension);
484 if (typeID && this._hasValue(typeID, NC_VALUE)) {
485 let type = this._getValue(typeID, NC_VALUE);
486 if (type == "")
487 throw Cr.NS_ERROR_FAILURE;
488 return type;
491 return "";
495 //**************************************************************************//
496 // Retrieval Methods
499 * Retrieve the preferred action for the info record with the given ID.
501 * @param aInfoID {string} the info record ID
503 * @returns {integer} the preferred action enumeration value
505 _retrievePreferredAction: function HS__retrievePreferredAction(aInfoID) {
506 if (this._getValue(aInfoID, NC_SAVE_TO_DISK) == "true")
507 return Ci.nsIHandlerInfo.saveToDisk;
509 if (this._getValue(aInfoID, NC_USE_SYSTEM_DEFAULT) == "true")
510 return Ci.nsIHandlerInfo.useSystemDefault;
512 if (this._getValue(aInfoID, NC_HANDLE_INTERNALLY) == "true")
513 return Ci.nsIHandlerInfo.handleInternal;
515 return Ci.nsIHandlerInfo.useHelperApp;
519 * Fill an array of possible handlers with the handlers for the given info ID.
521 * @param aInfoID {string} the ID of the info record
522 * @param aPossibleHandlers {nsIMutableArray} the array of possible handlers
523 * @param aPreferredHandler {nsIHandlerApp} the preferred handler, if any
525 _fillPossibleHandlers: function HS__fillPossibleHandlers(aInfoID,
526 aPossibleHandlers,
527 aPreferredHandler) {
528 // The set of possible handlers should include the preferred handler,
529 // but legacy datastores (from before we added possible handlers) won't
530 // include the preferred handler, so check if it's included as we build
531 // the list of handlers, and, if it's not included, add it to the list.
532 if (aPreferredHandler)
533 aPossibleHandlers.appendElement(aPreferredHandler, false);
535 var possibleHandlerTargets = this._getTargets(aInfoID, NC_POSSIBLE_APP);
537 while (possibleHandlerTargets.hasMoreElements()) {
538 let possibleHandlerTarget = possibleHandlerTargets.getNext();
539 if (!(possibleHandlerTarget instanceof Ci.nsIRDFResource))
540 continue;
542 let possibleHandlerID = possibleHandlerTarget.ValueUTF8;
543 let possibleHandler = this._retrieveHandlerApp(possibleHandlerID);
544 if (possibleHandler && (!aPreferredHandler ||
545 !possibleHandler.equals(aPreferredHandler)))
546 aPossibleHandlers.appendElement(possibleHandler, false);
551 * Retrieve the handler app object with the given ID.
553 * @param aHandlerAppID {string} the ID of the handler app to retrieve
555 * @returns {nsIHandlerApp} the handler app, if any; otherwise null
557 _retrieveHandlerApp: function HS__retrieveHandlerApp(aHandlerAppID) {
558 var handlerApp;
560 // If it has a path, it's a local handler; otherwise, it's a web handler.
561 if (this._hasValue(aHandlerAppID, NC_PATH)) {
562 let executable =
563 this._getFileWithPath(this._getValue(aHandlerAppID, NC_PATH));
564 if (!executable)
565 return null;
567 handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
568 createInstance(Ci.nsILocalHandlerApp);
569 handlerApp.executable = executable;
571 else if (this._hasValue(aHandlerAppID, NC_URI_TEMPLATE)) {
572 let uriTemplate = this._getValue(aHandlerAppID, NC_URI_TEMPLATE);
573 if (!uriTemplate)
574 return null;
576 handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"].
577 createInstance(Ci.nsIWebHandlerApp);
578 handlerApp.uriTemplate = uriTemplate;
580 else if (this._hasValue(aHandlerAppID, NC_SERVICE)) {
581 let service = this._getValue(aHandlerAppID, NC_SERVICE);
582 if (!service)
583 return null;
585 let method = this._getValue(aHandlerAppID, NC_METHOD);
586 if (!method)
587 return null;
589 let objpath = this._getValue(aHandlerAppID, NC_OBJPATH);
590 if (!objpath)
591 return null;
593 let interface = this._getValue(aHandlerAppID, NC_INTERFACE);
594 if (!interface)
595 return null;
597 handlerApp = Cc["@mozilla.org/uriloader/dbus-handler-app;1"].
598 createInstance(Ci.nsIDBusHandlerApp);
599 handlerApp.service = service;
600 handlerApp.method = method;
601 handlerApp.objectPath = objpath;
602 handlerApp.dBusInterface = interface;
605 else
606 return null;
608 handlerApp.name = this._getValue(aHandlerAppID, NC_PRETTY_NAME);
610 return handlerApp;
614 * Retrieve file extensions, if any, for the MIME type with the given type ID.
616 * @param aTypeID {string} the type record ID
618 _retrieveFileExtensions: function HS__retrieveFileExtensions(aTypeID) {
619 var fileExtensions = [];
621 var fileExtensionTargets = this._getTargets(aTypeID, NC_FILE_EXTENSIONS);
623 while (fileExtensionTargets.hasMoreElements()) {
624 let fileExtensionTarget = fileExtensionTargets.getNext();
625 if (fileExtensionTarget instanceof Ci.nsIRDFLiteral &&
626 fileExtensionTarget.Value != "")
627 fileExtensions.push(fileExtensionTarget.Value);
630 return fileExtensions;
634 * Get the file with the given path. This is not as simple as merely
635 * initializing a local file object with the path, because the path might be
636 * relative to the current process directory, in which case we have to
637 * construct a path starting from that directory.
639 * @param aPath {string} a path to a file
641 * @returns {nsILocalFile} the file, or null if the file does not exist
643 _getFileWithPath: function HS__getFileWithPath(aPath) {
644 var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
646 try {
647 file.initWithPath(aPath);
649 if (file.exists())
650 return file;
652 catch(ex) {
653 // Note: for historical reasons, we don't actually check to see
654 // if the exception is NS_ERROR_FILE_UNRECOGNIZED_PATH, which is what
655 // nsILocalFile::initWithPath throws when a path is relative.
657 file = this._dirSvc.get("XCurProcD", Ci.nsIFile);
659 try {
660 file.append(aPath);
661 if (file.exists())
662 return file;
664 catch(ex) {}
667 return null;
671 //**************************************************************************//
672 // Storage Methods
674 _storePreferredAction: function HS__storePreferredAction(aHandlerInfo) {
675 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
677 switch(aHandlerInfo.preferredAction) {
678 case Ci.nsIHandlerInfo.saveToDisk:
679 this._setLiteral(infoID, NC_SAVE_TO_DISK, "true");
680 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
681 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
682 break;
684 case Ci.nsIHandlerInfo.handleInternally:
685 this._setLiteral(infoID, NC_HANDLE_INTERNALLY, "true");
686 this._removeTarget(infoID, NC_SAVE_TO_DISK);
687 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
688 break;
690 case Ci.nsIHandlerInfo.useSystemDefault:
691 this._setLiteral(infoID, NC_USE_SYSTEM_DEFAULT, "true");
692 this._removeTarget(infoID, NC_SAVE_TO_DISK);
693 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
694 break;
696 // This value is indicated in the datastore either by the absence of
697 // the three properties or by setting them all "false". Of these two
698 // options, the former seems preferable, because it reduces the size
699 // of the RDF file and thus the amount of stuff we have to parse.
700 case Ci.nsIHandlerInfo.useHelperApp:
701 default:
702 this._removeTarget(infoID, NC_SAVE_TO_DISK);
703 this._removeTarget(infoID, NC_HANDLE_INTERNALLY);
704 this._removeTarget(infoID, NC_USE_SYSTEM_DEFAULT);
705 break;
709 _storePreferredHandler: function HS__storePreferredHandler(aHandlerInfo) {
710 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
711 var handlerID =
712 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
714 var handler = aHandlerInfo.preferredApplicationHandler;
716 if (handler) {
717 this._storeHandlerApp(handlerID, handler);
719 // Make this app be the preferred app for the handler info.
721 // Note: nsExternalHelperAppService::FillContentHandlerProperties ignores
722 // this setting and instead identifies the preferred app as the resource
723 // whose URI follows the pattern urn:<class>:externalApplication:<type>.
724 // But the old downloadactions.js code used to set this property, so just
725 // in case there is still some code somewhere that relies on its presence,
726 // we set it here.
727 this._setResource(infoID, NC_PREFERRED_APP, handlerID);
729 else {
730 // There isn't a preferred handler. Remove the existing record for it,
731 // if any.
732 this._removeTarget(infoID, NC_PREFERRED_APP);
733 this._removeAssertions(handlerID);
738 * Store the list of possible handler apps for the content type represented
739 * by the given handler info object.
741 * @param aHandlerInfo {nsIHandlerInfo} the handler info object
743 _storePossibleHandlers: function HS__storePossibleHandlers(aHandlerInfo) {
744 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
746 // First, retrieve the set of handler apps currently stored for the type,
747 // keeping track of their IDs in a hash that we'll use to determine which
748 // ones are no longer valid and should be removed.
749 var currentHandlerApps = {};
750 var currentHandlerTargets = this._getTargets(infoID, NC_POSSIBLE_APP);
751 while (currentHandlerTargets.hasMoreElements()) {
752 let handlerApp = currentHandlerTargets.getNext();
753 if (handlerApp instanceof Ci.nsIRDFResource) {
754 let handlerAppID = handlerApp.ValueUTF8;
755 currentHandlerApps[handlerAppID] = true;
759 // Next, store any new handler apps.
760 var newHandlerApps =
761 aHandlerInfo.possibleApplicationHandlers.enumerate();
762 while (newHandlerApps.hasMoreElements()) {
763 let handlerApp =
764 newHandlerApps.getNext().QueryInterface(Ci.nsIHandlerApp);
765 let handlerAppID = this._getPossibleHandlerAppID(handlerApp);
766 if (!this._hasResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID)) {
767 this._storeHandlerApp(handlerAppID, handlerApp);
768 this._addResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID);
770 delete currentHandlerApps[handlerAppID];
773 // Finally, remove any old handler apps that aren't being used anymore,
774 // and if those handler apps aren't being used by any other type either,
775 // then completely remove their record from the datastore so we don't
776 // leave it clogged up with information about handler apps we don't care
777 // about anymore.
778 for (let handlerAppID in currentHandlerApps) {
779 this._removeResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID);
780 if (!this._existsResourceTarget(NC_POSSIBLE_APP, handlerAppID))
781 this._removeAssertions(handlerAppID);
786 * Store the given handler app.
788 * Note: the reason this method takes the ID of the handler app in a param
789 * is that the ID is different than it usually is when the handler app
790 * in question is a preferred handler app, so this method can't just derive
791 * the ID of the handler app by calling _getPossibleHandlerAppID, its callers
792 * have to do that for it.
794 * @param aHandlerAppID {string} the ID of the handler app to store
795 * @param aHandlerApp {nsIHandlerApp} the handler app to store
797 _storeHandlerApp: function HS__storeHandlerApp(aHandlerAppID, aHandlerApp) {
798 aHandlerApp.QueryInterface(Ci.nsIHandlerApp);
799 this._setLiteral(aHandlerAppID, NC_PRETTY_NAME, aHandlerApp.name);
801 // In the case of the preferred handler, the handler ID could have been
802 // used to refer to a different kind of handler in the past (i.e. either
803 // a local hander or a web handler), so if the new handler is a local
804 // handler, then we remove any web handler properties and vice versa.
805 // This is unnecessary but harmless for possible handlers.
807 if (aHandlerApp instanceof Ci.nsILocalHandlerApp) {
808 this._setLiteral(aHandlerAppID, NC_PATH, aHandlerApp.executable.path);
809 this._removeTarget(aHandlerAppID, NC_URI_TEMPLATE);
810 this._removeTarget(aHandlerAppID, NC_METHOD);
811 this._removeTarget(aHandlerAppID, NC_SERVICE);
812 this._removeTarget(aHandlerAppID, NC_OBJPATH);
813 this._removeTarget(aHandlerAppID, NC_INTERFACE);
815 else if(aHandlerApp instanceof Ci.nsIWebHandlerApp){
816 aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
817 this._setLiteral(aHandlerAppID, NC_URI_TEMPLATE, aHandlerApp.uriTemplate);
818 this._removeTarget(aHandlerAppID, NC_PATH);
819 this._removeTarget(aHandlerAppID, NC_METHOD);
820 this._removeTarget(aHandlerAppID, NC_SERVICE);
821 this._removeTarget(aHandlerAppID, NC_OBJPATH);
822 this._removeTarget(aHandlerAppID, NC_INTERFACE);
824 else if(aHandlerApp instanceof Ci.nsIDBusHandlerApp){
825 aHandlerApp.QueryInterface(Ci.nsIDBusHandlerApp);
826 this._setLiteral(aHandlerAppID, NC_SERVICE, aHandlerApp.service);
827 this._setLiteral(aHandlerAppID, NC_METHOD, aHandlerApp.method);
828 this._setLiteral(aHandlerAppID, NC_OBJPATH, aHandlerApp.objectPath);
829 this._setLiteral(aHandlerAppID, NC_INTERFACE, aHandlerApp.dBusInterface);
830 this._removeTarget(aHandlerAppID, NC_PATH);
831 this._removeTarget(aHandlerAppID, NC_URI_TEMPLATE);
833 else {
834 throw "unknown handler type";
839 _storeAlwaysAsk: function HS__storeAlwaysAsk(aHandlerInfo) {
840 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
841 this._setLiteral(infoID,
842 NC_ALWAYS_ASK,
843 aHandlerInfo.alwaysAskBeforeHandling ? "true" : "false");
847 //**************************************************************************//
848 // Convenience Getters
850 // Observer Service
851 __observerSvc: null,
852 get _observerSvc() {
853 if (!this.__observerSvc)
854 this.__observerSvc =
855 Cc["@mozilla.org/observer-service;1"].
856 getService(Ci.nsIObserverService);
857 return this.__observerSvc;
860 // Directory Service
861 __dirSvc: null,
862 get _dirSvc() {
863 if (!this.__dirSvc)
864 this.__dirSvc =
865 Cc["@mozilla.org/file/directory_service;1"].
866 getService(Ci.nsIProperties);
867 return this.__dirSvc;
870 // MIME Service
871 __mimeSvc: null,
872 get _mimeSvc() {
873 if (!this.__mimeSvc)
874 this.__mimeSvc =
875 Cc["@mozilla.org/mime;1"].
876 getService(Ci.nsIMIMEService);
877 return this.__mimeSvc;
880 // Protocol Service
881 __protocolSvc: null,
882 get _protocolSvc() {
883 if (!this.__protocolSvc)
884 this.__protocolSvc =
885 Cc["@mozilla.org/uriloader/external-protocol-service;1"].
886 getService(Ci.nsIExternalProtocolService);
887 return this.__protocolSvc;
890 // RDF Service
891 __rdf: null,
892 get _rdf() {
893 if (!this.__rdf)
894 this.__rdf = Cc["@mozilla.org/rdf/rdf-service;1"].
895 getService(Ci.nsIRDFService);
896 return this.__rdf;
899 // RDF Container Utils
900 __containerUtils: null,
901 get _containerUtils() {
902 if (!this.__containerUtils)
903 this.__containerUtils = Cc["@mozilla.org/rdf/container-utils;1"].
904 getService(Ci.nsIRDFContainerUtils);
905 return this.__containerUtils;
908 // RDF datasource containing content handling config (i.e. mimeTypes.rdf)
909 __ds: null,
910 get _ds() {
911 if (!this.__ds) {
912 var file = this._dirSvc.get("UMimTyp", Ci.nsIFile);
913 // FIXME: make this a memoizing getter if we use it anywhere else.
914 var ioService = Cc["@mozilla.org/network/io-service;1"].
915 getService(Ci.nsIIOService);
916 var fileHandler = ioService.getProtocolHandler("file").
917 QueryInterface(Ci.nsIFileProtocolHandler);
918 this.__ds =
919 this._rdf.GetDataSourceBlocking(fileHandler.getURLSpecFromFile(file));
922 return this.__ds;
926 //**************************************************************************//
927 // Datastore Utils
930 * Get the string identifying whether this is a MIME or a protocol handler.
931 * This string is used in the URI IDs of various RDF properties.
933 * @param aHandlerInfo {nsIHandlerInfo} the handler for which to get the class
935 * @returns {string} the class
937 _getClass: function HS__getClass(aHandlerInfo) {
938 if (aHandlerInfo instanceof Ci.nsIMIMEInfo)
939 return CLASS_MIMEINFO;
940 else
941 return CLASS_PROTOCOLINFO;
945 * Return the unique identifier for a content type record, which stores
946 * the value field plus a reference to the content type's handler info record.
948 * |urn:<class>:<type>|
950 * XXX: should this be a property of nsIHandlerInfo?
952 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
953 * @param aType {string} the type (a MIME type or protocol scheme)
955 * @returns {string} the ID
957 _getTypeID: function HS__getTypeID(aClass, aType) {
958 return "urn:" + aClass + ":" + aType;
962 * Return the unique identifier for a handler info record, which stores
963 * the preferredAction and alwaysAsk fields plus a reference to the preferred
964 * handler app. Roughly equivalent to the nsIHandlerInfo interface.
966 * |urn:<class>:handler:<type>|
968 * FIXME: the type info record should be merged into the type record,
969 * since there's a one to one relationship between them, and this record
970 * merely stores additional attributes of a content type.
972 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
973 * @param aType {string} the type (a MIME type or protocol scheme)
975 * @returns {string} the ID
977 _getInfoID: function HS__getInfoID(aClass, aType) {
978 return "urn:" + aClass + ":handler:" + aType;
982 * Return the unique identifier for a preferred handler record, which stores
983 * information about the preferred handler for a given content type, including
984 * its human-readable name and the path to its executable (for a local app)
985 * or its URI template (for a web app).
987 * |urn:<class>:externalApplication:<type>|
989 * XXX: should this be a property of nsIHandlerApp?
991 * FIXME: this should be an arbitrary ID, and we should retrieve it from
992 * the datastore for a given content type via the NC:ExternalApplication
993 * property rather than looking for a specific ID, so a handler doesn't
994 * have to change IDs when it goes from being a possible handler to being
995 * the preferred one (once we support possible handlers).
997 * @param aClass {string} the class (CLASS_MIMEINFO or CLASS_PROTOCOLINFO)
998 * @param aType {string} the type (a MIME type or protocol scheme)
1000 * @returns {string} the ID
1002 _getPreferredHandlerID: function HS__getPreferredHandlerID(aClass, aType) {
1003 return "urn:" + aClass + ":externalApplication:" + aType;
1007 * Return the unique identifier for a handler app record, which stores
1008 * information about a possible handler for one or more content types,
1009 * including its human-readable name and the path to its executable (for a
1010 * local app) or its URI template (for a web app).
1012 * Note: handler app IDs for preferred handlers are different. For those,
1013 * see the _getPreferredHandlerID method.
1015 * @param aHandlerApp {nsIHandlerApp} the handler app object
1017 _getPossibleHandlerAppID: function HS__getPossibleHandlerAppID(aHandlerApp) {
1018 var handlerAppID = "urn:handler:";
1020 if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
1021 handlerAppID += "local:" + aHandlerApp.executable.path;
1022 else if(aHandlerApp instanceof Ci.nsIWebHandlerApp){
1023 aHandlerApp.QueryInterface(Ci.nsIWebHandlerApp);
1024 handlerAppID += "web:" + aHandlerApp.uriTemplate;
1026 else if(aHandlerApp instanceof Ci.nsIDBusHandlerApp){
1027 aHandlerApp.QueryInterface(Ci.nsIDBusHandlerApp);
1028 handlerAppID += "dbus:" + aHandlerApp.service + " " + aHandlerApp.method + " " + aHandlerApp.uriTemplate;
1029 }else{
1030 throw "unknown handler type";
1033 return handlerAppID;
1037 * Get the list of types for the given class, creating the list if it doesn't
1038 * already exist. The class can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO
1039 * (i.e. the result of a call to _getClass).
1041 * |urn:<class>s|
1042 * |urn:<class>s:root|
1044 * @param aClass {string} the class for which to retrieve a list of types
1046 * @returns {nsIRDFContainer} the list of types
1048 _ensureAndGetTypeList: function HS__ensureAndGetTypeList(aClass) {
1049 var source = this._rdf.GetResource("urn:" + aClass + "s");
1050 var property =
1051 this._rdf.GetResource(aClass == CLASS_MIMEINFO ? NC_MIME_TYPES
1052 : NC_PROTOCOL_SCHEMES);
1053 var target = this._rdf.GetResource("urn:" + aClass + "s:root");
1055 // Make sure we have an arc from the source to the target.
1056 if (!this._ds.HasAssertion(source, property, target, true))
1057 this._ds.Assert(source, property, target, true);
1059 // Make sure the target is a container.
1060 if (!this._containerUtils.IsContainer(this._ds, target))
1061 this._containerUtils.MakeSeq(this._ds, target);
1063 // Get the type list as an RDF container.
1064 var typeList = Cc["@mozilla.org/rdf/container;1"].
1065 createInstance(Ci.nsIRDFContainer);
1066 typeList.Init(this._ds, target);
1068 return typeList;
1072 * Make sure there are records in the datasource for the given content type
1073 * by creating them if they don't already exist. We have to do this before
1074 * storing any specific data, because we can't assume the presence
1075 * of the records (the nsIHandlerInfo object might have been created
1076 * from the OS), and the records have to all be there in order for the helper
1077 * app service to properly construct an nsIHandlerInfo object for the type.
1079 * Based on old downloadactions.js::_ensureMIMERegistryEntry.
1081 * @param aHandlerInfo {nsIHandlerInfo} the type to make sure has a record
1083 _ensureRecordsForType: function HS__ensureRecordsForType(aHandlerInfo) {
1084 // Get the list of types.
1085 var typeList = this._ensureAndGetTypeList(this._getClass(aHandlerInfo));
1087 // If there's already a record in the datastore for this type, then we
1088 // don't need to do anything more.
1089 var typeID = this._getTypeID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1090 var type = this._rdf.GetResource(typeID);
1091 if (typeList.IndexOf(type) != -1)
1092 return;
1094 // Create a basic type record for this type.
1095 typeList.AppendElement(type);
1096 this._setLiteral(typeID, NC_VALUE, aHandlerInfo.type);
1098 // Create a basic info record for this type.
1099 var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1100 this._setLiteral(infoID, NC_ALWAYS_ASK, "false");
1101 this._setResource(typeID, NC_HANDLER_INFO, infoID);
1102 // XXX Shouldn't we set preferredAction to useSystemDefault?
1103 // That's what it is if there's no record in the datastore; why should it
1104 // change to useHelperApp just because we add a record to the datastore?
1106 // Create a basic preferred handler record for this type.
1107 // XXX Not sure this is necessary, since preferred handlers are optional,
1108 // and nsExternalHelperAppService::FillHandlerInfoForTypeFromDS doesn't seem
1109 // to require the record , but downloadactions.js::_ensureMIMERegistryEntry
1110 // used to create it, so we'll do the same.
1111 var preferredHandlerID =
1112 this._getPreferredHandlerID(this._getClass(aHandlerInfo), aHandlerInfo.type);
1113 this._setLiteral(preferredHandlerID, NC_PATH, "");
1114 this._setResource(infoID, NC_PREFERRED_APP, preferredHandlerID);
1118 * Append known handlers of the given class to the given array. The class
1119 * can be either CLASS_MIMEINFO or CLASS_PROTOCOLINFO.
1121 * @param aHandlers {array} the array of handlers to append to
1122 * @param aClass {string} the class for which to append handlers
1124 _appendHandlers: function HS__appendHandlers(aHandlers, aClass) {
1125 var typeList = this._ensureAndGetTypeList(aClass);
1126 var enumerator = typeList.GetElements();
1128 while (enumerator.hasMoreElements()) {
1129 var element = enumerator.getNext();
1131 // This should never happen. If it does, that means our datasource
1132 // is corrupted with type list entries that point to literal values
1133 // instead of resources. If it does happen, let's just do our best
1134 // to recover by ignoring this entry and moving on to the next one.
1135 if (!(element instanceof Ci.nsIRDFResource))
1136 continue;
1138 // Get the value of the element's NC:value property, which contains
1139 // the MIME type or scheme for which we're retrieving a handler info.
1140 var type = this._getValue(element.ValueUTF8, NC_VALUE);
1141 if (!type)
1142 continue;
1144 var handler;
1145 if (typeList.Resource.ValueUTF8 == "urn:mimetypes:root")
1146 handler = this._mimeSvc.getFromTypeAndExtension(type, null);
1147 else
1148 handler = this._protocolSvc.getProtocolHandlerInfo(type);
1150 aHandlers.appendElement(handler, false);
1155 * Whether or not a property of an RDF source has a value.
1157 * @param sourceURI {string} the URI of the source
1158 * @param propertyURI {string} the URI of the property
1159 * @returns {boolean} whether or not the property has a value
1161 _hasValue: function HS__hasValue(sourceURI, propertyURI) {
1162 var source = this._rdf.GetResource(sourceURI);
1163 var property = this._rdf.GetResource(propertyURI);
1164 return this._ds.hasArcOut(source, property);
1168 * Get the value of a property of an RDF source.
1170 * @param sourceURI {string} the URI of the source
1171 * @param propertyURI {string} the URI of the property
1172 * @returns {string} the value of the property
1174 _getValue: function HS__getValue(sourceURI, propertyURI) {
1175 var source = this._rdf.GetResource(sourceURI);
1176 var property = this._rdf.GetResource(propertyURI);
1178 var target = this._ds.GetTarget(source, property, true);
1180 if (!target)
1181 return null;
1183 if (target instanceof Ci.nsIRDFResource)
1184 return target.ValueUTF8;
1186 if (target instanceof Ci.nsIRDFLiteral)
1187 return target.Value;
1189 return null;
1193 * Get all targets for the property of an RDF source.
1195 * @param sourceURI {string} the URI of the source
1196 * @param propertyURI {string} the URI of the property
1198 * @returns {nsISimpleEnumerator} an enumerator of targets
1200 _getTargets: function HS__getTargets(sourceURI, propertyURI) {
1201 var source = this._rdf.GetResource(sourceURI);
1202 var property = this._rdf.GetResource(propertyURI);
1204 return this._ds.GetTargets(source, property, true);
1208 * Set a property of an RDF source to a literal value.
1210 * @param sourceURI {string} the URI of the source
1211 * @param propertyURI {string} the URI of the property
1212 * @param value {string} the literal value
1214 _setLiteral: function HS__setLiteral(sourceURI, propertyURI, value) {
1215 var source = this._rdf.GetResource(sourceURI);
1216 var property = this._rdf.GetResource(propertyURI);
1217 var target = this._rdf.GetLiteral(value);
1219 this._setTarget(source, property, target);
1223 * Set a property of an RDF source to a resource target.
1225 * @param sourceURI {string} the URI of the source
1226 * @param propertyURI {string} the URI of the property
1227 * @param targetURI {string} the URI of the target
1229 _setResource: function HS__setResource(sourceURI, propertyURI, targetURI) {
1230 var source = this._rdf.GetResource(sourceURI);
1231 var property = this._rdf.GetResource(propertyURI);
1232 var target = this._rdf.GetResource(targetURI);
1234 this._setTarget(source, property, target);
1238 * Assert an arc into the RDF datasource if there is no arc with the given
1239 * source and property; otherwise, if there is already an existing arc,
1240 * change it to point to the given target. _setLiteral and _setResource
1241 * call this after converting their string arguments into resources
1242 * and literals, and most callers should call one of those two methods
1243 * instead of this one.
1245 * @param source {nsIRDFResource} the source
1246 * @param property {nsIRDFResource} the property
1247 * @param target {nsIRDFNode} the target
1249 _setTarget: function HS__setTarget(source, property, target) {
1250 if (this._ds.hasArcOut(source, property)) {
1251 var oldTarget = this._ds.GetTarget(source, property, true);
1252 this._ds.Change(source, property, oldTarget, target);
1254 else
1255 this._ds.Assert(source, property, target, true);
1259 * Assert that a property of an RDF source has a resource target.
1261 * The difference between this method and _setResource is that this one adds
1262 * an assertion even if one already exists, which allows its callers to make
1263 * sets of assertions (i.e. to set a property to multiple targets).
1265 * @param sourceURI {string} the URI of the source
1266 * @param propertyURI {string} the URI of the property
1267 * @param targetURI {string} the URI of the target
1269 _addResourceAssertion: function HS__addResourceAssertion(sourceURI,
1270 propertyURI,
1271 targetURI) {
1272 var source = this._rdf.GetResource(sourceURI);
1273 var property = this._rdf.GetResource(propertyURI);
1274 var target = this._rdf.GetResource(targetURI);
1276 this._ds.Assert(source, property, target, true);
1280 * Remove an assertion with a resource target.
1282 * @param sourceURI {string} the URI of the source
1283 * @param propertyURI {string} the URI of the property
1284 * @param targetURI {string} the URI of the target
1286 _removeResourceAssertion: function HS__removeResourceAssertion(sourceURI,
1287 propertyURI,
1288 targetURI) {
1289 var source = this._rdf.GetResource(sourceURI);
1290 var property = this._rdf.GetResource(propertyURI);
1291 var target = this._rdf.GetResource(targetURI);
1293 this._ds.Unassert(source, property, target);
1297 * Whether or not a property of an RDF source has a given resource target.
1299 * @param sourceURI {string} the URI of the source
1300 * @param propertyURI {string} the URI of the property
1301 * @param targetURI {string} the URI of the target
1303 * @returns {boolean} whether or not there is such an assertion
1305 _hasResourceAssertion: function HS__hasResourceAssertion(sourceURI,
1306 propertyURI,
1307 targetURI) {
1308 var source = this._rdf.GetResource(sourceURI);
1309 var property = this._rdf.GetResource(propertyURI);
1310 var target = this._rdf.GetResource(targetURI);
1312 return this._ds.HasAssertion(source, property, target, true);
1316 * Whether or not a property of an RDF source has a given literal value.
1318 * @param sourceURI {string} the URI of the source
1319 * @param propertyURI {string} the URI of the property
1320 * @param value {string} the literal value
1322 * @returns {boolean} whether or not there is such an assertion
1324 _hasLiteralAssertion: function HS__hasLiteralAssertion(sourceURI,
1325 propertyURI,
1326 value) {
1327 var source = this._rdf.GetResource(sourceURI);
1328 var property = this._rdf.GetResource(propertyURI);
1329 var target = this._rdf.GetLiteral(value);
1331 return this._ds.HasAssertion(source, property, target, true);
1335 * Whether or not there is an RDF source that has the given property set to
1336 * the given literal value.
1338 * @param propertyURI {string} the URI of the property
1339 * @param value {string} the literal value
1341 * @returns {boolean} whether or not there is a source
1343 _existsLiteralTarget: function HS__existsLiteralTarget(propertyURI, value) {
1344 var property = this._rdf.GetResource(propertyURI);
1345 var target = this._rdf.GetLiteral(value);
1347 return this._ds.hasArcIn(target, property);
1351 * Get the source for a property set to a given literal value.
1353 * @param propertyURI {string} the URI of the property
1354 * @param value {string} the literal value
1356 _getSourceForLiteral: function HS__getSourceForLiteral(propertyURI, value) {
1357 var property = this._rdf.GetResource(propertyURI);
1358 var target = this._rdf.GetLiteral(value);
1360 var source = this._ds.GetSource(property, target, true);
1361 if (source)
1362 return source.ValueUTF8;
1364 return null;
1368 * Whether or not there is an RDF source that has the given property set to
1369 * the given resource target.
1371 * @param propertyURI {string} the URI of the property
1372 * @param targetURI {string} the URI of the target
1374 * @returns {boolean} whether or not there is a source
1376 _existsResourceTarget: function HS__existsResourceTarget(propertyURI,
1377 targetURI) {
1378 var property = this._rdf.GetResource(propertyURI);
1379 var target = this._rdf.GetResource(targetURI);
1381 return this._ds.hasArcIn(target, property);
1385 * Remove a property of an RDF source.
1387 * @param sourceURI {string} the URI of the source
1388 * @param propertyURI {string} the URI of the property
1390 _removeTarget: function HS__removeTarget(sourceURI, propertyURI) {
1391 var source = this._rdf.GetResource(sourceURI);
1392 var property = this._rdf.GetResource(propertyURI);
1394 if (this._ds.hasArcOut(source, property)) {
1395 var target = this._ds.GetTarget(source, property, true);
1396 this._ds.Unassert(source, property, target);
1401 * Remove all assertions about a given RDF source.
1403 * Note: not recursive. If some assertions point to other resources,
1404 * and you want to remove assertions about those resources too, you need
1405 * to do so manually.
1407 * @param sourceURI {string} the URI of the source
1409 _removeAssertions: function HS__removeAssertions(sourceURI) {
1410 var source = this._rdf.GetResource(sourceURI);
1411 var properties = this._ds.ArcLabelsOut(source);
1413 while (properties.hasMoreElements()) {
1414 let property = properties.getNext();
1415 let targets = this._ds.GetTargets(source, property, true);
1416 while (targets.hasMoreElements()) {
1417 let target = targets.getNext();
1418 this._ds.Unassert(source, property, target);
1426 //****************************************************************************//
1427 // More XPCOM Plumbing
1429 function NSGetModule(compMgr, fileSpec) {
1430 return XPCOMUtils.generateModule([HandlerService]);