blob: c4d98ac3fe784537285dd720d931514ac92b0396 [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 v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*/
package org.eclipse.osbp.xtext.reportdsl.common;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.OdaDataSetHandle;
import org.eclipse.birt.report.model.api.OdaDataSourceHandle;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.SessionHandle;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.command.ContentException;
import org.eclipse.birt.report.model.api.command.NameException;
import org.eclipse.birt.report.model.api.css.CssStyleSheetHandle;
import org.eclipse.birt.report.model.css.CssStyleSheet;
import org.eclipse.e4.core.contexts.IEclipseContext;
import org.eclipse.e4.ui.di.Focus;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBar;
import org.eclipse.e4.ui.model.application.ui.menu.MToolBarElement;
import org.eclipse.osbp.dsl.semantic.entity.LEntity;
import org.eclipse.osbp.osgi.hybrid.api.AbstractHybridVaaclipseView;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent.EventDispatcherCommand;
import org.eclipse.osbp.runtime.common.event.EventDispatcherEvent.EventDispatcherDataTag;
import org.eclipse.osbp.runtime.common.event.IEventDispatcher;
import org.eclipse.osbp.ui.api.customfields.IBlobService;
import org.eclipse.osbp.ui.api.datamart.DatamartFilter;
import org.eclipse.osbp.ui.api.datamart.DatamartPrimary;
import org.eclipse.osbp.ui.api.datamart.IDataMart;
import org.eclipse.osbp.ui.api.datamart.IDatamartFilterGenerator;
import org.eclipse.osbp.ui.api.layout.IViewLayoutManager;
import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService;
import org.eclipse.osbp.ui.api.report.IReportProvider.Rendering;
import org.eclipse.osbp.ui.api.themes.IThemeResourceService;
import org.eclipse.osbp.ui.api.user.IUser;
import org.eclipse.osbp.utils.common.EntityUtils;
import org.eclipse.osbp.utils.constants.ExtendedDate;
import org.eclipse.osbp.utils.vaadin.PropertyLookup;
import org.eclipse.osbp.utils.vaadin.ViewLayoutManager;
import org.eclipse.osbp.xtext.action.ReportActionEnum;
import org.eclipse.osbp.xtext.action.common.IToolbarAction;
import org.eclipse.osbp.xtext.datamart.common.DatamartFilterGenerator;
import org.eclipse.osbp.xtext.datamartdsl.DatamartDSLPackage;
import org.eclipse.osbp.xtext.datamartdsl.DatamartDefinition;
import org.eclipse.osbp.xtext.datamartdsl.DatamartEntity;
import org.eclipse.osbp.xtext.datamartdsl.DatamartNavigation;
import org.eclipse.osbp.xtext.reportdsl.common.item.BodyItem;
import org.eclipse.osbp.xtext.reportdsl.jvmmodel.ReportGeneratorWorkSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ibm.icu.util.ULocale;
import com.vaadin.data.Container.Filter;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.DownloadStream;
import com.vaadin.server.FileDownloader;
import com.vaadin.server.StreamResource;
import com.vaadin.ui.BrowserFrame;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
/**
*
* @author mokross, riegel
*
*/
public abstract class BaseReport extends AbstractHybridVaaclipseView
implements StreamResource.StreamSource, IUser.UserLocaleListener, IDatamartFilterGenerator.FilterChangeListener,
IEventDispatcher.Receiver, ClientConnector.DetachListener, ClientConnector.AttachListener {
private static final String BODY_HTML = "</body></html>";
private static final String HTML_BODY = "<html><body>";
private static final String RPTDESIGN = ".rptdesign";
private static final long serialVersionUID = -2774341697829389431L;
private static final Logger LOGGER = LoggerFactory.getLogger(BaseReport.class);
public static final String CAPTION_I18NKEY_SAVE_PDF = "save PDF";
public static final String CAPTION_I18NKEY_PRINT_PDF = "print PDF";
protected transient IViewLayoutManager layoutManager;
protected transient BrowserFrame frame;
protected transient IDatamartFilterGenerator filterGenerator;
protected transient BodyItem body;
protected transient Map<String, PropertyLookup> propertyLookupMapMap = new HashMap<>();
protected transient ReportGeneratorWorkSet workset;
protected Locale locale;
protected StreamResource reportResource;
protected transient IDataMart datamartInstance;
/** needs to be equivalent to the datamata ODA bundle symbolic name */
public static final String DATASOURCE_EXTENSION_ID = "org.eclipse.osbp.xtext.reportdsl.oda.datamart";
/**
* in order to have data in header and foooter areas we must provide them as
* translations. to get not mixed up with attribute name translations, this
* prefix must be used
*/
public static final String ATTRIBUTE_TRANSLATION_PREFIX = "$$$";
@Inject
protected IThemeResourceService themeResourceService;
@Inject
private IUser user;
@Inject
private IDSLMetadataService dslMetadataService;
@Inject
private IBlobService blobService;
@Inject
private IEventDispatcher eventDispatcher;
@Inject
public BaseReport() {
super();
layoutManager = new ViewLayoutManager();
}
@Inject
public BaseReport(VerticalLayout parent, IEclipseContext context, MApplication app) {
super(parent, context, app);
layoutManager = new ViewLayoutManager();
layoutManager.init(parent);
parent.addAttachListener(this);
parent.addDetachListener(this);
}
@Override
public void attach(final ClientConnector.AttachEvent event) {
user.addUserLocaleListener(this);
this.locale = user.getLocale();
filterGenerator.addFilterChangeListener(this);
eventDispatcher.addEventReceiver(this);
}
@Override
public void detach(final ClientConnector.DetachEvent event) {
user.removeUserLocaleListener(this);
filterGenerator.removeFilterChangeListener(this);
eventDispatcher.removeEventReceiver(this);
}
@Override
protected void preInit() {
workset = new ReportGeneratorWorkSet();
super.preInit();
}
public StreamResource getReportStreamResource() {
return getReportStreamResource(locale);
}
public StreamResource getReportStreamResource(Locale locale) {
setLocale(locale);
return reportResource;
}
@Override
protected void createView(VerticalLayout parent) {
initReport();
}
protected boolean getSelectById() {
return false;
}
protected abstract List<String> getStaticData();
public void addCss(ReportDesignHandle designHandle) {
if (getExternalCssURI() != null) {
CssStyleSheet css = new CssStyleSheet();
css.setFileName(getExternalCssURI());
css.setExternalCssURI(getExternalCssURI());
CssStyleSheetHandle cssh = new CssStyleSheetHandle(designHandle.getModuleHandle(), css);
try {
designHandle.addCss(cssh);
} catch (SemanticException e) {
LOGGER.error(e.getLocalizedMessage());
if (e.getCause() != null)
LOGGER.error(" " + e.getCause());
}
}
}
protected final void initReport() {
try {
LOGGER.debug("BaseReport " + getClass().getSimpleName() + " initReport");
SessionHandle session = BirtEngine.getDesignEngine().newSessionHandle(ULocale.forLocale(user.getLocale()));
SessionHandle.setBirtResourcePath("i18n/I18N");
if (getUsedReportDesignFilename() == null) {
// Create a new report design.
workset.setDesign(session.createDesign());
// The element factory creates instances of the various BIRT
// elements.
workset.setFactory(workset.getDesign().getElementFactory());
// Create a simple master page that describes how the report
// will appear when printed.
//
// Note: The report will fail to load in the BIRT designer
// unless you create a master page.
DesignElementHandle element = workset.getFactory().newSimpleMasterPage("Page Master"); //$NON-NLS-1$
workset.getDesign().getMasterPages().add(element);
// add external CSS
addCss(workset.getDesign());
body = new BodyItem(workset);
}
} catch (Exception e) {
LOGGER.error(e.getLocalizedMessage());
if (e.getCause() != null)
LOGGER.error(" " + e.getCause());
}
}
protected final void createFilter() {
datamartInstance = getDatamartInstance(user);
filterGenerator = new DatamartFilterGenerator(datamartInstance, dslMetadataService);
filterGenerator.createUIFilters(layoutManager);
}
public IDataMart getDatamartInstance() {
return datamartInstance;
}
protected abstract IDataMart getDatamartInstance(IUser user);
/**
* @return the explicit given file name of the report design file
*/
protected String getReportDesignFilename() {
return null;
}
/**
* @return either the explicit given file name, any automatic generated
* report design file or null
*/
protected final String getUsedReportDesignFilename() {
// --- either the explicit given file name ---
String retcode = getReportDesignFilename();
if (retcode == null) {
String pathName = getClass().getCanonicalName().replace(".", "/");
if (pathName.endsWith("Report")) {
pathName = pathName.substring(0, pathName.length() - "Report".length());
}
// --- or a copy of the automatic generated report file ---
retcode = "rptdesign/" + pathName + RPTDESIGN;
try {
getClass().getClassLoader().getResource(retcode).openStream();
} catch (Exception e1) {
// --- or the automatic generated report file ---
Collection<String> roles = getAuthenticatedRoles();
// for the moment - take the first role
if (roles != null && roles.iterator().hasNext()) {
retcode = "rptdesign-gen/" + pathName + roles.iterator().next() + RPTDESIGN;
} else {
retcode = "rptdesign-gen/" + pathName + RPTDESIGN;
}
try {
getClass().getClassLoader().getResource(retcode).openStream();
} catch (Exception e2) {
retcode = null;
}
}
}
return retcode;
}
protected String getExternalCssURI() {
return null;
}
protected String getExternalCssURIBundle() {
return null;
}
protected Rendering getRenderingAs() {
return Rendering.PDF_STREAM;
}
protected String getReportFilename() {
return getClass().getSimpleName() + getTimestampPostfix() + "-" + user.getLocale().toString();
}
protected final String getFileExtension() {
return getFileExtension(getRenderingAs());
}
final String getFileExtension(Rendering renderer) {
switch (renderer) {
case HTML_FILE:
case HTML_STREAM:
return ".html";
case PDF_FILE:
case PDF_STREAM:
case PDF_PRINT_STREAM:
return ".pdf";
default:
return ".unknown";
}
}
protected final String getTimestampPostfix() {
return "-" + ExtendedDate.timeStampToString();
}
@Override
protected final void createComponents() {
// remove any previous component
if (frame != null) {
layoutManager.getDataArea().removeComponent(frame);
frame = null;
}
frame = new BrowserFrame(null, null);
frame.setAlternateText("unable to display report");
frame.setSizeFull();
layoutManager.getDataArea().addComponent(frame);
layoutManager.getDataArea().setExpandRatio(frame, 1);
String filename = getReportFilename() + getFileExtension();
reportResource = new StreamResource(this, filename);
reportResource.setCacheTime(0);
frame.setSource(reportResource);
}
@SuppressWarnings("serial")
public void addPDFDownload(IToolbarAction target) {
MToolBar toolbar = target.getToolBar();
for (MToolBarElement element : toolbar.getChildren()) {
Object widget = element.getWidget();
if (widget instanceof Button) {
List<String> tags = element.getTags();
if (tags.contains(ReportActionEnum.REPORT_ACTION_DOWNLOAD_PDF.getLiteral())) {
FileDownloader fileDownloader = new FileDownloader(
new StreamResource(this, getReportFilename() + ".pdf") {
@Override
public DownloadStream getStream() {
final DownloadStream ds = new DownloadStream(getPDF(), getMIMEType(),
getFilename());
ds.setBufferSize(getBufferSize());
ds.setCacheTime(getCacheTime());
return ds;
}
});
fileDownloader.extend((Button) widget);
}
if (tags.contains(ReportActionEnum.REPORT_ACTION_PRINT_ON_SERVER_PDF.getLiteral())) {
((Button) widget).addClickListener(new Button.ClickListener() {
private static final long serialVersionUID = 3396112960709977314L;
@Override
public void buttonClick(ClickEvent event) {
PdfPrintService.printReportAsPdf(BaseReport.this, user.getPrintService());
}
});
}
}
}
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public Locale getLocale() {
return locale;
}
public void buildReportDesign(String fullQualifiedFileName) throws IOException {
try {
URL baseUrl = getClass().getClassLoader().getResource("/rptdesign-gen/.");
if (LOGGER.isDebugEnabled())
LOGGER.debug(baseUrl.toString());
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("{}", exceptionDetails);
}
workset.getDesign().saveAs(fullQualifiedFileName);
}
protected final Object getRunnableOrFilename() {
if (getUsedReportDesignFilename() != null) {
return getUsedReportDesignFilename();
} else {
return workset.getDesign();
}
}
/**
* @return the property lookup map defined inside the report dsl
*/
public Map<String, PropertyLookup> getPropertyLookupMap() {
return propertyLookupMapMap;
}
protected void add(DesignElementHandle handle) {
if (handle instanceof OdaDataSourceHandle) {
workset.getDesign().getModule().addElementID(handle.getElement());
// design.
} else if (handle instanceof OdaDataSetHandle) {
workset.getDesign().getModule().addElementID(handle.getElement());
} else {
try {
workset.getDesign().getBody().add(handle);
} catch (ContentException | NameException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("exception occured:{}", exceptionDetails);
}
}
}
public final ByteArrayInputStream getPDF(String path) {
try {
return BirtEngine.get(this, Rendering.PDF_FILE, path);
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("exception PDF occured:{}", exceptionDetails);
return null;
}
}
public final ByteArrayInputStream getHTML(String path) {
try {
return BirtEngine.get(this, Rendering.HTML_FILE, path);
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("exception HTML occured:{}", exceptionDetails);
return new ByteArrayInputStream(
(HTML_BODY + getClass().getSimpleName() + ": " + e.getLocalizedMessage() + BODY_HTML).getBytes());
}
}
public ByteArrayInputStream getPDF() {
try {
return BirtEngine.get(this, Rendering.PDF_STREAM);
} catch (Exception e) {
LOGGER.debug(getClass().getSimpleName() + " PDF_STREAM: " + e.getLocalizedMessage() + BODY_HTML);
return new ByteArrayInputStream(
(HTML_BODY + getClass().getSimpleName() + ": " + e.getLocalizedMessage() + BODY_HTML).getBytes());
}
}
public ByteArrayInputStream getPDFPrint() {
try {
return BirtEngine.get(this, Rendering.PDF_PRINT_STREAM);
} catch (Exception e) {
LOGGER.debug(getClass().getSimpleName() + " PDF_PRINT_STREAM: " + e.getLocalizedMessage() + BODY_HTML);
return new ByteArrayInputStream(
(HTML_BODY + getClass().getSimpleName() + ": " + e.getLocalizedMessage() + BODY_HTML).getBytes());
}
}
public ByteArrayInputStream getHTML() {
try {
return BirtEngine.get(this, Rendering.HTML_STREAM);
} catch (Exception e) {
LOGGER.debug(getClass().getSimpleName() + " HTML_STREAM: " + e.getLocalizedMessage() + BODY_HTML);
return new ByteArrayInputStream(
(HTML_BODY + getClass().getSimpleName() + ": " + e.getLocalizedMessage() + BODY_HTML).getBytes());
}
}
public ByteArrayInputStream getStream() {
return getStream(getRenderingAs());
}
protected ByteArrayInputStream getStream(Rendering renderer) {
try {
switch (renderer) {
case HTML_STREAM:
return getHTML();
case PDF_STREAM:
return getPDF();
case PDF_PRINT_STREAM:
return getPDFPrint();
default:
return null;
}
} catch (Exception e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String exceptionDetails = sw.toString();
LOGGER.error("{}", exceptionDetails);
}
return null;
}
public IDSLMetadataService getDslMetadataService() {
return dslMetadataService;
}
public IUser getUser() {
return user;
}
@Focus
public void setFocus() {
Component parent = getParent();
while (!(parent instanceof Panel) && parent != null) {
parent = parent.getParent();
}
if (parent != null) {
((Panel) parent).focus();
}
}
public void localeChanged(Locale locale) {
setLocale(locale);
if (layoutManager != null) {
layoutManager.setLabelValue(dslMetadataService.translate(locale.toLanguageTag(), getReportName()));
}
renderData();
}
@Override
public void filterChanged(DatamartFilter changedFilter) {
if (changedFilter != null) {
EventDispatcherEvent evnt = new EventDispatcherEvent(EventDispatcherCommand.SELECT, changedFilter.getName(),
getClass().getCanonicalName());
evnt.addData(changedFilter.getSelectedData());
eventDispatcher.sendEvent(evnt);
}
renderData();
}
@Override
public void receiveEvent(final EventDispatcherEvent event) {
switch (event.getCommand()) {
case SELECT:
if (!event.getSender().equals(getClass().getCanonicalName())) {
filterGenerator.selectItem(event, getSelectById());
}
break;
case REFRESH:
if (!event.getSender().equals(getClass().getCanonicalName())) {
renderData();
if(filterGenerator != null) {
filterGenerator.createUIFilters(layoutManager);
}
}
break;
case SAVE:
case DELETE:
if (!event.getSender().equals(getClass().getCanonicalName())) {
for (LEntity entity : getEntities()) {
String entityName = EntityUtils.getFQNForLEntity(entity);
detectDeletion(event, entity, entityName);
}
}
break;
default:
break;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void detectDeletion(final EventDispatcherEvent event, LEntity entity, String entityName) {
if (entityName.equals(event.getTopic())) {
List<DatamartPrimary<?>> primaryKeys = datamartInstance.getPrimaryList();
for (DatamartPrimary key : primaryKeys) {
if (entity.getPrimaryKeyAttribute() != null && entity.getPrimaryKeyAttribute().isId()
&& key.contains(event.getData().get(EventDispatcherDataTag.ID))) {
renderData();
if(filterGenerator != null) {
filterGenerator.createUIFilters(layoutManager);
}
}
}
}
}
private Set<LEntity> getEntities() {
HashSet<LEntity> entities = new HashSet<>();
DatamartDefinition datamart = (DatamartDefinition) dslMetadataService.getMetadata(
datamartInstance.getClass().getCanonicalName().replace("Datamart", ""),
DatamartDSLPackage.Literals.DATAMART_DEFINITION);
if (datamart == null) {
LOGGER.error("datamart with id " + datamartInstance.getClass().getCanonicalName() + " not found");
return entities;
}
if (datamart.getSource() instanceof DatamartEntity) {
entities.add(((DatamartEntity) datamart.getSource()).getEntityRef());
for (DatamartNavigation navigation : ((DatamartEntity) datamart.getSource()).getNavigations()) {
entities.add(navigation.getDatamartEntity().getEntityRef());
}
}
return entities;
}
public final void resetBean() {
filterGenerator = null;
}
protected abstract String getReportName();
public abstract void applyBeanFilter(Filter filter);
public abstract void applyBeanDto(Object dto);
@PreDestroy
@Override
public void preDestroy() {
user.removeUserLocaleListener(this);
eventDispatcher.removeEventReceiver(this);
layoutManager = null;
frame = null;
filterGenerator = null;
body = null;
propertyLookupMapMap = null;
workset = null;
reportResource = null;
super.preDestroy();
}
public IBlobService getBlobService() {
return blobService;
}
}