AnsweredAssumed Answered

Webscript to export nodes to Excel: cannot call getWriter() after getOutputStream()

Question asked by sorin_postelnicu on Apr 26, 2016
Latest reply on Jan 19, 2018 by sorin_postelnicu
Hello everybody,

I have created a Spring Surf presentation webscript that queries the Alfresco repository for some list of nodes, and then exports a selection of node properties to an Excel file, to be downloaded by the user.
The Excel is generated on-the-fly, without being saved to the repository, and it is being streamed directly to the browser.

I have used the following XML webscript description:

<webscript>
  <shortname>ElasticSearch search and export as Excel</shortname>
  <description>ElasticSearch search and export as Excel</description>
  <url>/es/exportexcel</url>
  <authentication>none</authentication>
  <format default=""></format>
</webscript>

and the webscript looks like this:


public class PublicSearchExportExcelWebScript extends AbstractWebScript {
   @Override
   public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException {
      res.setContentType("application/vnd.ms-excel");
      res.setHeader("Content-Disposition", "attachment; filename=\"export.xls\"");
      Workbook wb = new HSSFWorkbook();
      //….. build Excel
      OutputStream contentOutputStream = res.getOutputStream();
      wb.write(contentOutputStream);
   }
}

But whenever I try to download the Excel file by using this webscript, I get this error in the logs (even if the file is downloaded successfully):


ERROR [org.springframework.extensions.webscripts.AbstractRuntime] Exception from executeScript - redirecting to status template error: strict servlet API: cannot call getWriter() after getOutputStream()
java.lang.IllegalStateException: strict servlet API: cannot call getWriter() after getOutputStream()
        at weblogic.servlet.internal.ServletResponseImpl.getWriter(ServletResponseImpl.java:324)
        at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:148)
        at org.springframework.extensions.webscripts.servlet.WebScriptServletResponse.getWriter(WebScriptServletResponse.java:198)
        at org.springframework.extensions.webscripts.LocalWebScriptRuntimeContainer.executeScript(LocalWebScriptRuntimeContainer.java:241)
        at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:377)
        at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:209)
        at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:104)
        at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1060)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:798)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:844)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
        at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
        at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:341)
        at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:238)
        at weblogic.servlet.internal.RequestDispatcherImpl.invokeServlet(RequestDispatcherImpl.java:573)
        at weblogic.servlet.internal.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:272)
        at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
        at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
        at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
        at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
        at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
        at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3367)
        at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3333)
        at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
        at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
        at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
        at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2220)
        at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2146)
        at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2124)
        at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1564)
        at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:254)
        at weblogic.work.ExecuteThread.execute(ExecuteThread.java:295)
        at weblogic.work.ExecuteThread.run(ExecuteThread.java:254)


ERROR org.springframework.extensions.webscripts.WebScriptException: 03260002 Internal error
        at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:335)
        at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:104)
        at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
        at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1060)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:798)
        Truncated. see log file for complete stacktrace
Caused By: java.lang.IllegalStateException: strict servlet API: cannot call getWriter() after getOutputStream()
        at weblogic.servlet.internal.ServletResponseImpl.getWriter(ServletResponseImpl.java:324)
        at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:148)
        at org.springframework.extensions.webscripts.servlet.WebScriptServletResponse.getWriter(WebScriptServletResponse.java:198)
        at org.springframework.extensions.webscripts.AbstractRuntime.executeScript(AbstractRuntime.java:330)
        at org.springframework.extensions.webscripts.servlet.mvc.WebScriptView.renderMergedOutputModel(WebScriptView.java:104)
        Truncated. see log file for complete stacktrace

I investigated a bit inside the Spring Surf sources, and I identified that the error occurs at the following lines inside LocalWebScriptRuntimeContainer:


        // call through to the parent container to perform the WebScript processing
        ExtensibilityModel extModel = openExtensibilityModel();
        super.executeScript(scriptReq, scriptRes, auth);
        closeExtensibilityModel(extModel, scriptRes.getWriter());

and then again inside AbstractRuntime when trying to redirect to the error status template:


        String validTemplatePath = container.getTemplateProcessorRegistry().findValidTemplatePath(statusTemplate.getPath());               
        TemplateProcessor statusProcessor = container.getTemplateProcessorRegistry().getTemplateProcessor(validTemplatePath);
        statusProcessor.process(validTemplatePath, statusModel, res.getWriter());

Is there a way for me to suppress the calling of getWriter after I have generated the binary content and streamed it to the response output stream?

Outcomes