Back to top
 
 
 

Adding a new Custom Report Class to CloudPortal Business Manager

There are two ways in which you can create a custom report, by implementing the "GenericReport" or by extending the "AbstractReport."

Generic Report Interface

CloudPortal Business Manager defines the following interface to support creation of custom reports:
package com.vmops.portal.reports;  public interface GenericReport {    public Report getReport();    public Report getFusionReport();  }  
The above interface is directly implemented and the object com.vmops.model.Report is returned. For custom reports, you can add implementation for the first method declaration and leave for the second method declaration blank.

Abstract Report Class

CloudPortal Business Manager has an abstraction layer to implement custom reports. The abstract class, that implements the above interface, is as follows:
public abstract class AbstractReport
This allows the following class member variables to be accessed by the sub class:
  • reportDataSource: Underlying data base connection source
  • report: Instance of the com.vmops.model.Report
  • recordCount: Number of records added to the Report File till now

If Custom Report class extends this abstract class, the following declarations from this abstract class have to be implemented:

  • protected abstract Statement getStatement(Connection connection) throws SQLException;
    The abstract class gets the statement that needs to be executed to fetch the records from the underlying database cloud_portal which are going to be included in the final report. Because only the sub class knows how to fetch the records from the underlying database, the sub class implements this method. For example,
     StringBuilder query = new StringBuilder("SELECT * FROM users WHERE id > 10 LIMIT 10");   Return connection.prepareStatement(query.toString())
  • protected abstract ResultSet executeQuery(Statement statement) throws SQLException

    Once the statement is got from the sub class, the statement is executed. Because the statement has been created by the sub class, only the sub class knows how to execute the statement. Therefore, the sub class defines this method also. Once it gets the required set of results from the above execution, the abstract class generates the report. As part of the report file, the first record is the header of that report and last record is the footer of that report if any. And all results fit in between these two records. Therefore, the abstract class gets the Header and Footer from the sub class because only the sub class knows what should be there in these two records. Also, only the sub class knows how to create a records from the results above.

    In the above example, the implementation of this method looks like this:
    PreparedStatement pstmt = (PreparedStatement) statement;  return pstmt.executeQuery();
  • protected abstract String getHeader(Statement pstmt) throws SQLException

    As mentioned above, only sub class knows what the header for this report should be. So, the sub class defines this method and if there is no header you can return null. This will be called for each report file only once. For example, return "column1, column2, column3,…";

  • protected abstract List<String> getRecord(Statement statement, ResultSet rs) throws SQLException

    This is called by the abstract class for every next call of ResultSet. Therefore, the pointer in ResultSet always points to the current row in the result set. Generally, only one record is returned for one ResultSet. However, based on the ResultSet, at times more than one record can be returned. The underlying implementation adds all records from this list to the report that is going to be generated.

  • protected abstract getFooter(Statement statement, ResultSet rs) throws SQLException

    Because only the sub class knows what should be the footer for this report, the sub class should define this method and if there is no footer you can return null. This will be called for each report file only once. For example, return "End of the Report";

  • protected abstract void setFileType();

    Only the sub class knows what type of file is going to be generated at the end, as records are returned by the sub class in a specific format. For example xml, csv, and so on. For example, report.setFileType("csv");

  • protected abstract void updateWithLastAddedRecrod();

    Once the report is generated, the abstract class should return a set of attributes as mentioned in the table above. The only information that is put in the attributes is the last added record. And this is used by the report service to generate multiple report files instead of generating one big report file. The Report service passes back this attribute in params to tell the corresponding report that records are already included till that last check point. Therefore, the Custom report generates report for records after that record.

    If sub class does not use the key limit which gets passed as part of the params (the variable in com.vmops.model.Report) or not even getting passed then leave empty implementation for this method in sub class as all records are included in a single report file. For example, this.report.getParams().put("last_record_id", lastAddedRecord); // Where lastAddedRecord is maintained by the sub class as part of each getRecord() call.

  • protected abstract Object getUniqueId(ResultSet rs) throws SQLException

    Currently, as this is not being called, there is a blank implementation for this.

Report Class

Both the above mentioned methods return the com.vmops.model.Report object.

The following are the key variables declared in com.vmops.model.Report:
Variable Definition
Format Format the file content. Currently this is not set.
reportFile File that is going to be generated. It is populated by the abstract layer if at all extending the abstract class to implement a custom report.
fileType Format of the file which is generated, for example csv, xml, and this is the file extension used to name the file once it is generated.
params Initial parameters passed to generate a report file. Currently the following will be passed:

type: type of the custom report (DAILY/MONTHLY)

sequenceService: bean reference for sequenceService

config: bean reference to Config Service

messageSource: bean reference to messageSource service

For Daily Type Custom Reports, date: date for which report need to be generated

For Monthly Type Custom Reports, month: month for which report need to be generated, year: year for which report need to be generated

limit: number of records need to be generated per file if at all passed by the caller

attributes Attributes that are populated at the end of the report generation. Currently, only the following attribute:

number_of_records: number of records generated as part of the custom report file

Custom reports, created by either implementing GenericReport interface or by extending AbstractReport class, must be added into the custom_reports and sched_custom_reports table as shown below:

Run the following queries:
  • INSERT INTO custom_reports (name, class) VALUES ('<Report Name>', '<Fully qualified name of Report Class>');
  • INSERT INTO sched_custom_reports (customreportid, frequency, deliveryurl) VALUES (<ID of the above insert> '<MONTHLY/DAILY>', '<The FTP path to transfer as in <TransaferType>://<FilePath Based on the TransferType>
 

Comments