0
头像

如何等待文档操作完成

我正在尝试创建一个使用 BLAST 插件 ( getDocumentOperation ( "sequenceSearch" )) 的插件,但我想在 BLAST 操作完成后进一步操作输入文档。  但是,例如,如果我尝试删除输入文档,则会收到空指针异常。  有没有什么办法可以监控BLAST文档操作的进度,等到完成后再继续?

埃里克·范姓名

9 条评论

0
头像

好的,我能够达到我想要达到的结果,但我认为必须有更好的方法。  首先,我使用 waitForSearchIndexingToComplete() 方法来确保在继续之前一切都已完成。  那行得通,但我认为这不是一个好方法,因为如果有人最近添加了一堆文档,那么我的插件在所有索引编制完成之前都不会完成。

我尝试的下一件事是实现 GeneiousServiceListener 并使用 CountDownLatch 来监视出现在我的文件夹中的结果数量。  不幸的是,结果的 childService 在原始文档完成 BLAST 操作之前被添加,所以我不能使用它。  但是,我注意到 childService 图标更改了 3 次(如果没有结果则更改为 4 次,但随后会出现一个对话框,这实际上使插件等待)。  所以,现在我有一个 CountDownLatch,从我期望的结果数量的三倍开始,每次调用 iconsChanged() 时倒计时。并在继续之前等待。

这是有效的,但它似乎是一个可怕的草率黑客,我希望你能提出更好的策略?  Thanks!

埃里克·范姓名 0 票
评论动作 永久链接
0
头像

与大多数操作不同,BLAST 操作在单独的线程中运行并立即从 performOperation 返回。我们有一个方法可以让它在同一个线程中执行,并且只有在搜索完成后才返回,但它不能从公共 API 中获得。下面是如何使用反射来调用它。

尝试 {
班级<?>privateUtilities = Class.forName("com.biomatters.geneious.common.privateapi.a");
方法 setRunningFromScript = privateUtilities.getDeclaredMethod("c", Boolean.TYPE);
setRunningFromScript.setAccessible(true);
setRunningFromScript.invoke(null, true); // 告诉 Geneious 我们正在从脚本运行
} 捕获(异常 e){
抛出新的运行时异常(e);
}

//在这里调用blast,当performOperation返回时,你就知道搜索完成了。

尝试 {
班级<?>privateUtilities = Class.forName("com.biomatters.geneious.common.privateapi.a");
方法 setRunningFromScript = privateUtilities.getDeclaredMethod("c", Boolean.TYPE);
setRunningFromScript.setAccessible(true);
setRunningFromScript.invoke(null, false); // 告诉 Geneious 我们不再从脚本运行
} 捕获(异常 e){
抛出新的运行时异常(e);
}

理查德·摩尔 0 票
评论动作 永久链接
0
头像

谢谢,这很有用!  所以我想确保我了解这是如何工作的,因为乍一看,这看起来比 BLAST 操作更通用。

当您调用 setRunningFromScript(true) 时,是否会将以下所有代码限制为单个线程,直到调用 setRunningFromScript(false) 为止?  或者它仅适用于操作的子集(例如,DocumentOperations 和 SequenceAnnotationGenerators),甚至仅适用于 BLAST 操作? 

另外,如果这是一个更通用的工具,单线程是否独立于主awt线程?  换句话说,如果我调用一些需要一段时间才能运行的东西,gui 会变得无响应吗?

埃里克·范姓名 0 票
评论动作 永久链接
0
头像

它仅适用于某些 DocumentOperations 和 SequenceAnnotationGenerators。这是一个标志,当他们想要做一些对脚本有害的事情时,操作会自愿检查它。最常见的情况是当一个操作想要弹出一个对话框来通知用户执行过程中的某些事情时。因为这会暂停脚本并等待输入,所以当标志为真时它会被抑制。

BLAST 操作是我唯一知道该标志在哪里影响线程的操作,在大多数其他情况下,它只是抑制对话框。

假设您正在自己编写 DocumentOperation,您通常不必担心阻塞 AWT 线程,因为 performOperation 是在后台线程上调用的。

理查德·摩尔 0 票
评论动作 永久链接
0
头像

感谢您的澄清。  我想我过于乐观了,因为我的插件的另一部分已经遇到了同样的问题。  我使用设置 BLAST 服务操作来检查用户是否有正确的公共 BLAST 文件夹,如果没有,则为他们设置。  不幸的是,那个也在它自己的线程中运行,所以如果我在它之后立即调用 BLAST 搜索,它将使用旧的 BLAST 文件夹位置。  不过,这没什么大不了的,因为如果我需要更改文件夹,我会作弊并弹出一个“有用”的对话框,通知用户有关更改(并购买插件有足够的时间在继续之前进行更改)。;)

埃里克·范姓名 0 票
评论动作 永久链接
0
头像

如果我们对自定义爆炸(例如矢量修剪)有这样的依赖性,我们只是告诉用户自己更改它,然后再试一次。这对他们来说不太方便,但不太可能引起问题。无论如何,它应该是一次性的。

理查德·摩尔 0 票
评论动作 永久链接
0
头像

好的,我终于开始尝试实施您的解决方案,但我遇到了一些问题。  起初,我只是在我调用爆炸操作的那一行周围添加了两个 try 块,但是遇到了一个 progressListener 错误:

“异常:java.lang.AssertionError:进步不应该倒退。在权重 = [0.95, 0.05] 的进度侦听器上从 0.95 变为 0.0"

我使用了相同的 progressListener ,它被传递到我的 performOperation 方法中,用于几件事,包括 BLAST 操作以及一些文档复制/删除。  因此,我尝试(暂时)通过使用 ProgressListener.EMPTY 进行文档复制/删除来解决该问题,从而消除了该错误。  但是,我不完全理解这一点,因此欢迎任何解释。

在任何情况下,虽然我能够摆脱 progressListener 错误,但是一旦我将这些 try 块添加到我的插件中,就会停止出现爆炸结果。  有什么建议么?

埃里克·范姓名 0 票
评论动作 永久链接
0
头像

重用 ProgressListener 是正确的做法,但您必须将其包装在CompositeProgressListener 中才能正确地将操作拆分为子任务。这会预先告诉 Geneious 有多少子任务以及每个子任务有多大,以便它可以为用户提供合理的进度。希望这是有道理的。

你有没有机会把代码发给我,让我看看?理查德在 biomatters dot com。

理查德·摩尔 0 票
评论动作 永久链接
0
头像

我们的记录发现:

在某些情况下,自定义blast 报告的进度可能会稍微倒退,这将导致从工作流运行时出现断言错误。由于是断言错误,因此只有开发人员在从 IDE 运行时才会看到崩溃。内部记录了一个低优先级的错误,以便稍后修复。

理查德·摩尔 0 票
评论动作 永久链接