2012-04-24 5 views
0

Где-то внутри моей Wicket Link, которая вызывает Утилиту, которая обслуживает файл отчета, , сгенерированный BIRT, я получаю исключение IllegalStateException.Отправка файла BIRT через HttpServletResponse через Wicket Link, вызывает IllegalStateException

На странице калитки:

Link<Void> downloadLink = new Link<Void>("download") { 
    private static final long serialVersionUID = 1L; 

    @Override 
    public void onClick() { 

     HttpServletResponse response = 
       (HttpServletResponse)((WebResponse)getResponse()).getContainerResponse(); 
     ReportUtility.getInstance().serveFile("myFileName.rptdesign", "pdf", response, null); 

    } 

}; 
add (downloadLink); 

Из ReportUtility.java:

public void serveFile(String reportDesignFile, String extType, 
     HttpServletResponse response, Map<String, Object> paramMap) { 

    InputStream is = null; 
    ServletOutputStream os = null; 
    try { 
     is = ReportUtility.class.getResourceAsStream(reportDesignFile); 
     os = response.getOutputStream(); 

     IReportRunnable irr = engine.openReportDesign(is); 
     IRunAndRenderTask task = engine.createRunAndRenderTask(irr); 

     HTMLRenderOption options = new HTMLRenderOption(); 
     options.setOutputFormat(extType); 
     options.closeOutputStreamOnExit(true); 
     options.setOutputStream(os); 

     // to force open/save/cancel with our specified filename 
     String outputFileName = createReportFileName(reportDesignFile, extType); 
     response.addHeader("Content-Disposition", "attachment;filename=" + outputFileName); 

     if (paramMap != null) { 
      task.setParameterValues(paramMap); 
     } 
     task.setRenderOption(options);  
     task.run(); 

    } 
    catch (EngineException ex) { 
     logger.error("Engine Exception while serving file", ex); 
     throw new RuntimeException(ex); 
    } 
    catch (IOException ioex) { 
     logger.error("IO Exception while openning response output stream", ioex); 
     throw new RuntimeException(ioex); 
    } 

    finally { 
     try { 
      if (os != null) 
       os.close(); 
      if (is != null) 
       is.close(); 
     } catch (IOException e) { 
      // ignore 
     } 
    } 
} 

Если это имеет значение, метод createReportFileName добавляет текущую дату и правильное расширение файла на базовое имя из файл описания проекта, то есть «myFileName.rptdesign» становится «myFileName_04_24_2012.pdf»

Вот трассировка statck:

Apr 24, 2012 9:35:04 AM org.apache.catalina.core.StandardWrapperValve invoke 
    SEVERE: Servlet.service() for servlet default threw exception 
    java.lang.IllegalStateException 
at org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435) 
at org.apache.wicket.protocol.http.servlet.ServletWebResponse.sendRedirect(ServletWebResponse.java:230) 
at org.apache.wicket.protocol.http.BufferedWebResponse$SendRedirectAction.invoke(BufferedWebResponse.java:392) 
at org.apache.wicket.protocol.http.BufferedWebResponse.writeTo(BufferedWebResponse.java:580) 
at org.apache.wicket.protocol.http.HeaderBufferingWebResponse.flush(HeaderBufferingWebResponse.java:89) 
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:195) 
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:241) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:113) 
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) 
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) 
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:602) 
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) 
at java.lang.Thread.run(Unknown Source) 

Это важно отметить, что это не влияет на работу: пользователь щелкает, открытый/сохранения/отмены появляется, файл приходит, и выглядит очень красиво. Однако после опеки, независимо от того, что пользователь пытается сделать дальше, отправляет на страницу ошибок с ошибкой StalePageException. После этого все снова возвращается к норме.

Я подозреваю, что это связано с HttpServletResponse, или, может быть, как я получаю его от Wicket. Тем не менее, эта часть мой код, который добавляет файл в ответ с заголовком, копируется почти точно из учебников BIRT. (Возможно, BIRT и Wicket просто не любят друг друга.)

Отмечу, что ни один из моих собственных кодов не отображается в трассировке стека. Кроме того, я попытался «поймать» IllegalStateException в нескольких местах, в том числе onClick, serveFile и даже моем приложении Wicket, без успеха . Конечно, даже если бы я мог это поймать, я бы предпочел никогда не причинять этого в первую очередь.

ответ

0

Лучшим способом доставки отчета будет реализация собственного ресурсаStream (... реализует IResourceStream). Ваша реализация возвращает сгенерированный отчет при нажатии пользователем.

Вот несколько примеров, как добавить ссылку калитки, что потоки отчета клиента:

add(new Link("reportAsPdfButton") { 
    @Override 
    public void onClick() { 
     BirtReportResourceStream brrs = new BirtReportResourceStream(); 
     getRequestCycle().scheduleRequestHandlerAfterCurrent(new ResourceStreamRequestHandler(brrs, "your_report_name.pdf")); 
    } 
}); 

Вот короткий пример горячего реализовать IResourceStream:

public class BirtReportResourceStream implements IResourceStream { 
    private byte[] content = null; 

    ... 

    public BirtReportResourceStream() { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     EngineConfig config = new EngineConfig(); 
     config.setEngineHome(basePath + "/WEB-INF/ext_lib/"); 

     try { 
      Platform.startup(config); 
      IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); 
      IReportEngine engine = factory.createReportEngine(config); 
      IReportRunnable report = engine.openReportDesign("path/to/your/report-definiton.rpt"); 
      IRunAndRenderTask task = engine.createRunAndRenderTask(report); 

      if (null != getParameter()) { 
       task.setParameterValues(getParameter()); 
      } 

      PDFRenderOption options = new PDFRenderOption(); 
      options.setOutputFormat(format.toString().toLowerCase()); 
      options.setOutputStream(baos); 
      task.setRenderOption(options); 
      task.run(); 
      task.close(); 
     } catch (BirtException e) { 
      // handle the exception... 
     } 

     content = baos.toByteArray(); 
    } 

    public InputStream getInputStream() throws ResourceStreamNotFoundException { 
     return new ByteArrayInputStream(content); 
    } 

    ... 
} 

Есть некоторые больше методов для реализации, но они просты. Наиболее сложной задачей было выяснить, как создать отчет и передать его в массив байтов и как передать его клиенту. Эти два метода показаны выше.

Надеюсь, это поможет.