Xpages Java异常:";Can';当OutputStream已在使用时,无法获取写入程序”;运行xAgent时

Xpages Java异常:";Can';当OutputStream已在使用时,无法获取写入程序”;运行xAgent时,xpages,Xpages,我试图实现Paul Calhoun的ApacheFop解决方案,用于从Xpages创建PDF(来自9#102中的注释)。当尝试运行执行处理-->的xAgent时,我遇到以下java异常,即在OutputStream已在使用时无法获取写入程序 我对Paul代码所做的唯一更改是更改包名。我已经隔离了SSJS行发生异常的时间:var jce:DominoXMLFO2PDF=new DominoXMLFO2PDF()行所做的只是实例化类,没有自定义构造函数。我不相信这是代码本身,但一些配置问题。SSJS

我试图实现Paul Calhoun的ApacheFop解决方案,用于从Xpages创建PDF(来自9#102中的注释)。当尝试运行执行处理-->的xAgent时,我遇到以下java异常,即在OutputStream已在使用时无法获取写入程序

我对Paul代码所做的唯一更改是更改包名。我已经隔离了SSJS行发生异常的时间:
var jce:DominoXMLFO2PDF=new DominoXMLFO2PDF()行所做的只是实例化类,没有自定义构造函数。我不相信这是代码本身,但一些配置问题。SSJS代码位于beforeRenderResponse事件中,我没有在xAgent上更改任何内容


我已经将jar文件从Paul的示例数据库复制到我的数据库中,我已经验证了两个数据库之间的构建路径是相同的。一切都很好(在我做了所有这些之后)。这个异常似乎是xpages唯一的异常。

我几乎删除了这个问题,但决定自己回答,因为当你搜索异常时,谷歌上几乎没有什么内容

问题出在xAgent中,有一行importPackage不正确。解决这个问题使一切正常。异常措辞:“OutputStream已在使用时无法获取写入程序”非常容易引起误解。我不知道还有什么触发了这个异常,但另一种描述是“Java类??yourClass??未找到”


如果你发现了这个问题,那么你可能也有同样的问题。我将忽略异常实际所说的内容,并在整个应用程序中检查您的包语句。java代码本身会出错,但引用java的SSJ在运行时才会出错,请关注该代码。

以下是此错误的真正原因:

XPages本质上是servlet。。。XPage中发生的一切都只是servlet引擎顶部的层。servlet基本上可以将两种类型的数据发送回启动连接的任何对象(例如浏览器):文本和二进制

普通的XPage发送文本——特别是HTML。一些Xagent还发送文本,如JSON或XML。但是,在任何一种情况下,Domino都使用Java发送响应内容,因为编写器在发送数据方面都经过了优化

当我们需要发送二进制内容时,我们使用一个,因为流是为发送通用字节数据而优化的。因此,如果我们发送PDF、DOC/XLS/PPT、图像等,我们需要使用流,因为我们发送的是二进制数据,而不是文本

问题是(你很快就会看到,这是一个双关语),我们每个响应只能使用一个

一旦任何HTTP客户机被告知响应的内容类型,它就会对如何处理该内容做出假设。因此,如果您告诉它期望
application/pdf
,它只希望接收二进制数据。相反,如果您告诉它期望
application/json
,它只希望接收字符数据。如果响应包含与承诺的内容类型不匹配的任何数据,则几乎总是使整个响应无效

因此,多米诺以其无限的智慧保护我们避免犯这种错误,因为它只允许我们在一个请求中发送一个或另一个请求,如果我们不遵守该规则,就会抛出异常

不幸的是。。。当我们试图发送二进制内容时,如果代码中有任何异常,Domino希望向消费者报告。。。它试图调用输出编写器来发送HTML报告,指出出现了问题。除了我们已经在输出流上获得了一个句柄,所以Domino不允许在输出编写器上获得一个句柄,因为这违反了它自己的规则,即每个响应只使用一个句柄。这反过来抛出您报告的异常,掩盖了实际导致问题的异常(在您的情况下,可能是一个异常)

那么,我们如何确保我们看到了真正的问题,而不是这种误导?我们
尝试

try {
  /*
   * Move all your existing code here...
   */
} catch (e) {
  print("Error generating dynamic PDF: " + e.toString());
} finally {
  facesContext.responseComplete();
}
这是一种首选方法,有两个原因:

  • 如果代码出现问题,我们不会让Domino抛出异常。相反,我们记录它(而不是使用
    print
    将它发送到控制台和日志,您也可以将它扔到OpenLog,或者您首选的任何日志机制)。这意味着Domino不会尝试向用户报告错误,因为我们承诺已经向自己报告了
  • 通过将关键的
    facesContext.responseComplete()
    调用(它最终告诉Domino不要发送自己的任何内容)移动到
    finally
    块,这确保了它将得到执行。如果我们将它放在
    try
    块中,如果发生异常,它将被跳过,因为我们将直接跳到
    catch
    。。。因此,尽管Domino没有报告我们的异常,因为我们捕获了它,但它仍然尝试调用响应编写器,因为我们没有告诉它不要这样做

  • 如果您遵循上述模式,并且代码有问题,那么浏览器将收到不完整或损坏的文件,但日志将告诉您出了什么问题,而不是报告与问题根本原因无关的错误。

    在正文解决此类问题后更新响应标头,例如:

    HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
    
    response.getWriter().write("<html><body>...</body></html>");
    
    response.setContentType("text/html");
    response.setHeader("Cache-Control", "no-cache");
    response.setCharacterEncoding("UTF-8");     
    
    HttpServletResponse=(HttpServletResponse)facesContext.getExternalContext().getResponse();
    response.getWriter().write(“…”);
    response.setContentType(“text/html”);
    setHeader(“缓存控制”、“无缓存”);
    响应。setCharacterEncoding(“UTF-8”);
    
    好吧,我是个白痴,我明白了,我在xAgent中的importPackage语句不正确。哇,Tim,回答得很好。你肯定是ser上的goto人