Writing IReport Plugins

  • Important Classes
  • IReport Netbeans plugin
  • Creating plugin
  • Adding Jars
  • ModuleInstall class
  • Defining classes to IReport / Jasper
  • Defining a JRDataSourceProvider to IReports
  • Define a IReportConnection
  • Define a Language to Jasper Reports
  • Define a Language to IReports
  • Examples
  • JRDataSourceProvider
  • FieldsProvider
  • IReportConnection

  • Writing IReport Plugins


    Important Classes

    These are some of the important iReports / Jasper Reports classes / interfaces


    Class Description
    JRDataSourceProvider Standard Jasper Reports designer interface. It can be used in iReports plus other designers.
    JRDataSource Standard Jasper Reports datasource.
    JRQueryExecuter Jasper Reports interface to execute a Query. Used to implement a Query Language.
    JRQueryExecuterFactory Jasper Reports interface to create JRQueryExecuter (Query Executer) classes. Used to implement a Query Language's
    IReportConnection iReports design interface, It provides an upgraded interface to iReports over JRDataSourceProvider.
    FieldsProvider Class to edit a Query / get the fields from a IReportConnection / JasperReport.
    IReportManager Main interface to iReports. It has a number of useful methods including

    addConnectionImplementation

    Adds a connection definition.

    addConnection

    Adds a connection to the list

    getConnections

    Get the current list of connections.

    getActiveReport

    Gets the active report. You can then get/set attributes get/set the query etc.

    saveiReportConfiguration

    Saves configuration.

    Misc iReports Misc class has some useful methods.
    IReportConnectionEditor iReports Class for editing a connections details.
    BasicIReportConnectionEditor Very basic connection editor
    WizardFieldsProvider iReports Interface for providing fields to iReports Report Wizard. If you wish to use your connection in the Report Wizard, you should implement this class.

    Typically if extending iReports you will either implement JRDataSourceProvider or extend IReportConnection (you also need to define a FieldsProvider class).. If implementing a Language, you will need to implement JRQueryExecuter and JRQueryExecuterFactory


    IReport Netbeans plugin

    Creating plugin

    The first step is to download the iReports source install into netbeans. Next Select File >> New Project to create your project


    Adding Jars

    In the Project Metadata you can specify jars you want to use. The class-path-extension is used to define the jars and package tag is used to define the java packages you intend to use.

       1:            <class-path-extension>
       2:                <runtime-relative-path>ext/FFReport.jar</runtime-relative-path>
       3:                <binary-origin>release/modules/ext/FFReport.jar</binary-origin>
       4:            </class-path-extension>
       5:            <class-path-extension>
       6:                <runtime-relative-path>ext/cb2xml.jar</runtime-relative-path>
       7:                <binary-origin>release/modules/ext/cb2xml.jar</binary-origin>
       8:            </class-path-extension>
       9:            <class-path-extension>
      10:                <runtime-relative-path>ext/JRecord.jar</runtime-relative-path>
      11:                <binary-origin>release/modules/ext/JRecord.jar</binary-origin>
      12:            </class-path-extension>
      13:            <class-path-extension>
      14:                <runtime-relative-path>ext/StAX.jar</runtime-relative-path>
      15:                <binary-origin>release/modules/ext/StAX.jar</binary-origin>
      16:            </class-path-extension>
      17:            <class-path-extension>
      18:                <runtime-relative-path>ext/TableLayout.jar</runtime-relative-path>
      19:                <binary-origin>release/modules/ext/TableLayout.jar</binary-origin>
      20:            </class-path-extension>
      21:            <class-path-extension>
      22:                <runtime-relative-path>ext/TableLayout.jar</runtime-relative-path>
      23:                <binary-origin>release/modules/ext/TableLayout.jar</binary-origin>
      24:            </class-path-extension>
      25:            <class-path-extension>
      26:                <runtime-relative-path>ext/properties.zip</runtime-relative-path>
      27:                <binary-origin>release/modules/ext/properties.zip</binary-origin>
      28:            </class-path-extension>
      29:            <public-packages>
      30:                <package>net.sf.FFReport.Connection</package>
      31:                <package>net.sf.FFReport.Screen</package>
      32:            </public-packages>
    

    ModuleInstall class

    Netbeans provides the ModuleInstall class (and a wizard to create them) to install your classes.

       1:package net.sf.ffreport;
       2:
       3:import org.openide.modules.ModuleInstall;
       4:
       5:/**
       6: * Manages a module's lifecycle. Remember that an installer is optional and
       7: * often not needed at all.
       8: */
       9:public class Installer extends ModuleInstall {
      10:
      11:    @Override
      12:    public void restored() {
      13:    // By default, do nothing.
      14:    // Put your startup code here.
      15:        net.sf.FFReport.Connection.DefineToIReport.define(
      16:                Manager.getInstance().getApllicationDirectory()
      17:        );
      18:    }
      19:}
      20:
    


    Defining classes to IReport / Jasper

    Defining a JRDataSourceProvider to IReports

    The class net.sf.FFReport.Provider.RecordXmlDataSourceProvider implements JRDataSourceProvider and acts as the interface between iReports and the RecordDataSource (file based data source for a report).

    Steps:



    Define a IReportConnection

    To define a generic connection implementation (which the user can taylor) to iReports

       1:        com.jaspersoft.ireport.designer.IReportManager.getInstance()
       2:                .addConnectionImplementation("net.sf.FFReport.Connection.RecordEditorConnection");
    

    to define a specific (fully defined) connection, use

       1:        com.jaspersoft.ireport.designer.IReportManager.getInstance()
       2:                .addConnection(connection);
    

    Define a Language to Jasper Reports

    To define a language to Jasper Reports, use the .JRProperties.setProperty method

       1:        net.sf.jasperreports.engine.util.JRProperties
       2:                .setProperty("net.sf.jasperreports.query.executer.factory.RecordEditor",
       3:                             "net.sf.FFReport.Connection.RecordEditorQryExecuterFactory");
    

    Define a Language to IReports

    To do it in java, use:

       1:        com.jaspersoft.ireport.designer.IReportManager.getInstance()
       2:                .addQueryExecuterDef(new com.jaspersoft.ireport.designer.data.queryexecuters.QueryExecuterDef(
       3:                        JasperConstants.LANGUAGE,
       4:                        "net.sf.FFReport.Connection.RecordEditorQryExecuterFactory",
       5:                        "net.sf.FFReport.Connection.RecordFieldsProvider"),
       6:                        false);
    

    To do it via screens

    1. Start iReports.

    2. Select Tools >> Options from the Main Menu.

    3. Select the iReports icon (if not already selected).

    4. Select the Query Executer tab

    5. Press the Add

    6. Enter the Language, JRQueryExecuterFactory class and FieldsProvider class.


    Examples

    JRDataSourceProvider

    JRDataSourceProvider is the standard Jasper Reports interface to a Report Desginer. iReports can use them

       1:package net.sf.FFReport.Provider;
       2:
       3:import java.util.ArrayList;
       4:
       5:import net.sf.FFReport.Common.JasperConstants;
       6:import net.sf.FFReport.Common.LayoutToJasperFields;
       7:import net.sf.FFReport.Common.Options;
       8:import net.sf.FFReport.Common.RecordDataSource;
       9:import net.sf.FFReport.Connection.QryDialog;
      10:import net.sf.FFReport.Screen.BaseRecordPnl;
      11:import net.sf.JRecord.Details.LayoutDetail;
      12:import net.sf.jasperreports.engine.JRDataSource;
      13:import net.sf.jasperreports.engine.JRDataSourceProvider;
      14:import net.sf.jasperreports.engine.JRException;
      15:import net.sf.jasperreports.engine.JRField;
      16:import net.sf.jasperreports.engine.JasperReport;
      17:import net.sf.jasperreports.engine.design.JRDesignField;
      18:
      19:/*
      20: * @Author Bruce Martin
      21: * Created on 30/11/2005
      22: *
      23: * Purpose:
      24: */
      25:
      26:/**
      27: * Base
      28: *
      29: * @author Bruce Martin
      30: *
      31: */
      32:public abstract class BaseDataSourceProvider implements JRDataSourceProvider {
      33:
      34:    private BaseRecordPnl panel;
      35:    private QryDialog dialog ;
      36:
      37:    protected String typeOfLayout;
      38:
      39:
      40:    private Options opt        = new Options();
      41:
      42:    private boolean toInitIRecord    = true;
      43:    private boolean isIRecordActive  = false;
      44:
      45:    static {
      46:        net.sf.FFReport.Connection.DefineToIReport.define();
      47:    }
      48:
      49:
      50:    protected final void init(BaseRecordPnl pnl) {
      51:        panel = pnl;
      52:
      53:        dialog = new QryDialog(panel);
      54:    }
      55:
      56:    /**
      57:     * @see net.sf.jasperreports.engine.JRDataSourceProvider#create(net.sf.jasperreports.engine.JasperReport)
      58:     * 
      59:     * Create a data-source for a report. In this case get the Data-Source properties from the reports properties Map
      60:     */
      61:    public JRDataSource create(JasperReport rpt) throws JRException {
      62:        RecordDataSource ret = null;
      63:
      64:        opt.parseMap(rpt.getPropertiesMap());
      65:
      66:        opt.setFileRequired(true);
      67:        panel.setOptions(opt);
      68:        dialog.setVisible(true);
      69:        updateAttributes(rpt);
      70:
      71:        if (opt.isAllOk()) {
      72:            ret = create_datasource(rpt);
      73:        }
      74:
      75:        return ret;
      76:    }
      77:
      78:    /**
      79:     * create a datasource from the options / report properties
      80:     * @param rpt jasper report definition
      81:     * @return the RecordDataSource
      82:     * @throws JRException any error that has occurred
      83:     */
      84:    private RecordDataSource create_datasource(JasperReport rpt) throws JRException {
      85:        RecordDataSource ret;
      86:        try {
      87:            int recordIdx = opt.getRptRecordIndex();
      88:            ret = new RecordDataSource(
      89:                    opt.getLayout(),
      90:                    rpt.getProperty(JasperConstants.PROPERTY_FILE)
      91:                  );
      92:            if (recordIdx >= 0) {
      93:                ret.setRequiredRecord(recordIdx);
      94:            }
      95:        } catch (Exception e) {
      96:            throw new JRException(e);
      97:        }
      98:        return ret;
      99:    }
     100:
     101:
     102:    /**
     103:     * @see net.sf.jasperreports.engine.JRDataSourceProvider#dispose(net.sf.jasperreports.engine.JRDataSource)
     104:     */
     105:    public void dispose(JRDataSource rpt) throws JRException {
     106:
     107:    }
     108:
     109:
     110:    /**
     111:     * @see net.sf.jasperreports.engine.JRDataSourceProvider#getFields(net.sf.jasperreports.engine.JasperReport)
     112:     * 
     113:     * Get the Report fields
     114:     */
     115:    public JRField[] getFields(JasperReport rpt) throws JRException {
     116:        LayoutDetail layout;
     117:        JRDesignField[] fields = null;
     118:
     119:
     120:        opt.setFileRequired(false);
     121:
     122:        panel.setOptions(opt);
     123:        dialog.setVisible(true);
     124:        updateAttributes(rpt);
     125:
     126:        layout = opt.getLayout();
     127:
     128:        LayoutToJasperFields cnv = new LayoutToJasperFields(
     129:                layout, opt.getSelectedRecords(),
     130:                opt.isFormatAsNumeric(), opt.getRptRecordIndex()
     131:        );
     132:        ArrayList<JRDesignField> flds = cnv.getFields();
     133:        fields = new JRDesignField[flds.size()];
     134:
     135:        fields = cnv.getFields().toArray(fields);
     136:
     137:        return fields;
     138:    }
     139:
     140:    /**
     141:     * Update the attributes in the report / back in iReports
     142:     * @param rpt Jasper Report Definition
     143:     */
     144:    private void updateAttributes(JasperReport rpt) {
     145:
     146:        String v;
     147:        opt = panel.getOptions();
     148:
     149:        for (int i = 0; i < Options.NUMBER_OF_ATTRIBUTES; i++) {
     150:            v = opt.getAttribute(i);
     151:
     152:            if (v != null) {
     153:                setProperty(rpt, Options.getAttributeName(i), v);
     154:            }
     155:        }
     156:
     157:        if (isIReport()) {
     158:            net.sf.FFReport.Common.Code.setQuery(opt.getQuery());
     159:        }
     160:    }
     161:
     162:
     163:    /**
     164:     * Set one jasper report property
     165:     * @param rpt jasper report definition
     166:     * @param name property name
     167:     * @param value value to assign to the property
     168:     */
     169:    protected final void setProperty(JasperReport rpt, String name, String value) {
     170:
     171:        if (rpt != null) {
     172:            rpt.setProperty(name, value);
     173:       }
     174:
     175:        if (isIReport()) {
     176:            net.sf.FFReport.Common.Code.setReportAttribute(name, value);
     177:        }
     178:    }
     179:
     180:    /**
     181:     * Is this being run from IReport Report designer
     182:     * @return is this being run from IReports
     183:     */
     184:    private boolean isIReport() {
     185:
     186:        if (toInitIRecord) {
     187:            try {
     188:                isIRecordActive = net.sf.FFReport.Common.Code.isIReport();
     189:            } catch (NoClassDefFoundError e) {
     190:                isIRecordActive = false;
     191:            }
     192:
     193:            toInitIRecord = false;
     194:        }
     195:        isIRecordActive = true;
     196:
     197:        return isIRecordActive;
     198:    }
     199:
     200:    /**
     201:     * @see net.sf.jasperreports.engine.JRDataSourceProvider#supportsGetFieldsOperation()
     202:     */
     203:    public final boolean supportsGetFieldsOperation() {
     204:        return true;
     205:    }
     206:
     207:
     208:
     209:    /**
     210:     * Check if the string is not null/""
     211:     * @param s string to test
     212:     * @return wether there is a value in the string
     213:     */
     214:    protected final boolean isPresent(String s) {
     215:        return s != null && ! "".equals(s);
     216:    }
     217:}
     218:
    

    FieldsProvider

    FieldsProvider provide a connection between iReports Designer and a IReportConnection class.

       1:package net.sf.FFReport.Connection;
       2:
       3:import java.util.List;
       4:import java.util.Map;
       5:
       6:
       7:import net.sf.jasperreports.engine.JRDataset;
       8:import net.sf.jasperreports.engine.JRException;
       9:import net.sf.jasperreports.engine.JRField;
      10:import net.sf.jasperreports.engine.design.JRDesignField;
      11:
      12:import com.jaspersoft.ireport.designer.FieldsProvider;
      13:import com.jaspersoft.ireport.designer.FieldsProviderEditor;
      14:import com.jaspersoft.ireport.designer.IReportConnection;
      15:import com.jaspersoft.ireport.designer.data.ReportQueryDialog;
      16:import com.jaspersoft.ireport.designer.data.WizardFieldsProvider;
      17:
      18:public class RecordFieldsProvider implements FieldsProvider {
      19:
      20:
      21:    @Override
      22:    public String designQuery(IReportConnection con, String query,
      23:            ReportQueryDialog reportQueryDialog) throws JRException,
      24:            UnsupportedOperationException {
      25:
      26:        String type = null;
      27:        if (con instanceof BaseConnection) {
      28:            type = ((BaseConnection) con).getTypeOfLayout();
      29:
      30:        }
      31:
      32:        return (new QryDialog(type)).editQuery(query);
      33:    }
      34:
      35:    @Override
      36:    public FieldsProviderEditor getEditorComponent(
      37:            ReportQueryDialog reportQueryDialog) {
      38:        return null;
      39:    }
      40:
      41:    @SuppressWarnings("unchecked")
      42:    public @Override JRField[] getFields(IReportConnection con, JRDataset reportDataset,
      43:            Map parameters) throws JRException, UnsupportedOperationException {
      44:
      45:        String query = "";
      46:
      47:        if (reportDataset.getQuery() != null
      48:            && reportDataset.getQuery().getText() != null) {
      49:            query = reportDataset.getQuery().getText();
      50:        }
      51:
      52:        JRField[] ret = null;
      53:
      54:        if (con instanceof WizardFieldsProvider) {
      55:            try {
      56:                List<JRDesignField> list = ((WizardFieldsProvider) con).readFields(query);
      57:                if (list != null && list.size() > 0) {
      58:                    ret = new JRDesignField[list.size()];
      59:                    ret = list.toArray(ret);
      60:                }
      61:            } catch (Exception e) {
      62:                e.printStackTrace();
      63:            }
      64:        }
      65:        return ret;
      66:    }
      67:
      68:    @Override
      69:    public boolean hasEditorComponent() {
      70:        return false;
      71:    }
      72:
      73:    @Override
      74:    public boolean hasQueryDesigner() {
      75:        return true;
      76:    }
      77:
      78:    @Override
      79:    public boolean supportsAutomaticQueryExecution() {
      80:        return false;
      81:    }
      82:
      83:    @Override
      84:    public boolean supportsGetFieldsOperation() {
      85:        return true;
      86:    }
      87:
      88:}
      89:
    

    IReportConnection

    IReportConnection's are the main designer classses in iReports

       1:package net.sf.FFReport.Connection;
       2:
       3:import java.util.List;
       4:
       5:import javax.swing.JOptionPane;
       6:
       7:
       8:import net.sf.FFReport.Common.JasperConstants;
       9:import net.sf.FFReport.Common.LayoutToJasperFields;
      10:import net.sf.FFReport.Common.Options;
      11:import net.sf.FFReport.Common.RecordDataSource;
      12:import net.sf.FFReport.Screen.BaseRecordPnl;
      13:
      14:import net.sf.jasperreports.engine.JRDataSource;
      15:import net.sf.jasperreports.engine.JREmptyDataSource;
      16:import net.sf.jasperreports.engine.JasperReport;
      17:import net.sf.jasperreports.engine.design.JRDesignField;
      18:
      19:import com.jaspersoft.ireport.designer.IReportConnectionEditor;
      20:import com.jaspersoft.ireport.designer.connection.JRDataSourceProviderConnection;
      21:import com.jaspersoft.ireport.designer.connection.gui.BasicIReportConnectionEditor;
      22:import com.jaspersoft.ireport.designer.data.WizardFieldsProvider;
      23:import com.jaspersoft.ireport.designer.utils.Misc;
      24:
      25:/**
      26: * @author bm
      27: *
      28: */
      29:public class BaseConnection extends JRDataSourceProviderConnection //IReportConnection 
      30:                         implements WizardFieldsProvider {
      31://TODO - need to change to extend IReportConnection instead of JRDataSourceProviderConnection
      32:
      33:    private BaseRecordPnl panel;
      34:    private QryDialog dialog ;
      35:    @SuppressWarnings("unchecked")
      36:    private java.util.HashMap properties = new java.util.HashMap();
      37:
      38:    private String dfltName;
      39:
      40:
      41:    @SuppressWarnings("unchecked")
      42:    protected final void init(BaseRecordPnl pnl, String defaultName) {
      43:        panel = pnl;
      44:        dfltName = defaultName;
      45:
      46:        properties.put(JasperConstants.PROPERTY_TYPE, panel.getTypeOfLayout());
      47:        dialog = new QryDialog(panel);
      48:    }
      49:
      50:    /**
      51:     * @see com.jaspersoft.ireport.designer.IReportConnection#getDescription()
      52:     */
      53:    @Override
      54:    public String getDescription() {
      55:        return "RecordEditor_" + panel.getTypeOfLayout();
      56:    }
      57:
      58:    @SuppressWarnings("unchecked")
      59:    public java.util.HashMap getProperties() {
      60:        return properties;
      61:    }
      62:
      63:    /** All properties of a IReportConnection are stored in a XML file as Pair key/value
      64:     *  This HashMap contains all properties found for this IReportConnection in the
      65:     *  XML. You must use this hashMap to initialize all attributes of your IReprotConnection
      66:     */
      67:    @SuppressWarnings("unchecked")
      68:    public void loadProperties(java.util.HashMap map) {
      69:        map.put(JasperConstants.PROPERTY_TYPE, panel.getTypeOfLayout());
      70:        properties = map;
      71:    }
      72:
      73:
      74:    /**
      75:     * @see com.jaspersoft.ireport.designer.IReportConnection#getJRDataSource()
      76:     */
      77:    @Override
      78:    public JRDataSource getJRDataSource() {
      79:        return getJRDataSource(null);
      80:    }
      81:
      82:    /**
      83:     * Create data-source for a jasper-report. 
      84:     */
      85:    public net.sf.jasperreports.engine.JRDataSource getJRDataSource(JasperReport jasper) {
      86:        Options opt;
      87:
      88:
      89:        if (jasper == null) {
      90:            opt = panel.getOptions();
      91:        } else {
      92:            opt = new Options();
      93:
      94:            opt.parseQuery(jasper.getQuery().getText());
      95:        }
      96:
      97:        try {
      98:            RecordDataSource ret = new RecordDataSource(opt.getLayout(), opt.getFileName());
      99:
     100:            if (opt.getRptRecordIndex() >= 0) {
     101:                ret.setRequiredRecord(opt.getRptRecordIndex());
     102:            }
     103:            return ret;
     104:        } catch (Exception e) {
     105:            e.printStackTrace();
     106:        }
     107:
     108:        return new JREmptyDataSource();
     109:    }
     110:
     111:
     112:    /**
     113:     * @see com.jaspersoft.ireport.designer.IReportConnection#getIReportConnectionEditor()
     114:     * Get Connection Details Editor
     115:     */
     116:    @Override
     117:    public IReportConnectionEditor getIReportConnectionEditor() {
     118:        IReportConnectionEditor ret = new BasicIReportConnectionEditor();
     119:        ret.setIReportConnection(this);
     120:
     121:        return ret;
     122:    }
     123:
     124:
     125:    /**
     126:     * @see com.jaspersoft.ireport.designer.connection.JRDataSourceProviderConnection#test()
     127:     */
     128:    @Override
     129:    public void test() throws Exception {
     130:        JOptionPane.showMessageDialog(Misc.getMainWindow(),
     131:                "Connection test successful!","",JOptionPane.INFORMATION_MESSAGE); //"messages.connectionDialog.connectionTestSuccessful"
     132:    }
     133:
     134:
     135:    /**
     136:     * @see com.jaspersoft.ireport.designer.IReportConnection#getName()
     137:     */
     138:    @Override
     139:    public String getName() {
     140:        String name = super.getName();
     141:
     142:        if (name == null || "".equals(name)) {
     143:            name = dfltName;
     144:        }
     145:
     146:        return name;
     147:    }
     148:
     149:
     150:    /**
     151:     * @see com.jaspersoft.ireport.designer.data.WizardFieldsProvider#designQuery(java.lang.String)
     152:     */
     153:    @Override
     154:    public String designQuery(String query) {
     155:
     156:        return  dialog.editQuery(query);
     157:    }
     158:
     159:    /**
     160:     * @see com.jaspersoft.ireport.designer.data.WizardFieldsProvider#getQueryLanguage()
     161:     */
     162:    @Override
     163:    public String getQueryLanguage() {
     164:        return "RecordEditor";
     165:    }
     166:
     167:    /**
     168:     * @see com.jaspersoft.ireport.designer.data.WizardFieldsProvider#readFields(java.lang.String)
     169:     */
     170:    @Override
     171:    public List<JRDesignField> readFields(String query) throws Exception {
     172:        List<JRDesignField> ret  = null;
     173:
     174:        try {
     175:            Options opts = new Options();
     176:
     177:            opts.qryType = panel.getTypeOfLayout();
     178:            opts.parseQuery(query);
     179:
     180:            if (opts.getLayout() != null) {
     181:                LayoutToJasperFields cnv = new LayoutToJasperFields(
     182:                        opts.getLayout(), opts.getSelectedRecords(),
     183:                        opts.isFormatAsNumeric(),
     184:                        opts.getRptRecordIndex()
     185:                );
     186:                ret =  cnv.getFields();
     187:            }
     188:
     189:            } catch (Exception e) {
     190:                e.printStackTrace();
     191:            }
     192:        return ret;
     193:    }
     194:
     195:
     196:    /**
     197:     * @see com.jaspersoft.ireport.designer.data.WizardFieldsProvider#supportsDesign()
     198:     * 
     199:     * Does the class support a Design dialog ??
     200:     */
     201:    @Override
     202:    public boolean supportsDesign() {
     203:        return true;
     204:    }
     205:
     206:
     207:    /**
     208:     * @return the typeOfLayout
     209:     */
     210:    public final String getTypeOfLayout() {
     211:        return panel.getTypeOfLayout();
     212:    }
     213:}
     214: