Hi all!

In order to resolve SYNAPSE-218 (TextFileDataSource violates OMDataSource contract), I think we need to review the following piece of code in VFSTransportSender#populateResponseFile (there is similar code in MailTransportSender#sendMail):

if (firstChild instanceof OMSourcedElementImpl) {
    firstChild.serializeAndConsume(os);
} else {
    os.write(firstChild.getText().getBytes());
}

The purpose of this piece of code is to write the content of {http://ws.apache.org/commons/ns/payload }text elements to the response file. OMSourcedElementImpl nodes are handled differently to ensure that large output from XSL transformations is processed efficiently (i.e. without loading the entire temporary output file into memory). The code has two problems:

1) Since OMSourcedElementImpl extends OMElement, a call to serializeAndConsume should normally write out the entire element, i.e. start tag, content (encoded as XML) and end tag. This is of course not what is indented here. The code only works as expected because TextFileDataSource doesn't respect the OMDataSource contract (which is what SYNAPSE-218 is all about).

2) The instruction os.write(firstChild.getText().getBytes()) will encode the content of the element using the default platform encoding, which is not always what is expected. Note that for the output of an XSL transformation, the content of the element is produced by the following instruction in XSLTMediator#performXSLT:

handleNonXMLResult(baosForTarget.toString(), traceOrDebugOn, traceOn)

While considered separately this is also incorrect (since ByteArrayOutputStream#toString uses the default platform encoding, while the encoding of the stream depends on the stylesheet), in most cases the net result is indeed that the response file will have the encoding specified in the stylesheet. However this only works if the combined transformation ByteArrayOutputStream#toString -> String#getBytes is equivalent to the identity transformation. This is not the case if the default platform encoding is e.g. UTF-8.

The solution for the first problem is actually surprisingly simple. The correct behavior can be achieved by replacing the code by the following instructions:

OMNode node = firstChild.getFirstOMChild();
while (node != null) {
    if (node instanceof OMText) {
        os.write(((OMText)node).getText().getBytes());
    }
    node = node.getNextOMSibling();
}

I checked that for an OMSourcesElementImpl node backed by a TextFileDataSource object, getFirstOMChild and getNextOMSibling will read a single chunk of text from the WrappedTextNodeStreamReader constructed by TextFileDataSource. Therefore the replacement code will handle large temporary files with the same efficiency as the original code.

An obviously solution for the second problem is to allow the configuration of the output encoding in the VFS transport (and to correct XSLTMediator!). However there might be cases where the user wants to specify the output encoding in the XSLT stylesheet. This could be achieved by allowing XSLTMediator to be configured to use a binary wrapper instead of a text wrapper for text output. In this case Synapse would strictly preserve the output of the XSL transformation.

I'm waiting for your comments!

Andreas


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to