在 xPages 中处理文档锁定的最佳方法是什么?目前我们使用标准的软锁定,它似乎在 Notes 客户端中运行良好。
在 xPages 中,我考虑使用“允许文档锁定”功能,但我担心人们会在不使用关闭或保存按钮的情况下关闭浏览器,然后锁定将永远不会被清除。
当用户关闭会话时,有没有办法清除锁定?我没有看到这样的事件。
或者有没有更简单的方法来锁定文档?
我意识到我可以使用代理清除锁,但是什么时候运行呢?我会想某个晚上的某个时候,我相当肯定锁应该不再真正处于活动状态。
在 xPages 中处理文档锁定的最佳方法是什么?目前我们使用标准的软锁定,它似乎在 Notes 客户端中运行良好。
在 xPages 中,我考虑使用“允许文档锁定”功能,但我担心人们会在不使用关闭或保存按钮的情况下关闭浏览器,然后锁定将永远不会被清除。
当用户关闭会话时,有没有办法清除锁定?我没有看到这样的事件。
或者有没有更简单的方法来锁定文档?
我意识到我可以使用代理清除锁,但是什么时候运行呢?我会想某个晚上的某个时候,我相当肯定锁应该不再真正处于活动状态。
这是我正在使用的代码:
/* DOCUMENT LOCKING */
/*
use the global object "documentLocking" with:
.lock(doc) -> locks a document
.unlock(doc) -> unlocks a document
.isLocked(doc) -> returns true/false
.lockedBy(doc) -> returns name of lock holder
.lockedDT(doc) -> returns datetime stamp of lock
*/
function ynDocumentLocking() {
/*
a lock is an entry in the application scope
with key = "$ynlock_"+UNID
containing an array with
(0) = username of lock holder
(1) = timestamp of lock
*/
var lockMaxAge = 60 * 120; // in seconds, default 120 min
this.getUNID = function(v) {
if (!v) return null;
if (typeof v == "NotesXspDocument") return v.getDocument().getUniversalID();
if (typeof v == "string") return v;
return v.getUniversalID();
}
/* puts a lock into application scope */
this.lock = function(doc:NotesDocument) {
var a = new Array(1);
a[0] = @UserName();
a[1] = @Now();
applicationScope.put("$ynlock_"+this.getUNID(doc), a);
// print("SET LOCK "+"$ynlock_"+doc.getUniversalID()+" / "+a[0]+" / "+a[1]);
}
/* removes a lock from the application scope */
this.unlock = function(doc:NotesDocument) {
applicationScope.put("$ynlock_"+this.getUNID(doc), null);
//print("REMOVED LOCK for "+"$ynlock_"+doc.getUniversalID());
}
this.isLocked = function(doc:NotesDocument) {
try {
//print("ISLOCKED for "+"$ynlock_"+doc.getUniversalID());
// check how old the lock is
var v = applicationScope.get("$ynlock_"+this.getUNID(doc));
if (!v) {
//print("no lock found -> return false");
return false;
}
// if lock holder is the current user, treat as not locked
if (v[0] == @UserName()) {
//print("lock holder = user -> not locked");
return false;
}
var dLock:NotesDateTime = session.createDateTime(v[1]);
var dNow:NotesDateTime = session.createDateTime(@Now());
// diff is in seconds
//print("time diff="+dNow.timeDifference(dLock)+" dLock="+v[1]+" now="+@Now());
// if diff > x seconds then remove lock, it not locked
if (dNow.timeDifference(dLock) > lockMaxAge) {
// print("LOCK is older than maxAge "+lockMaxAge+" -> returning false");
return false;
}
//print("return true");
return true;
// TODO: check how old the lock is
} catch (e) {
print("ynDocumentLocking.isLocked: "+e);
}
}
this.lockedBy = function(doc:NotesDocument) {
try {
var v = applicationScope.get("$ynlock_"+this.getUNID(doc));
if (!v) return "";
//print("ISLOCKEDBY "+"$ynlock_"+doc.getUniversalID()+" = "+v[0]);
return v[0];
} catch (e) {
print("ynDocumentLocking.isLockedBy: "+e);
}
}
this.lockedDT = function(doc:NotesDocument) {
try {
var v = applicationScope.get("$ynlock_"+this.getUNID(doc));
if (!v) return "";
return v[1];
} catch (e) {
print("ynDocumentLocking.isLockedBy: "+e);
}
}
}
var documentLocking = new ynDocumentLocking();
ApplicationScope 可能是捕获“锁定”文档的好地方。毕竟,要使 applicationScope 过期,所有用户的会话都必须过期,因此任何打开页面的人都无法保存。
当有人编辑文档时,可能会捕获 UNID、用户和时间。保存文档时清除该值。请记住,用户可能会关闭浏览器等。我一直在内部讨论这种方法,如果我们最终构建它,我会考虑将它添加到 OpenNTF。但我们不太可能在下个月内完成它。
您可以从 webDAV 的工作方式中获取一个页面。servlet 管理锁定文档的“锁定列表”。锁会在 10 分钟后自动失效。可以通过调用更新或终止锁。因此,当您编辑文档时,您将请求锁定,然后启动一个 CSJS 计时器,该计时器每 8 分钟调用一次重新锁定功能(因此您有一些错误余地),并且 postSave 调用解锁(除非您保持在编辑模式)。如果用户在 10 分钟后关闭浏览器,文档将自动解锁。由于您可以自由地实现锁定功能,因此您可以捕获用户/位置并在“锁定失败”显示中使用该信息(您可以进一步推动该信息并让原作者知道它或做一些“重试”选项. 实现起来并不简单,
我更喜欢使用类似于威瑟斯先生回答的解决方案。主要问题是如何处理不需要的和可怕的后退按钮。文档打开时锁定很容易,但是关闭 XPage 的方法有很多,用户不仅限于您提供的导航,还可以如他所说,完全关闭浏览器,使用返回按钮等。因此,我能想到的最好方法是创建一些我们将在应用程序和会话范围中使用的 java 对象。
第一步是创建一个“LockedDocument”类。众所周知,文档是不可序列化的,我们不想将文档本身保存在这个对象中,我们想保存 UNID 和保存时间。我们希望这样做,以便我们可以在给定时间(如三十分钟到一个小时)后设法清除对象。此类还应实现可比较的接口,以便在此时对集合进行排序,以便最旧的文档排在第一位,最新的文档排在最后。
接下来,我们创建另一个类,其中包含带有这些 LockedDocuments 的列表或映射。这个类还必须有一个线程(实现 Runnable),它将每五分钟左右检查一次所有文档,我还没有对此进行测试,但它应该可以工作)。任何在 30 到 60 分钟前被锁定(预定义)的文档都将被解锁(从列表中删除)。重要的是,列表按上述方式排序,并且当达到小于锁定时间的时间时,循环“中断”,以防止不需要的处理。
下一步是在 sessionScope 中包含用户特定列表。此列表是当前用户拥有的 LockedDocuments。它在用户将文档的状态更改为可编辑时设置,并在文档设置为可编辑之前进行检查,以防止同一用户在多个选项卡中打开一个文档。onquerysave() 再次检查锁。打开主页后,锁会自动释放。onquerysave() 还必须检查以确保文档 UNID 在 sessionScope 列表中,或者在允许保存之前文档是否是新的。
快速回顾
任何保存在 applicationScope LockedDocumentList 中的 UNID 都不能被任何人编辑,除非它存在于他们自己的 sessionScope 列表中。
可以警告用户他们的lockedTime 即将到来并重置计时器。
包含锁定文档列表的类必须是单例
可能有改进这个答案的方法,我确信我遗漏了一些东西。这只是一个想法。
可能有更好的方法来处理这个问题,但这是我发现的最好的。
window.onunload
您可以在事件中移除 Domino 锁定:
window.onunload = function(){
dojo.xhrGet(...
}
无需重新发明轮子。