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>
* @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();
}
}