blob: ff007039acfa936fbb36a6dea83a44a2f2d340d0 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*/
package org.eclipse.osbp.xtext.reportdsl.common;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.framework.IPlatformContext;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.core.framework.PlatformFileContext;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.HTMLRenderOption;
import org.eclipse.birt.report.engine.api.IRenderOption;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.PDFRenderOption;
import org.eclipse.birt.report.model.api.DesignConfig;
import org.eclipse.birt.report.model.api.IDesignEngine;
import org.eclipse.birt.report.model.api.IDesignEngineFactory;
import org.eclipse.birt.report.model.api.OdaDataSourceHandle;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.command.CustomMsgException;
import org.eclipse.osbp.preferences.DataSourceConfiguration;
import org.eclipse.osbp.preferences.PersistenceUnitConfiguration;
import org.eclipse.osbp.preferences.ProductConfiguration;
import org.eclipse.osbp.preferences.ProductConfigurationPrefs;
import org.eclipse.osbp.ui.api.datamart.IDataMart;
import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService;
import org.eclipse.osbp.ui.api.report.IReportProvider;
import org.eclipse.osbp.ui.api.report.IReportProvider.Rendering;
import org.eclipse.osbp.utils.session.VaadinSessionAttributes;
import org.eclipse.osbp.xtext.reportdsl.common.BaseReport.Parameter;
import org.eclipse.osbp.xtext.reportdsl.jvmmodel.ReportModelGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopyFields;
import com.lowagie.text.pdf.PdfReader;
public class BirtEngine {
private static final Logger LOGGER = LoggerFactory.getLogger(BirtEngine.class);
private static java.util.logging.Logger BIRT_LOGGER = java.util.logging.Logger.getLogger(BirtEngine.class.getName());
private final static String CONFIG_FILE = "BirtConfig.properties";
private final static String ODA_DATA_SOURCE_NAME = "osbpdb";
private static Properties configProps = new Properties();
private static EngineConfig config = new EngineConfig();
private static boolean isStarted = false;
private static boolean isTaskRunning = false;
public static void start() {
if (!isStarted) {
LOGGER.debug("start");
loadEngineProps();
isStarted = true;
}
}
public static void stop() {
if (isStarted) {
LOGGER.debug("stop");
Platform.shutdown();
isStarted = false;
}
}
/**
* <b>only callable by</b><ul>
* <li>{@link #getReportEngine()}</li>
* <li>{@link ReportModelGenerator#generateReportFile(org.eclipse.osbp.xtext.reportdsl.ReportPackage, org.eclipse.osbp.xtext.reportdsl.Report, org.eclipse.xtext.generator.IFileSystemAccess)}</li>
* </ul>
*/
public static IReportEngine createReportEngine(BaseReport report) {
start();
config.setResourcePath("i18n");
config.setResourceLocator(new ResourceLocator(report));
// config.setLogConfig("log/birt.log",Level.FINE);
ClassLoader clzLoader = BirtEngine.class.getClassLoader();
URL resource = clzLoader.getResource("resources/log4j.properties");
String path = resource.getFile();
System.setProperty("java.util.logging.config.file", path);
config.setLogger(BIRT_LOGGER);
String logbackConfig = System.getProperty("logback.configurationFile");
if(logbackConfig != null) {
// In case that a sub directory META-INF exists
logbackConfig = logbackConfig.replace("META-INF/", "");
// replacing the logback.xml with log
config.setLogConfig(logbackConfig.replace("logback.xml", "log") , Level.FINE);
config.setLogFile("birt.log");
}
IPlatformContext context = new PlatformFileContext();
config.setPlatformContext( context );
try {
Platform.startup( config );
}
catch ( BirtException e ) {
LOGGER.error("{}",e);
if (e.getCause()!=null) LOGGER.error(" "+e.getCause());
}
IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject( IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY );
return factory.createReportEngine( config );
}
public static synchronized IReportEngine getReportEngine(BaseReport report) {
IReportEngine result = (IReportEngine) VaadinSessionAttributes.get(IReportEngine.class);
if (result == null) {
result = createReportEngine(report);
VaadinSessionAttributes.set(IReportEngine.class, result);
LOGGER.debug("session-static report engine created");
}
return result;
}
public static synchronized void destroyReportEngine() {
IReportEngine result = (IReportEngine) VaadinSessionAttributes.get(IReportEngine.class);
if (result != null) {
result.destroy();
VaadinSessionAttributes.remove(IReportEngine.class);
LOGGER.debug("session-static report engine destroyed");
}
}
/**
* <b>only callable by</b><ul>
* <li>{@link #getDesignEngine()}</li>
* <li>{@link ReportModelGenerator#generateReportFile(org.eclipse.osbp.xtext.reportdsl.ReportPackage, org.eclipse.osbp.xtext.reportdsl.Report, org.eclipse.xtext.generator.IFileSystemAccess)}</li>
* </ul>
*/
public static IDesignEngine createDesignEngine() {
IDesignEngine result = null;
try {
start();
DesignConfig config = new DesignConfig();
IDesignEngineFactory engineFactory = (IDesignEngineFactory) Platform.createFactoryObject(IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY);
Platform.startup(config);
result = engineFactory.createDesignEngine(config);
} catch (BirtException e) {
LOGGER.error("{}",e);
if (e.getCause()!=null) LOGGER.error(" "+e.getCause());
}
return result;
}
public static synchronized IDesignEngine getDesignEngine() {
IDesignEngine result = (IDesignEngine) VaadinSessionAttributes.get(IDesignEngine.class);
if (result == null) {
result = createDesignEngine();
if (result != null) {
VaadinSessionAttributes.set(IDesignEngine.class, result);
LOGGER.debug("session-static design engine created");
}
}
return result;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
private static void loadEngineProps() {
try {
//Config File must be in classpath
ClassLoader cl = Thread.currentThread ().getContextClassLoader();
InputStream in = null;
in = cl.getResourceAsStream (CONFIG_FILE);
if (in != null) {
configProps.load(in);
in.close();
}
} catch (Exception e) {
LOGGER.error("{}",e);
if (e.getCause()!=null) LOGGER.error(" "+e.getCause());
}
}
public static ByteArrayInputStream get(BaseReport report, Rendering renderer) {
return get(report, renderer, null);
}
public static ByteArrayInputStream get(BaseReport report, Rendering renderer, String path) {
IReportEngine reportEngine = getReportEngine(report);
IReportRunnable design = null;
if(isTaskRunning) {
LOGGER.debug("{}", "get ignored as task is running");
return null;
}
LOGGER.debug("{}", "get called");
isTaskRunning = true;
// Open report design
Object object = report.getRunnableOrFilename();
if (object instanceof String) {
URL url = report.getClass().getClassLoader().getResource((String)object);
try (InputStream inputStream = url.openStream()) {
design = reportEngine.openReportDesign(url.toExternalForm(), inputStream);
if (design.getDesignHandle() instanceof ReportDesignHandle) {
report.addCss((ReportDesignHandle) design.getDesignHandle());
addTranslations((ReportDesignHandle) design.getDesignHandle(), report.getDslMetadataService());
addStaticData((ReportDesignHandle) design.getDesignHandle(), report, report.getDslMetadataService());
fillOdaDatasource((ReportDesignHandle) design.getDesignHandle(), report);
}
} catch (IOException | EngineException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("{}", exceptionDetails);
}
}
else if (object instanceof IReportRunnable) {
design = (IReportRunnable)object;
}
else if (object instanceof ReportDesignHandle) {
try {
design = reportEngine.openReportDesign((ReportDesignHandle)object);
} catch (EngineException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("{}", exceptionDetails);
}
}
// create task to run and render report
if (design != null) {
try {
ByteArrayInputStream stream = taskAndRun(report, renderer, path, reportEngine, design);
LOGGER.debug("task is finished");
isTaskRunning = false;
return stream;
} catch (EngineException | IOException | DocumentException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("{}", exceptionDetails);
}
}
LOGGER.debug("task failed");
isTaskRunning = false;
return null;
}
@SuppressWarnings("unchecked")
private static ByteArrayInputStream taskAndRun(BaseReport report, Rendering renderer, String path,
IReportEngine reportEngine, IReportRunnable design)
throws EngineException, IOException, DocumentException {
ByteArrayInputStream bis = null;
IRunAndRenderTask task = reportEngine.createRunAndRenderTask(design);
task.getAppContext().put(IReportProvider.APPCONTEXT_REPORT, report);
task.getAppContext().put(IReportProvider.APPCONTEXT_ECLIPSECONTEXT, report.getEclipseContext());
task.getAppContext().put(IReportProvider.APPCONTEXT_DATAMARTINSTANCE, report.getDatamartInstanceMap());
task.setLocale(report.getUser().getLocale());
// set output options
IRenderOption options = null;
ByteArrayOutputStream bos = null;
if (renderer.asHtml()) {
options = new HTMLRenderOption();
options.setOutputFormat(HTMLRenderOption.OUTPUT_FORMAT_HTML);
((HTMLRenderOption)options).setEmbeddable(true);
((HTMLRenderOption)options).setImageHandler(new HTMLServerEmbeddedImageHandler());
}
else if (renderer.asPdf()) {
options = new PDFRenderOption();
options.setOutputFormat(PDFRenderOption.OUTPUT_FORMAT_PDF);
}
if (options != null) {
if (renderer.asFile()) {
options.setOutputFileName(path);
}
else if (renderer.asStream()) {
bos = new ByteArrayOutputStream();
options.setOutputStream(bos);
}
}
task.setRenderOption(options);
// get parameter in case of a parametrized report
for (Parameter parameter : report.getParameterList()) {
task.setParameter(parameter.getName(), parameter.getValue(), parameter.getDisplayText());
}
// run report
task.run();
List<EngineException> errorList = task.getErrors();
for (EngineException error : errorList){
LOGGER.error(task.getClass().getName() + ": " + error.getLocalizedMessage());
}
if (renderer.asStream()) {
if (renderer.forPrinting() && (bos != null)) {
// --- get the generated BIRT PDF document ---
PdfReader js1 = new PdfReader(bos.toByteArray());
// --- create a new output stream ---
bos = new ByteArrayOutputStream();
// --- generate a new PDF document ---
PdfCopyFields cpy = new PdfCopyFields(bos);
// --- add the previously generated BIRT PDF document ---
cpy.addDocument(js1);
// --- add a print-statement into the new PDF document ---
cpy.addJavaScript( "this.print({bUI: true,bSilent: false,bShrinkToFit:true});" );
cpy.close();
}
if (bos != null) {
bis = new ByteArrayInputStream(bos.toByteArray());
}
}
task.close();
return bis;
}
private static void addStaticData(ReportDesignHandle reportDesignHandle, BaseReport report, IDSLMetadataService dslMetadataService) {
for (String locale : dslMetadataService.getTranslations().keySet()) {
// TODO: birt4.4 cannot handle fallbacks of language variants with
// missing keys when locale was added - so don't supply for this
// version
if (!locale.contains("_")) {
for(String attributeName:report.getStaticData()) {
for (IDataMart datamartInstance : report.getDatamartInstanceMap().values()){
String value = datamartInstance.getResultAttribute(attributeName);
if(value != null) {
try {
reportDesignHandle.addTranslation(BaseReport.ATTRIBUTE_TRANSLATION_PREFIX+attributeName, locale, value);
} catch (CustomMsgException e) {
LOGGER.error("{}", e);
}
}
}
}
}
}
}
private static void addTranslations(ReportDesignHandle reportDesignHandle,
IDSLMetadataService dslMetadataService) {
for (String locale : dslMetadataService.getTranslations().keySet()) {
// TODO: birt4.4 cannot handle fallbacks of language variants with
// missing keys when locale was added - so don't supply for this
// version
if (!locale.contains("_")) {
for (Object key : dslMetadataService.getTranslations()
.get(locale).keySet()) {
try {
reportDesignHandle.addTranslation((String) key, locale,
(String) dslMetadataService.getTranslations()
.get(locale).get(key));
} catch (CustomMsgException e) {
LOGGER.error("{}", e);
}
}
}
}
}
private static void fillOdaDatasource(ReportDesignHandle design, BaseReport report) {
if (report.isParametrized()) {
ProductConfigurationPrefs pref = ProductConfiguration.prefs();
PersistenceUnitConfiguration persistConfig = pref.getPersistenceUnit(report.getPersistenceUnitName());
DataSourceConfiguration dataSource = pref.getDataSource(persistConfig.getJndiName());
OdaDataSourceHandle odsourceh = (OdaDataSourceHandle) design.findDataSource(ODA_DATA_SOURCE_NAME);
try {
odsourceh.setProperty("odaDriverClass", dataSource.getDriverClass());
odsourceh.setProperty("odaURL", dataSource.getJdbcURL());
odsourceh.setProperty("odaUser", dataSource.getDatabaseUser());
odsourceh.setProperty("odaPassword", dataSource.getDatabasePass());
odsourceh.setEncryption("odaPassword", "base64");
} catch (SemanticException e) {
LOGGER.error("{}", e);
} catch (NullPointerException e) {
LOGGER.error("The oda datasource named '" + ODA_DATA_SOURCE_NAME + "' does not exist in the report design!", e);
}
}
}
}