Writing a Plugin part 3 - Implementing an API
Please ensure you have run the dependent module Part 2 before following this tutorial.
In this module you will learn how to implement a plugin interface and then package the plugin into a JAR ready to distribute and deploy.
Implement a Plugin API
In this example we will implement a reporting plugin by implementing the IPluginReport interface.
The main method in this interface is generateReport. It is where the report is generated. The return method is a byte[] so the framework can send the report back to the users browser.
public byte[] generateReport(final EntityManager em, final PluginData data) throws RapidDeployException
Example Report Plugin Class
Here is an example class
package com.midvision.rapiddeploy.plugins.report.custom;
import java.io.InputStream;
import java.util.Map;
import javax.persistence.EntityManager;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.xml.JRXmlLoader;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import com.midvision.rapiddeploy.domain.plugin.IPluginReport;
import com.midvision.rapiddeploy.domain.plugin.PluginData;
import com.midvision.rapiddeploy.domain.plugin.PluginType;
import com.midvision.rapiddeploy.exceptions.RapidDeployException;
import com.midvision.rapiddeploy.plugins.report.generator.JasperReportGenerator;
import com.midvision.rapiddeploy.plugins.report.generator.MyCustomReportGenerator;
import com.midvision.rapiddeploy.service.report.AbstractReportHandler;
@SuppressWarnings("unused")
public class CustomReports extends AbstractReportHandler<CustomReportsDomain> implements IPluginReport {
private static final Log log = LogFactory.getLog(CustomReports.class);
private CustomReportsDomain customReportsDomain;
/*
* This method returns the unique plugin name and version.
*
* @see com.midvision.rapiddeploy.domain.plugin.IPluginFunction#getPluginName()
*/
@Override
public String getPluginName() {
return "Custom Reports (v" + getPluginVersion() + ")";
}
/*
* This method returns this plugin type. This plugin is a reporting plugin.
*
* @see com.midvision.rapiddeploy.domain.plugin.IPluginFunction#getPluginType()
*/
@Override
public PluginType getPluginType() {
return PluginType.report;
}
/*
* This method initialises the plugin and loads the default UI data.
*
* @see com.midvision.rapiddeploy.service.plugin.AbstractPluginHandler#init()
*/
@Override
public void init() {
customReportsDomain = super.init(CustomReportsDomain.class);
}
/*
* The method returns the version of the plugin
*
* @see com.midvision.rapiddeploy.domain.plugin.IPluginFunction#getPluginVersion()
*/
@Override
public String getPluginVersion() {
return "1.0.0";
}
/**
* This method is used to load the report template from the plugin JAR file based on the
* template name the user selects in the UI.
*
* @param templateName
* @return
* @throws RapidDeployException
*/
private InputStream loadReportTemplate(final String templateName) throws RapidDeployException {
if (StringUtils.isNotBlank(templateName)) {
for (final String validTemplateName : getAllReportTemplateNames()) {
if (validTemplateName.trim().equals(templateName)) {
if ("List Tables".equals(templateName)) {
return CustomReports.class.getClassLoader().getResourceAsStream("com/midvision/rapiddeploy/plugins/report/custom/templates/tableList.jrxml");
}
}
}
}
throw new RapidDeployException("Report template named [" + templateName + "] has not been defined for this plugin.");
}
/**
* This method loads the report logo from the plugin Jar file
* @return
* @throws RapidDeployException
*/
private InputStream loadReportLogo() throws RapidDeployException {
return CustomReports.class.getClassLoader().getResourceAsStream("com/midvision/rapiddeploy/plugins/report/custom/templates/images/my_report_logo.png");
}
/*
* This method implements the Reporting plugin interface. It generates the report as a byte array.
*
* The database connection and the UI plugin data are parameters to this method.
* In this example the JasperReport template is loaded and compiled.
* Then the report, data, and format are passed into the JasperReportGenerator to fill the template with the
* data and then generate the report.
*
* @see com.midvision.rapiddeploy.domain.plugin.IPluginReport#generateReport(javax.persistence.EntityManager, com.midvision.rapiddeploy.domain.plugin.PluginData)
*/
@Override
public byte[] generateReport(final EntityManager em, final PluginData data) throws RapidDeployException {
this.setPluginData(data);
final String selectedReportTemplateName = getSelectedReportTemplateName();
final String reportFormat = getSelectedReportFormat();
final Map<String, Object> params = getSelectedReportParameters();
InputStream templateStream = null;
try {// Load report template
templateStream = loadReportTemplate(getSelectedReportTemplateName());
final JasperDesign design = JRXmlLoader.load(templateStream);
// Compile report template
final JasperReport report = JasperCompileManager.compileReport(design);
params.put("logo", loadReportLogo());
final Session session = em.unwrap(org.hibernate.Session.class);
try {
final JasperReportGenerator generator = new JasperReportGenerator(report, params, reportFormat);
session.doWork(generator);
return generator.getReport();
} finally {
if (session != null) session.close();
}
/*
* If you want to use another database connection to get the data then you can
* use a different Hibernate session factory.
*
* You can also create a new ReportGenerator if you do not want to use JapserReports.
* New report generators must implement the org.hibernate.jdbc.Work Interface.
*
*/
/*
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session1 = sessionFactory.openSession();
try {
final MyCustomReportGenerator myGenerator = new MyCustomReportGenerator(params, reportFormat);
session1.doWork(myGenerator);
return myGenerator.getReport();
} finally {
if (session1 != null) session1.close();
}
*/
} catch (final Exception e) {
throw new RapidDeployException("Error generating " + reportFormat + " report.", e);
} finally {
IOUtils.closeQuietly(templateStream);
}
}
/*
* This method returns the report icon, which is diplayed when the plugin is selected.
*
* @see com.midvision.rapiddeploy.service.plugin.AbstractPluginHandler#getIconResourceName()
*/
@Override
public String getIconResourceName() {
return "image/jasper_report_64.png";
}
/*
* This method returns the thumbnail report icon, which is diplayed when the plugin is in a table view.
*
* @see com.midvision.rapiddeploy.service.plugin.AbstractPluginHandler#getThumbnailResourceName()
*/
@Override
public String getThumbnailResourceName() {
return "image/jasper_report_24.png";
}
}Create the Service Provider
For the framework to be able to load the plugin from within the Jar file, a service provider file needs to be created to define which class contains the plugin implementation. In this example, create a file in the META-INF/services directory called com.midvision.rapiddeploy.domain.plugin.IPluginFunction. Add the class name of the plugin implementation class.
com.midvision.rapiddeploy.plugins.report.custom.CustomReports
Build the Plugin
Use maven to build the JAR file by running: mvn clean install.
Deploy the Plugin.
Copy the built Jar file to the $MV_HOME/lib dir, then restart the RapidDeploy server.
Conclusion
We have learnt how we implement a plugin API to generate a report. We then created a service provider so the framework knows which class to load.
Finally the plugin was built and deployed to the framework server.

