Java exception: "Can't get a Writer while an OutputStream is already in use" when running xAgent

Steve Zavocki

I am trying to implement Paul Calhoun's Apache FOP solution for creating PDF's from Xpages (from Notes In 9 #102). I am getting the following java exception when trying to run the xAgent that does the processing --> Can't get a Writer while an OutputStream is already in use

The only changes that I have done from Paul's code was to change the package name. I have isolated when the exception happens to the SSJS line: var jce: DominoXMLFO2PDF = new DominoXMLFO2PDF(); All that line does is instantiate the class, there is no custom constructor. I don't believe it is the code itself, but some configuration issue. The SSJS code is in the beforeRenderResponse event where it should be, I haven't changed anything on the xAgent.

I have copied the jar files from Paul's sample database to mine, I have verified that the build paths are the same between the two databases. Everything compiles fine (after I did all this.) This exception appears to be an xpages only exception.

Tim Tripcony

Here's what's really going on with this error:

XPages are essentially servlets... everything that happens in an XPage is just layers on top of a servlet engine. There are basically two types of data that a servlet can send back to whatever is initiating the connection (e.g. a browser): text and binary.

An ordinary XPage sends text -- specifically, HTML. Some xAgents also send text, such as JSON or XML. In any of these scenarios, however, Domino uses a Java Writer to send the response content, because Writers are optimized for sending Character data.

When we need to send binary content, we use an OutputStream instead, because streams are optimized for sending generic byte data. So if we're sending PDF, DOC/XLS/PPT, images, etc., we need to use a stream, because we're sending binary data, not text.

The catch (as you'll soon see, that's a pun) is that we can only use one per response.

Once any HTTP client is told what the content type of a response is, it makes assumptions about how to process that content. So if you tell it to expect application/pdf, it's expecting to only receive binary data. Conversely, if you tell it to expect application/json, it's expecting to only receive character data. If the response includes any data that doesn't match the promised content type, that nearly always invalidates the entire response.

So Domino in its infinite wisdom protects us from making this mistake by only allowing us to send one or the other in a single request, and throws an exception if we disobey that rule.

Unfortunately... if there's any exception in our code when we're trying to send binary content, Domino wants to report that to the consumer... which tries to invoke the output writer to send HTML reporting that something went wrong. Except we already got a handle on the output stream, so Domino isn't allowed to get a handle on the output writer, because that would violate its own rule against only using one per response. This, in turn, throws the exception you reported, masking the exception that actually caused the problem (in your case, probably a ClassNotFoundException).

So how do we make sure that we see the real problem, and not this misdirection? We try:

try {
  /*
   * Move all your existing code here...
   */
} catch (e) {
  print("Error generating dynamic PDF: " + e.toString());
} finally {
  facesContext.responseComplete();
}

There are two reasons this is a preferred approach:

  1. If something goes wrong with our code, we don't let Domino throw an exception about it. Instead, we log it (instead of using print to send it to the console and log, you could also toss it to OpenLog, or whatever your preferred logging mechanism happens to be). This means that Domino doesn't try to report the error to the user, because we've promised that we already reported it to ourselves.
  2. By moving the crucial facesContext.responseComplete() call (which is what ultimately tells Domino not to send any content of its own) to the finally block, this ensures it will get executed. If we left it inside the try block, it would get skipped if an exception occurs, because we'd skip straight to the catch... so even though Domino isn't reporting our exception because we caught it, it still tries to invoke the response writer because we didn't tell it not to.

If you follow the above pattern, and something's wrong with your code, then the browser will receive an incomplete or corrupt file, but the log will tell you what went wrong, rather than reporting an error that has nothing to do with the root cause of the problem.

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Java异常:运行xAgent时“在使用OutputStream时无法获取Writer”

来自分类Dev

Connection refused exception while running hadoop jar

来自分类Dev

XAgent importPackage与无范围内的托管bean

来自分类Dev

Define custom exception handler in Java?

来自分类Dev

在Java中扩展Exception / RunTimeException?

来自分类Dev

Java中的Throwable和Exception

来自分类Dev

Java中的Throwable和Exception

来自分类Dev

GCM BroadcastReceiver fired only when app is running or running at background

来自分类Dev

Exception when Android App is deployed via TestFairy

来自分类Dev

what the cause of exception when connecting to the server

来自分类Dev

what the cause of exception when connecting to the server

来自分类Dev

Bogus escape error when running regex

来自分类Dev

Problems running JerseyTest when dealing with HttpServletResponse

来自分类Dev

How to handle socketIO when app is not running

来自分类Dev

No ressources availbable when running unit test

来自分类Dev

Error when running emulator in Android Studio

来自分类Dev

AcceptSecurityContext fails when application is running as a service

来自分类Dev

IllegalArgumentException when running app. (Android)

来自分类Dev

调用XAgent和备用对话框自定义控件

来自分类Dev

Java JNI EXCEPTION_ACCESS_VIOLATION

来自分类Dev

RequestLocationUpdates抛出Java.Lang.Exception

来自分类Dev

getActionBar(),getSupportActionBar()返回java.nullpointer.exception

来自分类Dev

java:Zip Exception无效代码长度?

来自分类Dev

Exception Java API是否违反Liskov原则?

来自分类Dev

getActionBar(),getSupportActionBar()返回java.nullpointer.exception

来自分类Dev

java.lang.Exception:java.lang.ArrayIndexOutOfBoundsException:7

来自分类Dev

Runtime Exception coming when show UIAlertController(actionsheet) iOS8

来自分类Dev

Return false vs raising an exception in Ruby- When and why?

来自分类Dev

TStrings is returned as "Inaccessible value" when exception is raised in function

Related 相关文章

  1. 1

    Java异常:运行xAgent时“在使用OutputStream时无法获取Writer”

  2. 2

    Connection refused exception while running hadoop jar

  3. 3

    XAgent importPackage与无范围内的托管bean

  4. 4

    Define custom exception handler in Java?

  5. 5

    在Java中扩展Exception / RunTimeException?

  6. 6

    Java中的Throwable和Exception

  7. 7

    Java中的Throwable和Exception

  8. 8

    GCM BroadcastReceiver fired only when app is running or running at background

  9. 9

    Exception when Android App is deployed via TestFairy

  10. 10

    what the cause of exception when connecting to the server

  11. 11

    what the cause of exception when connecting to the server

  12. 12

    Bogus escape error when running regex

  13. 13

    Problems running JerseyTest when dealing with HttpServletResponse

  14. 14

    How to handle socketIO when app is not running

  15. 15

    No ressources availbable when running unit test

  16. 16

    Error when running emulator in Android Studio

  17. 17

    AcceptSecurityContext fails when application is running as a service

  18. 18

    IllegalArgumentException when running app. (Android)

  19. 19

    调用XAgent和备用对话框自定义控件

  20. 20

    Java JNI EXCEPTION_ACCESS_VIOLATION

  21. 21

    RequestLocationUpdates抛出Java.Lang.Exception

  22. 22

    getActionBar(),getSupportActionBar()返回java.nullpointer.exception

  23. 23

    java:Zip Exception无效代码长度?

  24. 24

    Exception Java API是否违反Liskov原则?

  25. 25

    getActionBar(),getSupportActionBar()返回java.nullpointer.exception

  26. 26

    java.lang.Exception:java.lang.ArrayIndexOutOfBoundsException:7

  27. 27

    Runtime Exception coming when show UIAlertController(actionsheet) iOS8

  28. 28

    Return false vs raising an exception in Ruby- When and why?

  29. 29

    TStrings is returned as "Inaccessible value" when exception is raised in function

热门标签

归档