0

I have seen many examples on how to use StreamingOutput. In my case I want to use it to stream the ResultSet from a database query.

ResultSet rs = (ResultSet) obj;
StreamingOutput stream = new StreamingOutput() {
    @Override
    public void write(OutputStream os) throws IOException,
                                       WebApplicationException {
        ResultSetFormatter.outputAsJSON(os, rs);

        res.close();
    }
};

return Response.ok(stream).build();

In this sense write method definition includes a throws IOException, WebApplicationException. There is where my problem arise. I need to properly close the connection to the database, resultset, etc. And if an exception is thrown while executing the streaming I don't know how to capture it.

I have tried the following but it's not a valid code as IOException is not thrown from the try-catch block.

try {
    ....  launch request to database ...
    ResultSet rs = (ResultSet) obj;
    StreamingOutput stream = new StreamingOutput() {
        @Override
        public void write(OutputStream os) throws IOException,
                                           WebApplicationException {
            if (accept.equals("application/json") {
                ResultSetFormatter.outputAsJSON(os, rs);
            } else {
                ResultSetFormatter.outputAsXML(os, rs);
            }

            res.close();
        }
    };

    return Response.ok(stream).build();
} catch (IOException | WebApplicationException e) {
    // Do cleanup
}

How can I proceed? Is it possible to properly cleanup everything? I have think even on include all the data processing within the write method, but the problem is that then I cannot set the Content-type of the response if it is not fixed.

TIA

Edit 1: I'm using SPARQL sentences based on Jena and not SQL database. Depending on the type of query I get different type of responses (Model, Resultset or boolean). Then each one have different valid content types, so I cannot set the content type of the response until the query has been executed or analysed.

jlanza
  • 1,070
  • 2
  • 18
  • 36
  • What are you trying to accomplish here? What does this code run in? It looks like you're trying to replicate a lazy load of data. There are probably better ways to accomplish this. – LAROmega Sep 19 '17 at 18:02
  • I have a big resultset that otherwise I have to locally store in memory. I want to stream it directly to the client. The problem arise in case something happens, as I have to close the resultset, etc. to free the resources. I dont' undertand your lazy load of data. – jlanza Sep 19 '17 at 18:39
  • See this [thread](https://stackoverflow.com/questions/36274/what-is-lazy-loading) for an explanation of lazy loading – LAROmega Sep 19 '17 at 18:44
  • I don't think is lazy loading. As I told you I don't want to store the whole set of results in memory to create the string. I prefer to stream it directly. – jlanza Sep 19 '17 at 19:10
  • You appear to want to load the data when it's used instead of loading everything then passing the data to your web service's response, i.e. lazy loading. In any case, semantics aside, typically you want to have your service handle the database transaction on a per request basis. That will keep your results alive until they're consumed. It's difficult to get into specifics without knowing if you're using any frameworks or if this is a servlet or something else. – LAROmega Sep 19 '17 at 20:05
  • As I updated (edit 1) I'm using Jena for SPARQL. In this case the resultset values are retrieved on each iteration and therefore there is no need to store all in memory. – jlanza Sep 20 '17 at 08:58

2 Answers2

0

You could check out try-with-resources, it automatically closes it for you.

Before Java SE 7, the way to go was through finally. It executes regardless of the try exit point.

users at 4325010
  • 3,596
  • 4
  • 28
  • 46
  • I had that try-with-resources, but the problem is that the resulset is then close as the stream is something that is executed after the return, and then when the StreamingOutput write is called it complains that resultset is no longer valid. So this is not valid for me :( – jlanza Sep 19 '17 at 18:13
0

user8 was right, but didn’t provide the details. You want your try-with-resources statement inside your write method:

@Override
public void write(OutputStream os) throws IOException,
                                   WebApplicationException {

    try (Statement statement = rs.getStatement();
         Connection conn = statement.getConnection()) {

        if (accept.equals("application/json") {
            ResultSetFormatter.outputAsJSON(os, rs);
        } else {
            ResultSetFormatter.outputAsXML(os, rs);
        }
    }
}

Auto-closing the Statement will automatically close the ResultSet as well.

VGR
  • 33,718
  • 4
  • 37
  • 50
  • That's right, but the problem is that `accept` value is retrieved based on the type of response from the query. I'm using Sparql and not SQL, and I can get different type of responses (Model, Resultset or boolean). I have updated my question. – jlanza Sep 19 '17 at 19:26