On Apr 24, 2009, at 12:42 PM, James Allchin wrote:
> 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();
If you want the method to fail you should re-throw, or declare "throws
Exception" and you do not require the try/catch, or throw a
WebApplication exception.
>
> }
> 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.
>
Jersey will stream it, and also add the Content-Length header.
Paul.
> 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
>
>
>
>