users@jersey.java.net

Re: [Jersey] returning an output stream

From: Witold Szczerba <pljosh.mail_at_gmail.com>
Date: Sun, 12 Oct 2008 15:10:42 +0200

Hi there,
you should have read JSR-311 specification [1].
Your resource classes can return javax.ws.rs.core.StreamingOutput
object like this:

@Path("/something")
public class SomethingResource {

    @GET
    @ProduceMime("application/xml")
    public StreamingOutput getResource(...) {
       // just create StreamingOutput and return it...
}

There is MessageBodyWriter, but StreamingOutput is more simple (but
less powerful).

StreamingOutput has method:
 void write(OutputStream outStream) throws IOException
so you do not care about outputStream - it is there for you, just push
your data into that object and it will go straight to your client.

I was testing it long time ago, there was an issue [2]:
1) client asks for data, which is huge
2) server returns StreamingOutput and stream starts
3) client receives data but decides to abandon and kill the process
4) server keeps sending data, there is no one reading it
5) in worst scenario there is OutOfMemory exception as something had
buferred unreceived data...

I hope this issue does not exist anymore.

[1] http://jcp.org/en/jsr/detail?id=311
Both documents are helpful:
JSR-000311 JAX-RS: the Java API For RESTful Web Services 1.0 FR specification
JSR-000311 JAX-RS: the Java API For RESTful Web Services 1.0 FR javadoc

[2] Jeresy issue #71:
StreamingOutput keeps writing even though connection/client is lost:
https://jersey.dev.java.net/issues/show_bug.cgi?id=71

Regards,
Witold Szczerba

2008/10/12 alex hendry <al_hendry_at_yahoo.com.au>:
> Hi all,
>
> Thanks to the quick replies to my questions so far, it has been much appreciated as I get my head around jersey.
>
> I work for the Australian institute of marine science and I am creating some web services that return weather station data as XML from our weather stations on the Great Barrier Reef.
>
> However as the XML files may be hundreds of mb or even gb I want to return the XML as an output stream. How much XML is returned will depend upon what time period is passed in the URL. So far I have done as follows:
>
> @Path("{dataPeriod}")
> @Provider
> public class XmlExport implements MessageBodyWriter {
>
> @GET
> public Response getXml(@PathParam("dataPeriod")String dataPeriod) {
>
> String fileName = "";
>
> if (dataPeriod.equalsIgnoreCase("latest")) {
> fileName = "latest.xml";
> } else if (dataPeriod.equalsIgnoreCase("last2hrs")) {
> fileName = "last2hrs.xml";
> } else if (dataPeriod.equalsIgnoreCase("last48hrs")) {
> fileName = "last48hrs.xml";
> } else if (dataPeriod.equalsIgnoreCase("lastWeek")) {
> fileName = "lastWeek.xml";
> } else if (dataPeriod.equalsIgnoreCase("lastMonth")) {
> fileName = "lastMonth.xml";
> }
> OutputStream outputStream = new ByteArrayOutputStream();
>
> try {
> writeTo(null, null, null, null, null, null, outputStream);
> } catch (IOException e) {
> e.printStackTrace();
> }
>
> return Response.ok(outputStream).type("application/xml").header("Content-Disposition", "attachment; filename=" + fileName).build();
>
> }
>
> public void writeTo(Object o, Class aClass, Type type, Annotation[] annotations, MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream) throws IOException, WebApplicationException {
>
> XMLOutputFactory xof = XMLOutputFactory.newInstance();
> XMLStreamWriter xtw = null;
> try {
> xtw = xof.createXMLStreamWriter(outputStream);
> } catch (XMLStreamException e) {
> e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
> }
> LastWeekViewDao lastWeekViewDao = new LastWeekViewDao();
> Collection<LastWeekViewEntity> lastWeekViewEntities = lastWeekViewDao.selectAll();
> SitesEntityManagedBean sitesEntityManagedBean = new SitesEntityManagedBean();
> List<SitesEntity> sites = sitesEntityManagedBean.getEntities();
>
> XmlOutputHandler handler;
> handler = new XmlOutput();
>
> handler.writeHeader(xtw);
>
> handler.writeBody(xtw, lastWeekViewEntities, sites);
>
> handler.writeFooter(xtw);
>
> try {
>
> if (xtw != null) {
> xtw.flush();
> }
> if (xtw != null) {
> xtw.close();
> }
>
> if (outputStream != null) {
> outputStream.flush();
> }
> if (outputStream != null) {
> outputStream.close();
> }
> } catch (XMLStreamException e) {
> e.printStackTrace();
> }
>
> }
>
>
> I have read in the mailing list that you can not return an output stream, only an input stream and I get an error from my code as follows:
>
> 12/10/2008 13:06:27 com.sun.jersey.spi.container.ContainerResponse write
> SEVERE: A message body reader for Java type, class java.io.ByteArrayOutputStream, and MIME media type, application/xml, was not found
>
> I can return the outputStream.toString() or create a file etc but I need to minimize my memory over head due to the file sizes.
>
> How can I return an output stream?
>
> Cheers,
>
> Alex
>
>
>
> Make the switch to the world's best email. Get Yahoo!7 Mail! http://au.yahoo.com/y7mail
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>
>