users@jersey.java.net

Jersey performance

From: Kaspar Fischer <hbf_at_rapsak.com>
Date: Sat, 27 Jun 2009 19:52:27 +0200

Dear list,

Is it correct that Jersey uses whatever connection infrastructure the
servlet container provides? For instance, if I use Jetty with a NIO
connector, then Jersey will use this? I suppose the answer is yes but
I prefer to be on the safe side as I am completely new to Jersey...

Here's the actual code I am using; it's a very simple REST service to
allow a user to download a movie:

   @Path("/movie/media/retrieve/{id: [0-9]+}")
   @Singleton
   public static class MovieMediaRetrieveResource
   {
     @Context
     Request request;

     @Inject("movieService")
     private MovieService movieService;

     @GET
     @Produces("video/*")
     public Response downloadMedia(@PathParam("id") int mediaId)
throws IOException
     {
       // Fetch media and check existence
       final Media media = movieService.getMedia(mediaId);
       if (media == null)
       {
         throw new NotFoundException();
       }

       // Cache forever, as media files do not change
       CacheControl cacheControl = new CacheControl();
       cacheControl.setMaxAge(12 * 30 * 24 * 3600);
       cacheControl.setSMaxAge(12 * 30 * 24 * 3600);
       cacheControl.setMustRevalidate(false);

       final MediaCharacteristics characteristics =
media.getCharacteristics();
       return JerseyUtils.newStreamingResponse(request, new
DefaultStreamableResource(characteristics.getFileSize(),
           characteristics.getMimetype(), media.getLastModified())
       {
         public InputStream getStream() throws IOException
         {
           return media.getContentStream();
         }
       }, cacheControl);
     }
   }

Thanks,
Kaspar

--
/**
  * A resource for streaming in Jersey that has a last-modified time,  
a content length, and a
  * mime-type.
  */
public interface StreamableResource
{
   /**
    * Size of the resource.
    *
    * @return size in bytes of the content returned by {_at_link  
#getStream()}
    */
   public long getSize();
   /**
    * Mime-type of the resource.
    *
    * @return mime-type
    */
   public String getMimetype();
   /**
    * Returns the last-modified date.
    *
    * @return date of last modification of the resource, used for  
caching
    */
   public Date getLastModified();
   /**
    * Returns the stream whose content needs to be streamed.
    *
    * @return stream; will be closed automatically
    * @throws IOException
    */
   public InputStream getStream() throws IOException;
}
public class JerseyUtils
{
   /**
    * Checks using the given last-modified timestamp whether the given  
resource needs to be
    * transferred at all and if not, returns an appropriate response;  
if the resource needs to be
    * transferred, an appropriate {_at_link StreamableResourceProvider}  
instance is created and wrapped
    * in a response.
    *
    * @param request
    *          request;use
    *
    *          <pre>
    * &#064;Context
    * Request request;
    * </pre>
    *
    *          in your class to inject the request
    * @param resource
    *          the resource to stream
    * @param cacheControl
    *          caching strategy
    * @return a response suitable for returning from your REST method
    * @throws IOException
    */
   public static Response newStreamingResponse(Request request,  
StreamableResource resource, CacheControl cacheControl)
       throws IOException
   {
     final Date lastModified = resource.getLastModified();
     ResponseBuilder cachedResponse =  
request.evaluatePreconditions(lastModified);
     if (cachedResponse != null)
     {
       return cachedResponse.build();
     }
     // Return an object that streams the data
     return Response.ok(resource,  
resource 
.getMimetype 
()).lastModified(lastModified).cacheControl(cacheControl).build();
   }
}
/**
  * A class similar to {_at_link StreamingOutput} but providing to the  
client with the length of the
  * stream's data.
  *
  * @author Kaspar Fischer (hbf)
  */
@Provider
public class StreamableResourceProvider implements  
MessageBodyWriter<StreamableResource>
{
   public boolean isWriteable(Class<?> type, Type genericType,  
Annotation[] annotations, MediaType mediaType)
   {
     return StreamableResource.class.isAssignableFrom(type);
   }
   public void writeTo(StreamableResource t, Class<?> type, Type  
genericType, Annotation annotations[],
       MediaType mediaType, MultivaluedMap<String, Object>  
httpHeaders, OutputStream entityStream) throws IOException
   {
     final InputStream stream = t.getStream();
     try
     {
       IOUtils.copy(stream, entityStream);
     }
     finally
     {
       stream.close();
     }
   }
   public long getSize(StreamableResource t, Class<?> type, Type  
genericType, Annotation[] annotations,
       MediaType mediaType)
   {
     return t.getSize();
   }
}