I’ve written a simple XSL:FO to PDF mediator. The transform of the XSL:FO document seems a success, but returning a PDF does not seem to work.
In the axis2.xml file I’ve added the rules for application/pdf:
<messageFormatter contentType="application/pdf" class="org.wso2.carbon.relay.ExpandingMessageFormatter"/>
<messageBuilder contentType="application/pdf" class="org.wso2.carbon.relay.BinaryRelayBuilder"/>
Error Message:
org.apache.axiom.om.OMException: Error reading data handler
at org.apache.axiom.om.impl.llom.OMTextImpl.internalSerialize(OMTextImpl.java:455)
at org.apache.axiom.om.impl.util.OMSerializerUtil.serializeChildren(OMSerializerUtil.java:555)
at org.apache.axiom.om.impl.llom.OMElementImpl.internalSerialize(OMElementImpl.java:879)
at org.apache.axiom.soap.impl.llom.SOAPEnvelopeImpl.internalSerialize(SOAPEnvelopeImpl.java:230)
at org.apache.axiom.om.impl.llom.OMSerializableImpl.serialize(OMSerializableImpl.java:125)
at org.apache.axiom.om.impl.llom.OMSerializableImpl.serialize(OMSerializableImpl.java:113)
at org.apache.axiom.om.impl.llom.OMElementImpl.toString(OMElementImpl.java:992)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuffer.append(StringBuffer.java:263)
at org.apache.synapse.mediators.builtin.LogMediator.getFullLogMessage(LogMediator.java:208)
at org.apache.synapse.mediators.builtin.LogMediator.getLogMessage(LogMediator.java:139)
at org.apache.synapse.mediators.builtin.LogMediator.mediate(LogMediator.java:102)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:109)
at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:71)
at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:158)
at org.apache.synapse.mediators.MediatorFaultHandler.onFault(MediatorFaultHandler.java:96)
at org.apache.synapse.FaultHandler.handleFault(FaultHandler.java:101)
at org.apache.synapse.core.axis2.ProxyServiceMessageReceiver.receive(ProxyServiceMessageReceiver.java:253)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at org.apache.synapse.transport.passthru.ServerWorker.processEntityEnclosingRequest(ServerWorker.java:415)
at org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:152)
at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.activation.UnsupportedDataTypeException: no object DCH for MIME type application/pdf
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:896)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at org.apache.axiom.util.stax.XMLStreamWriterUtils.writeBase64(XMLStreamWriterUtils.java:62)
at org.apache.axiom.util.stax.XMLStreamWriterUtils.writeDataHandler(XMLStreamWriterUtils.java:138)
at org.apache.axiom.om.impl.llom.OMTextImpl.internalSerialize(OMTextImpl.java:452)
The mediator code is currently:
public class PDFMediator extends AbstractMediator {
public boolean mediate(MessageContext context) {
trace.info(new String("PdfMediator Process Started"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
OMElement body = context.getEnvelope().getBody();
String text = body.getFirstElement().toString();
Source src = new StreamSource(new StringReader(text));
final FopFactory fopFactory = FopFactory.newInstance(new File(".").toURI());
Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, out);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
Result res = new SAXResult(fop.getDefaultHandler());
transformer.transform(src, res);
trace.info("PDF: " + out.toString());
DataHandler dataHandler = new DataHandler(out, MimeConstants.MIME_PDF);
OMFactory fac = OMAbstractFactory.getOMFactory();
OMText textData = fac.createOMText(dataHandler, true);
body.addChild(textData);
context.setProperty(Constants.Configuration.ENABLE_MTOM, Constants.VALUE_TRUE);
context.setProperty(Constants.Configuration.MESSAGE_TYPE, MimeConstants.MIME_PDF);
context.setProperty(Constants.Configuration.CONTENT_TYPE, MimeConstants.MIME_PDF);
context.setProperty(org.apache.axis2.Constants.Configuration.CONTENT_TYPE, MimeConstants.MIME_PDF);
Object o = context.getProperty(org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
Map<String, String> headers = (Map<String, String>) o;
if (headers != null) {
headers.remove(HTTP.CONTENT_TYPE);
headers.put(HTTP.CONTENT_TYPE, MimeConstants.MIME_PDF);
}
trace.info(new String("PdfMediator Process Finished successfully"));
} catch (FOPException e) {
trace.error(new String("PdfMediator Process Failed (FOP): ")+e.toString());
e.printStackTrace();
context.setProperty(NhttpConstants.HTTP_SC, 500);
context.setProperty(NhttpConstants.ERROR_DETAIL, "XSL:FO to PDF transformation failed");
context.setProperty(NhttpConstants.ERROR_MESSAGE, "XSL:FO to PDF transformation failed: "+e.toString());
handleException("XSL:FO to PDF transformation failed (FOP): "+e.toString(), context);
} catch (TransformerException e) {
trace.error(new String("PdfMediator Process Failed (transform): ")+e.toString());
e.printStackTrace();
context.setProperty(NhttpConstants.HTTP_SC, 500);
context.setProperty(NhttpConstants.ERROR_DETAIL, "XSL:FO to PDF transformation failed");
context.setProperty(NhttpConstants.ERROR_MESSAGE, "XSL:FO to PDF transformation failed: "+e.toString());
handleException("XSL:FO to PDF transformation failed (transform): "+e.toString(), context);
} finally {
// Clean-up
try {
out.close();
} catch (IOException e) {
trace.error(new String("PdfMediator Process Failed"));
handleException("IOError: "+e.toString(), context);
e.printStackTrace();
}
}
return true;
}
}
The 'trace.info("PDF: " + out.toString());' is printed with the correct PDF. So is the 'trace.info(new String("PdfMediator Process Finished successfully"));'
The document that is used for testing is:
<?xml version="1.1" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="my_page" margin="0.5in">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="my_page">
<fo:flow flow-name="xsl-region-body">
<fo:block>Hello world!</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
The proxy in WSO2 looks like:
<?xml version="1.0" encoding="UTF-8"?>
<proxy xmlns="http://ws.apache.org/ns/synapse"
name="PDFTest"
startOnLoad="true"
statistics="disable"
trace="disable"
transports="http,https">
<target>
<inSequence>
<log level="custom">
<property expression="/" name="input"/>
</log>
<class name="com.example.PDFMediator"/>
<log level="custom">
<property expression="/" name="output"/>
</log>
<send/>
</inSequence>
</target>
<description/>
</proxy>
The solution is to use SynapseBinaryDataSource, this will use the correct translation. The only remaining issue is that the output is not seen as PDF, therefor the calling proxy needs to add the message type.