2016-02-12 2 views
3

Je rencontre des problèmes avec ma ressource Restlet. Il utilise TrueZip pour construire un sous-ensemble d'une archive Zip et permet à l'utilisateur de le télécharger.Restlet - StreamClosedException utilisant StreamingOutput

// Create a Streaming Response Entity. 
    final StreamingOutput stream = new StreamingOutput() { 
     @Override 
     public void write(final OutputStream output) { 
       ZipBrowser.extract(source, path, output); 
     } 
    }; 
    LOGGER.debug("Download of Path {} with the length {} initiated", path, length); 
    ResponseBuilder rb = Response.ok(stream); 
    rb.header(HeaderConstants.HEADER_CONTENT_DISPOSITION, CONDISPOVALUE + fileName); 
    rb.header(HeaderConstants.HEADER_CONTENT_LENGTH, length); 
    return rb.build(); 

Même si cela fonctionne, je reçois une exception StreamClosedException ennuyante. Cette erreur apparaît uniquement lorsque je tente de télécharger un sous-ensemble et non l'ensemble archive Zip:

An exception occured writing the responseentity 

    sun.net.httpserver.StreamClosedException 
    at sun.net.httpserver.ChunkedOutputStream.flush(ChunkedOutputStream.java:156) 
    at sun.net.httpserver.PlaceholderOutputStream.flush(ExchangeImpl.java:449) 
    at org.restlet.engine.adapter.ServerCall.writeResponseBody(ServerCall.java:511) 
    at org.restlet.engine.adapter.ServerCall.sendResponse(ServerCall.java:454) 
    at org.restlet.engine.adapter.ServerAdapter.commit(ServerAdapter.java:187) 
    at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:144) 
    at org.restlet.engine.connector.HttpServerHelper$1.handle(HttpServerHelper.java:64) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) 
    at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80) 
    at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:677) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) 
    at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:649) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745)Unable to send error response 

    java.io.IOException: headers already sent 

    at sun.net.httpserver.ExchangeImpl.sendResponseHeaders(ExchangeImpl.java:204) 
    at sun.net.httpserver.HttpExchangeImpl.sendResponseHeaders(HttpExchangeImpl.java:86) 
    at org.restlet.engine.connector.HttpExchangeCall.writeResponseHead(HttpExchangeCall.java:148) 
    at org.restlet.engine.adapter.ServerCall.sendResponse(ServerCall.java:450) 
    at org.restlet.engine.adapter.ServerAdapter.commit(ServerAdapter.java:205) 
    at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:144) 
    at org.restlet.engine.connector.HttpServerHelper$1.handle(HttpServerHelper.java:64) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) 
    at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80) 
    at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:677) 
    at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77) 
    at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:649) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

Répondre

2

Ceci est dû à la fois la bibliothèque zip et le cadre Restlet essayant de fermer la OutputStream une fois qu'ils ont terminé.

Je l'ai expérimenté dans le passé avec d'autres bibliothèques et j'ai réussi à éliminer l'exception en enveloppant le OutputStream que je passe à la bibliothèque zip dans une classe qui remplace close() pour ne rien faire. Avec toutes les autres méthodes déléguées. Cela permet ensuite à Restlet de fermer le flux.

Alors que la ligne d'appeler l'utilitaire Zip dans votre code devient:

ZipBrowser.extract(source, path, new WrappedOutputStream(output)); 

Lorsque la classe WrappedOutputStream est indiquée ci-dessous (déléguant les méthodes devront être ajoutées).

import java.io.IOException; 
import java.io.OutputStream; 

public class WrappedOutputStream extends OutputStream { 

    private final OutputStream delegate; 

    public WrappedOutputStream(final OutputStream delegate) { 
     this.delegate = delegate; 
    } 

    public void close() throws IOException { 
     // Do Nothing to allow Restlet to close the underlying stream 
    } 

    // TODO Delegate other Outpt Stream methods. 
} 
+1

Bonne idée! Juste essayé et fonctionne. Merci beaucoup :-) – user1291536