In
https://issues.apache.org/struts/browse/WW-1808, the FreemarkerResult was improved to support not writing to the response until it had completed processing.
Unfortunately, if you are using an s.action tag, then that means the s.action output ends up before the main template output rather than inline.
One way to fix this (which I did locally) is to add a thread local that keeps track of the "parent" writer such that if there is one present the child writes to that at the end rather than the response's writer.
Something like:
/** Thread local for the current writer. */
private static final ThreadLocal<CharArrayWriter> WRITER_THREAD_LOCAL
= new ThreadLocal<CharArrayWriter>();
...
// Inside the case where we are writing upon completion
CharArrayWriter parentCharArrayWriter = WRITER_THREAD_LOCAL.get();
try {
// Process the template with the normal writer since it was available
// But delay writing in case exception
CharArrayWriter charArrayWriter = new CharArrayWriter(1024);
if (parentCharArrayWriter == null) {
WRITER_THREAD_LOCAL.set(charArrayWriter);
}
template.process(model, charArrayWriter);
charArrayWriter.flush();
// Only the template that created the writer can actually write
// to the response. This is necessary to support the s.action tag.
if (parentCharArrayWriter == null) {
charArrayWriter.writeTo(writer); // Write to the response writer
} else {
// Copying to parent enmass so don't get partially rendered s.actions
charArrayWriter.writeTo(parentCharArrayWriter);
}
} finally {
if (parentCharArrayWriter == null) {
WRITER_THREAD_LOCAL.remove();
}
}
CharArrayWriter parentCharArrayWriter = WRITER_THREAD_LOCAL.get();
try {
// Process the template with the normal writer since it was available
// But delay writing in case exception
CharArrayWriter charArrayWriter;
if (parentCharArrayWriter == null) {
charArrayWriter = new CharArrayWriter(1024);
WRITER_THREAD_LOCAL.set(charArrayWriter);
} else {
charArrayWriter = parentCharArrayWriter;
}
template.process(model, charArrayWriter);
// Only the template that created the writer can actually write
// to the response. This is necessary to support the s.action tag.
if (parentCharArrayWriter == null) {
// Process the template
Writer writer = getWriter();
charArrayWriter.flush();
charArrayWriter.writeTo(writer);
}
} finally {
if (parentCharArrayWriter == null) {
WRITER_THREAD_LOCAL.remove();
}
}