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?