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
>>
>>
>>
>