org.glom.web.server.ReportGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.glom.web.server.ReportGenerator.java

Source

/*
 * Copyright (C) 2012 Openismus GmbH
 *
 * This file is part of GWT-Glom.
 *
 * GWT-Glom is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with GWT-Glom.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.glom.web.server;

import java.io.ByteArrayOutputStream;
import java.sql.Connection;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignField;
import net.sf.jasperreports.engine.design.JRDesignGroup;
import net.sf.jasperreports.engine.design.JRDesignLine;
import net.sf.jasperreports.engine.design.JRDesignQuery;
import net.sf.jasperreports.engine.design.JRDesignSection;
import net.sf.jasperreports.engine.design.JRDesignStaticText;
import net.sf.jasperreports.engine.design.JRDesignStyle;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRXhtmlExporter;

import org.apache.commons.lang3.StringUtils;
import org.glom.web.server.libglom.Document;
import org.glom.web.shared.TypedDataItem;
import org.glom.web.shared.libglom.Field.GlomFieldType;
import org.glom.web.shared.libglom.NumericFormat;
import org.glom.web.shared.libglom.Report;
import org.glom.web.shared.libglom.layout.Formatting;
import org.glom.web.shared.libglom.layout.LayoutGroup;
import org.glom.web.shared.libglom.layout.LayoutItem;
import org.glom.web.shared.libglom.layout.LayoutItemField;
import org.glom.web.shared.libglom.layout.SortClause;
import org.glom.web.shared.libglom.layout.UsesRelationship;
import org.glom.web.shared.libglom.layout.reportparts.LayoutItemGroupBy;
import org.glom.web.shared.libglom.layout.reportparts.LayoutItemVerticalGroup;
import org.jooq.Condition;

/**
 * @author Murray Cumming <murrayc@openimus.com>
 * 
 */
public class ReportGenerator {

    private static class Position {
        public Position(final int x, final int y) {
            this.x = x;
            this.y = y;
        }

        public Position(final Position pos) {
            this.x = pos.x;
            this.y = pos.y;
        }

        public int x = 0;
        public int y = 0;
    }

    final int height = 30; // Points, as specified later.
    // An arbitrary width, because we must specify _some_ width:
    final int width = 100; // Points, as specified later.

    List<LayoutItemField> fieldsToGet = new ArrayList<LayoutItemField>();
    SortClause sortClause = new SortClause();
    String localeID;

    final JasperDesign design = new JasperDesign();
    JRDesignStyle titleStyle = new JRDesignStyle();
    JRDesignStyle normalStyle = new JRDesignStyle();
    JRDesignStyle fieldTitleStyle = new JRDesignStyle();

    ReportGenerator(final String localeID) {
        this.localeID = StringUtils.defaultString(localeID);
    }

    /**
     */
    public String generateReport(final Document glomDocument, final String tableName, final Report report,
            final Connection connection, final String quickFind) {

        final LayoutGroup layout_group = report.getLayoutGroup();

        design.setName(report.getTitle(localeID)); // TODO: Actually, we want the title.

        titleStyle.setName("Sans_Title");
        titleStyle.setFontName("DejaVu Sans");
        titleStyle.setFontSize(24);
        normalStyle.setName("Sans_Normal");
        normalStyle.setDefault(true);
        normalStyle.setFontName("DejaVu Sans");
        normalStyle.setFontSize(12);
        normalStyle.setBlankWhenNull(true); // Avoid "null" appearing in reports.
        fieldTitleStyle.setName("Sans_Bold");
        fieldTitleStyle.setFontName("DejaVu Sans");
        fieldTitleStyle.setFontSize(12);
        fieldTitleStyle.setBold(true);
        fieldTitleStyle.setBlankWhenNull(true); // Avoid "null" appearing in reports when this is used for a GroupBy
        // title.
        try {
            design.addStyle(titleStyle);
            design.addStyle(normalStyle);
            design.addStyle(fieldTitleStyle);
        } catch (final JRException ex) {
            // TODO Auto-generated catch block
            ex.printStackTrace();
        }

        final JRDesignBand titleBand = new JRDesignBand();
        titleBand.setHeight(height);
        final JRDesignStaticText staticTitle = new JRDesignStaticText();
        staticTitle.setText(report.getTitle(localeID));
        staticTitle.setY(0);
        staticTitle.setX(0);
        staticTitle.setWidth(width * 5); // No data will be shown without this.
        // staticTitle.setStretchWithOverflow(true);
        staticTitle.setHeight(height); // We must specify _some_ height.
        staticTitle.setStyle(titleStyle);
        titleBand.addElement(staticTitle);
        design.setTitle(titleBand);

        final JRDesignBand detailBand = new JRDesignBand();
        detailBand.setHeight(height + 20);

        final JRDesignBand headerBand = new JRDesignBand();
        headerBand.setHeight(height + 20);

        fieldsToGet = new ArrayList<LayoutItemField>();
        final int x = 0;
        addGroupToReport(layout_group, detailBand, x, headerBand, 0);

        design.setColumnHeader(headerBand);
        ((JRDesignSection) design.getDetailSection()).addBand(detailBand);

        // Later versions of libglom actually return an empty SqlExpr when quickFindValue is empty,
        // but let's be sure:
        Condition whereClause = null;
        if (!StringUtils.isEmpty(quickFind)) {
            final TypedDataItem quickFindValue = new TypedDataItem();
            quickFindValue.setText(quickFind);
            whereClause = SqlUtils.getFindWhereClauseQuick(glomDocument, tableName, quickFindValue);
        }

        String sqlQuery = "";
        if (!fieldsToGet.isEmpty()) {
            sqlQuery = SqlUtils.buildSqlSelectWithWhereClause(tableName, fieldsToGet, whereClause, sortClause,
                    glomDocument.getSqlDialect());
        } else {
            Log.info("generateReport(): fieldsToGet is empty.");
        }

        final JRDesignQuery query = new JRDesignQuery();
        query.setText(sqlQuery); // TODO: Extra sort clause to sort the rows within the groups.
        design.setQuery(query);

        JasperReport jasperreport;
        try {
            jasperreport = JasperCompileManager.compileReport(design);
        } catch (final JRException ex) {
            ex.printStackTrace();
            return "Failed to Generate HTML: compileReport() failed.";
        }

        JasperPrint print;
        try {
            final HashMap<String, Object> parameters = new HashMap<String, Object>();
            parameters.put("ReportTitle", report.getTitle(localeID)); // TODO: Use the title, not the name.
            print = JasperFillManager.fillReport(jasperreport, parameters, connection);
        } catch (final JRException ex) {
            ex.printStackTrace();
            return "Failed to Generate HTML: fillReport() failed.";
        }

        final ByteArrayOutputStream output = new ByteArrayOutputStream();

        // We use this because there is no JasperExportManager.exportReportToHtmlStream() method.
        // JasperExportManager.exportReportToXmlStream(print, output);
        try {
            final JRXhtmlExporter exporter = new JRXhtmlExporter();
            exporter.setParameter(JRExporterParameter.JASPER_PRINT, print);
            exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, output);

            // Use points instead of pixels for sizes, because pixels are silly
            // in HTML:
            exporter.setParameter(JRHtmlExporterParameter.SIZE_UNIT, "pt");

            // Avoid the page breaks, because they do not make sense for HTML:
            // TODO: These do not seem to preven the page break gap.
            exporter.setParameter(JRHtmlExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
            exporter.setParameter(JRHtmlExporterParameter.BETWEEN_PAGES_HTML, "");

            exporter.exportReport();
        } catch (final JRException ex) {
            ex.printStackTrace();
            return "Failed to Generate HTML: exportReport() failed.";
        }

        // System.out.print(output.toString() + "\n");
        final String html = output.toString();

        // This does not work because jasperReports does not put individual rows in separate table rows.
        // jasperReports just puts the whole thing in one table row.
        // Remove the arbitrary width and height that JasperReports forced us to specify:
        // html = html.replaceAll("position:absolute;", "");
        // html = html.replaceAll("top:(\\d*)pt;", "");
        // html = html.replaceAll("left:(\\d*)pt;", "");
        // html = html.replaceAll("height:(\\d*)pt;", "");
        // html = html.replaceAll("width:(\\d*)pt;", "");
        // html = html.replaceAll("overflow: hidden;", "");

        return html;
    }

    /**
     * A vertical group lays the fields out vertically instead of horizontally, with titles to the left.
     * 
     * @param layout_group
     * @param parentBand
     * @param x
     * @param fieldTitlesY
     *            TODO
     * @param height
     */
    private Position addVerticalGroupToReport(final LayoutItemVerticalGroup layout_group,
            final JRDesignBand parentBand, final Position pos) {
        Position pos_result = new Position(pos);

        final List<LayoutItem> layoutItemsVec = layout_group.getItems();
        final int numItems = Utils.safeLongToInt(layoutItemsVec.size());
        for (int i = 0; i < numItems; i++) {
            final LayoutItem libglomLayoutItem = layoutItemsVec.get(i);

            if (libglomLayoutItem instanceof LayoutItemField) {
                final LayoutItemField libglomLayoutItemField = (LayoutItemField) libglomLayoutItem;
                pos_result = addFieldToDetailBandVertical(parentBand, pos_result, libglomLayoutItemField);
                pos_result.x = pos.x;
            } else {

                // TODO: Handle other item types.

                // Recurse into sub-groups:
                // TODO: x = addGroupToReport(libglomLayoutGroup, parentBand, x, fieldTitlesBand, thisFieldTitlesY);
            }
        }

        pos_result.x += width * 2;
        return pos_result;
    }

    /**
     * @param layout_group
     * @param parentBand
     * @param x
     * @param fieldTitlesY
     *            TODO
     * @param height
     */
    private Position addGroupToReport(final LayoutGroup layout_group, final JRDesignBand parentBand, final int x,
            final JRDesignBand headerBand, final int fieldTitlesY) {

        Position pos_result = new Position(x, 0);

        /**
         * * If this is a vertical group then we will lay the fields out vertically instead of horizontally.
         */
        if (layout_group instanceof LayoutItemVerticalGroup) {
            final LayoutItemVerticalGroup verticalGroup = (LayoutItemVerticalGroup) layout_group;
            return addVerticalGroupToReport(verticalGroup, parentBand, pos_result);
        }

        // Where we put the field titles depends on whether we are in a group-by:
        JRDesignBand fieldTitlesBand = headerBand;
        int thisFieldTitlesY = fieldTitlesY; // If they are in a group title then they must be lower.

        final List<LayoutItem> layoutItemsVec = layout_group.getItems();
        final int numItems = Utils.safeLongToInt(layoutItemsVec.size());
        for (int i = 0; i < numItems; i++) {
            final LayoutItem libglomLayoutItem = layoutItemsVec.get(i);

            if (libglomLayoutItem instanceof LayoutItemField) {
                final LayoutItemField libglomLayoutItemField = (LayoutItemField) libglomLayoutItem;
                pos_result = addFieldToDetailBand(parentBand, headerBand, pos_result.x, libglomLayoutItemField,
                        thisFieldTitlesY, pos_result.y);
            } else if (libglomLayoutItem instanceof LayoutGroup) {
                final LayoutGroup libglomLayoutGroup = (LayoutGroup) libglomLayoutItem;

                if (libglomLayoutGroup instanceof LayoutItemGroupBy) {
                    final LayoutItemGroupBy libglomGroupBy = (LayoutItemGroupBy) libglomLayoutGroup;
                    final LayoutItemField fieldGroupBy = libglomGroupBy.getFieldGroupBy();
                    if (fieldGroupBy == null) {
                        continue;
                    }

                    final String fieldName = addField(fieldGroupBy);
                    if (StringUtils.isEmpty(fieldName)) {
                        continue;
                    }

                    // We must sort by the group field,
                    // so that JasperReports can start a new group when its value changes.
                    // Note that this is not like a SQL GROUP BY.
                    final SortClause.SortField pair = new SortClause.SortField();
                    pair.field = fieldGroupBy;
                    pair.ascending = true;
                    sortClause.add(pair);

                    final JRDesignGroup group = new JRDesignGroup();
                    group.setName(fieldName);

                    // Show the field value:
                    final JRDesignExpression expression = createFieldExpression(fieldGroupBy);
                    group.setExpression(expression);

                    try {
                        design.addGroup(group);
                    } catch (final JRException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    // Show the group-by field:
                    final JRDesignBand groupBand = new JRDesignBand();

                    // TODO: Use height instead of height*2 if there are no child fields,
                    // for instance if the only child is a sub group-by.
                    groupBand.setHeight(height * 2); // Enough height for the title and the field titles.
                    ((JRDesignSection) group.getGroupHeaderSection()).addBand(groupBand);

                    // Put the field titles inside the group-by instead of just at the top of the page.
                    // (or instead of just in the parent group-by):
                    fieldTitlesBand = groupBand;
                    thisFieldTitlesY = height;

                    /*
                     * final JRDesignBand footerBand = new JRDesignBand(); footerBand.setHeight(height);
                     * ((JRDesignSection) group.getGroupFooterSection()).addBand(footerBand);
                     */

                    int groupX = addFieldToGroupBand(groupBand, x, fieldGroupBy);

                    // Show the secondary fields:
                    final LayoutGroup groupSecondaries = libglomGroupBy.getSecondaryFields();
                    if (groupSecondaries != null) {
                        groupX = addSecondaryFieldsToGroupBand(groupSecondaries, groupBand, groupX);
                    }

                    final JRDesignLine line = new JRDesignLine();
                    final int lineheight = 1;
                    line.setX(0);

                    // TODO: Automatically place it below the text, though that needs us to know how much height the
                    // text really needs.
                    line.setY(height - 15);

                    // TODO: Make it as wide as needed by the details band.
                    line.setWidth(groupX);
                    line.setHeight(lineheight);
                    groupBand.addElement(line);
                }

                // Recurse into sub-groups:
                pos_result = addGroupToReport(libglomLayoutGroup, parentBand, pos_result.x, fieldTitlesBand,
                        thisFieldTitlesY);
            }
        }

        return pos_result;
    }

    private int addSecondaryFieldsToGroupBand(final LayoutGroup layout_group, final JRDesignBand groupBand, int x) {
        final List<LayoutItem> layoutItemsVec = layout_group.getItems();
        final int numItems = Utils.safeLongToInt(layoutItemsVec.size());
        for (int i = 0; i < numItems; i++) {
            final LayoutItem libglomLayoutItem = layoutItemsVec.get(i);

            if (libglomLayoutItem instanceof LayoutItemField) {
                final LayoutItemField libglomLayoutItemField = (LayoutItemField) libglomLayoutItem;
                x = addFieldToGroupBand(groupBand, x, libglomLayoutItemField);
            } else if (libglomLayoutItem instanceof LayoutGroup) {
                final LayoutGroup libglomLayoutGroup = (LayoutGroup) libglomLayoutItem;

                // We do not expect LayoutItem_GroupBy in the secondary fields:
                // final LayoutItem_GroupBy libglomGroupBy = LayoutItem_GroupBy.cast_dynamic(libglomLayoutGroup);

                // Recurse into sub-groups:
                x = addSecondaryFieldsToGroupBand(libglomLayoutGroup, groupBand, x);
            }
        }

        return x;
    }

    /**
     * @param libglomLayoutItemField
     * @return
     */
    private JRDesignExpression createFieldExpression(final LayoutItemField libglomLayoutItemField) {
        final JRDesignExpression expression = new JRDesignExpression();

        final String fieldName = libglomLayoutItemField.getName(); // TODO: Is this enough for related fields?

        // TODO: Where is this format documented?
        expression.setText("$F{" + fieldName + "}");
        return expression;
    }

    /**
     * @param parentBand
     * @param x
     * @param libglomLayoutItemField
     * @param fieldTitlesY
     *            TODO
     * @return
     */
    private Position addFieldToDetailBand(final JRDesignBand parentBand, final JRDesignBand headerBand, final int x,
            final LayoutItemField libglomLayoutItemField, final int fieldTitlesY, final int fieldY) {
        addField(libglomLayoutItemField);

        // Show the field title:
        final JRDesignStaticText textFieldColumn = createFieldTitleElement(new Position(x, fieldTitlesY),
                libglomLayoutItemField, false);
        textFieldColumn.setStyle(fieldTitleStyle);
        headerBand.addElement(textFieldColumn);

        // Show an instance of the field (the field value):
        final JRDesignTextField textField = createFieldValueElement(new Position(x, 0), libglomLayoutItemField);
        textField.setStyle(normalStyle);
        parentBand.addElement(textField);

        return new Position(x + width, 0);
    }

    /**
     * @param parentBand
     * @param x
     * @param libglomLayoutItemField
     * @param fieldTitlesY
     *            TODO
     * @return
     */
    private Position addFieldToDetailBandVertical(final JRDesignBand parentBand, final Position pos,
            final LayoutItemField libglomLayoutItemField) {
        addField(libglomLayoutItemField);

        final Position pos_result = new Position(pos);

        // Make the band high enough if necessary:
        if (parentBand.getHeight() < (pos_result.y + height)) {
            parentBand.setHeight(pos_result.y + height + 20);
        }

        // Show the field title:
        final JRDesignStaticText textFieldColumn = createFieldTitleElement(pos_result, libglomLayoutItemField,
                true);
        textFieldColumn.setStyle(fieldTitleStyle);
        parentBand.addElement(textFieldColumn);
        pos_result.x += width;

        // Show an instance of the field (the field value):
        final JRDesignTextField textField = createFieldValueElement(pos_result, libglomLayoutItemField);
        textField.setStyle(normalStyle);
        parentBand.addElement(textField);

        pos_result.x += width;

        pos_result.y += height;

        return pos_result;
    }

    private int addFieldToGroupBand(final JRDesignBand parentBand, final int x,
            final LayoutItemField libglomLayoutItemField) {
        addField(libglomLayoutItemField);

        final Position pos = new Position(x, 0);

        // Show the field title:
        final JRDesignStaticText textFieldColumn = createFieldTitleElement(pos, libglomLayoutItemField, true);

        // Instead, the field value will be bold, because here it is like a title.
        textFieldColumn.setStyle(normalStyle);

        parentBand.addElement(textFieldColumn);
        pos.x += width;

        // Show an instance of the field (the field value):
        final JRDesignTextField textField = createFieldValueElement(pos, libglomLayoutItemField);
        parentBand.addElement(textField);
        textField.setStyle(fieldTitleStyle);

        pos.x += width;
        return pos.x;
    }

    /**
     * @param x
     * @param libglomLayoutItemField
     * @return
     */
    private JRDesignTextField createFieldValueElement(final Position pos,
            final LayoutItemField libglomLayoutItemField) {
        final JRDesignTextField textField = new JRDesignTextField();

        // Make sure this field starts at the right of the previous field,
        // because JasperReports uses absolute positioning.
        textField.setY(pos.y);
        textField.setX(pos.x);
        textField.setWidth(width); // No data will be shown without this.

        // This only stretches vertically, but that is better than
        // nothing.
        textField.setStretchWithOverflow(true);
        textField.setHeight(height); // We must specify _some_ height.

        final JRDesignExpression expression = createFieldExpression(libglomLayoutItemField);
        textField.setExpression(expression);

        if (libglomLayoutItemField.getGlomType() == GlomFieldType.TYPE_NUMERIC) {
            // Numeric formatting:
            final Formatting formatting = libglomLayoutItemField.getFormattingUsed();
            final NumericFormat numericFormat = formatting.getNumericFormat();

            final DecimalFormat format = new DecimalFormat();
            format.setMaximumFractionDigits(numericFormat.getDecimalPlaces());
            format.setGroupingUsed(numericFormat.getUseThousandsSeparator());

            // TODO: Use numericFormat.get_currency_symbol(), possibly via format.setCurrency().
            textField.setPattern(format.toPattern());
        } else if (libglomLayoutItemField.getGlomType() == GlomFieldType.TYPE_DATE) {
            // Date formatting
            // TODO: Use a 4-digit-year short form, somehow.
            try // We use a try block because getDateInstance() is not guaranteed to return a SimpleDateFormat.
            {
                final SimpleDateFormat format = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
                        Locale.ROOT);

                textField.setPattern(format.toPattern());
            } catch (final Exception ex) {
                Log.info("ReportGenerator: The cast of SimpleDateFormat failed.");
            }
        } else if (libglomLayoutItemField.getGlomType() == GlomFieldType.TYPE_TIME) {
            // Time formatting
            try // We use a try block because getDateInstance() is not guaranteed to return a SimpleDateFormat.
            {
                final SimpleDateFormat format = (SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.SHORT,
                        Locale.ROOT);

                textField.setPattern(format.toPattern());
            } catch (final Exception ex) {
                Log.info("ReportGenerator: The cast of SimpleDateFormat failed.");
            }
        }

        return textField;
    }

    /**
     * @param x
     * @param y
     *            TODO
     * @param libglomLayoutItemField
     * @return
     */
    private JRDesignStaticText createFieldTitleElement(final Position pos,
            final LayoutItemField libglomLayoutItemField, final boolean withColon) {
        final JRDesignStaticText textFieldColumn = new JRDesignStaticText();

        String title = StringUtils.defaultString(libglomLayoutItemField.getTitle(this.localeID));

        // If the title is at the left, instead of above, we need a : to show that it's a title.
        if (withColon) {
            title += ":";
        }

        textFieldColumn.setText(title);
        textFieldColumn.setY(pos.y);
        textFieldColumn.setX(pos.x);
        textFieldColumn.setWidth(width); // No data will be shown without this.
        // textFieldColumn.setStretchWithOverflow(true);
        textFieldColumn.setHeight(height); // We must specify _some_ height.
        return textFieldColumn;
    }

    /**
     * @param libglomLayoutItemField
     * @return
     */
    private String addField(final LayoutItemField libglomLayoutItemField) {

        final String fieldName = libglomLayoutItemField.getName(); // TODO: Is this enough for related fields?

        // Avoid an unnamed field:
        if (StringUtils.isEmpty(fieldName)) {
            Log.info("addField(): Ignoring LayoutItemField with no field name");
            return fieldName;
        }

        // Avoid adding duplicate fields,
        // because JasperDesign.addField() throws a "Duplicate declaration of field" exception.
        for (int i = 0; i < fieldsToGet.size(); ++i) {
            final UsesRelationship thisField = fieldsToGet.get(i);
            if (thisField.equals(libglomLayoutItemField)) {
                return fieldName;
            }
        }

        fieldsToGet.add(libglomLayoutItemField);

        // System.out.print("fieldName=" + fieldName + "\n");

        // Tell the JasperDesign about the database field that will be in the SQL query,
        // specified later:
        final JRDesignField field = new JRDesignField();
        field.setName(fieldName); // TODO: Related fields.

        final Class<?> klass = getClassTypeForGlomType(libglomLayoutItemField);
        if (klass != null) {
            field.setValueClass(klass);
        } else {
            Log.info("getClassTypeForGlomType() returned null");
        }

        try {
            design.addField(field);
        } catch (final JRException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }

        return fieldName;
    }

    /**
     * @param libglomLayoutItemField
     * @return
     */
    private Class<?> getClassTypeForGlomType(final LayoutItemField libglomLayoutItemField) {
        // Choose a suitable java class type for the SQL field:
        Class<?> klass = null;

        final GlomFieldType glom_type = libglomLayoutItemField.getGlomType();
        switch (glom_type) {
        case TYPE_TEXT:
            klass = java.lang.String.class;
            break;
        case TYPE_BOOLEAN:
            klass = java.lang.Boolean.class;
            break;
        case TYPE_NUMERIC:
            klass = java.lang.Double.class;
            break;
        case TYPE_DATE:
            klass = java.util.Date.class;
            break;
        case TYPE_TIME:
            klass = java.sql.Time.class;
            break;
        case TYPE_IMAGE:
            klass = java.sql.Blob.class; // TODO: This does not work.
            break;
        case TYPE_INVALID:
            Log.info("getClassTypeForGlomType() returning null for TYPE_INVALID glom type. Field name="
                    + libglomLayoutItemField.getLayoutDisplayName());
        default:
            Log.info("getClassTypeForGlomType() returning null for glom type: " + glom_type + ". Field name="
                    + libglomLayoutItemField.getLayoutDisplayName());
            break;
        }
        return klass;
    }
}