/** * */ package de.unioninvestment.eai.portal.portlet.crud.export; import java.io.InputStream; import java.io.Serializable; import org.codehaus.groovy.runtime.StackTraceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vaadin.server.Page; import com.vaadin.server.StreamResource; import com.vaadin.server.StreamResource.StreamSource; import com.vaadin.ui.UI; import de.unioninvestment.eai.portal.portlet.crud.domain.model.DataContainer.ExportWithExportSettings; import de.unioninvestment.eai.portal.portlet.crud.domain.model.Download; import de.unioninvestment.eai.portal.portlet.crud.domain.model.Download.Status; /** * Export-Task that is intended to be given its download-content asynchronously * - it is not capable of creating any content on its own (like i.e. * <code>ExcelExportTask</code>). The method * <code>TableExport#convertTable()</code> defined in * <code>{@link #createExport()}</code> will poll for content to become * available in <code>{@link #content}</code>. * * @author Jan Malcomess * @since 1.46 */ public class DownloadExportTask extends AbstractExportTask implements ExportTask { private static final Logger LOGGER = LoggerFactory .getLogger(DownloadExportTask.class); private de.unioninvestment.eai.portal.portlet.crud.domain.model.Table tableModel; private Download download; private InputStream content; private volatile boolean finished; private volatile boolean cancelled; private volatile boolean started = false; /** * @param ui * the ui the corresponding table belongs to. * @param tableModel * the table's model. * @param automaticDownload * <code>true</code> if browser supports automatic download. */ public DownloadExportTask( UI ui, de.unioninvestment.eai.portal.portlet.crud.domain.model.Table tableModel, Download download, boolean automaticDownloadIsPossible) { super(ui, automaticDownloadIsPossible); this.tableModel = tableModel; this.download = download; } @Override public void runWithContext() { LOGGER.info("Started export thread for report '{}'", download.getFilename()); started = true; try { doWithExportSettingsAndProperLocking(tableModel, new ExportWithExportSettings() { public void export() { LOGGER.info("Building Report"); try { Status status = new Download.Status() { @Override public void updateProgress(float progress) { checkForInterruption(); informFrontendAboutProgress(progress); } }; content = download.build(status); finished = true; informFrontendAboutFinish(); LOGGER.info("Finished Building Report '{}'", download.getFilename()); } catch (ExportInterruptionException e) { LOGGER.info("Report generation was cancelled/interrupted"); cancelled = true; } } }); LOGGER.info("Finished export thread for report '{}'", download.getFilename()); } catch (Exception e) { finished = true; LOGGER.error("Error during report generation", StackTraceUtils.deepSanitize(e)); informFrontendAboutException(e); } finally { finished = true; } } @Override public void cancel() { cancelled = true; if (started) { waitForFinishing(); } } protected void checkForInterruption() { if (cancelled || Thread.currentThread().isInterrupted()) { cancelled = true; throw new ExportInterruptionException(); } } private void waitForFinishing() { while (true) { if (finished) { return; } try { Thread.sleep(100); } catch (InterruptedException e) { return; } } } @Override public boolean isFinished() { return finished; } @Override public void sendToClient(String exportWindow) { if (finished && !cancelled) { StreamResource resource = createResourceForContent(); Page.getCurrent().open(resource, exportWindow, !"_self".equals(exportWindow)); } else { throw new IllegalStateException( "Cannot send export to client when not finished"); } } @Override protected StreamResource createResourceForContent() { StreamResource resource = new StreamResource(new StreamSource() { /** * @see Serializable */ private static final long serialVersionUID = 1L; @Override public InputStream getStream() { return content; } }, download.getFilename()); resource.setMIMEType(download.getMimeType()); return resource; } }