Sending a BIRT file via HttpServletResponse through a Wicket Link, causes IllegalStateException - httpresponse

Somewhere within my Wicket Link, that calls a Utility, which serves a report file,
generated by BIRT, I am getting an IllegalStateException.
From the Wicket page:
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);
From the 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
}
}
}
If it matters, the createReportFileName method appends today's date and the proper file extension to
the basename of the report design file, i.e. "myFileName.rptdesign" becomes "myFileName_04_24_2012.pdf"
Here is the statck trace:
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)
It is important to state that this does not effect the operation: the user clicks, the open/save/cancel appears,
the file comes, and looks very pretty. After ward, however, whatever the user tries to do next, sends to
our error page with a StalePageException. After that, everything returns to normal again.
I suspect this involves the HttpServletResponse, or perhaps how I am getting it from Wicket. However, that portion of
my code that adds the file to the response with the header is copied almost exactly from BIRT's tutorials. (Maybe BIRT and Wicket
just don't like each other.)
I note that none of my own code shows in the stack trace. Also, I have tried to "catch" the IllegalStateException in
a handful of places, including the onClick, the serveFile, and even my Wicket Application, all without
success. Of course, even if I could catch it, I would prefer to have never caused it in the first place.

A better way to deliver the report will be to implement your own ResourceStream (...implements IResourceStream). Your implementation returns the generated report when the user click.
Here is some example how to add a wicket link that streams the report to the client:
add(new Link("reportAsPdfButton") {
#Override
public void onClick() {
BirtReportResourceStream brrs = new BirtReportResourceStream();
getRequestCycle().scheduleRequestHandlerAfterCurrent(new ResourceStreamRequestHandler(brrs, "your_report_name.pdf"));
}
});
Here is a short sample hot to implement the 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);
}
...
}
There are some more methods to implement but they are simple. The most complex part was to find out how to create the report and stream it into an byte array and how to stream it to the client. These two methods are shown above.
Hope it helps.

Related

Java 8 how to read file twice and fix java.io.IOException: Stream closed

I am trying to read a text file twice in order to calculate an average (calcAverage) and then to filter on the average to get a results list (processFile). When the second step is run the exception,
java.io.UncheckedIOException: java.io.IOException: Stream closed
is thrown.
Below is a simplified version of my failing code and a unit-test to drive the code.
A parameter (source) of type Reader is passed into App from a unit test and is a FileReader to a text file. I dont know how to access the File handler (or filename) from the Reader object to re-open it - I've tried implementing this inside App and this would fix the problem. The method signature of runProcess (Reader source) can not be changed - the other method signatures however can be.
I am using a try-with-resources block to open the Reader object and to read it through - its then closed automatically - which is all fine. I just need a way to re-open the file from the Reader to perform the filtering for pass-2.
I have read from similar questions, that the BufferedReader is like an iterator and you can only read it once.
I have tried using the mark() and reset() methods on my source object, but this throws an exception that these aren't supported.
I could read the whole file into a List object and then use this to calculate both steps but I dont know how large my file is going to be and so if possible would like to try and find a solution using the approach below.
Does anyone know how I can implement this ?
public class App {
public static void runProcess(Reader source) {
Collection<?> col = calcAverage(source);
processFile(source).forEach(x -> System.out.println(x));
}
private static Collection processFile(Reader source) {
Collection<?> col = processFile(source, ((BufferedReader reader) -> reader.lines()
.skip(1)
.collect(Collectors.toList()))
);
return col;
}
private static Collection<?> calcAverage(Reader source) {
Collection<?> col = processFile(source, ((BufferedReader reader) -> reader.lines()
.skip(1)
.collect(Collectors.toList())));
return col;
}
private static Collection<?> processFile(Reader source, BufferedReaderProcessor p){
try (BufferedReader reader = new BufferedReader(source)) {
return p.process(reader);
}catch (FileNotFoundException f){
f.printStackTrace();
return null;
}catch (IOException e){
e.printStackTrace();
return null;
}catch (Exception ex){
ex.printStackTrace();
return null;
}
}
#FunctionalInterface
public interface BufferedReaderProcessor {
Collection<?> process(BufferedReader b) throws IOException;
}
}
public class AppTest {
#Test
public void shouldReadFileTwice() throws FileNotFoundException {
App.runProcess(openFile("src/main/java/functions/example4/resources/list-of-fruits"));
}
private static Reader openFile(String filename) throws FileNotFoundException {
return new FileReader(new File(filename));
}
}
I believe you shouldn't use try with resources. It calls close on its BufferedReader which causes all the incapsulated readers to be closed.
I.e. it closes BufferedReader, Reader and FileReader.
When you invoke calcAverage in App::runProcess it closes all the readers. Then you're trying to read closed Reader when calling processFile on the next line.

Generated PDF not send in the browser

I build a PDF document with iText library, and i want to get this document by clicking a link in the webapp.
But, it happens... nothing. No error message, no exception, really nothing.
I really don't master IO Streaming, so I think I made a mistake on this point, but after few hours of research, I don't know and I need a bit of help.
I have two methods. The first is the one to create pdf doc.
public void exporterPDF(SomeObjectIWillUse o) {
Document documentPDF = new Document(PageSize.A4);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(documentPDF, baos);
documentPDF.open();
documentPDF.addTitle("Test ! ");
Paragraph par = new Paragraph("Liste des participants");
documentPDF.add(par)
documentPDF.close();
telechargerPdfViaVue(FacesContext.getCurrentInstance(), baos, "filename.pdf");
} catch (Exception e) {
// TODO Auto-generated catch block
JsfUtils.addMessageByCode(FacesMessage.SEVERITY_FATAL, "drc.export.generation.pdf.erreur");
}
}
And the second is use to send the document.
public static final void telechargerPdfViaVue(FacesContext context, ByteArrayOutputStream baos, String fileName) throws IOException, DocumentException {
ExternalContext externalContext = context.getExternalContext();
externalContext.setResponseContentType("application/pdf");
externalContext.setResponseHeader("Expires", "0");
externalContext.setResponseHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
externalContext.setResponseHeader("Pragma", "public");
externalContext.setResponseHeader("Content-disposition", "attachment;filename=" + fileName);
externalContext.setResponseContentLength(baos.size());
OutputStream out = externalContext.getResponseOutputStream();
baos.writeTo(out);
externalContext.responseFlushBuffer();
context.responseComplete();
}
and it's called on my web page by a simple commandeLink
<p:commandLink id="exportPdf" action="#{myBean.exporterPDF(o)}">
Literally, in debug mode, all is done, but nothing happen...
Thank you for your help!
More informations, I use :
- JSF 2.2.7
- Spring 4.0.6

How to download data from url?

I can download data via HttpUrlConnection and InputStream but I need to download raw-data. So, i want to create a DownloadManager via raw-data, then using raw-data I convert this data to binary or image format. According to my research, I see "download file from url" but I can't download file in mac? Always, I get FileNotFoundException. Please help me. How I can download data from url?
public class DownloadData extends AsyncTask<Void,Void,Void> {
#Override
protected Void doInBackground(Void... params) {
try {
downloadData("https://blablalabla/get");
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void downloadData(String myurl) throws IOException {
URL u = new URL(myurl);
InputStream is = u.openStream();
DataInputStream dis = new DataInputStream(is);
byte[] buffer = new byte[1024];
int length;
OutputStream fos = new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/Users/ilknurpc/Desktop/text.docx"));
while ((length = dis.read(buffer))>0) {
fos.write(buffer, 0, length);
}
}
}
If you want to construct a workable download manager, I would suggest that you take a look at the
Tomcat Default Servlet Implementation
.
There a few number of HTTP headers that you need to understand such as E-Tags and Http Range Headers for a proper implementation.
Thankfully the Tomcat Default Servlet handles the prerequisites for you.
You can adapt this servlet in your code with minor changes (package declaration etc).

Exception in thread "main" java.lang.IllegalArgumentException: Unable to find StyleMasterPage name

I'm developing an app that processes files in ODS format.The code snippet is as follows:
public static void main(String[] args) throws IOException {
// Set the platform L&F.
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
display();
//print();
}
private static void display() throws IOException {
// Load the spreadsheet.
final OpenDocument doc = new OpenDocument();
doc.loadFrom("temperature3.ods");
String styleName = "Calibri";
StyleHeader header = new StyleHeader();
header.setStyleDisplay("Testing");
StyleMasterPage page = new StyleMasterPage();
page.setStyleHeader(header);
page.setStyleName(styleName);
OfficeMasterStyles off = new OfficeMasterStyles();
off.addMasterPage(off.getMasterPageFromStyleName(styleName));
doc.setMasterStyles(off);
// Show time !
final JFrame mainFrame = new JFrame("Viewer");
DefaultDocumentPrinter printer = new DefaultDocumentPrinter();
ODSViewerPanel viewerPanel = new ODSViewerPanel(doc, true);
mainFrame.setContentPane(viewerPanel);
mainFrame.pack();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setLocation(10, 10);
mainFrame.setVisible(true);
}
I intend loading the file into a jcomponent for easy manipulation but I'm having this error message in the netbeans console:
Exception in thread "main" java.lang.IllegalArgumentException: Unable to find StyleMasterPage named:Calibri
at org.jopendocument.model.office.OfficeMasterStyles.getMasterPageFromStyleName(Unknown Source)
at starzsmarine1.PrintSpreadSheet.display(PrintSpreadSheet.java:60)
at starzsmarine1.PrintSpreadSheet.main(PrintSpreadSheet.java:45)
Is there an alternative API for this purpose?

GWT FormPanel onSubmitComplete event not firing when downloading a file

I created servlet to download file from a server. In GWT I created a FormPanel and I am able to download a file.
Problem is, that I want to fire an event, when the file is ready. I tried to use onSubmitComplete event, but it isn't firing.
I found a suggestion, to change ContetType to "text/html", but still no luck. I found, that the problem lies in writing to OutputStream - when commented out, event is fired.
Here is my servlet code
public void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setHeader("Content-Disposition", "attachment; filename=File.xls");
HSSFWorkbook workbook = new HSSFWorkbook();
try {
workbook = fileCreator.getWorkbook();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
OutputStream out = response.getOutputStream();
workbook.write(out);
out.close();
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().print("something");
response.flushBuffer();
}
So file is downloaded successfully, but event is not triggered. Even when I just get OutputStream and close it (without writing to it), event stops working.
When I remove whole "writing-to-output-stream" code, event works like a charm.
Any suggestions?
UPDATE
Here is code for FormPanel and its handlers, meby there is a problem?
Form:
downloadFileFormPanel.setEncoding(FormPanel.ENCODING_URLENCODED);
downloadFileFormPanel.setMethod(FormPanel.METHOD_POST);
VerticalPanel panel = new VerticalPanel();
panel.setWidth(UIConstatns.SIZE_100percent);
downloadFileFormPanel.setWidget(panel);
downloadFileButton = new Button(messages.EXPORT_LIMITS());
downloadFileButton.setWidth(UIConstatns.SIZE_100percent);
downloadFileButton.addStyleName("navigation-button");
panel.add(downloadFileButton);
Handlers
private void registerExportLimitsHandler() {
registerHandler(getView().getDownloadFileButton().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
getView().showLoadingDialog();
getDownloadFileForm().submit();
}
}));
}
private void registerFormSubmitCompleteHandler() {
getView().getDownloadFileForm().addSubmitCompleteHandler(new SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
Window.alert("download complete");
getView().hideLoadingDialog();
}
});
}
According to the Javadoc of ServletResponse#getWriter() you can either use response.getOutputStream() or response.getWriter() to write the body of the response, but not both. Furthermore it is better to set the status code of the response before writing the body. Please try the following:
// ...
response.setStatus(HttpServletResponse.SC_OK);
OutputStream out = response.getOutputStream();
workbook.write(out);
out.flush();
out.close();
// response.getWriter().print("something");
// response.flushBuffer();
You did not post the line where you create your FormPanel so I'm not sure if this was your problem:
Looks like the FormPanel(String target) constructor does not work with the SubmitCompleteHandler. With the default constructor it seems to work.

Resources