Waqas Ali Razzaq
Waqas Ali Razzaq

Reputation: 669

How to respond application/pdf content from WSO2 ESB

I am trying to respond PDFcontent from wso2 esb rest api and want to view in browser. I have enabled the messageFormatter and messageBuilder for application/pdf as well. But when I invoke my api from browser I am getting exception below in wso2 esb.

axis2.xml:

<messageBuilder contentType="application/pdf" class="org.wso2.carbon.relay.BinaryRelayBuilder"/>

<messageFormatter contentType="application/pdf" class="org.wso2.carbon.relay.ExpandingMessageFormatter"/>

Exception:

ERROR {org.apache.synapse.transport.passthru.PassThroughHttpSender} -  Failed to submit the response {org.apache.synapse.transport.passthru.PassThroughHttpSender}
java.lang.RuntimeException: ContentID is null
    at org.apache.axiom.om.impl.llom.OMTextImpl.getDataHandler(OMTextImpl.java:381)
    at org.wso2.carbon.relay.ExpandingMessageFormatter.findAndWrite2OutputStream(ExpandingMessageFormatter.java:179)
    at org.wso2.carbon.relay.ExpandingMessageFormatter.writeTo(ExpandingMessageFormatter.java:97)
    at org.apache.synapse.transport.passthru.PassThroughHttpSender.submitResponse(PassThroughHttpSender.java:573)
    at org.apache.synapse.transport.passthru.PassThroughHttpSender.invoke(PassThroughHttpSender.java:264)
    at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:442)
    at org.apache.synapse.core.axis2.Axis2Sender.sendBack(Axis2Sender.java:230)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.send(Axis2SynapseEnvironment.java:531)
    at org.apache.synapse.mediators.builtin.SendMediator.mediate(SendMediator.java:118)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:59)
    at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:158)
    at org.apache.synapse.rest.Resource.process(Resource.java:343)
    at org.apache.synapse.rest.API.process(API.java:338)
    at org.apache.synapse.rest.RESTRequestHandler.apiProcess(RESTRequestHandler.java:123)
    at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:101)
    at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:56)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:304)
    at org.apache.synapse.mediators.builtin.LoopBackMediator.mediate(LoopBackMediator.java:63)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:59)
    at org.apache.synapse.config.xml.AnonymousListMediator.mediate(AnonymousListMediator.java:37)
    at org.apache.synapse.config.xml.SwitchCase.mediate(SwitchCase.java:69)
    at org.apache.synapse.mediators.filters.SwitchMediator.mediate(SwitchMediator.java:148)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:260)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.mediateFromContinuationStateStack(Axis2SynapseEnvironment.java:775)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:282)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:554)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:188)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
    at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:262)
    at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Unexpected error sending message back {org.apache.synapse.core.axis2.Axis2Sender}
org.apache.axis2.AxisFault: Failed to submit the response
    at org.apache.synapse.transport.passthru.PassThroughHttpSender.handleException(PassThroughHttpSender.java:632)
    at org.apache.synapse.transport.passthru.PassThroughHttpSender.invoke(PassThroughHttpSender.java:266)
    at org.apache.axis2.engine.AxisEngine.send(AxisEngine.java:442)
    at org.apache.synapse.core.axis2.Axis2Sender.sendBack(Axis2Sender.java:230)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.send(Axis2SynapseEnvironment.java:531)
    at org.apache.synapse.mediators.builtin.SendMediator.mediate(SendMediator.java:118)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:59)
    at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:158)
    at org.apache.synapse.rest.Resource.process(Resource.java:343)
    at org.apache.synapse.rest.API.process(API.java:338)
    at org.apache.synapse.rest.RESTRequestHandler.apiProcess(RESTRequestHandler.java:123)
    at org.apache.synapse.rest.RESTRequestHandler.dispatchToAPI(RESTRequestHandler.java:101)
    at org.apache.synapse.rest.RESTRequestHandler.process(RESTRequestHandler.java:56)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:304)
    at org.apache.synapse.mediators.builtin.LoopBackMediator.mediate(LoopBackMediator.java:63)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:59)
    at org.apache.synapse.config.xml.AnonymousListMediator.mediate(AnonymousListMediator.java:37)
    at org.apache.synapse.config.xml.SwitchCase.mediate(SwitchCase.java:69)
    at org.apache.synapse.mediators.filters.SwitchMediator.mediate(SwitchMediator.java:148)
    at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:97)
    at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:260)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.mediateFromContinuationStateStack(Axis2SynapseEnvironment.java:775)
    at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.injectMessage(Axis2SynapseEnvironment.java:282)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.handleMessage(SynapseCallbackReceiver.java:554)
    at org.apache.synapse.core.axis2.SynapseCallbackReceiver.receive(SynapseCallbackReceiver.java:188)
    at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
    at org.apache.synapse.transport.passthru.ClientWorker.run(ClientWorker.java:262)
    at org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

API Content:

<payloadFactory media-type="xml">
                  <format>
                     <soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope">
                        <soapenv:Body>
                           <ns:binary xmlns:ns="http://ws.apache.org/commons/ns/payload">$1</ns:binary>
                        </soapenv:Body>
                     </soapenv:Envelope>
                  </format>
                  <args>
                     <arg evaluator="xml" expression="//*[local-name()='Binary']/text()"/>
                  </args>
               </payloadFactory>
               <property name="NO_ENTITY_BODY" scope="axis2" action="remove"/>
               <property name="ContentType" value="application/pdf" scope="axis2" type="STRING"/>
               <property name="messageType" value="application/pdf" scope="axis2" type="STRING"/>
               <respond/>

I have tried to convert binary to pdf using online tool and it works fine.

Upvotes: 3

Views: 2776

Answers (1)

simar
simar

Reputation: 1832

Find out eventually how to do it.

I use postgres in my experiments. Let's create table which will store files content. It is pretty simple. Anyway there are 2 cases. File might be stored as base64 or blob (bytea in postgres). I implemented case when file is stored as string in base64 format in database.

drop table if exists pdf_files ;
create table pdf_files(
     id serial primary key, 
     file_name text, 
     pdf_base64 text, 
     pdf_binary bytea
 );

Insert data file content into table in base64 format. File in base64 format can be converted online here or any other online tool http://www.motobit.com/util/base64-decoder-encoder.asp

insert into pdf_files(file_name, pdf_base64)
values('title.pdf',   'JVBERi0x.....................NjMKJSVFT0YK');

Now lets get binary field filled

update pdf_files set pdf_binary = decode(pdf_base64, 'base64');

I got this in database:

Table content

First i tried to implement soap service which will respond pdf. There is service I made:

<proxy xmlns="http://ws.apache.org/ns/synapse" name="Sample" startOnLoad="true" statistics="disable" trace="disable" transports="http,https">
    <target>
        <inSequence>
            <dblookup>
                <connection>
                    <pool>
                        <dsName>pgConn</dsName>
                    </pool>
                </connection>
                <statement>
                    <sql>select pdf_base64 from pdf_files where id = ?</sql>
                    <parameter xmlns:nb="http://mru" expression="//nb:id" type="INTEGER"/>
                    <result column="pdf_base64" name="pdf_base64"/>
                </statement>
            </dblookup>
            <payloadFactory media-type="xml">
                <format>
                    <ns:binary xmlns:ns="http://ws.apache.org/commons/ns/payload">$1</ns:binary>
                </format>
                <args>
                    <arg evaluator="xml" expression="get-property('pdf_base64')"/>
                </args>
            </payloadFactory>
            <loopback/>
        </inSequence>
        <outSequence>
            <script language="js">
            var binaryNode = mc.getEnvelope().getBody().getFirstElement().getFirstOMChild();  
            binaryNode.setBinary(true);
            </script>
            <property name="messageType" scope="axis2" type="STRING" value="application/pdf"/>
            <respond/>
        </outSequence>
    </target>
    <description/>
</proxy>

It accepts request with tag id which is refers to table id(primary key)

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:nb="http://mru">
    <soap:Body>
        <nb:id>1</nb:id>
    </soap:Body>
</soap:Envelope>

Let's make request using curl (I assume request is saved in file request.xml)

curl -v -X POST -H "Content-Type:text/xml" -d @./request.xml http://localhost:8280/services/Sample.SampleHttpSoap12Endpoint > title1.pdf

This what i got

Curl request to soap service

As you see after I can open pdf file returned by service.

Now same thing for API. It is actually easy and almost the same. Only need to configure url-template to catch parameter id for sql query.

 <api xmlns="http://ws.apache.org/ns/synapse" name="GetPdf" context="/pdf">
    <resource methods="GET" uri-template="/id/{fileId}">
      <inSequence>
         <property name="ID" expression="get-property('uri.var.fileId')"/>
         <dblookup>
            <connection><pool><dsName>pgConn</dsName></pool></connection>
            <statement>
               <sql>select pdf_base64 from pdf_files where id = ?</sql>
               <parameter expression="get-property('ID')" type="INTEGER"/>
               <result name="pdf_base64" column="pdf_base64"/>
            </statement>
         </dblookup>
         <payloadFactory media-type="xml">
            <format>
               <ns:binary xmlns:ns="http://ws.apache.org/commons/ns/payload">$1</ns:binary>
            </format>
            <args>
               <arg evaluator="xml" expression="get-property('pdf_base64')"/>
            </args>
         </payloadFactory>
         <loopback/>
      </inSequence>
      <outSequence>
         <script language="js">
             var binaryNode = mc.getEnvelope().getBody().getFirstElement().getFirstOMChild();     
             binaryNode.setBinary(true);
         </script>
         <property name="messageType" value="application/pdf" scope="axis2" type="STRING"/>
         <respond/>
      </outSequence>
   </resource>
</api>

This api will return PDF file using proper Content-Type header so browser will understand it.

Picture is underneath. Browser properly identify content, via content type header, and use builtin pdf renderer to display pdf file served by wsoesb server.

PDF File opened in browser

Upvotes: 4

Related Questions