commit 41437738b0b5ae4e9a408cd0c2255d65ff36974d
parent 46209bd4f3984ab49778713489279c4b41df1dd7
Author: Dan Stillman <dstillman@zotero.org>
Date: Mon, 6 Jul 2009 10:13:02 +0000
- Add triggers for full sync on various errors
- Add Zotero.Error(message, error) constructor to create a throwable error object with an error code
- Allow only one automatic client reset between manual syncs
- Fix "Source item for keyed source doesn't exist in Zotero.Item.getSource()" error
- Object produced by item.serialize() now contains .sourceItemKey instead of .sourceItemID
- Better error logging for missing XPCOM files
Diffstat:
5 files changed, 110 insertions(+), 44 deletions(-)
diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js
@@ -1016,7 +1016,9 @@ Zotero.Collection.prototype._getParent = function() {
}
var parentCollection = Zotero.Collections.getByLibraryAndKey(this.libraryID, this._parent);
if (!parentCollection) {
- throw ("Parent collection for keyed parent doesn't exist in Zotero.Collection._getParent()");
+ var msg = "Parent collection for keyed parent doesn't exist in Zotero.Collection._getParent()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
// Replace stored key with id
this._parent = parentCollection.id;
diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js
@@ -1380,8 +1380,10 @@ Zotero.Item.prototype.save = function() {
}
var newSourceItemNotifierData = {};
- newSourceItemNotifierData[newSourceItem.id] =
- { old: newSourceItem.serialize() };
+ newSourceItemNotifierData[newSourceItem.id] = {
+ old: newSourceItem.serialize()
+ };
+ Zotero.Notifier.trigger('modify', 'item', newSourceItem.id, newSourceItemNotifierData);
switch (Zotero.ItemTypes.getName(this.itemTypeID)) {
case 'note':
@@ -1752,24 +1754,28 @@ Zotero.Item.prototype.save = function() {
if (newSourceItem) {
var newSourceItemNotifierData = {};
- newSourceItemNotifierData[newSourceItem.id] =
- { old: newSourceItem.serialize() };
+ newSourceItemNotifierData[newSourceItem.id] = {
+ old: newSourceItem.serialize()
+ };
+ Zotero.Notifier.trigger('modify', 'item', newSourceItem.id, newSourceItemNotifierData);
}
if (this._previousData) {
- var oldSourceItemID = this._previousData.sourceItemID;
- if (oldSourceItemID) {
- var oldSourceItem = Zotero.Items.get(oldSourceItemID);
+ var oldSourceItemKey = this._previousData.sourceItemKey;
+ if (oldSourceItemKey) {
+ var oldSourceItem = Zotero.Items.getByKey(this.libraryID, oldSourceItemKey);
}
if (oldSourceItem) {
var oldSourceItemNotifierData = {};
- oldSourceItemNotifierData[oldSourceItem.id] =
- { old: oldSourceItem.serialize() };
+ oldSourceItemNotifierData[oldSourceItem.id] = {
+ old: oldSourceItem.serialize()
+ };
+ Zotero.Notifier.trigger('modify', 'item', oldSourceItem.id, oldSourceItemNotifierData);
}
- else if (oldSourceItemID) {
+ else if (oldSourceItemKey) {
var oldSourceItemNotifierData = null;
- Zotero.debug("Old source item " + oldSourceItemID
- + " didn't exist in setSource()", 2);
+ Zotero.debug("Old source item " + oldSourceItemKey
+ + " didn't exist in Zotero.Item.save()", 2);
}
}
@@ -1777,7 +1783,7 @@ Zotero.Item.prototype.save = function() {
// If this was an independent item, remove from any collections
// where it existed previously and add source instead if
// there is one
- if (!oldSourceItemID) {
+ if (!oldSourceItemKey) {
var sql = "SELECT collectionID FROM collectionItems "
+ "WHERE itemID=?";
var changedCollections = Zotero.DB.columnQuery(sql, this.id);
@@ -1946,15 +1952,6 @@ Zotero.Item.prototype.save = function() {
Zotero.Notifier.trigger('modify', 'item', this.id, { old: this._previousData });
}
- if (oldSourceItem) {
- Zotero.Notifier.trigger('modify', 'item',
- oldSourceItemID, oldSourceItemNotifierData);
- }
- if (newSourceItem) {
- Zotero.Notifier.trigger('modify', 'item',
- newSourceItem.id, newSourceItemNotifierData);
- }
-
if (isNew) {
var id = this.id;
this._disabled = true;
@@ -2003,7 +2000,9 @@ Zotero.Item.prototype.getSource = function() {
}
var sourceItem = Zotero.Items.getByLibraryAndKey(this.libraryID, this._sourceItem);
if (!sourceItem) {
- throw ("Source item for keyed source doesn't exist in Zotero.Item.getSource()");
+ var msg = "Source item for keyed source doesn't exist in Zotero.Item.getSource()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
// Replace stored key with id
this._sourceItem = sourceItem.id;
@@ -3836,9 +3835,9 @@ Zotero.Item.prototype.toArray = function (mode) {
// Notes
if (this.isNote()) {
arr.note = this.getNote();
- var parent = this.getSource();
+ var parent = this.getSourceKey();
if (parent) {
- arr.sourceItemID = parent;
+ arr.sourceItemKey = parent;
}
}
@@ -3847,9 +3846,9 @@ Zotero.Item.prototype.toArray = function (mode) {
// Attachments can have embedded notes
arr.note = this.getNote();
- var parent = this.getSource();
+ var parent = this.getSourceKey();
if (parent) {
- arr.sourceItemID = parent;
+ arr.sourceItemKey = parent;
}
}
@@ -4005,9 +4004,9 @@ Zotero.Item.prototype.serialize = function(mode) {
}
arr.note = this.getNote();
- var parent = this.getSource();
+ var parent = this.getSourceKey();
if (parent) {
- arr.sourceItemID = parent;
+ arr.sourceItemKey = parent;
}
}
diff --git a/chrome/content/zotero/xpcom/error.js b/chrome/content/zotero/xpcom/error.js
@@ -0,0 +1,17 @@
+Zotero.Error = function (message, error) {
+ this.name = "ZOTERO_ERROR";
+ this.message = message;
+ if (parseInt(error) == error) {
+ this.error = error;
+ }
+ else {
+ this.error = Zotero.Error["ERROR_" + error] ? Zotero.Error["ERROR_" + error] : 0;
+ }
+}
+
+Zotero.Error.ERROR_UNKNOWN = 0;
+Zotero.Error.ERROR_MISSING_OBJECT = 1;
+
+Zotero.Error.prototype.toString = function () {
+ return this.message;
+}
diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js
@@ -837,6 +837,7 @@ Zotero.Sync.Server = new function () {
var _sessionID;
var _sessionLock;
var _throttleTimeout;
+ var _canAutoResetClient = true;
function login(callback, callbackCallback) {
var url = _serverURL + "login";
@@ -1356,6 +1357,8 @@ Zotero.Sync.Server = new function () {
function resetClient() {
+ Zotero.debug("Resetting client");
+
Zotero.DB.beginTransaction();
var sql = "DELETE FROM version WHERE schema IN "
@@ -1498,11 +1501,20 @@ Zotero.Sync.Server = new function () {
break;
case 'FULL_SYNC_REQUIRED':
- Zotero.DB.rollbackAllTransactions();
// Let current sync fail, and then do a full sync
var background = Zotero.Sync.Runner.background;
setTimeout(function () {
+ if (Zotero.Prefs.get('sync.debugNoAutoResetClient')) {
+ Components.utils.reportError("Skipping automatic client reset due to debug pref");
+ return;
+ }
+ if (!Zotero.Sync.Server.canAutoResetClient) {
+ Components.utils.reportError("Client has already been auto-reset in Zotero.Sync.Server._checkResponse() -- manual sync required");
+ return;
+ }
+
Zotero.Sync.Server.resetClient();
+ Zotero.Sync.Server.canAutoResetClient = false;
Zotero.Sync.Runner.sync(background);
}, 1);
break;
@@ -1511,8 +1523,6 @@ Zotero.Sync.Server = new function () {
if (!Zotero.Sync.Runner.background) {
var tag = xmlhttp.responseXML.firstChild.getElementsByTagName('tag');
if (tag.length) {
- Zotero.DB.rollbackAllTransactions();
-
var tag = tag[0].firstChild.nodeValue;
setTimeout(function () {
var callback = function () {
@@ -1667,6 +1677,28 @@ Zotero.Sync.Server = new function () {
function _error(e, extraInfo) {
+ if (e.name && e.name == 'ZOTERO_ERROR') {
+ switch (e.error) {
+ case Zotero.Error.ERROR_MISSING_OBJECT:
+ // Let current sync fail, and then do a full sync
+ var background = Zotero.Sync.Runner.background;
+ setTimeout(function () {
+ if (Zotero.Prefs.get('sync.debugNoAutoResetClient')) {
+ Components.utils.reportError("Skipping automatic client reset due to debug pref");
+ return;
+ }
+ if (!Zotero.Sync.Server.canAutoResetClient) {
+ Components.utils.reportError("Client has already been auto-reset in Zotero.Sync.Server._error() -- manual sync required");
+ return;
+ }
+ Zotero.Sync.Server.resetClient();
+ Zotero.Sync.Server.canAutoResetClient = false;
+ Zotero.Sync.Runner.sync(background);
+ }, 1);
+ break;
+ }
+ }
+
if (extraInfo) {
// Server errors will generally be HTML
extraInfo = Zotero.Utilities.prototype.unescapeHTML(extraInfo);
@@ -1685,7 +1717,7 @@ Zotero.Sync.Server = new function () {
Zotero.Sync.Runner.setError(e.message ? e.message : e);
Zotero.Sync.Runner.reset();
- throw(e);
+ Components.utils.reportError(e);
}
}
@@ -3001,9 +3033,11 @@ Zotero.Sync.Server.Data = new function() {
// the item's creator block, where a copy should be provided
if (!creatorObj) {
if (creator.creator.length() == 0) {
- throw ("Data for missing local creator "
+ var msg = "Data for missing local creator "
+ data.libraryID + "/" + creator.@key.toString()
- + " not provided in Zotero.Sync.Server.Data.xmlToItem()");
+ + " not provided in Zotero.Sync.Server.Data.xmlToItem()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
var l = creator.@libraryID.toString();
l = l ? l : null;
@@ -3054,8 +3088,10 @@ Zotero.Sync.Server.Data = new function() {
for each(var key in related) {
var relItem = Zotero.Items.getByLibraryAndKey(item.libraryID, key);
if (!relItem) {
- throw ("Related item " + item.libraryID + "/" + key
- + " doesn't exist in Zotero.Sync.Server.Data.xmlToItem()");
+ var msg = "Related item " + item.libraryID + "/" + key
+ + " doesn't exist in Zotero.Sync.Server.Data.xmlToItem()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
relatedIDs.push(relItem.id);
}
@@ -3172,8 +3208,11 @@ Zotero.Sync.Server.Data = new function() {
for each(var key in childItems) {
var childItem = Zotero.Items.getByLibraryAndKey(collection.libraryID, key);
if (!childItem) {
- throw ("Missing child item " + key + " for collection " + collection.libraryID + "/" + collection.key
- + " in Zotero.Sync.Server.Data.xmlToCollection()");
+ var msg = "Missing child item " + key + " for collection "
+ + collection.libraryID + "/" + collection.key
+ + " in Zotero.Sync.Server.Data.xmlToCollection()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
childItemIDs.push(childItem.id);
}
@@ -3446,7 +3485,9 @@ Zotero.Sync.Server.Data = new function() {
for each(var key in keys) {
var item = Zotero.Items.getByLibraryAndKey(tag.libraryID, key);
if (!item) {
- throw ("Linked item " + key + " doesn't exist in Zotero.Sync.Server.Data.xmlToTag()");
+ var msg = "Linked item " + key + " doesn't exist in Zotero.Sync.Server.Data.xmlToTag()";
+ var e = new Zotero.Error(msg, "MISSING_OBJECT");
+ throw (e);
}
ids.push(item.id);
}
diff --git a/components/zotero-service.js b/components/zotero-service.js
@@ -42,6 +42,7 @@ var xpcomFiles = [
'db',
'duplicate',
'enstyle',
+ 'error',
'file',
'fulltext',
'id',
@@ -68,9 +69,15 @@ var xpcomFiles = [
];
for (var i=0; i<xpcomFiles.length; i++) {
- Cc["@mozilla.org/moz/jssubscript-loader;1"]
- .getService(Ci.mozIJSSubScriptLoader)
- .loadSubScript("chrome://zotero/content/xpcom/" + xpcomFiles[i] + ".js");
+ try {
+ Cc["@mozilla.org/moz/jssubscript-loader;1"]
+ .getService(Ci.mozIJSSubScriptLoader)
+ .loadSubScript("chrome://zotero/content/xpcom/" + xpcomFiles[i] + ".js");
+ }
+ catch (e) {
+ Components.utils.reportError("Error loading " + xpcomFiles[i] + ".js");
+ throw (e);
+ }
}