Error java.lang.IllegalStateException: Unable to obtain OutputStream because Writer is already in use

389 views Asked by At

I'm trying to download an Excel in a liferay portlet but when I'm going to get the outPutPortletStream I obtain the next exception:

java.lang.IllegalStateException: Unable to obtain OutputStream because Writer is already in use

This is the method I'm using to download the Excel:

public static void descargaFichero(ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws Exception {

        HttpServletRequest request = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(resourceRequest));
        OutputStreamWriter osWriter = null;
        BufferedWriter bWriter = null;
        OutputStream outputStream = null;
        InputStream is = null;
        InputStreamReader isr = null;
        File tempFile = null;
        
        try {
            String idDescarga = request.getParameter("id-descarga");
            String rutaFicheroDescarga = Encriptador.decrypt(ConstantesFlujos.CLAVE_ENCRIPTADO_JSON, idDescarga);
            
            String extension = FileUtil.getExtension(rutaFicheroDescarga);
            String nombreArchivo = String.format("%s%s.%s", 
                    ConstantesFlujos.PREFIJO_NOMBRE_FICHERO_RENOVACION,
                    fechaDesglosada(),
                    extension);
            
            if(GestorLog.isInfoEnabled(clase)){
                GestorLog.info(clase, String.format("Descargando fichero temporal: '%s' a '%s'", rutaFicheroDescarga, nombreArchivo));
            }
            
            if (extension.equalsIgnoreCase("xls")) {
                resourceResponse.setContentType("application/vnd.ms-excel");
                
            } else {
                resourceResponse.setContentType("application/octet-stream");
            }
            
            ((PortletResponse) resourceResponse).addProperty("Content-disposition", String.format("atachment; filename=%s", nombreArchivo));
            
            tempFile = new File(rutaFicheroDescarga);
            
            outputStream = resourceResponse.getPortletOutputStream();
            osWriter = new OutputStreamWriter(outputStream, "ISO-8859-1");
            
            char[] buf = new char[8192];
            is = new FileInputStream(tempFile);
            isr = new InputStreamReader(is, "ISO-8859-1");
            int c = 0;
            
            while ((c = isr.read(buf, 0, buf.length)) > 0) {
                osWriter.write(buf, 0, c);
                osWriter.flush();
            }
            
        } catch(Exception e){
            GestorLog.error(clase, "Error en el metodo descargaFichero: " + e.getMessage());
            throw e;
            
        } finally {
            if (isr != null) {
                isr.close();
            }
            if (is != null) {
                is.close();
            }
            if (bWriter != null) {
                bWriter.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (tempFile != null) {
                tempFile.delete();
            }
        }
    }

And I get the error in the line:

outputStream = resourceResponse.getPortletOutputStream();

1

There are 1 answers

0
Olaf Kock On

This might be due to resourceResponse.addProperty being called before accessing the stream. Those operations can be nasty, as two parties will now try to write data to the output.

An easy way to omit all problems is to just delegate it all to the portal: PortletResponseUtil.sendFile exists in a couple of different variations, e.g.

PortletResponseUtil.sendFile(
      resourceRequest,
      resourceResponse,
      fileName,
      inputStream,
      contentLength,
      contentType,
      contentDispositionType); // e.g. HttpHeaders.CONTENT_DISPOSITION_ATTACHMENT