2 * Copyright (C) 2012 Openismus GmbH
4 * This file is part of GWT-Glom.
6 * GWT-Glom is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
11 * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with GWT-Glom. If not, see <http://www.gnu.org/licenses/>.
20 package org.glom.web.server;
22 import java.io.ByteArrayOutputStream;
23 import java.sql.Connection;
24 import java.util.HashMap;
26 import net.sf.jasperreports.engine.JRException;
27 import net.sf.jasperreports.engine.JasperCompileManager;
28 import net.sf.jasperreports.engine.JasperFillManager;
29 import net.sf.jasperreports.engine.JasperPrint;
30 import net.sf.jasperreports.engine.JasperReport;
31 import net.sf.jasperreports.engine.design.JRDesignBand;
32 import net.sf.jasperreports.engine.design.JRDesignExpression;
33 import net.sf.jasperreports.engine.design.JRDesignField;
34 import net.sf.jasperreports.engine.design.JRDesignQuery;
35 import net.sf.jasperreports.engine.design.JRDesignSection;
36 import net.sf.jasperreports.engine.design.JRDesignStaticText;
37 import net.sf.jasperreports.engine.design.JRDesignTextField;
38 import net.sf.jasperreports.engine.design.JasperDesign;
39 import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
40 import net.sf.jasperreports.engine.export.JRXhtmlExporter;
42 import org.apache.commons.lang.StringUtils;
43 import org.glom.libglom.Document;
44 import org.glom.libglom.Glom;
45 import org.glom.libglom.LayoutFieldVector;
46 import org.glom.libglom.LayoutGroup;
47 import org.glom.libglom.LayoutItemVector;
48 import org.glom.libglom.LayoutItem_Field;
49 import org.glom.libglom.Relationship;
50 import org.glom.libglom.SortClause;
51 import org.glom.libglom.SqlBuilder;
52 import org.glom.libglom.SqlExpr;
53 import org.glom.libglom.Value;
56 * @author Murray Cumming <murrayc@openimus.com>
59 public class ReportGenerator {
61 final int height = 30;
62 LayoutFieldVector fieldsToGet = new LayoutFieldVector();
67 * @param configuredDoc
71 public String generateReport(final Document document, final String tableName, final String reportName,
72 final Connection connection, final org.glom.libglom.LayoutGroup layout_group) {
74 final JasperDesign design = new JasperDesign();
75 design.setName(reportName); // TODO: Actually, we want the title.
77 final JRDesignBand titleBand = new JRDesignBand();
78 titleBand.setHeight(height);
79 final JRDesignStaticText staticTitle = new JRDesignStaticText();
80 staticTitle.setText("debug: test report title text");
81 titleBand.addElement(staticTitle);
82 design.setTitle(titleBand);
84 final JRDesignBand detailBand = new JRDesignBand();
85 detailBand.setHeight(height + 20);
87 fieldsToGet = new LayoutFieldVector();
89 addToReport(layout_group, design, detailBand, x);
91 ((JRDesignSection) design.getDetailSection()).addBand(detailBand);
93 // Later versions of libglom actually return an empty SqlExpr when quickFindValue is empty,
95 final String quickFind = ""; // TODO
96 final SortClause sortClause = new SortClause(); // TODO
98 if (StringUtils.isEmpty(quickFind)) {
99 whereClause = new SqlExpr();
101 final Value quickFindValue = new Value(quickFind);
102 whereClause = Glom.get_find_where_clause_quick(document, tableName, quickFindValue);
105 final Relationship extraJoin = new Relationship(); // Ignored.
106 final SqlBuilder builder = Glom.build_sql_select_with_where_clause(tableName, fieldsToGet, whereClause,
107 extraJoin, sortClause);
108 final String sqlQuery = Glom.sqlbuilder_get_full_query(builder);
110 final JRDesignQuery query = new JRDesignQuery();
111 query.setText(sqlQuery); // TODO: quickfind and sort clause.
112 design.setQuery(query);
116 report = JasperCompileManager.compileReport(design);
117 } catch (final JRException ex) {
118 ex.printStackTrace();
119 return "Failed to Generate HTML: compileReport() failed.";
124 final HashMap<String, Object> parameters = new HashMap<String, Object>();
125 parameters.put("ReportTitle", reportName); // TODO: Use the title, not the name.
126 print = JasperFillManager.fillReport(report, parameters, connection);
127 } catch (final JRException ex) {
128 ex.printStackTrace();
129 return "Failed to Generate HTML: fillReport() failed.";
132 final ByteArrayOutputStream output = new ByteArrayOutputStream();
134 // We use this because there is no JasperExportManager.exportReportToHtmlStream() method.
135 // JasperExportManager.exportReportToXmlStream(print, output);
137 final JRXhtmlExporter exporter = new JRXhtmlExporter();
138 exporter.setParameter(JRHtmlExporterParameter.JASPER_PRINT, print);
139 exporter.setParameter(JRHtmlExporterParameter.OUTPUT_STREAM, output);
141 // Use points instead of pixels for sizes, because pixels are silly
143 exporter.setParameter(JRHtmlExporterParameter.SIZE_UNIT, "pt");
145 exporter.exportReport();
146 } catch (final JRException ex) {
147 ex.printStackTrace();
148 return "Failed to Generate HTML: exportReport() failed.";
151 // System.out.print(output.toString() + "\n");
152 return output.toString();
156 * @param layout_group
162 private int addToReport(final org.glom.libglom.LayoutGroup layout_group, final JasperDesign design,
163 final JRDesignBand detailBand, int x) {
164 final LayoutItemVector layoutItemsVec = layout_group.get_items();
165 final int numItems = Utils.safeLongToInt(layoutItemsVec.size());
166 for (int i = 0; i < numItems; i++) {
167 final org.glom.libglom.LayoutItem libglomLayoutItem = layoutItemsVec.get(i);
169 final LayoutGroup libglomLayoutGroup = LayoutGroup.cast_dynamic(libglomLayoutItem);
170 final LayoutItem_Field libglomLayoutItemField = LayoutItem_Field.cast_dynamic(libglomLayoutItem);
171 if (libglomLayoutItemField != null) {
172 fieldsToGet.add(libglomLayoutItemField);
174 final String fieldName = libglomLayoutItemField.get_name();
175 // System.out.print("fieldName=" + fieldName + "\n");
177 // Tell the JasperDesign about the database field that will be in the SQL query,
179 final JRDesignField field = new JRDesignField();
180 field.setName(fieldName); // TODO: Related fields.
182 // Choose a suitable java class type for the SQL field:
183 Class<?> klass = null;
184 switch (libglomLayoutItemField.get_glom_type()) {
186 klass = java.lang.String.class;
189 klass = java.lang.Boolean.class;
192 klass = java.lang.Double.class;
195 klass = java.util.Date.class;
198 klass = java.sql.Time.class;
201 klass = java.sql.Blob.class; // TODO: This does not work.
204 field.setValueClass(klass);
207 design.addField(field);
208 } catch (final JRException e2) {
209 // TODO Auto-generated catch block
210 e2.printStackTrace();
213 // Tell the JasperDesign to show an instance of the field:
214 final JRDesignTextField textField = new JRDesignTextField();
216 // Make sure this field starts at the right of the previous field,
217 // because JasperReports uses absolute positioning.
221 // An arbitrary width, because we must specify _some_ width:
222 final int width = 100; // Points, as specified later.
223 textField.setWidth(width); // No data will be shown without this.
226 // This only stretches vertically, but that is better than
228 textField.setStretchWithOverflow(true);
229 textField.setHeight(height); // We must specify _some_ height.
231 // TODO: Where is this format documented?
232 final JRDesignExpression expression = new JRDesignExpression();
233 expression.setText("$F{" + fieldName + "}");
235 textField.setExpression(expression);
236 detailBand.addElement(textField);
237 } else if (libglomLayoutGroup != null) {
238 // Recurse into sub-groups:
239 x = addToReport(libglomLayoutGroup, design, detailBand, x);