From e777491d76154c6fe5a82471443d81bb5de313f9 Mon Sep 17 00:00:00 2001 From: John Woodlock Date: Sat, 13 Apr 2013 19:33:16 +0100 Subject: [PATCH] wip mifosx-195 refactor list reports api for maintenance function use and change api-docs --- api-docs/apiLive.htm | 818 ++------------- .../dataqueries/api/ReportsApiResource.java | 26 +- .../dataqueries/data/ReportData.java | 47 + .../dataqueries/data/ReportParameterData.java | 24 + .../data/ReportParameterJoinData.java | 86 ++ .../service/ReadReportingService.java | 18 +- .../service/ReadReportingServiceImpl.java | 962 +++++++++++------- 7 files changed, 836 insertions(+), 1145 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterJoinData.java diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 9195fe296..3da9f7d10 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -10254,19 +10254,6 @@ No Request Body:

Reports

-

The reports resource allows you to run and receive output - from pre-defined Mifos X reports. The default output is a JSON - formatted "Generic Resultset". The Generic Resultset contains - Column Heading as well as Data information. However, you can - export to CSV format by simply adding "&exportCSV=true" to the end - of your URL.

-

If Pentaho reports have been pre-defined, they can also be - run through this resource. Pentaho reports can return HTML, PDF or - CSV formats.

-

The Mifos X Individual Lending client application uses a - JQuery plugin called stretchyreporting which, itself, uses this - reports resource to provide a pretty flexible reporting User - Interface (UI).

@@ -10276,753 +10263,67 @@ No Request Body:

List Reports

-

Lists all reports and their parameters. If a report has more - than one parameter it will be listed the same number of times as - it has parameters.

+

Lists all reports and their parameters.

-
Arguments
-
-
exportCSV
-
- optional, The only valid value is 'true'. If any - other value is provided the argument will be ignored -
-
Output will be delivered as a CSV file instead of JSON.
-
-

Example Requests:

+

Example Request:

reports
-
-
-
reports?exportCSV=true
GET https://DomainName/api/v1/reports -{ - "columnHeaders": [ - { - "columnName": "report_id", - "columnType": "INT", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "report_name", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "report_type", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "report_subtype", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "report_category", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "parameter_id", - "columnType": "INT", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "report_parameter_name", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - }, - { - "columnName": "parameter_name", - "columnType": "VARCHAR", - "isColumnNullable": false, - "isColumnPrimaryKey": false, - "columnValues": [] - } - ], - "data": [ - { - "row": [ - "10", - "Active Loans Portfolio Status", - "Table", - null, - "Loan", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "10", - "Active Loans Portfolio Status", - "Table", - null, - "Loan", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "10", - "Active Loans Portfolio Status", - "Table", - null, - "Loan", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "10", - "Active Loans Portfolio Status", - "Table", - null, - "Loan", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "10", - "Active Loans Portfolio Status", - "Table", - null, - "Loan", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "11", - "Active Loans Summary per Branch", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "11", - "Active Loans Summary per Branch", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "48", - "Balance Sheet", - "Pentaho", - null, - "Accounting", - "5", - "branch", - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "48", - "Balance Sheet", - "Pentaho", - null, - "Accounting", - "41", - "date", - "endDateSelect" - ] - }, - { - "row": [ - "1", - "Client Listing", - "Table", - null, - "Client", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "2", - "Client Loans Listing", - "Table", - null, - "Client", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "2", - "Client Loans Listing", - "Table", - null, - "Client", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "2", - "Client Loans Listing", - "Table", - null, - "Client", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "2", - "Client Loans Listing", - "Table", - null, - "Client", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "2", - "Client Loans Listing", - "Table", - null, - "Client", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "20", - "Funds Disbursed Between Dates Summary", - "Table", - null, - "Fund", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "20", - "Funds Disbursed Between Dates Summary", - "Table", - null, - "Fund", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "20", - "Funds Disbursed Between Dates Summary", - "Table", - null, - "Fund", - "40", - null, - "startDateSelect" - ] - }, - { - "row": [ - "20", - "Funds Disbursed Between Dates Summary", - "Table", - null, - "Fund", - "41", - null, - "endDateSelect" - ] - }, - { - "row": [ - "21", - "Funds Disbursed Between Dates Summary by Office", - "Table", - null, - "Fund", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "21", - "Funds Disbursed Between Dates Summary by Office", - "Table", - null, - "Fund", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "21", - "Funds Disbursed Between Dates Summary by Office", - "Table", - null, - "Fund", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "21", - "Funds Disbursed Between Dates Summary by Office", - "Table", - null, - "Fund", - "40", - null, - "startDateSelect" - ] - }, - { - "row": [ - "21", - "Funds Disbursed Between Dates Summary by Office", - "Table", - null, - "Fund", - "41", - null, - "endDateSelect" - ] - }, - { - "row": [ - "49", - "Income Statement", - "Pentaho", - null, - "Accounting", - "5", - "branch", - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "49", - "Income Statement", - "Pentaho", - null, - "Accounting", - "40", - "fromDate", - "startDateSelect" - ] - }, - { - "row": [ - "49", - "Income Statement", - "Pentaho", - null, - "Accounting", - "41", - "toDate", - "endDateSelect" - ] - }, - { - "row": [ - "5", - "Loans Awaiting Disbursal", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "5", - "Loans Awaiting Disbursal", - "Table", - null, - "Loan Portfolio", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "5", - "Loans Awaiting Disbursal", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "5", - "Loans Awaiting Disbursal", - "Table", - null, - "Loan Portfolio", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "5", - "Loans Awaiting Disbursal", - "Table", - null, - "Loan Portfolio", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "6", - "Loans Awaiting Disbursal Summary", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "6", - "Loans Awaiting Disbursal Summary", - "Table", - null, - "Loan Portfolio", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "6", - "Loans Awaiting Disbursal Summary", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "6", - "Loans Awaiting Disbursal Summary", - "Table", - null, - "Loan Portfolio", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "6", - "Loans Awaiting Disbursal Summary", - "Table", - null, - "Loan Portfolio", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "7", - "Loans Awaiting Disbursal Summary by Month", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "7", - "Loans Awaiting Disbursal Summary by Month", - "Table", - null, - "Loan Portfolio", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "7", - "Loans Awaiting Disbursal Summary by Month", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "7", - "Loans Awaiting Disbursal Summary by Month", - "Table", - null, - "Loan Portfolio", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "7", - "Loans Awaiting Disbursal Summary by Month", - "Table", - null, - "Loan Portfolio", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "15", - "Portfolio at Risk", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "15", - "Portfolio at Risk", - "Table", - null, - "Loan Portfolio", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "15", - "Portfolio at Risk", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "15", - "Portfolio at Risk", - "Table", - null, - "Loan Portfolio", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "15", - "Portfolio at Risk", - "Table", - null, - "Loan Portfolio", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "16", - "Portfolio at Risk by Branch", - "Table", - null, - "Loan Portfolio", - "5", - null, - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "16", - "Portfolio at Risk by Branch", - "Table", - null, - "Loan Portfolio", - "6", - null, - "loanOfficerIdSelectAll" - ] - }, - { - "row": [ - "16", - "Portfolio at Risk by Branch", - "Table", - null, - "Loan Portfolio", - "10", - null, - "currencyIdSelectAll" - ] - }, - { - "row": [ - "16", - "Portfolio at Risk by Branch", - "Table", - null, - "Loan Portfolio", - "20", - null, - "fundIdSelectAll" - ] - }, - { - "row": [ - "16", - "Portfolio at Risk by Branch", - "Table", - null, - "Loan Portfolio", - "25", - null, - "loanProductIdSelectAll" - ] - }, - { - "row": [ - "50", - "Trial Balance", - "Pentaho", - null, - "Accounting", - "5", - "branch", - "OfficeIdSelectOne" - ] - }, - { - "row": [ - "50", - "Trial Balance", - "Pentaho", - null, - "Accounting", - "40", - "fromDate", - "startDateSelect" - ] - }, - { - "row": [ - "50", - "Trial Balance", - "Pentaho", - null, - "Accounting", - "41", - "toDate", - "endDateSelect" - ] - } +[ + { + "reportId": 1, + "reportName": "Client Listing", + "reportType": "Table", + "reportCategory": "Client", + "coreReport": true, + "useReport": true, + "reportParameters": [ + { + "reportParameterId": 5, + "parameterName": "OfficeIdSelectOne" + } ] -} - + }, + { + "reportId": 2, + "reportName": "Client Loans Listing", + "reportType": "Table", + "reportCategory": "Client", + "coreReport": true, + "useReport": true, + "reportParameters": [ + { + "reportParameterId": 5, + "parameterName": "OfficeIdSelectOne" + }, + { + "reportParameterId": 6, + "parameterName": "loanOfficerIdSelectAll" + }, + { + "reportParameterId": 10, + "parameterName": "currencyIdSelectAll" + }, + { + "reportParameterId": 20, + "parameterName": "fundIdSelectAll" + }, + { + "reportParameterId": 25, + "parameterName": "loanProductIdSelectAll" + }, + { + "reportParameterId": 26, + "parameterName": "loanPurposeIdSelectAll" + } + ] + },... + ] +
@@ -11030,7 +10331,20 @@ GET https://DomainName/api/v1/reports

Running a Report

-

Runs a report and returns the report output.

+

This resource allows you to run and receive output from pre-defined Mifos X reports.

+

Reports can also be used to provide data for searching and workflow functionality.

+

+ The default output is a JSON formatted "Generic Resultset". The Generic Resultset contains + Column Heading as well as Data information. However, you can + export to CSV format by simply adding "&exportCSV=true" to the end + of your URL.

+

If Pentaho reports have been pre-defined, they can also be + run through this resource. Pentaho reports can return HTML, PDF or + CSV formats.

+

The Mifos X reference application uses a + JQuery plugin called stretchyreporting which, itself, uses this + reports resource to provide a pretty flexible reporting User + Interface (UI).

Arguments
R_'parameter names' ...
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/ReportsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/ReportsApiResource.java index 7039067bf..6dc55e88a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/ReportsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/api/ReportsApiResource.java @@ -6,6 +6,7 @@ package org.mifosplatform.infrastructure.dataqueries.api; import java.io.File; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -26,6 +27,7 @@ import javax.ws.rs.core.UriInfo; import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; +import org.mifosplatform.infrastructure.dataqueries.data.ReportData; import org.mifosplatform.infrastructure.dataqueries.service.GenericDataService; import org.mifosplatform.infrastructure.dataqueries.service.ReadReportingService; import org.mifosplatform.infrastructure.security.exception.NoAuthorizationException; @@ -56,32 +58,16 @@ public class ReportsApiResource { @GET @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload" }) + @Produces({ MediaType.APPLICATION_JSON }) public Response retrieveReportList(@Context final UriInfo uriInfo) { - Map extractedQueryParams = new HashMap(); boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo.getQueryParameters()); - boolean exportPdf = ApiParameterHelper.exportPdf(uriInfo.getQueryParameters()); + final Collection result = this.readExtraDataAndReportingService.retrieveReportList(); + final String json = this.toApiJsonSerializer.serializePretty(prettyPrint, result); - if (exportPdf) { - String result = this.readExtraDataAndReportingService.retrieveReportPDF(".", ".", extractedQueryParams); - return Response.ok().entity(result).header("Content-Disposition", "attachment;filename=ReportList.pdf").build(); - } - - if (!exportCsv) { - GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(".", ".", extractedQueryParams); - - final String json = this.toApiJsonSerializer.serializePretty(prettyPrint, result); - - return Response.ok().entity(json).build(); - } - - StreamingOutput result = this.readExtraDataAndReportingService.retrieveReportCSV(".", ".", extractedQueryParams); - - return Response.ok().entity(result).header("Content-Disposition", "attachment;filename=ReportList.csv").build(); + return Response.ok().entity(json).build(); } @GET diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportData.java new file mode 100644 index 000000000..63f078df7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportData.java @@ -0,0 +1,47 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.dataqueries.data; + +import java.util.Collection; + +final public class ReportData { + + @SuppressWarnings("unused") + private final Long reportId; + @SuppressWarnings("unused") + private final String reportName; + @SuppressWarnings("unused") + private final String reportType; + @SuppressWarnings("unused") + private final String reportSubType; + @SuppressWarnings("unused") + private final String reportCategory; + @SuppressWarnings("unused") + private final String reportSql; + @SuppressWarnings("unused") + private final Boolean coreReport; + @SuppressWarnings("unused") + private final Boolean useReport; + @SuppressWarnings("unused") + private final Collection reportParameters; + + public ReportData(final Long reportId, final String reportName, + final String reportType, final String reportSubType, + final String reportCategory, final String reportSql, + final Boolean coreReport, final Boolean useReport, + final Collection reportParameters) { + this.reportId = reportId; + this.reportName = reportName; + this.reportType = reportType; + this.reportSubType = reportSubType; + this.reportCategory = reportCategory; + this.reportParameters = reportParameters; + this.reportSql = reportSql; + this.coreReport = coreReport; + this.useReport = useReport; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterData.java new file mode 100644 index 000000000..1f8f4f8f4 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterData.java @@ -0,0 +1,24 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.dataqueries.data; + +final public class ReportParameterData { + + @SuppressWarnings("unused") + private final Long reportParameterId; + @SuppressWarnings("unused") + private final String reportParameterName; + @SuppressWarnings("unused") + private final String parameterName; + + public ReportParameterData(final Long reportParameterId, + final String reportParameterName, final String parameterName) { + this.reportParameterId = reportParameterId; + this.reportParameterName = reportParameterName; + this.parameterName = parameterName; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterJoinData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterJoinData.java new file mode 100644 index 000000000..debf85c5e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/data/ReportParameterJoinData.java @@ -0,0 +1,86 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.dataqueries.data; + +final public class ReportParameterJoinData { + + private final Long reportId; + private final String reportName; + private final String reportType; + private final String reportSubType; + private final String reportCategory; + private final String reportSql; + private final Boolean coreReport; + private final Boolean useReport; + + private final Long reportParameterId; + private final String reportParameterName; + private final String parameterName; + + public ReportParameterJoinData(final Long reportId, + final String reportName, final String reportType, + final String reportSubType, final String reportCategory, + final String reportSql, final Boolean coreReport, + final Boolean useReport, final Long reportParameterId, + final String reportParameterName, final String parameterName) { + this.reportId = reportId; + this.reportName = reportName; + this.reportType = reportType; + this.reportSubType = reportSubType; + this.reportCategory = reportCategory; + this.reportSql = reportSql; + this.coreReport = coreReport; + this.useReport = useReport; + this.reportParameterId = reportParameterId; + this.reportParameterName = reportParameterName; + this.parameterName = parameterName; + } + + public Long getReportId() { + return reportId; + } + + public String getReportName() { + return reportName; + } + + public String getReportType() { + return reportType; + } + + public String getReportSubType() { + return reportSubType; + } + + public String getReportCategory() { + return reportCategory; + } + + public String getReportSql() { + return reportSql; + } + + public Boolean getCoreReport() { + return coreReport; + } + + public Boolean getUseReport() { + return useReport; + } + + public Long getReportParameterId() { + return reportParameterId; + } + + public String getReportParameterName() { + return reportParameterName; + } + + public String getParameterName() { + return parameterName; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingService.java index 0ef57d4df..12ce25cac 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingService.java @@ -5,22 +5,30 @@ */ package org.mifosplatform.infrastructure.dataqueries.service; +import java.util.Collection; import java.util.Map; import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; +import org.mifosplatform.infrastructure.dataqueries.data.ReportData; public interface ReadReportingService { - StreamingOutput retrieveReportCSV(String name, String type, Map extractedQueryParams); + StreamingOutput retrieveReportCSV(String name, String type, + Map extractedQueryParams); - GenericResultsetData retrieveGenericResultset(String name, String type, Map extractedQueryParams); + GenericResultsetData retrieveGenericResultset(String name, String type, + Map extractedQueryParams); - Response processPentahoRequest(String reportName, String outputType, Map queryParams); + Response processPentahoRequest(String reportName, String outputType, + Map queryParams); - String retrieveReportPDF(String name, String type, Map extractedQueryParams); + String retrieveReportPDF(String name, String type, + Map extractedQueryParams); - String getReportType(String reportName); + String getReportType(String reportName); + + Collection retrieveReportList(); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingServiceImpl.java index 130c70a12..4d73fdfd8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReadReportingServiceImpl.java @@ -13,6 +13,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -22,10 +26,14 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.StreamingOutput; import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.service.FileUtils; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; +import org.mifosplatform.infrastructure.dataqueries.data.ReportData; +import org.mifosplatform.infrastructure.dataqueries.data.ReportParameterData; +import org.mifosplatform.infrastructure.dataqueries.data.ReportParameterJoinData; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData; import org.mifosplatform.infrastructure.dataqueries.exception.ReportNotFoundException; @@ -48,6 +56,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.stereotype.Service; @@ -59,372 +68,589 @@ import com.lowagie.text.pdf.PdfWriter; @Service public class ReadReportingServiceImpl implements ReadReportingService { - private final static Logger logger = LoggerFactory.getLogger(ReadReportingServiceImpl.class); - - private final JdbcTemplate jdbcTemplate; - private final DataSource dataSource; - private final PlatformSecurityContext context; - private final GenericDataService genericDataService; - private boolean noPentaho = false; - - @Autowired - public ReadReportingServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource, - final GenericDataService genericDataService) { - // kick off pentaho reports server - ClassicEngineBoot.getInstance().start(); - noPentaho = false; - - this.context = context; - this.dataSource = dataSource; - this.jdbcTemplate = new JdbcTemplate(this.dataSource); - this.genericDataService = genericDataService; - } - - @Override - public StreamingOutput retrieveReportCSV(final String name, final String type, final Map queryParams) { - - return new StreamingOutput() { - - @Override - public void write(final OutputStream out) { - try { - - GenericResultsetData result = retrieveGenericResultset(name, type, queryParams); - StringBuffer sb = generateCsvFileBuffer(result); - - InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8")); - - byte[] outputByte = new byte[4096]; - Integer readLen = in.read(outputByte, 0, 4096); - - while (readLen != -1) { - out.write(outputByte, 0, readLen); - readLen = in.read(outputByte, 0, 4096); - } - // in.close(); - // out.flush(); - // out.close(); - } catch (Exception e) { - throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage()); - } - } - }; - - } - - private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) { - StringBuffer writer = new StringBuffer(); - - List columnHeaders = result.getColumnHeaders(); - logger.info("NO. of Columns: " + columnHeaders.size()); - Integer chSize = columnHeaders.size(); - for (int i = 0; i < chSize; i++) { - writer.append('"' + columnHeaders.get(i).getColumnName() + '"'); - if (i < (chSize - 1)) writer.append(","); - } - writer.append('\n'); - - List data = result.getData(); - List row; - Integer rSize; - // String currCol; - String currColType; - String currVal; - String doubleQuote = "\""; - String twoDoubleQuotes = doubleQuote + doubleQuote; - logger.info("NO. of Rows: " + data.size()); - for (int i = 0; i < data.size(); i++) { - row = data.get(i).getRow(); - rSize = row.size(); - for (int j = 0; j < rSize; j++) { - // currCol = columnHeaders.get(j).getColumnName(); - currColType = columnHeaders.get(j).getColumnType(); - currVal = row.get(j); - if (currVal != null) { - if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT") - || currColType.equals("SMALLINT") || currColType.equals("INT")) - writer.append(currVal); - else - writer.append('"' + genericDataService.replace(currVal, doubleQuote, twoDoubleQuotes) + '"'); - - } - if (j < (rSize - 1)) writer.append(","); - } - writer.append('\n'); - } - - return writer; - } - - @Override - public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map queryParams) { - - long startTime = System.currentTimeMillis(); - logger.info("STARTING REPORT: " + name + " Type: " + type); - - String sql; - if (name.equals(".")) { - // this is to support api /reports - which isn't an important - // call. It isn't used in the default reporting UI. But there is a - // need to provide an api that does bring back 'permitted' reports - // PERMITTED REPORTS SQL - sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category," - + " rp.parameter_id, rp.report_parameter_name, p.parameter_name" + " from stretchy_report r" - + " left join stretchy_report_parameter rp on rp.report_id = r.report_id" - + " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + " where exists" + " (select 'f'" - + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id" - + " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id" - + " where ur.appuser_id = " + context.authenticatedUser().getId() - + " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) " - + " order by r.report_name, rp.parameter_id"; - } else { - sql = getSQLtoRun(name, type, queryParams); - } - - GenericResultsetData result = genericDataService.fillGenericResultSet(sql); - - long elapsed = System.currentTimeMillis() - startTime; - logger.info("FINISHING Report/Request Name: " + name + " - " + type + " Elapsed Time: " + elapsed); - return result; - } - - private String getSQLtoRun(final String name, final String type, final Map queryParams) { - - String sql = getSql(name, type); - - Set keys = queryParams.keySet(); - for (String key : keys) { - String pValue = queryParams.get(key); - // logger.info("(" + key + " : " + pValue + ")"); - sql = genericDataService.replace(sql, key, pValue); - } - - AppUser currentUser = context.authenticatedUser(); - // Allows sql query to restrict data by office hierarchy if required - sql = genericDataService.replace(sql, "${currentUserHierarchy}", currentUser.getOffice().getHierarchy()); - // Allows sql query to restrict data by current user Id if required - // (typically used to return report lists containing only reports - // permitted to be run by the user - sql = genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString()); - - sql = genericDataService.wrapSQL(sql); - - return sql; - - } - - private String getSql(final String name, final String type) { - - final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'"; - final String inputSqlWrapped = genericDataService.wrapSQL(inputSql); - - final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped); - - if (rs.next()) { return rs.getString("the_sql"); } - throw new ReportNotFoundException(inputSql); - } - - @Override - public String getReportType(final String reportName) { - - final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "'"; - - final String sqlWrapped = genericDataService.wrapSQL(sql); - - final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped); - - if (rs.next()) { return rs.getString("report_type"); } - throw new ReportNotFoundException(sql); - } - - @Override - public Response processPentahoRequest(final String reportName, final String outputTypeParam, final Map queryParams) { - - String outputType = "HTML"; - if (StringUtils.isNotBlank(outputTypeParam)) outputType = outputTypeParam; - - if (!(outputType.equalsIgnoreCase("HTML") || outputType.equalsIgnoreCase("PDF") || outputType.equalsIgnoreCase("XLS") || outputType - .equalsIgnoreCase("CSV"))) - throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType); - - if (noPentaho) { throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled", - "Pentaho is not enabled"); } - - // TODO - JW - use pentaho location finder like Pawel does in Mifos - // String reportPath = - // "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\" - // + reportName + ".prpt"; - /* - * String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator + - * ThreadLocalContextUtil.getTenant().getName() .replaceAll(" ", - * "").trim() + File.separator + "reports" + File.separator + reportName - * + ".prpt"; - */ - final String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator + "pentahoReports" + File.separator + reportName + ".prpt"; - logger.info("Report path: " + reportPath); - - // load report definition - ResourceManager manager = new ResourceManager(); - manager.registerDefaults(); - Resource res; - - try { - res = manager.createDirectly(reportPath, MasterReport.class); - MasterReport masterReport = (MasterReport) res.getResource(); - - addParametersToReport(masterReport, queryParams); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - if ("PDF".equalsIgnoreCase(outputType)) { - PdfReportUtil.createPDF(masterReport, baos); - return Response.ok().entity(baos.toByteArray()).type("application/pdf").build(); - } - - if ("XLS".equalsIgnoreCase(outputType)) { - ExcelReportUtil.createXLS(masterReport, baos); - return Response.ok().entity(baos.toByteArray()).type("application/vnd.ms-excel") - .header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".xls").build(); - } - - if ("CSV".equalsIgnoreCase(outputType)) { - CSVReportUtil.createCSV(masterReport, baos, "UTF-8"); - return Response.ok().entity(baos.toByteArray()).type("application/x-msdownload") - .header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build(); - } - - if ("HTML".equalsIgnoreCase(outputType)) { - HtmlReportUtil.createStreamHTML(masterReport, baos); - return Response.ok().entity(baos.toByteArray()).type("text/html").build(); - } - } catch (ResourceException e) { - throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage()); - } catch (ReportProcessingException e) { - throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage()); - } catch (IOException e) { - throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage()); - } - - throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType); - } - - private void addParametersToReport(final MasterReport report, final Map queryParams) { - - AppUser currentUser = context.authenticatedUser(); - - try { - - ReportParameterValues rptParamValues = report.getParameterValues(); - ReportParameterDefinition paramsDefinition = report.getParameterDefinition(); - - /* - * only allow integer, long, date and string parameter types and - * assume all mandatory - could go more detailed like Pawel did in - * Mifos later and could match incoming and pentaho parameters - * better... currently assuming they come in ok... and if not an - * error - */ - for (ParameterDefinitionEntry paramDefEntry : paramsDefinition.getParameterDefinitions()) { - String paramName = paramDefEntry.getName(); - if (!((paramName.equals("tenantdb")) || (paramName.equals("userhierarchy")))) { - logger.info("paramName:" + paramName); - String pValue = queryParams.get(paramName); - if (StringUtils.isBlank(pValue)) - throw new PlatformDataIntegrityException("error.msg.reporting.error", "Pentaho Parameter: " + paramName - + " - not Provided"); - - Class clazz = paramDefEntry.getValueType(); - logger.info("addParametersToReport(" + paramName + " : " + pValue + " : " + clazz.getCanonicalName() + ")"); - if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Integer")) - rptParamValues.put(paramName, Integer.parseInt(pValue)); - else if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Long")) - rptParamValues.put(paramName, Long.parseLong(pValue)); - else if (clazz.getCanonicalName().equalsIgnoreCase("java.sql.Date")) - rptParamValues.put(paramName, Date.valueOf(pValue)); - else - rptParamValues.put(paramName, pValue); - } - - } - - // tenant database name and current user's office hierarchy - // passed as parameters to allow multitenant penaho reporting - // and - // data scoping - String tenantdb = dataSource.getConnection().getCatalog(); - String userhierarchy = currentUser.getOffice().getHierarchy(); - logger.info("db name:" + tenantdb + " userhierarchy:" + userhierarchy); - rptParamValues.put("tenantdb", tenantdb); - rptParamValues.put("userhierarchy", userhierarchy); - } catch (Exception e) { - logger.error("error.msg.reporting.error:" + e.getMessage()); - throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage()); - } - } - - @Override - public String retrieveReportPDF(final String reportName, final String type, final Map queryParams) { - - String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + ""; - if (!new File(fileLocation).isDirectory()) { - new File(fileLocation).mkdirs(); - } - - String genaratePdf = fileLocation + File.separator + reportName + ".pdf"; - - try { - GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams); - - List columnHeaders = result.getColumnHeaders(); - List data = result.getData(); - List row; - - logger.info("NO. of Columns: " + columnHeaders.size()); - Integer chSize = columnHeaders.size(); - - Document document = new Document(PageSize.B0.rotate()); - - PdfWriter.getInstance(document, new FileOutputStream(new File(fileLocation + reportName + ".pdf"))); - document.open(); - - PdfPTable table = new PdfPTable(chSize); - table.setWidthPercentage(100); - - for (int i = 0; i < chSize; i++) { - - table.addCell(columnHeaders.get(i).getColumnName()); - - } - table.completeRow(); - - Integer rSize; - String currColType; - String currVal; - logger.info("NO. of Rows: " + data.size()); - for (int i = 0; i < data.size(); i++) { - row = data.get(i).getRow(); - rSize = row.size(); - for (int j = 0; j < rSize; j++) { - currColType = columnHeaders.get(j).getColumnType(); - currVal = row.get(j); - if (currVal != null) { - if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT") - || currColType.equals("SMALLINT") || currColType.equals("INT")) { - - table.addCell(currVal.toString()); - } else { - table.addCell(currVal.toString()); - } - } - } - } - table.completeRow(); - document.add(table); - document.close(); - return genaratePdf; - } catch (Exception e) { - logger.error("error.msg.reporting.error:" + e.getMessage()); - throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage()); - } - } + private final static Logger logger = LoggerFactory + .getLogger(ReadReportingServiceImpl.class); + + private final JdbcTemplate jdbcTemplate; + private final DataSource dataSource; + private final PlatformSecurityContext context; + private final GenericDataService genericDataService; + private boolean noPentaho = false; + + @Autowired + public ReadReportingServiceImpl(final PlatformSecurityContext context, + final TenantAwareRoutingDataSource dataSource, + final GenericDataService genericDataService) { + // kick off pentaho reports server + ClassicEngineBoot.getInstance().start(); + noPentaho = false; + + this.context = context; + this.dataSource = dataSource; + this.jdbcTemplate = new JdbcTemplate(this.dataSource); + this.genericDataService = genericDataService; + } + + @Override + public StreamingOutput retrieveReportCSV(final String name, + final String type, final Map queryParams) { + + return new StreamingOutput() { + + @Override + public void write(final OutputStream out) { + try { + + GenericResultsetData result = retrieveGenericResultset( + name, type, queryParams); + StringBuffer sb = generateCsvFileBuffer(result); + + InputStream in = new ByteArrayInputStream(sb.toString() + .getBytes("UTF-8")); + + byte[] outputByte = new byte[4096]; + Integer readLen = in.read(outputByte, 0, 4096); + + while (readLen != -1) { + out.write(outputByte, 0, readLen); + readLen = in.read(outputByte, 0, 4096); + } + // in.close(); + // out.flush(); + // out.close(); + } catch (Exception e) { + throw new PlatformDataIntegrityException( + "error.msg.exception.error", e.getMessage()); + } + } + }; + + } + + private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) { + StringBuffer writer = new StringBuffer(); + + List columnHeaders = result + .getColumnHeaders(); + logger.info("NO. of Columns: " + columnHeaders.size()); + Integer chSize = columnHeaders.size(); + for (int i = 0; i < chSize; i++) { + writer.append('"' + columnHeaders.get(i).getColumnName() + '"'); + if (i < (chSize - 1)) + writer.append(","); + } + writer.append('\n'); + + List data = result.getData(); + List row; + Integer rSize; + // String currCol; + String currColType; + String currVal; + String doubleQuote = "\""; + String twoDoubleQuotes = doubleQuote + doubleQuote; + logger.info("NO. of Rows: " + data.size()); + for (int i = 0; i < data.size(); i++) { + row = data.get(i).getRow(); + rSize = row.size(); + for (int j = 0; j < rSize; j++) { + // currCol = columnHeaders.get(j).getColumnName(); + currColType = columnHeaders.get(j).getColumnType(); + currVal = row.get(j); + if (currVal != null) { + if (currColType.equals("DECIMAL") + || currColType.equals("DOUBLE") + || currColType.equals("BIGINT") + || currColType.equals("SMALLINT") + || currColType.equals("INT")) + writer.append(currVal); + else + writer.append('"' + genericDataService.replace(currVal, + doubleQuote, twoDoubleQuotes) + '"'); + + } + if (j < (rSize - 1)) + writer.append(","); + } + writer.append('\n'); + } + + return writer; + } + + @Override + public GenericResultsetData retrieveGenericResultset(final String name, + final String type, final Map queryParams) { + + long startTime = System.currentTimeMillis(); + logger.info("STARTING REPORT: " + name + " Type: " + type); + + String sql; + if (name.equals(".")) { + // this is to support api /reports - which isn't an important + // call. It isn't used in the default reporting UI. But there is a + // need to provide an api that does bring back 'permitted' reports + // PERMITTED REPORTS SQL + sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category," + + " rp.parameter_id, rp.report_parameter_name, p.parameter_name" + + " from stretchy_report r" + + " left join stretchy_report_parameter rp on rp.report_id = r.report_id" + + " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + + " where exists" + + " (select 'f'" + + " from m_appuser_role ur " + + " join m_role r on r.id = ur.role_id" + + " left join m_role_permission rp on rp.role_id = r.id" + + " left join m_permission p on p.id = rp.permission_id" + + " where ur.appuser_id = " + + context.authenticatedUser().getId() + + " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) " + + " order by r.report_name, rp.parameter_id"; + } else { + sql = getSQLtoRun(name, type, queryParams); + } + + GenericResultsetData result = genericDataService + .fillGenericResultSet(sql); + + long elapsed = System.currentTimeMillis() - startTime; + logger.info("FINISHING Report/Request Name: " + name + " - " + type + + " Elapsed Time: " + elapsed); + return result; + } + + private String getSQLtoRun(final String name, final String type, + final Map queryParams) { + + String sql = getSql(name, type); + + Set keys = queryParams.keySet(); + for (String key : keys) { + String pValue = queryParams.get(key); + // logger.info("(" + key + " : " + pValue + ")"); + sql = genericDataService.replace(sql, key, pValue); + } + + AppUser currentUser = context.authenticatedUser(); + // Allows sql query to restrict data by office hierarchy if required + sql = genericDataService.replace(sql, "${currentUserHierarchy}", + currentUser.getOffice().getHierarchy()); + // Allows sql query to restrict data by current user Id if required + // (typically used to return report lists containing only reports + // permitted to be run by the user + sql = genericDataService.replace(sql, "${currentUserId}", currentUser + .getId().toString()); + + sql = genericDataService.wrapSQL(sql); + + return sql; + + } + + private String getSql(final String name, final String type) { + + final String inputSql = "select " + type + + "_sql as the_sql from stretchy_" + type + " where " + type + + "_name = '" + name + "'"; + final String inputSqlWrapped = genericDataService.wrapSQL(inputSql); + + final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped); + + if (rs.next()) { + return rs.getString("the_sql"); + } + throw new ReportNotFoundException(inputSql); + } + + @Override + public String getReportType(final String reportName) { + + final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + + reportName + "'"; + + final String sqlWrapped = genericDataService.wrapSQL(sql); + + final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped); + + if (rs.next()) { + return rs.getString("report_type"); + } + throw new ReportNotFoundException(sql); + } + + @Override + public Response processPentahoRequest(final String reportName, + final String outputTypeParam, final Map queryParams) { + + String outputType = "HTML"; + if (StringUtils.isNotBlank(outputTypeParam)) + outputType = outputTypeParam; + + if (!(outputType.equalsIgnoreCase("HTML") + || outputType.equalsIgnoreCase("PDF") + || outputType.equalsIgnoreCase("XLS") || outputType + .equalsIgnoreCase("CSV"))) + throw new PlatformDataIntegrityException( + "error.msg.invalid.outputType", "No matching Output Type: " + + outputType); + + if (noPentaho) { + throw new PlatformDataIntegrityException("error.msg.no.pentaho", + "Pentaho is not enabled", "Pentaho is not enabled"); + } + + final String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator + + "pentahoReports" + File.separator + reportName + ".prpt"; + logger.info("Report path: " + reportPath); + + // load report definition + ResourceManager manager = new ResourceManager(); + manager.registerDefaults(); + Resource res; + + try { + res = manager.createDirectly(reportPath, MasterReport.class); + MasterReport masterReport = (MasterReport) res.getResource(); + + addParametersToReport(masterReport, queryParams); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + if ("PDF".equalsIgnoreCase(outputType)) { + PdfReportUtil.createPDF(masterReport, baos); + return Response.ok().entity(baos.toByteArray()) + .type("application/pdf").build(); + } + + if ("XLS".equalsIgnoreCase(outputType)) { + ExcelReportUtil.createXLS(masterReport, baos); + return Response + .ok() + .entity(baos.toByteArray()) + .type("application/vnd.ms-excel") + .header("Content-Disposition", + "attachment;filename=" + + reportName.replaceAll(" ", "") + + ".xls").build(); + } + + if ("CSV".equalsIgnoreCase(outputType)) { + CSVReportUtil.createCSV(masterReport, baos, "UTF-8"); + return Response + .ok() + .entity(baos.toByteArray()) + .type("application/x-msdownload") + .header("Content-Disposition", + "attachment;filename=" + + reportName.replaceAll(" ", "") + + ".csv").build(); + } + + if ("HTML".equalsIgnoreCase(outputType)) { + HtmlReportUtil.createStreamHTML(masterReport, baos); + return Response.ok().entity(baos.toByteArray()) + .type("text/html").build(); + } + } catch (ResourceException e) { + throw new PlatformDataIntegrityException( + "error.msg.reporting.error", e.getMessage()); + } catch (ReportProcessingException e) { + throw new PlatformDataIntegrityException( + "error.msg.reporting.error", e.getMessage()); + } catch (IOException e) { + throw new PlatformDataIntegrityException( + "error.msg.reporting.error", e.getMessage()); + } + + throw new PlatformDataIntegrityException( + "error.msg.invalid.outputType", "No matching Output Type: " + + outputType); + } + + private void addParametersToReport(final MasterReport report, + final Map queryParams) { + + AppUser currentUser = context.authenticatedUser(); + + try { + + ReportParameterValues rptParamValues = report.getParameterValues(); + ReportParameterDefinition paramsDefinition = report + .getParameterDefinition(); + + /* + * only allow integer, long, date and string parameter types and + * assume all mandatory - could go more detailed like Pawel did in + * Mifos later and could match incoming and pentaho parameters + * better... currently assuming they come in ok... and if not an + * error + */ + for (ParameterDefinitionEntry paramDefEntry : paramsDefinition + .getParameterDefinitions()) { + String paramName = paramDefEntry.getName(); + if (!((paramName.equals("tenantdb")) || (paramName + .equals("userhierarchy")))) { + logger.info("paramName:" + paramName); + String pValue = queryParams.get(paramName); + if (StringUtils.isBlank(pValue)) + throw new PlatformDataIntegrityException( + "error.msg.reporting.error", + "Pentaho Parameter: " + paramName + + " - not Provided"); + + Class clazz = paramDefEntry.getValueType(); + logger.info("addParametersToReport(" + paramName + " : " + + pValue + " : " + clazz.getCanonicalName() + ")"); + if (clazz.getCanonicalName().equalsIgnoreCase( + "java.lang.Integer")) + rptParamValues.put(paramName, Integer.parseInt(pValue)); + else if (clazz.getCanonicalName().equalsIgnoreCase( + "java.lang.Long")) + rptParamValues.put(paramName, Long.parseLong(pValue)); + else if (clazz.getCanonicalName().equalsIgnoreCase( + "java.sql.Date")) + rptParamValues.put(paramName, Date.valueOf(pValue)); + else + rptParamValues.put(paramName, pValue); + } + + } + + // tenant database name and current user's office hierarchy + // passed as parameters to allow multitenant penaho reporting + // and + // data scoping + String tenantdb = dataSource.getConnection().getCatalog(); + String userhierarchy = currentUser.getOffice().getHierarchy(); + logger.info("db name:" + tenantdb + " userhierarchy:" + + userhierarchy); + rptParamValues.put("tenantdb", tenantdb); + rptParamValues.put("userhierarchy", userhierarchy); + } catch (Exception e) { + logger.error("error.msg.reporting.error:" + e.getMessage()); + throw new PlatformDataIntegrityException( + "error.msg.reporting.error", e.getMessage()); + } + } + + @Override + public String retrieveReportPDF(final String reportName, final String type, + final Map queryParams) { + + String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + ""; + if (!new File(fileLocation).isDirectory()) { + new File(fileLocation).mkdirs(); + } + + String genaratePdf = fileLocation + File.separator + reportName + + ".pdf"; + + try { + GenericResultsetData result = retrieveGenericResultset(reportName, + type, queryParams); + + List columnHeaders = result + .getColumnHeaders(); + List data = result.getData(); + List row; + + logger.info("NO. of Columns: " + columnHeaders.size()); + Integer chSize = columnHeaders.size(); + + Document document = new Document(PageSize.B0.rotate()); + + PdfWriter.getInstance(document, new FileOutputStream(new File( + fileLocation + reportName + ".pdf"))); + document.open(); + + PdfPTable table = new PdfPTable(chSize); + table.setWidthPercentage(100); + + for (int i = 0; i < chSize; i++) { + + table.addCell(columnHeaders.get(i).getColumnName()); + + } + table.completeRow(); + + Integer rSize; + String currColType; + String currVal; + logger.info("NO. of Rows: " + data.size()); + for (int i = 0; i < data.size(); i++) { + row = data.get(i).getRow(); + rSize = row.size(); + for (int j = 0; j < rSize; j++) { + currColType = columnHeaders.get(j).getColumnType(); + currVal = row.get(j); + if (currVal != null) { + if (currColType.equals("DECIMAL") + || currColType.equals("DOUBLE") + || currColType.equals("BIGINT") + || currColType.equals("SMALLINT") + || currColType.equals("INT")) { + + table.addCell(currVal.toString()); + } else { + table.addCell(currVal.toString()); + } + } + } + } + table.completeRow(); + document.add(table); + document.close(); + return genaratePdf; + } catch (Exception e) { + logger.error("error.msg.reporting.error:" + e.getMessage()); + throw new PlatformDataIntegrityException( + "error.msg.exception.error", e.getMessage()); + } + } + + @Override + public Collection retrieveReportList() { + + ReportParameterJoinMapper rm = new ReportParameterJoinMapper(); + + String sql = rm.schema(false, context.authenticatedUser().getId()); + + Collection rpJoins = this.jdbcTemplate.query( + sql, rm, new Object[] {}); + + Collection reportList = new ArrayList(); + if (rpJoins == null) + return reportList; + + Collection reportParameters = null; + + Long reportId = null; + String reportName = null; + String reportType = null; + String reportSubType = null; + String reportCategory = null; + Boolean coreReport = null; + Boolean useReport = null; + String reportSql = null; + + Long prevReportId = (long) -1234; + Boolean firstReport = true; + for (ReportParameterJoinData rpJoin : rpJoins) { + + if (rpJoin.getReportId().equals(prevReportId)) { + // more than one parameter for report + reportParameters.add(new ReportParameterData(rpJoin + .getReportParameterId(), rpJoin + .getReportParameterName(), rpJoin.getParameterName())); + + } else { + if (firstReport) { + firstReport = false; + } + else + { + // write report entry + reportList + .add(new ReportData(reportId, reportName, + reportType, reportSubType, reportCategory, + reportSql, coreReport, useReport, + reportParameters)); + } + + prevReportId = rpJoin.getReportId(); + + reportId = rpJoin.getReportId(); + reportName = rpJoin.getReportName(); + reportType = rpJoin.getReportType(); + reportSubType = rpJoin.getReportSubType(); + reportCategory = rpJoin.getReportCategory(); + reportSql = rpJoin.getReportSql(); + coreReport = rpJoin.getCoreReport(); + useReport = rpJoin.getUseReport(); + + if (rpJoin.getReportParameterId() != null) { + // report has at least one parameter + reportParameters = new ArrayList(); + reportParameters.add(new ReportParameterData(rpJoin + .getReportParameterId(), rpJoin + .getReportParameterName(), rpJoin + .getParameterName())); + } else { + reportParameters = null; + } + } + + } + // write last report + reportList.add(new ReportData(reportId, reportName, reportType, + reportSubType, reportCategory, reportSql, coreReport, + useReport, reportParameters)); + + return reportList; + } + + private static final class ReportParameterJoinMapper implements + RowMapper { + + public String schema(boolean includeSql, Long userId) { + + String sql = "select r.report_id as reportId, r.report_name as reportName, r.report_type as reportType, " + + " r.report_subtype as reportSubType, r.report_category as reportCategory, r.core_report as coreReport, r.use_report as useReport, " + + " rp.parameter_id as reportParameterId, rp.report_parameter_name as reportParameterName, p.parameter_name as parameterName"; + + if (includeSql) + sql += ", r.report_sql as reportSql "; + + sql += " from stretchy_report r" + + " left join stretchy_report_parameter rp on rp.report_id = r.report_id" + + " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + + " where exists" + + " (select 'f'" + + " from m_appuser_role ur " + + " join m_role r on r.id = ur.role_id" + + " left join m_role_permission rp on rp.role_id = r.id" + + " left join m_permission p on p.id = rp.permission_id" + + " where ur.appuser_id = " + + userId + + " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) " + + " order by r.report_id, rp.parameter_id"; + + return sql; + } + + @Override + public ReportParameterJoinData mapRow(final ResultSet rs, + @SuppressWarnings("unused") final int rowNum) + throws SQLException { + + final Long reportId = rs.getLong("reportId"); + final String reportName = rs.getString("reportName"); + final String reportType = rs.getString("reportType"); + final String reportSubType = rs.getString("reportSubType"); + final String reportCategory = rs.getString("reportCategory"); + final Boolean coreReport = rs.getBoolean("coreReport"); + final Boolean useReport = rs.getBoolean("useReport"); + + String reportSql; + // reportSql might not be on the select list of columns + try { + reportSql = rs.getString("reportSql"); + } catch (SQLException e) { + reportSql = null; + } + + final Long reportParameterId = JdbcSupport.getLong(rs, + "reportParameterId"); + final String reportParameterName = rs + .getString("reportParameterName"); + final String parameterName = rs.getString("parameterName"); + + return new ReportParameterJoinData(reportId, reportName, + reportType, reportSubType, reportCategory, reportSql, + coreReport, useReport, reportParameterId, + reportParameterName, parameterName); + } + + } + } \ No newline at end of file