In the end I went for the following - I simply returned the File object:
@GET
@Path("user/{userId}/artifacts/{artifactId}/content")
@Produces("application/*")
public File getArtifactBinaryContent(@PathParam("userId") long userId
, @PathParam("artifactId") long
artifactId
)
throws Exception {
File f = null;
try {
// Get an internal representation of an artifact
InternalArtifact ia = dA.getInternalArtifact(0, userId,
artifactId);
// Get the file from disk
f = new File(ia.getLink());
}
catch (Exception e) {
e.printStackTrace();
}
return f;
}
I am not sure that this particularly performant though as I suspect it will
put the whole file into memory and return the file content in one bang -
instead of streaming.
Anyone have any better thoughts for serving a file via Jersey?
Thanks
James
On Fri, Apr 24, 2009 at 10:42 AM, James Allchin <james_at_knowledgemill.com>wrote:
> OK - I suspect it is something to do with a VOID method instead of
> returning a type...
>
> How do I overcome this if I wish to serve via HttpServletResponse?
>
>
>
> On Fri, Apr 24, 2009 at 10:09 AM, James Allchin <james_at_knowledgemill.com>wrote:
>
>> Hi All,
>>
>> Thanks to everyone who keeps answering my questions on the forum. The
>> support is excellent.
>>
>> My current question is how to serve binary content i.e. a file out through
>> my RESTful services.
>>
>> I have managed to accept a file through my REST implementation with the
>> following method (it uses apache.commons upload) which is a nice combo in my
>> view (particularly streaming capabilities).
>>
>> @POST
>> @Path("user/{userId}/artifacts/{artifactId}/content")
>> @Consumes("multipart/form-data")
>> //_at_Consumes("multipart/mixed")
>> public void setArtifactBinaryContent(@PathParam("userId") long userId
>> , @PathParam("artifactId") long
>> artifactId
>> , @javax.ws.rs.core.Context
>> HttpServletRequest request)
>> throws Exception {
>> // First write the file to disk
>> FileItemFactory factory = new DiskFileItemFactory();
>> ServletFileUpload upload = new ServletFileUpload(factory);
>> List items = null;
>> try {
>> items = upload.parseRequest(request);
>> Iterator iter = items.iterator();
>> while (iter.hasNext()) {
>> FileItem item = (FileItem)iter.next();
>> if (!item.isFormField()) {
>> File fileLocator = new File("/fileshare/filedata/"
>> + artifactId + ".dat");
>> item.write(fileLocator);
>> }
>> }
>> // Assuming success we now update the link and set to
>> enabled
>> dA.updateArtifactLink(0, userId, artifactId,
>> "/fileshare/filedata/" + artifactId + ".dat");
>> dA.updateArtifactEnabled(0, userId, artifactId, true);
>> }
>> catch (Exception e) {
>> e.printStackTrace();
>> }
>>
>> }
>>
>> This works a treat... The problem I am having is now serving the file. I
>> am trying the following:
>>
>> @GET
>> @Path("user/{userId}/artifacts/{artifactId}/content")
>> @Produces("application/octet-stream")
>> public void getArtifactBinaryContent(@PathParam("userId") long userId
>> , @PathParam("artifactId") long
>> artifactId
>> , @javax.ws.rs.core.Context
>> HttpServletResponse response)
>> throws Exception {
>> try {
>> // Get an internal representation of an artifact
>> InternalArtifact ia = dA.getInternalArtifact(0, userId,
>> artifactId);
>>
>> // Get the file from disk
>> File f = new File(ia.getLink());
>> int fLength = (int)f.length();
>>
>> // Set the response header header
>> response.setContentType("application/octet-stream");
>> response.setContentLength(fLength);
>> response.setHeader( "Content-Disposition", "attachment;
>> filename=\"" + artifactId + "\"" );
>> ServletOutputStream sos = response.getOutputStream();
>>
>> // Output the file stream
>> byte[] bbuf = new byte[100];
>> DataInputStream in = new DataInputStream(new
>> FileInputStream(f));
>> int length = 0;
>> while ((in != null) && ((length = in.read(bbuf)) != -1))
>> {
>> sos.write(bbuf,0,length);
>> }
>> in.close();
>> sos.flush();
>> sos.close();
>> }
>> catch (Exception e) {
>> e.printStackTrace();
>> }
>> }
>>
>> When deploying it moans with the following error:
>>
>> SEVERE: Servlet /ACMERest threw load() exception
>> com.sun.jersey.api.container.ContainerException: Method, public void
>> com.acme.rest.MainService.getArtifactBinaryContent(long,long,javax.servlet.http.HttpServletResponse)
>> throws java.lang.Exception, annotated with GET of resource, class
>> com.acme.rest.MainService, is not recognized as valid Java method annotated
>> with @HttpMethod.
>>
>> Does anyone know what the issue is here. Is it incorrect to be using
>> @Context to access the HttpServletResponse object?
>>
>> Is there another way to serve a file perhaps?
>>
>> Thanks,
>>
>> James
>>
>>
>>
>