diff --git a/pom.xml b/pom.xml
index a86bfd92cb..4cc7360fac 100644
--- a/pom.xml
+++ b/pom.xml
@@ -618,6 +618,7 @@
spring-boot-keycloak
spring-boot-logging-log4j2
spring-boot-mvc
+ spring-boot-mvc-birt
spring-boot-ops
spring-boot-rest
spring-boot-data
@@ -1260,6 +1261,7 @@
spring-boot-keycloak
spring-boot-logging-log4j2
spring-boot-mvc
+ spring-boot-mvc-birt
spring-boot-ops
spring-boot-rest
spring-boot-data
diff --git a/spring-boot-mvc-birt/pom.xml b/spring-boot-mvc-birt/pom.xml
new file mode 100644
index 0000000000..05d3f3865a
--- /dev/null
+++ b/spring-boot-mvc-birt/pom.xml
@@ -0,0 +1,83 @@
+
+
+ 4.0.0
+ com.baeldung
+ spring-boot-mvc-birt
+ spring-boot-mvc-birt
+ 0.0.1-SNAPSHOT
+ jar
+ Module For Spring Boot Integration with BIRT
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-logging
+
+
+ ch.qos.logback
+ logback-classic
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ com.innoventsolutions.birt.runtime
+ org.eclipse.birt.runtime_4.8.0-20180626
+ 4.8.0
+
+
+
+ log4j
+ log4j
+ 1.2.17
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.6
+ provided
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+ 2.1.1.RELEASE
+ com.baeldung.springbootmvc.SpringBootMvcApplication
+ 1.8
+ 1.8
+
+
+
diff --git a/spring-boot-mvc-birt/reports/csv_data_report.rptdesign b/spring-boot-mvc-birt/reports/csv_data_report.rptdesign
new file mode 100644
index 0000000000..f390c5e69b
--- /dev/null
+++ b/spring-boot-mvc-birt/reports/csv_data_report.rptdesign
@@ -0,0 +1,2032 @@
+
+
+ Eclipse BIRT Designer Version 4.7.0.v201706222054
+ new_report
+
+
+ queryText
+ 5
+
+
+ HOME
+ 4
+
+
+ URI
+ 4
+
+
+ DELIMTYPE
+ 4
+
+
+ CHARSET
+ 4
+
+
+ INCLCOLUMNNAME
+ 4
+
+
+ INCLTYPELINE
+ 4
+
+
+ TRAILNULLCOLS
+ 4
+
+
+ OdaConnProfileName
+ 4
+
+
+ OdaConnProfileStorePath
+ 4
+
+
+ in
+ /templates/blank_report.gif
+ ltr
+ 96
+
+
+ reports/data.csv
+ COMMA
+ UTF-8
+ YES
+ NO
+ NO
+
+
+
+
+ nulls lowest
+
+
+ Student
+ dimension
+ Student
+
+
+ Math
+ measure
+ Math
+
+
+ Geography
+ measure
+ Geography
+
+
+ History
+ measure
+ History
+
+
+
+
+
+
+ 1
+ Student
+ string
+
+
+ 2
+ Math
+ integer
+
+
+ 3
+ Geography
+ integer
+
+
+ 4
+ History
+ integer
+
+
+
+ Data Source
+
+
+ 1
+ Student
+ Student
+ string
+ 12
+
+
+ 2
+ Math
+ Math
+ integer
+ 12
+
+
+ 3
+ Geography
+ Geography
+ integer
+ 12
+
+
+ 4
+ History
+ History
+ integer
+ 12
+
+
+
+
+
+ 2.0
+
+
+
+
+
+
+ Studen
+ 1
+
+ 12
+ -1
+ -1
+ Unknown
+
+
+ Studen
+
+
+
+
+
+
+ Math
+ 2
+
+ 12
+ -1
+ -1
+ Unknown
+
+
+ Math
+
+
+
+
+
+
+ Geography
+ 3
+
+ 12
+ -1
+ -1
+ Unknown
+
+
+ Geography
+
+
+
+
+
+
+ History
+ 4
+
+ 12
+ -1
+ -1
+ Unknown
+
+
+ History
+
+
+
+
+
+
+
+]]>
+
+
+
+
+
+
+
+
+
+
+
+ 7.947916666666667in
+
+ 2.15625in
+
+
+
+
+ 2
+ 1
+
+
+ 2.6.1
+ Bar Chart
+ Side-by-side
+
+
+
+ 0.0
+ 0.0
+ 0.0
+ 0.0
+
+
+ 3.0
+ 3.0
+ 3.0
+ 3.0
+
+ -1
+ -1
+ -1
+ -1
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+ true
+
+
+
+
+ 0.0
+ 0.0
+ 0.0
+ 0.0
+
+
+ 3.0
+ 3.0
+ 3.0
+ 3.0
+
+ -1
+ -1
+ -1
+ -1
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+ true
+ 5
+ 5
+
+
+
+ 0
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+
+ 0.0
+ 0.0
+ 0.0
+ 0.0
+
+
+
+
+
+ 0.0
+ 0.0
+ 0.0
+ 0.0
+
+
+ 3.0
+ 3.0
+ 3.0
+ 3.0
+
+ -1
+ -1
+ -1
+ -1
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+ true
+
+
+
+ 0
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+
+ 2.0
+ 2.0
+ 2.0
+ 2.0
+
+
+
+
+
+
+
+
+ Vertical
+ Top_Bottom
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ true
+
+ Right
+ Series
+
+
+
+
+
+
+
+
+ 0
+ 255
+ 255
+ 255
+
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+
+ 0.0
+ 2.0
+ 0.0
+ 3.0
+
+ false
+
+ Above
+ false
+
+
+ 0.0
+ 0.0
+ 572.25
+ 286.125
+
+
+ 3.0
+ 3.0
+ 3.0
+ 3.0
+
+ -1
+ -1
+ -1
+ -1
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ false
+
+ true
+
+ Two_Dimensional
+ Points
+ 10.0
+
+ enable.area.alt
+ false
+
+
+
+ A, B, C
+
+
+ 5,4,12
+ 0
+
+
+ 10.0,8.0,24.0
+ 1
+
+
+ 15.0,12.0,36.0
+ 2
+
+
+
+ ToggleSerieVisibility
+
+
+
+ This chart contains no data.
+
+
+ Center
+ Center
+
+
+
+
+ 64
+ 127
+ 127
+ 127
+
+
+
+ 128
+ 127
+ 127
+ 127
+
+ true
+
+
+ 10.0
+ 10.0
+ 10.0
+ 10.0
+
+ false
+
+
+ Text
+
+
+ X-Axis Title
+
+ 14.0
+ true
+
+ Center
+ Center
+
+
+
+
+ 0
+ 255
+ 255
+ 255
+
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+
+
+ 0.0
+ 2.0
+ 0.0
+ 3.0
+
+ false
+
+ Below
+
+ Linear
+
+
+ Y-Axis Title
+
+ 14.0
+ true
+
+ Center
+ Center
+
+
+
+
+ 0
+ 255
+ 255
+ 255
+
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+
+
+ 0.0
+ 2.0
+ 0.0
+ 3.0
+
+ false
+
+ Left
+
+
+
+
+ Numeric
+
+
+
+
+ 255
+ 80
+ 166
+ 218
+
+
+ 255
+ 242
+ 88
+ 106
+
+
+ 255
+ 232
+ 172
+ 57
+
+
+ 255
+ 128
+ 255
+ 128
+
+
+ 255
+ 64
+ 128
+ 128
+
+
+ 255
+ 128
+ 128
+ 192
+
+
+ 255
+ 170
+ 85
+ 85
+
+
+ 255
+ 128
+ 128
+ 0
+
+
+ 255
+ 192
+ 192
+ 192
+
+
+ 255
+ 255
+ 255
+ 128
+
+
+ 255
+ 128
+ 192
+ 128
+
+
+ 255
+ 7
+ 146
+ 94
+
+
+ 255
+ 0
+ 128
+ 255
+
+
+ 255
+ 255
+ 128
+ 192
+
+
+ 255
+ 0
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 128
+
+
+ 255
+ 0
+ 128
+ 192
+
+
+ 255
+ 255
+ 0
+ 255
+
+
+ 255
+ 128
+ 64
+ 64
+
+
+ 255
+ 255
+ 128
+ 64
+
+
+ 255
+ 80
+ 240
+ 120
+
+
+ 255
+ 0
+ 64
+ 128
+
+
+ 255
+ 128
+ 0
+ 64
+
+
+ 255
+ 255
+ 0
+ 128
+
+
+ 255
+ 128
+ 128
+ 64
+
+
+ 255
+ 128
+ 128
+ 128
+
+
+ 255
+ 255
+ 128
+ 255
+
+
+ 255
+ 0
+ 64
+ 0
+
+
+ 255
+ 0
+ 0
+ 0
+
+
+ 255
+ 255
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 0
+
+
+
+ true
+
+
+ row["Geography"]
+
+ Text
+ Sum
+
+
+ Geo
+
+
+ Orthogonal_Value
+
+ ,
+
+ Outside
+ false
+
+ onmouseover
+
+ Show_Tooltip
+
+
+ 200
+
+
+
+ Rectangle
+
+
+ Text
+ Sum
+
+
+
+
+
+
+ Numeric
+
+
+
+
+ 255
+ 242
+ 88
+ 106
+
+
+ 255
+ 232
+ 172
+ 57
+
+
+ 255
+ 128
+ 255
+ 128
+
+
+ 255
+ 64
+ 128
+ 128
+
+
+ 255
+ 128
+ 128
+ 192
+
+
+ 255
+ 170
+ 85
+ 85
+
+
+ 255
+ 128
+ 128
+ 0
+
+
+ 255
+ 192
+ 192
+ 192
+
+
+ 255
+ 255
+ 255
+ 128
+
+
+ 255
+ 128
+ 192
+ 128
+
+
+ 255
+ 7
+ 146
+ 94
+
+
+ 255
+ 0
+ 128
+ 255
+
+
+ 255
+ 255
+ 128
+ 192
+
+
+ 255
+ 0
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 128
+
+
+ 255
+ 0
+ 128
+ 192
+
+
+ 255
+ 255
+ 0
+ 255
+
+
+ 255
+ 128
+ 64
+ 64
+
+
+ 255
+ 255
+ 128
+ 64
+
+
+ 255
+ 80
+ 240
+ 120
+
+
+ 255
+ 0
+ 64
+ 128
+
+
+ 255
+ 128
+ 0
+ 64
+
+
+ 255
+ 255
+ 0
+ 128
+
+
+ 255
+ 128
+ 128
+ 64
+
+
+ 255
+ 128
+ 128
+ 128
+
+
+ 255
+ 255
+ 128
+ 255
+
+
+ 255
+ 0
+ 64
+ 0
+
+
+ 255
+ 0
+ 0
+ 0
+
+
+ 255
+ 255
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 0
+
+
+ 255
+ 80
+ 166
+ 218
+
+
+
+ true
+
+
+ row["History"]
+
+ false
+ Text
+ Sum
+
+
+ History
+
+
+ Orthogonal_Value
+
+ ,
+
+ Outside
+ false
+
+ onmouseover
+
+ Show_Tooltip
+
+
+ 200
+
+
+
+ Rectangle
+
+
+ Text
+ Sum
+
+
+
+
+
+
+ Numeric
+
+
+
+
+ 255
+ 232
+ 172
+ 57
+
+
+ 255
+ 128
+ 255
+ 128
+
+
+ 255
+ 64
+ 128
+ 128
+
+
+ 255
+ 128
+ 128
+ 192
+
+
+ 255
+ 170
+ 85
+ 85
+
+
+ 255
+ 128
+ 128
+ 0
+
+
+ 255
+ 192
+ 192
+ 192
+
+
+ 255
+ 255
+ 255
+ 128
+
+
+ 255
+ 128
+ 192
+ 128
+
+
+ 255
+ 7
+ 146
+ 94
+
+
+ 255
+ 0
+ 128
+ 255
+
+
+ 255
+ 255
+ 128
+ 192
+
+
+ 255
+ 0
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 128
+
+
+ 255
+ 0
+ 128
+ 192
+
+
+ 255
+ 255
+ 0
+ 255
+
+
+ 255
+ 128
+ 64
+ 64
+
+
+ 255
+ 255
+ 128
+ 64
+
+
+ 255
+ 80
+ 240
+ 120
+
+
+ 255
+ 0
+ 64
+ 128
+
+
+ 255
+ 128
+ 0
+ 64
+
+
+ 255
+ 255
+ 0
+ 128
+
+
+ 255
+ 128
+ 128
+ 64
+
+
+ 255
+ 128
+ 128
+ 128
+
+
+ 255
+ 255
+ 128
+ 255
+
+
+ 255
+ 0
+ 64
+ 0
+
+
+ 255
+ 0
+ 0
+ 0
+
+
+ 255
+ 255
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 0
+
+
+ 255
+ 80
+ 166
+ 218
+
+
+ 255
+ 242
+ 88
+ 106
+
+
+
+ true
+
+
+ row["Math"]
+
+ false
+ Text
+ Sum
+
+
+ Math
+
+
+ Orthogonal_Value
+
+ ,
+
+ Outside
+ false
+
+ onmouseover
+
+ Show_Tooltip
+
+
+ 200
+
+
+
+ Rectangle
+
+
+ Text
+ Sum
+
+
+ Vertical
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ true
+
+
+ Left
+
+
+
+ 1
+
+ 255
+ 196
+ 196
+ 196
+
+ false
+
+ Across
+
+
+ 1
+
+ 255
+ 196
+ 196
+ 196
+
+ true
+
+
+
+
+
+ 1
+
+ 255
+ 225
+ 225
+ 225
+
+ false
+
+ Across
+
+
+ 1
+
+ 255
+ 225
+ 225
+ 225
+
+ false
+
+
+
+ 5
+
+
+ Min
+
+ 0.0
+
+
+ true
+ false
+
+
+
+
+
+
+
+ 255
+ 80
+ 166
+ 218
+
+
+ 255
+ 242
+ 88
+ 106
+
+
+ 255
+ 232
+ 172
+ 57
+
+
+ 255
+ 128
+ 255
+ 128
+
+
+ 255
+ 64
+ 128
+ 128
+
+
+ 255
+ 128
+ 128
+ 192
+
+
+ 255
+ 170
+ 85
+ 85
+
+
+ 255
+ 128
+ 128
+ 0
+
+
+ 255
+ 192
+ 192
+ 192
+
+
+ 255
+ 255
+ 255
+ 128
+
+
+ 255
+ 128
+ 192
+ 128
+
+
+ 255
+ 7
+ 146
+ 94
+
+
+ 255
+ 0
+ 128
+ 255
+
+
+ 255
+ 255
+ 128
+ 192
+
+
+ 255
+ 0
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 128
+
+
+ 255
+ 0
+ 128
+ 192
+
+
+ 255
+ 255
+ 0
+ 255
+
+
+ 255
+ 128
+ 64
+ 64
+
+
+ 255
+ 255
+ 128
+ 64
+
+
+ 255
+ 80
+ 240
+ 120
+
+
+ 255
+ 0
+ 64
+ 128
+
+
+ 255
+ 128
+ 0
+ 64
+
+
+ 255
+ 255
+ 0
+ 128
+
+
+ 255
+ 128
+ 128
+ 64
+
+
+ 255
+ 128
+ 128
+ 128
+
+
+ 255
+ 255
+ 128
+ 255
+
+
+ 255
+ 0
+ 64
+ 0
+
+
+ 255
+ 0
+ 0
+ 0
+
+
+ 255
+ 255
+ 255
+ 255
+
+
+ 255
+ 255
+ 128
+ 0
+
+
+
+ true
+
+
+ row["Student"]
+
+
+
+
+ Orthogonal_Value
+
+ ,
+
+ Outside
+ false
+
+
+ true
+ Text
+ Sum
+
+
+ Horizontal
+
+
+ 1
+
+ 255
+ 0
+ 0
+ 0
+
+ true
+
+
+ Below
+
+
+
+ 1
+
+ 255
+ 196
+ 196
+ 196
+
+ false
+
+ Across
+
+
+ 1
+
+ 255
+ 196
+ 196
+ 196
+
+ true
+
+
+
+
+
+ 1
+
+ 255
+ 225
+ 225
+ 225
+
+ false
+
+ Across
+
+
+ 1
+
+ 255
+ 225
+ 225
+ 225
+
+ false
+
+
+
+ 5
+
+
+ Min
+
+ 0.0
+
+
+ true
+ true
+ false
+
+ Vertical
+ 50.0
+
+
+ -20.0
+ 45.0
+ 0.0
+ None
+
+
+
+]]>
+ SVG
+ true
+ 286.125pt
+ 572.25pt
+ Data Set
+
+
+ Student
+ Student
+ dataSetRow["Student"]
+ string
+
+
+ Math
+ Math
+ dataSetRow["Math"]
+ integer
+
+
+ Geography
+ Geography
+ dataSetRow["Geography"]
+ integer
+
+
+ History
+ History
+ dataSetRow["History"]
+ integer
+
+
+
+ |
+
+
+
+ 2
+ 1
+
+ Data Set
+
+
+ Student
+ Student
+ dataSetRow["Student"]
+ string
+
+
+ Math
+ Math
+ dataSetRow["Math"]
+ integer
+
+
+ Geography
+ Geography
+ dataSetRow["Geography"]
+ integer
+
+
+ History
+ History
+ dataSetRow["History"]
+ integer
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+ Student
+
+ |
+
+
+ Math
+
+ |
+
+
+ Geography
+
+ |
+
+
+ History
+
+ |
+
+
+
+
+ |
+
+
+
+
diff --git a/spring-boot-mvc-birt/reports/data.csv b/spring-boot-mvc-birt/reports/data.csv
new file mode 100644
index 0000000000..d05e58415e
--- /dev/null
+++ b/spring-boot-mvc-birt/reports/data.csv
@@ -0,0 +1,4 @@
+Student, Math, Geography, History
+Bill, 10,3,8
+Tom, 5,6,5
+Anne, 7, 4,9
\ No newline at end of file
diff --git a/spring-boot-mvc-birt/reports/static_report.rptdesign b/spring-boot-mvc-birt/reports/static_report.rptdesign
new file mode 100644
index 0000000000..d96ff76856
--- /dev/null
+++ b/spring-boot-mvc-birt/reports/static_report.rptdesign
@@ -0,0 +1,27 @@
+
+
+ Sample Report
+
+
+
+
+
+ 100%
+
+
+
+
+
+ url
+ "https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png"
+
+ |
+
+
+ |
+
+
+
+
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java
new file mode 100644
index 0000000000..f1e1619a58
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/designer/ReportDesignApplication.java
@@ -0,0 +1,93 @@
+package com.baeldung.birt.designer;
+
+import com.ibm.icu.util.ULocale;
+import org.apache.log4j.Logger;
+import org.eclipse.birt.core.exception.BirtException;
+import org.eclipse.birt.core.framework.Platform;
+import org.eclipse.birt.report.model.api.*;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+import java.io.File;
+import java.io.IOException;
+
+@SpringBootApplication
+public class ReportDesignApplication implements CommandLineRunner {
+
+ private static final Logger log = Logger.getLogger(ReportDesignApplication.class);
+
+ @Value("${reports.relative.path}")
+ private String REPORTS_FOLDER;
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(ReportDesignApplication.class).web(WebApplicationType.NONE).build().run(args);
+ }
+
+ @Override public void run(String... args) throws Exception {
+ buildReport();
+ }
+
+ private void buildReport() throws IOException, BirtException {
+ final DesignConfig config = new DesignConfig();
+
+ final IDesignEngine engine;
+ try {
+ Platform.startup(config);
+ IDesignEngineFactory factory = (IDesignEngineFactory) Platform
+ .createFactoryObject(IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY);
+ engine = factory.createDesignEngine(config);
+
+ } catch (Exception ex) {
+ log.error("Exception during creation of DesignEngine", ex);
+ throw ex;
+ }
+
+ SessionHandle session = engine.newSessionHandle(ULocale.ENGLISH);
+
+ ReportDesignHandle design = session.createDesign();
+ design.setTitle("Sample Report");
+
+ // The element factory creates instances of the various BIRT elements.
+ ElementFactory factory = design.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 = factory.newSimpleMasterPage("Page Master"); //$NON-NLS-1$
+ design.getMasterPages().add(element);
+
+ // Create a grid
+ GridHandle grid = factory.newGridItem(null, 2 /* cols */, 1 /* row */);
+ design.getBody().add(grid);
+ grid.setWidth("100%");
+
+ RowHandle row0 = (RowHandle) grid.getRows().get(0);
+
+ // Create an image and add it to the first cell.
+ ImageHandle image = factory.newImage(null);
+ CellHandle cell = (CellHandle) row0.getCells().get(0);
+ cell.getContent().add(image);
+ image.setURL("\"https://www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png\"");
+
+ // Create a label and add it to the second cell.
+ LabelHandle label = factory.newLabel(null);
+ cell = (CellHandle) row0.getCells().get(1);
+ cell.getContent().add(label);
+ label.setText("Hello, Baeldung world!");
+
+ // Save the design and close it.
+ File report = new File(REPORTS_FOLDER);
+ report.mkdirs();
+
+ design.saveAs(new File(report, "static_report.rptdesign").getAbsolutePath());
+ design.close();
+ log.info("Report generated");
+ }
+
+}
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java
new file mode 100644
index 0000000000..6d72017c9d
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/ReportEngineApplication.java
@@ -0,0 +1,29 @@
+package com.baeldung.birt.engine;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@SpringBootApplication
+@EnableWebMvc
+public class ReportEngineApplication implements WebMvcConfigurer {
+ @Value("${reports.relative.path}")
+ private String reportsPath;
+ @Value("${images.relative.path}")
+ private String imagesPath;
+
+ public static void main(final String[] args) {
+ SpringApplication.run(ReportEngineApplication.class, args);
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry
+ .addResourceHandler(reportsPath + imagesPath + "/**")
+ .addResourceLocations("file:///" + System.getProperty("user.dir") + "/" + reportsPath + imagesPath);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java
new file mode 100644
index 0000000000..e2405d02ec
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/controller/BirtReportController.java
@@ -0,0 +1,51 @@
+package com.baeldung.birt.engine.controller;
+
+import com.baeldung.birt.engine.dto.OutputType;
+import com.baeldung.birt.engine.dto.Report;
+import com.baeldung.birt.engine.service.BirtReportService;
+import org.apache.log4j.Logger;
+import org.eclipse.birt.report.engine.api.EngineException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+@Controller
+public class BirtReportController {
+ private static final Logger log = Logger.getLogger(BirtReportController.class);
+
+ @Autowired
+ private BirtReportService reportService;
+
+ @RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report")
+ @ResponseBody
+ public List listReports() {
+ return reportService.getReports();
+ }
+
+ @RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "/report/reload")
+ @ResponseBody
+ public ResponseEntity reloadReports(HttpServletResponse response) {
+ try {
+ log.info("Reloading reports");
+ reportService.loadReports();
+ } catch (EngineException e) {
+ log.error("There was an error reloading the reports in memory: ", e);
+ return ResponseEntity.status(HttpServletResponse.SC_INTERNAL_SERVER_ERROR).build();
+ }
+ return ResponseEntity.ok().build();
+ }
+
+ @RequestMapping(method = RequestMethod.GET, value = "/report/{name}")
+ @ResponseBody
+ public void generateFullReport(HttpServletResponse response, HttpServletRequest request,
+ @PathVariable("name") String name, @RequestParam("output") String output) {
+ log.info("Generating full report: " + name + "; format: " + output);
+ OutputType format = OutputType.from(output);
+ reportService.generateMainReport(name, format, response, request);
+ }
+}
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java
new file mode 100644
index 0000000000..3180a347ba
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/OutputType.java
@@ -0,0 +1,21 @@
+package com.baeldung.birt.engine.dto;
+
+import org.eclipse.birt.report.engine.api.IRenderOption;
+
+public enum OutputType {
+ HTML(IRenderOption.OUTPUT_FORMAT_HTML),
+ PDF(IRenderOption.OUTPUT_FORMAT_PDF),
+ INVALID("invalid");
+
+ String val;
+ OutputType(String val) {
+ this.val = val;
+ }
+
+ public static OutputType from(String text) {
+ for (OutputType output : values()) {
+ if(output.val.equalsIgnoreCase(text)) return output;
+ }
+ return INVALID;
+ }
+}
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java
new file mode 100644
index 0000000000..a2d2444b80
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/dto/Report.java
@@ -0,0 +1,37 @@
+package com.baeldung.birt.engine.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Report DTO class
+ */
+@Data
+@NoArgsConstructor
+public class Report {
+ private String title;
+ private String name;
+ private List parameters;
+
+ public Report(String title, String name) {
+ this.title = title;
+ this.name = name;
+ }
+
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class Parameter {
+ private String title;
+ private String name;
+ private ParameterType type;
+
+ }
+
+ public enum ParameterType {
+ INT, STRING
+ }
+}
diff --git a/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java
new file mode 100644
index 0000000000..540bbbb530
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/java/com/baeldung/birt/engine/service/BirtReportService.java
@@ -0,0 +1,168 @@
+package com.baeldung.birt.engine.service;
+
+import com.baeldung.birt.engine.dto.OutputType;
+import com.baeldung.birt.engine.dto.Report;
+import org.eclipse.birt.core.exception.BirtException;
+import org.eclipse.birt.core.framework.Platform;
+import org.eclipse.birt.report.engine.api.*;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.util.*;
+
+@Service
+public class BirtReportService implements ApplicationContextAware, DisposableBean {
+ @Value("${reports.relative.path}")
+ private String reportsPath;
+ @Value("${images.relative.path}")
+ private String imagesPath;
+
+ private HTMLServerImageHandler htmlImageHandler = new HTMLServerImageHandler();
+
+ @Autowired
+ private ResourceLoader resourceLoader;
+ @Autowired
+ private ServletContext servletContext;
+
+ private IReportEngine birtEngine;
+ private ApplicationContext context;
+ private String imageFolder;
+
+ private Map reports = new HashMap<>();
+
+ @SuppressWarnings("unchecked")
+ @PostConstruct
+ protected void initialize() throws BirtException {
+ EngineConfig config = new EngineConfig();
+ config.getAppContext().put("spring", this.context);
+ Platform.startup(config);
+ IReportEngineFactory factory = (IReportEngineFactory) Platform
+ .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
+ birtEngine = factory.createReportEngine(config);
+ imageFolder = System.getProperty("user.dir") + File.separatorChar + reportsPath + imagesPath;
+ loadReports();
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) {
+ this.context = context;
+ }
+
+ /**
+ * Load report files to memory
+ *
+ */
+ public void loadReports() throws EngineException {
+ File folder = new File(reportsPath);
+ for (String file : Objects.requireNonNull(folder.list())) {
+ if (!file.endsWith(".rptdesign")) {
+ continue;
+ }
+
+ reports.put(file.replace(".rptdesign", ""),
+ birtEngine.openReportDesign(folder.getAbsolutePath() + File.separator + file));
+
+ }
+ }
+
+ public List getReports() {
+ List response = new ArrayList<>();
+ for (Map.Entry entry : reports.entrySet()) {
+ IReportRunnable report = reports.get(entry.getKey());
+ IGetParameterDefinitionTask task = birtEngine.createGetParameterDefinitionTask(report);
+ Report reportItem = new Report(report.getDesignHandle().getProperty("title").toString(), entry.getKey());
+ for (Object h : task.getParameterDefns(false)) {
+ IParameterDefn def = (IParameterDefn) h;
+ reportItem.getParameters()
+ .add(new Report.Parameter(def.getPromptText(), def.getName(), getParameterType(def)));
+ }
+ response.add(reportItem);
+ }
+ return response;
+ }
+
+ private Report.ParameterType getParameterType(IParameterDefn param) {
+ if (IParameterDefn.TYPE_INTEGER == param.getDataType()) {
+ return Report.ParameterType.INT;
+ }
+ return Report.ParameterType.STRING;
+ }
+
+ public void generateMainReport(String reportName, OutputType output, HttpServletResponse response, HttpServletRequest request) {
+ switch (output) {
+ case HTML:
+ generateHTMLReport(reports.get(reportName), response, request);
+ break;
+ case PDF:
+ generatePDFReport(reports.get(reportName), response, request);
+ break;
+ default:
+ throw new IllegalArgumentException("Output type not recognized:" + output);
+ }
+ }
+
+ /**
+ * Generate a report as HTML
+ */
+ @SuppressWarnings("unchecked")
+ private void generateHTMLReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) {
+ IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report);
+ response.setContentType(birtEngine.getMIMEType("html"));
+ IRenderOption options = new RenderOption();
+ HTMLRenderOption htmlOptions = new HTMLRenderOption(options);
+ htmlOptions.setOutputFormat("html");
+ htmlOptions.setBaseImageURL("/" + reportsPath + imagesPath);
+ htmlOptions.setImageDirectory(imageFolder);
+ htmlOptions.setImageHandler(htmlImageHandler);
+ runAndRenderTask.setRenderOption(htmlOptions);
+ runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_BIRT_VIEWER_HTTPSERVET_REQUEST, request);
+
+ try {
+ htmlOptions.setOutputStream(response.getOutputStream());
+ runAndRenderTask.run();
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ runAndRenderTask.close();
+ }
+ }
+
+ /**
+ * Generate a report as PDF
+ */
+ @SuppressWarnings("unchecked")
+ private void generatePDFReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) {
+ IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report);
+ response.setContentType(birtEngine.getMIMEType("pdf"));
+ IRenderOption options = new RenderOption();
+ PDFRenderOption pdfRenderOption = new PDFRenderOption(options);
+ pdfRenderOption.setOutputFormat("pdf");
+ runAndRenderTask.setRenderOption(pdfRenderOption);
+ runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT, request);
+
+ try {
+ pdfRenderOption.setOutputStream(response.getOutputStream());
+ runAndRenderTask.run();
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ runAndRenderTask.close();
+ }
+ }
+
+ @Override
+ public void destroy() {
+ birtEngine.destroy();
+ Platform.shutdown();
+ }
+}
diff --git a/spring-boot-mvc-birt/src/main/resources/application.properties b/spring-boot-mvc-birt/src/main/resources/application.properties
new file mode 100644
index 0000000000..5b015c70b1
--- /dev/null
+++ b/spring-boot-mvc-birt/src/main/resources/application.properties
@@ -0,0 +1,2 @@
+reports.relative.path=reports/
+images.relative.path=images/
\ No newline at end of file