package au.com.vaadinutils.jasper;
import java.awt.Color;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.sql.Connection;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import javax.activation.DataSource;
import javax.mail.util.ByteArrayDataSource;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.base.Preconditions;
import com.vaadin.server.Page;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.WrappedSession;
import com.vaadin.ui.UI;
import au.com.vaadinutils.jasper.parameter.ReportChooser;
import au.com.vaadinutils.jasper.parameter.ReportParameter;
import au.com.vaadinutils.jasper.servlet.VaadinJasperPrintServlet;
import au.com.vaadinutils.jasper.ui.CleanupCallback;
import au.com.vaadinutils.jasper.ui.JasperReportProperties;
import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRBand;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRStaticText;
import net.sf.jasperreports.engine.JRTextField;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignElement;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignImage;
import net.sf.jasperreports.engine.design.JRDesignParameter;
import net.sf.jasperreports.engine.design.JRDesignStaticText;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRExportProgressMonitor;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.fill.FillListener;
import net.sf.jasperreports.engine.fill.JRSwapFileVirtualizer;
import net.sf.jasperreports.engine.type.HorizontalAlignEnum;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.type.VerticalAlignEnum;
import net.sf.jasperreports.engine.type.WhenNoDataTypeEnum;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRSwapFile;
import net.sf.jasperreports.web.servlets.AsyncJasperPrintAccessor;
import net.sf.jasperreports.web.servlets.ReportExecutionStatus;
@SuppressWarnings("deprecation")
public class JasperManager implements Runnable
{
private JasperReport jasperReport;
private static transient Logger logger = LogManager.getLogger(JasperManager.class);
private final Map<String, Object> boundParams = new HashMap<>();
private CustomAsynchronousFillHandle fillHandle;
volatile private boolean stop;
private JasperReportProperties reportProperties;
private final static int reportLimit = Math.max(Runtime.getRuntime().availableProcessors() / 2, 1);
private final static Semaphore concurrentLimit = new Semaphore(reportLimit, true);
public enum Disposition
{
inline, mixed
}
public enum OutputFormat
{
PDF
{
@Override
public String getMimeType()
{
return "application/pdf";
}
@Override
public String getFileExtension()
{
return ".pdf";
}
@Override
public AttachmentType getAttachementType()
{
return AttachmentType.PDF;
}
},
HTML
{
@Override
public String getMimeType()
{
return "text/html";
}
@Override
public String getFileExtension()
{
return ".html";
}
@Override
public AttachmentType getAttachementType()
{
return AttachmentType.HTML;
}
},
CSV
{
@Override
public String getMimeType()
{
return "text/csv";
}
@Override
public String getFileExtension()
{
return ".csv";
}
@Override
public AttachmentType getAttachementType()
{
return AttachmentType.CSV;
}
};
abstract public String getMimeType();
abstract public String getFileExtension();
abstract public AttachmentType getAttachementType();
}
/**
* key: report filename <br>
* value: last time it was compiled
*/
final static Map<String, Long> compiledReports = new ConcurrentHashMap<>();
/**
*
* @param jasperReport
* path to jasper report.
* @throws JRException
*/
public JasperManager(JasperReportProperties reportProperties)
{
this.reportProperties = reportProperties;
}
private void compileReport()
{
try
{
String suppliedFileName = reportProperties.getReportFileName();
if (suppliedFileName.contains("."))
{
suppliedFileName = suppliedFileName.substring(0, suppliedFileName.indexOf("."));
}
String reportFileName = suppliedFileName + ".jasper";
String reportDesignName = suppliedFileName + ".jrxml";
File designFile = new File(reportProperties.getReportFolder(), reportDesignName);
Preconditions.checkArgument(designFile.exists(),
"The passed Jasper Report File doesn't exist: " + designFile.getAbsolutePath());
File sourcePath = designFile.getParentFile();
if (!compiledReports.containsKey(reportFileName)
|| compiledReports.get(reportFileName) < designFile.lastModified() || reportProperties.isDevMode())
{
// compileReport(getDesignFile(sourcePath, reportDesignName),
// sourcePath, sourcePath, reportDesignName);
JasperReportCompiler jasperReportCompiler = new JasperReportCompiler();
JasperDesign design = jasperReportCompiler.getDesignFile(sourcePath, reportDesignName);
String templateName = reportProperties.getHeaderFooterTemplateName();
if (templateName != null)
{
JasperDesign headerTemplate = jasperReportCompiler.getDesignFile(sourcePath, templateName);
replaceHeader(design, headerTemplate);
}
setCSVOptions(design);
jasperReportCompiler.compileReport(design, sourcePath, sourcePath, suppliedFileName);
}
this.jasperReport = (JasperReport) JRLoader
.loadObject(new File(reportProperties.getReportFolder(), reportFileName));
compiledReports.put(reportFileName, designFile.lastModified());
}
catch (Throwable e)
{
logger.error(e, e);
throw new RuntimeException("Bad report compilation");
}
}
/**
* replaces the header, footer, nodata band and dynamically adds user
* friendly report parameter display to the report.
*
* @param designFile
* @param template
* @throws JRException
*/
private void replaceHeader(JasperDesign designFile, JasperDesign template) throws JRException
{
JRBand title = template.getTitle();
JRDesignBand newTitle = new JRDesignBand();
int margin = 50;
designFile.setLeftMargin(margin);
designFile.setRightMargin(margin);
designFile.setTopMargin(margin);
designFile.setBottomMargin(margin);
double pageWidth = designFile.getPageWidth() + (margin * 2);
double ratio = 0.75; // landscape
if (designFile.getPageHeight() / pageWidth >= 1)
{
ratio = 1.5; // portrait
}
int pageHeight = (int) (pageWidth * ratio);
designFile.setPageWidth((int) pageWidth);
designFile.setPageHeight(pageHeight);
int maxY = determineSizeOfTemplateBandAndReplaceTitlePlaceHolder(designFile, title, newTitle, margin);
maxY += 2;
mergeExistingTitleWithTemplateTitle(designFile, newTitle, maxY);
JRBand footer = replaceFooterWithTemplateFooter(designFile, template, margin);
designFile.setPageFooter(footer);
JRDesignBand noDataBand = new JRDesignBand();
int noDataHeight = determineSizeOfTemplateBandAndReplaceTitlePlaceHolder(designFile, template.getNoData(),
noDataBand, margin);
designFile.setNoData(noDataBand);
noDataBand.setHeight(noDataHeight);
designFile.setWhenNoDataType(WhenNoDataTypeEnum.NO_DATA_SECTION);
}
/**
* replace the footer with the template footer, including update the place
* holder for the report title in the footer
*
* @param designFile
* @param template
* @param margin
* @return
*/
private JRBand replaceFooterWithTemplateFooter(JasperDesign designFile, JasperDesign template, int margin)
{
JRBand footer = template.getPageFooter();
for (JRElement element : footer.getElements())
{
if (element instanceof JRDesignElement)
{
if (element instanceof JRTextField)
{
JRTextField st = (JRTextField) element;
JRDesignExpression expr = (JRDesignExpression) st.getExpression();
expr.setText("\"" + reportProperties.getReportTitle() + "\"+" + expr.getText());
st.setWidth((designFile.getPageWidth() - st.getX()) - (margin * 2));
}
}
}
return footer;
}
/**
* we are now dropping the existing title on the ground in favour of the
* dynamically generated one based on the template
*
* @param designFile
* @param newTitle
* @param yoffset
*/
private void mergeExistingTitleWithTemplateTitle(JasperDesign designFile, JRDesignBand newTitle, int yoffset)
{
int maxY = 0;
// for (JRElement element : designFile.getTitle().getElements())
// {
//
// JRDesignElement de = (JRDesignElement) element;
// de.setY(de.getY() + yoffset);
// maxY = Math.max(maxY, de.getY() + element.getHeight());
// newTitle.addElement(element);
// }
newTitle.setHeight(Math.max(maxY + 2, yoffset + 2));
designFile.setTitle(newTitle);
}
/**
* replace the place holder in the targetBand with the report title, also
* add a set of dynamically generated user friendly report parameter fields
* to this band and add parameters to the report for them if not already
* present.
*
* @param designFile
* @param templateBand
* @param targetBand
* @param margin
* @return
* @throws JRException
*/
private int determineSizeOfTemplateBandAndReplaceTitlePlaceHolder(JasperDesign designFile, JRBand templateBand,
JRDesignBand targetBand, int margin) throws JRException
{
int maxY = 0;
for (JRElement element : templateBand.getElements())
{
JRDesignElement de = (JRDesignElement) element;
if (element instanceof JRStaticText)
{
JRStaticText st = (JRStaticText) element;
if (st.getText().equalsIgnoreCase("report name place holder"))
{
st.setText(reportProperties.getReportTitle());
st.setWidth((designFile.getPageWidth() - st.getX()) - (margin * 2));
}
}
if (element instanceof JRDesignImage)
{
JRDesignImage im = (JRDesignImage) element;
String expr = im.getExpression().getText();
if (expr.contains("logo.png"))
{
int height = 140;
final int imageWidth = designFile.getPageWidth() - (margin * 2);
String fileName = reportProperties.generateDynamicHeaderImage(imageWidth, height,
reportProperties.getReportTitle());
im.setWidth(imageWidth);
// im.setHeight(height);
im.setX(-8);
expr = expr.replace("logo.png", fileName);
im.setExpression(new JRDesignExpression(expr));
}
}
maxY = Math.max(maxY, de.getY() + de.getHeight());
targetBand.addElement(de);
}
JRDesignStaticText paramElement = new JRDesignStaticText();
paramElement.setText("Parameters");
paramElement.setWidth(525);
paramElement.setHeight(15);
paramElement.setBackcolor(new Color(95, 96, 98));
paramElement.setForecolor(new Color(255, 255, 255));
paramElement.setMode(ModeEnum.OPAQUE);
paramElement.setX(0);
paramElement.setY(maxY + 2);
paramElement.setFontName("Arial");
paramElement.setBold(true);
paramElement.setFontSize(12);
paramElement.setHorizontalAlignment(HorizontalAlignEnum.CENTER);
paramElement.setVerticalAlignment(VerticalAlignEnum.MIDDLE);
targetBand.addElement(paramElement);
maxY = paramElement.getY() + paramElement.getHeight();
maxY = addParametersToDisplayReportParameters(designFile, targetBand, maxY);
return maxY;
}
/**
* add user friendly paramters to the band and report port parameters if not
* already present
*
* @param designFile
* @param targetBand
* @param maxY
* @return
* @throws JRException
*/
private int addParametersToDisplayReportParameters(JasperDesign designFile, JRDesignBand targetBand, int maxY)
throws JRException
{
for (ReportParameter<?> param : reportProperties.getFilterBuilder().getReportParameters())
{
if (param.displayInreport())
{
for (String parameterName : param.getParameterNames())
{
JRDesignStaticText labelElement = new JRDesignStaticText();
String strippedLabel = param.getLabel(parameterName).replaceAll("ReportParameter", "");
labelElement.setText(strippedLabel);
labelElement.setWidth(125);
labelElement.setHeight(20);
labelElement.setBackcolor(new Color(208, 208, 208));
labelElement.setMode(ModeEnum.OPAQUE);
labelElement.setVerticalAlignment(VerticalAlignEnum.MIDDLE);
labelElement.setX(0);
labelElement.setY(maxY);
labelElement.setFontName("SansSerif");
labelElement.setFontSize(12);
targetBand.addElement(labelElement);
JRDesignTextField valueElement = new JRDesignTextField();
valueElement.setExpression(new JRDesignExpression("$P{ParamDisplay-" + parameterName + "}"));
valueElement.setWidth(400);
valueElement.setHeight(20);
valueElement.setBackcolor(new Color(208, 208, 208));
valueElement.setMode(ModeEnum.OPAQUE);
valueElement.setX(125);
valueElement.setY(maxY);
valueElement.setFontName("SansSerif");
valueElement.setFontSize(12);
valueElement.setVerticalAlignment(VerticalAlignEnum.MIDDLE);
targetBand.addElement(valueElement);
maxY = valueElement.getY() + valueElement.getHeight();
if (!designFile.getParametersMap().containsKey("ParamDisplay-" + parameterName))
{
JRDesignParameter parameter = new JRDesignParameter();
parameter.setName("ParamDisplay-" + parameterName);
parameter.setValueClass(String.class);
parameter.setForPrompting(false);
designFile.addParameter(parameter);
}
}
}
}
return maxY;
}
private void setCSVOptions(JasperDesign designFile)
{
designFile.setProperty("net.sf.jasperreports.export.csv.exclude.origin.keep.first.band.columnHeader",
"columnHeader");
designFile.setProperty("net.sf.jasperreports.export.csv.exclude.origin.band.title", "title");
designFile.setProperty("net.sf.jasperreports.export.csv.exclude.origin.band.pageHeader", "pageHeader");
designFile.setProperty("net.sf.jasperreports.export.csv.exclude.origin.band.pageFooter", "pageFooter");
designFile.setProperty("net.sf.jasperreports.export.csv.exclude.origin.band.footer", "footer");
}
public JRParameter[] getParameters()
{
return jasperReport.getParameters();
}
public boolean paramExists(String parameterName)
{
return getParameter(parameterName) != null;
}
public JRParameter getParameter(String parameterName)
{
JRParameter result = null;
for (JRParameter param : jasperReport.getParameters())
{
if (param.getName().equals(parameterName))
{
result = param;
break;
}
}
return result;
}
/**
* Binds a value to a report parameter.
*
* Essentially a report can have a no. of named parameters which are used to
* filter the report or display on the report. This method allows you to set
* the parameters value at runtime.
*
* @param parameterName2
*
* @param parameterName
* @param parameterValue
*/
public void bindParameter(ReportParameter<?> param, final String parameterName)
{
// ReportChooser is not actually a report parameter
if (!(param instanceof ReportChooser))
{
// specific work around for prefixed report parameters
String strippedParameterName = parameterName;
if (strippedParameterName.startsWith("ReportParameter"))
{
strippedParameterName = strippedParameterName.substring("ReportParameter".length(),
strippedParameterName.length());
}
if (!paramExists(strippedParameterName))
{
logger.info("The passed Jasper Report parameter: " + param.getParameterNames()
+ " does not exist in the Report");
}
boundParams.put(strippedParameterName, param.getValue(parameterName));
}
}
// /**
// * Binds a value to a report parameter.
// *
// * Essentially a report can have a no. of named parameters which are used
// to
// * filter the report or display on the report. This method allows you to
// * pass in a map (name, value) of parameter value at runtime.
// *
// * @param parameters
// * a map of name/value pairs to bind to report parameters of the
// * given names.
// */
//
// private void bindParameters(Map<String, Object> parameters)
// {
// for (String parameterName : parameters.keySet())
// {
// Preconditions.checkArgument(paramExists(parameterName),
// "The passed Jasper Report parameter: "
// + parameterName + " does not existing on the Report");
//
// boundParams.put(parameterName, parameters.get(parameterName));
// }
// }
private JasperPrint fillReport(OutputFormat outputFormat) throws JRException
{
Connection connection = reportProperties.getConnection();
fillHandle = CustomAsynchronousFillHandle.createCustomHandle(jasperReport, boundParams, connection);
fillHandle.setDataProvider(reportProperties, outputFormat);
fillHandle.addFillListener(new FillListener()
{
@Override
public void pageUpdated(JasperPrint jasperPrint, int pageIndex)
{
queueEntry.setStatus("Filling page " + pageIndex);
}
@Override
public void pageGenerated(JasperPrint jasperPrint, int pageIndex)
{
queueEntry.setStatus("Generating page " + pageIndex);
}
});
AsyncJasperPrintAccessor asyncAccessor = new AsyncJasperPrintAccessor(fillHandle);
if (!stop)
{
fillHandle.startFill();
}
// jasper_print = JasperFillManager.fillReport(jasperReport,
// boundParams, connection);
while (asyncAccessor.getReportStatus().getStatus() == ReportExecutionStatus.Status.RUNNING)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
logger.error(e, e);
}
}
return asyncAccessor.getFinalJasperPrint();
}
public void cancelPrint()
{
stop = true;
if (queueEntry != null)
{
queueEntry.setCancelling();
thread.interrupt();
}
}
private PipedInputStream inputStream;
private PipedOutputStream outputStream;
private OutputFormat exportMethod;
CountDownLatch completeBarrier;
Map<String, byte[]> images;
private Collection<ReportParameter<?>> params;
private DataSource[] imagesrcs;
private JasperProgressListener progressListener;
private CountDownLatch readerReady;
private CountDownLatch writerReady;
volatile private QueueEntry queueEntry;
private Thread thread;
volatile private boolean inQueue;
public RenderedReport export(OutputFormat exportMethod, Collection<ReportParameter<?>> params)
throws InterruptedException
{
final CountDownLatch latch = new CountDownLatch(1);
exportAsync(exportMethod, params, new JasperProgressListener()
{
@Override
public void outputStreamReady()
{
latch.countDown();
}
@Override
public void failed(String string)
{
latch.countDown();
}
@Override
public void completed()
{
latch.countDown();
}
});
latch.await();
InputStream stream = getStream();
if (stream == null)
{
throw new RuntimeException("Unable to get stream");
}
// completeBarrier.await();
return new RenderedReport(stream, imagesrcs, exportMethod);
}
public int checkQueueSize()
{
return concurrentLimit.getQueueLength();
}
public InputStream getStream() throws InterruptedException
{
inputStream = new PipedInputStream();
readerReady.countDown();
if (!writerReady.await(10, TimeUnit.SECONDS))
{
try
{
inputStream.close();
}
catch (IOException e)
{
logger.error(e, e);
}
throw new RuntimeException("Couldn't attach to writer stream");
}
return inputStream;
}
public void exportAsync(OutputFormat exportMethod, Collection<ReportParameter<?>> params,
JasperProgressListener progressListener)
{
if (params == null)
{
params = new LinkedList<>();
}
this.params = params;
images = new ConcurrentHashMap<>();
if (UI.getCurrent() != null)
{
WrappedSession session = UI.getCurrent().getSession().getSession();
session.setAttribute(VaadinJasperPrintServlet.IMAGES_MAP, images);
}
else
{
logger.warn("No vaadin UI present");
}
stop = false;
writerReady = new CountDownLatch(1);
completeBarrier = new CountDownLatch(1);
readerReady = new CountDownLatch(1);
this.progressListener = progressListener;
if (progressListener == null)
{
this.progressListener = new JasperProgressListener()
{
@Override
public void failed(String string)
{
// noop
}
@Override
public void completed()
{
// noop
}
@Override
public void outputStreamReady()
{
// noop
}
};
}
inputStream = null;
outputStream = null;
queueEntry = new QueueEntry(reportProperties.getReportTitle(), reportProperties.getUsername());
inQueue = true;
jobQueue.add(queueEntry);
this.exportMethod = exportMethod;
thread = new Thread(this, "JasperManager");
thread.start();
}
static final LinkedBlockingQueue<QueueEntry> jobQueue = new LinkedBlockingQueue<>();
@Override
public void run()
{
JRSwapFileVirtualizer fileVirtualizer = null;
CleanupCallback cleanupCallback = null;
boolean initialized = false;
try
{
logger.warn("{} permits are available", concurrentLimit.availablePermits());
concurrentLimit.acquire();
initialized = true;
inQueue = false;
queueEntry.setStatus("Gathering report data phase 1");
reportProperties.initDBConnection();
cleanupCallback = reportProperties.getCleanupCallback();
List<ReportParameter<?>> extraParams = reportProperties.prepareData(params,
reportProperties.getReportFileName(), cleanupCallback);
compileReport();
if (reportProperties.getCustomReportParameterMap() != null)
{
boundParams.putAll(reportProperties.getCustomReportParameterMap());
}
if (extraParams != null)
{
params.removeAll(extraParams);
params.addAll(extraParams);
}
logger.info("Running report " + reportProperties.getReportFileName());
for (ReportParameter<?> param : params)
{
for (String parameterName : param.getParameterNames())
{
bindParameter(param, parameterName);
if (param.displayInreport())
{
// populate dynamically added parameters to display user
// friendly parameters on the report
boundParams.put("ParamDisplay-" + parameterName, param.getDisplayValue(parameterName));
}
logger.info(parameterName + " " + param.getValue(parameterName));
}
}
reportProperties.prepareForOutputFormat(exportMethod);
CustomJRHyperlinkProducerFactory.setUseCustomHyperLinks(true);
@SuppressWarnings("rawtypes")
JRAbstractExporter exporter = null;
queueEntry.setStatus("Gathering report data phase 2");
// use file virtualizer to prevent out of heap
String fileName = "/tmp";
JRSwapFile file = new JRSwapFile(fileName, 100, 10);
fileVirtualizer = new JRSwapFileVirtualizer(500, file);
boundParams.put(JRParameter.REPORT_VIRTUALIZER, fileVirtualizer);
if (stop)
{
return;
}
if (exportMethod == OutputFormat.CSV)
{
boundParams.put(JRParameter.IS_IGNORE_PAGINATION, true);
}
JasperPrint jasper_print = fillReport(exportMethod);
switch (exportMethod)
{
case HTML:
{
exporter = new JRHtmlExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasper_print);
exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, images);
if (VaadinServlet.getCurrent() != null)
{
String context = VaadinServlet.getCurrent().getServletContext().getContextPath();
int contextIndex = Page.getCurrent().getLocation().toString().lastIndexOf(context);
String baseurl = Page.getCurrent().getLocation().toString().substring(0,
contextIndex + context.length() + 1);
String imageUrl = baseurl + "VaadinJasperPrintServlet?image=";
exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, imageUrl);
}
else
{
logger.warn("Vaadin Servlet doens't have a current context");
}
break;
}
case PDF:
{
exporter = new JRPdfExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasper_print);
break;
}
case CSV:
{
exporter = new JRCsvExporter();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasper_print);
break;
}
default:
{
throw new RuntimeException("Unsupported export option " + exportMethod);
}
}
imagesrcs = (images.size() <= 0) ? null : new DataSource[images.size()];
if (imagesrcs != null)
{
int xi = 0;
for (Map.Entry<String, byte[]> entry : images.entrySet())
{
ByteArrayDataSource image = new ByteArrayDataSource(entry.getValue(), "image/gif");
image.setName(entry.getKey());
imagesrcs[xi++] = image;
}
}
if (stop)
{
return;
}
createPageProgressMonitor(exporter);
queueEntry.setStatus("Waiting for browser to start streaming");
progressListener.outputStreamReady();
if (readerReady.await(10, TimeUnit.SECONDS))
{
outputStream = new PipedOutputStream(inputStream);
writerReady.countDown();
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
exporter.exportReport();
}
else
{
logger.error("Couldn't attach to reader stream");
}
Thread.sleep(750);
queueEntry.setStatus("Cleaning up");
}
catch (Exception e)
{
logger.error(e, e);
}
finally
{
if (queueEntry != null)
{
jobQueue.remove(queueEntry);
queueEntry = null;
}
try
{
if (outputStream != null)
{
outputStream.close();
}
}
catch (IOException e)
{
logger.error(e, e);
}
if (cleanupCallback != null)
{
try
{
cleanupCallback.cleanup();
}
catch (Exception e)
{
logger.error(e, e);
}
}
if (fileVirtualizer != null)
{
try
{
fileVirtualizer.cleanup();
}
catch (Exception e)
{
logger.error(e, e);
}
}
CustomJRHyperlinkProducerFactory.setUseCustomHyperLinks(false);
if (initialized)
{
concurrentLimit.release();
try
{
reportProperties.closeDBConnection();
}
catch (Exception e)
{
logger.error(e, e);
}
}
completeBarrier.countDown();
if (progressListener != null)
{
progressListener.completed();
}
}
}
@SuppressWarnings("rawtypes")
private void createPageProgressMonitor(JRAbstractExporter exporter)
{
exporter.setParameter(JRExporterParameter.PROGRESS_MONITOR, new JRExportProgressMonitor()
{
int pageCount = 0;
@Override
public void afterPageExport()
{
pageCount++;
queueEntry.setStatus("Rendering page " + pageCount);
}
});
}
protected static String getJasperFile(final String dir, final String name) throws IOException
{
final File file = new File(dir, name);
if (!file.exists())
{
throw new FileNotFoundException(file.toString());
}
return file.getCanonicalPath();
}
public ReportStatus getStatus()
{
ReportStatus reportStatus = new ReportStatus();
try
{
if (queueEntry == null)
{
reportStatus.setStatus("Complete");
}
else
{
reportStatus.setStatus(queueEntry.getStatus());
}
if (inQueue)
{
int pos = 0;
int ctr = 0;
for (QueueEntry entry : jobQueue)
{
ctr++;
if (entry == queueEntry)
{
// status += "<b>" + entry + "</b><br>";
pos = ctr;
break;
}
reportStatus.addQueueEntry(entry);
}
if (pos > reportLimit)
{
reportStatus.setStatus("Waiting for " + (pos - reportLimit) + " of the queued reports to complete");
}
}
}
catch (Exception e)
{
// there are possible race conditions that could lead to queueEntry
// being null here, so just catch and log it. this state should be
// transient
reportStatus.setStatus("waiting...");
logger.error(e, e);
}
return reportStatus;
}
}