Reputation: 539
I am working on client side of a RESTful service to let a user to download a file. I don't have access to server side code.
The client is under the Struts 2 and submits a POST request with some XML, and the server (under Spring) will generate a byte array representation of a zip file after processing that XML.
My problem is that, how to transfer the byte array as some InputStream
, which is required by Struts 2 for downloading.
The client is using Struts 2 and here is the configuration in struts.xml
for downloading a file:
<action name="getResponseMessage"
class="DownloadAction"
method="retrieveDownloadableMessage">
<interceptor-ref name="logger" />
<interceptor-ref name="defaultStack" />
<result name="success" type="stream">
<param name="contentType">application/octet-stream</param>
<param name="inputName">inputStream</param>
<param name="contentDisposition">attachment;filename="${bundleName}"</param>
<param name="bufferSize">1024</param>
</result>
</action>
and in the Java action class using Jersey (there are HTTP status check and appropriate getters for fields, that I omit for simplicity.):
public class DownloadAction extends ActionSupport {
private InputStream inputStream;
private String bundleName;
public String retrieveDownloadableMessage() throws IOException {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
URI restfulURI = getRestfulURI();
WebResource resource = client.resource(restfulURI);
inputStream = resource.accept(MediaType.APPLICATION_OCTET_STREAM).post(InputStream.class, someXML);
bundleName = "response.zip";
return SUCCESS;
}
}
The backbone of the REST server side code:
@POST
@Produces(MediaType.APPLICATION_OCTET_STREAM)
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response getPtrXml(Source source) throws IOException {
byte[] myByteArray = generateByteArr(source); // I cannot modify this method.
ByteArrayInputStream byteInputStream = new ByteArrayInputStream(myByteArray);
return Response.ok(byteInputStream, MediaType.APPLICATION_OCTET_STREAM).build();
}
Running the client side code I see the output in console like this. Seems there is nothing being sent out to the client. What could be the problem?
Streaming result [inputStream] type=[application/octet-stream] length=[0] content-disposition=[attachment;filename="${packagePtrName}"] charset=[null]
WLTC0017E: Resources rolled back due to setRollbackOnly() being called.
com.ibm.ws.webcontainer.webapp.WebApp logServletError SRVE0293E: [Servlet Error]-[ServletNameNotFound]: java.lang.IllegalStateException: Response already committed.
UPDATE:
Struts 2 silently saves the file to a temp
folder
I found if I used a File
object to accept the returned ByteArrayInputStream
, then Struts 2 somehow saves the file (exactly what I am looking for) to a local temp
folder without opening a download dialog box to users. Any idea how to dig it out?
File fileToDownload = resource.accept(MediaType.APPLICATION_OCTET_STREAM).post(File.class, someXML);
inputStream = new FileInputStream(fileToDownload);
Upvotes: 1
Views: 1680
Reputation: 1
You should check status code before you return the client response. Since you didn't do that you can't return an input stream until you read it.
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ response.getStatus());
}
You can get input stream from response
inputStream = response.getEntityInputStream();
if (inputStream != null) {
//read it to make sure the data is available
Also you didn't provide a public getter for bundleName
and you got ${bundleName}
filename.
Upvotes: 1