1:
31: package ;
32:
33: import ;
34: import ;
35: import ;
36: import ;
37: import ;
38: import ;
39: import ;
40: import ;
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51:
52:
57: public class SimpleSQLReportDataFactory implements ReportDataFactory, Cloneable
58: {
59: private static final Object NULL_TOKEN = new Object();
60:
61: private static class PreparedStatementCarrier
62: {
63: private PreparedStatement preparedStatement;
64: private String[] parameters;
65:
66: private PreparedStatementCarrier(final PreparedStatement preparedStatement,
67: final String[] parameters)
68: {
69: this.preparedStatement = preparedStatement;
70: this.parameters = parameters;
71: }
72:
73: public PreparedStatement getPreparedStatement()
74: {
75: return preparedStatement;
76: }
77:
78: public String[] getParameters()
79: {
80: return parameters;
81: }
82: }
83:
84: private HashMap preparedStatements;
85: private Connection connection;
86: private ConnectionProvider connectionProvider;
87:
88: private boolean labelMapping;
89: private static final String COLUMN_NAME_MAPPING_KEY =
90: "org.jfree.report.modules.data.sql.ColumnNameMapping";
91:
92: public SimpleSQLReportDataFactory(final Connection connection)
93: {
94: this (new StaticConnectionProvider(connection));
95: }
96:
97: public SimpleSQLReportDataFactory(final ConnectionProvider connectionProvider)
98: {
99: if (connectionProvider == null)
100: {
101: throw new NullPointerException();
102: }
103: this.connectionProvider = connectionProvider;
104: this.preparedStatements = new HashMap();
105: final Configuration globalConfig =
106: JFreeReportBoot.getInstance().getGlobalConfig();
107: this.labelMapping = "Label".equals(globalConfig.getConfigProperty
108: (SimpleSQLReportDataFactory.COLUMN_NAME_MAPPING_KEY, "Label"));
109: }
110:
111: public boolean isLabelMapping()
112: {
113: return labelMapping;
114: }
115:
116: public void setLabelMapping(final boolean labelMapping)
117: {
118: this.labelMapping = labelMapping;
119: }
120:
121: private synchronized Connection getConnection() throws SQLException
122: {
123: if (connection == null)
124: {
125: connection = connectionProvider.getConnection();
126: }
127: return connection;
128: }
129:
130: private int getBestResultSetType() throws SQLException
131: {
132: final Connection connection = getConnection();
133: final boolean supportsScrollInsensitive =
134: connection.getMetaData().supportsResultSetType
135: (ResultSet.TYPE_SCROLL_INSENSITIVE);
136: final boolean supportsScrollSensitive =
137: connection.getMetaData().supportsResultSetType
138: (ResultSet.TYPE_SCROLL_SENSITIVE);
139:
140: if (supportsScrollInsensitive)
141: {
142: return ResultSet.TYPE_SCROLL_INSENSITIVE;
143: }
144: if (supportsScrollSensitive)
145: {
146: return ResultSet.TYPE_SCROLL_SENSITIVE;
147: }
148: return ResultSet.TYPE_FORWARD_ONLY;
149: }
150:
151:
161: public synchronized ReportData queryData(final String query, final DataSet parameters)
162: throws ReportDataFactoryException
163: {
164: try
165: {
166: PreparedStatementCarrier pstmtCarrier = (PreparedStatementCarrier)
167: preparedStatements.get(query);
168: if (pstmtCarrier == null)
169: {
170: final SQLParameterLookupParser parser = new SQLParameterLookupParser();
171: final String translatedQuery = parser.translateAndLookup(query);
172: final PreparedStatement pstmt = getConnection().prepareStatement
173: (translatedQuery, getBestResultSetType(), ResultSet.CONCUR_READ_ONLY);
174: pstmtCarrier = new PreparedStatementCarrier(pstmt, parser.getFields());
175: preparedStatements.put(query, pstmtCarrier);
176: }
177:
178: final PreparedStatement pstmt = pstmtCarrier.getPreparedStatement();
179: pstmt.clearParameters();
180:
181: final String[] params = pstmtCarrier.getParameters();
182: for (int i = 0; i < params.length; i++)
183: {
184: final String param = params[i];
185: final Object pvalue = DataSetUtility.getByName(parameters, param, NULL_TOKEN);
186: if (pvalue == NULL_TOKEN)
187: {
188:
189:
190: throw new ReportDataFactoryException ("Setting parameter '" +
191: param + "' failed: No such column.");
192: }
193: else if (pvalue == null)
194: {
195:
196:
197:
198: pstmt.setObject(i+1, null);
199: }
200: else
201: {
202: pstmt.setObject(i+1, pvalue);
203: }
204: }
205: final ResultSet res = pstmt.executeQuery();
206: final int resultSetType = res.getType();
207:
208: if (resultSetType == ResultSet.TYPE_FORWARD_ONLY)
209: {
210: final TableModel model = generateDefaultTableModel(res, labelMapping);
211: res.close();
212: return new TableReportData(model);
213: }
214: else
215: {
216: return new SQLReportData(res, labelMapping);
217: }
218: }
219: catch(ReportDataFactoryException rdfe)
220: {
221: throw rdfe;
222: }
223: catch (Exception e)
224: {
225: throw new ReportDataFactoryException("Failed at query: " + query, e);
226: }
227: }
228:
229: public void open()
230: {
231:
232: }
233:
234: public synchronized void close()
235: {
236: if (connection == null)
237: {
238: return;
239: }
240:
241: try
242: {
243: connection.close();
244: }
245: catch (SQLException e)
246: {
247:
248: }
249: connection = null;
250: }
251:
252:
267: private TableModel generateDefaultTableModel
268: (final ResultSet rs, final boolean labelMapping)
269: throws SQLException
270: {
271: final ResultSetMetaData rsmd = rs.getMetaData();
272: final int colcount = rsmd.getColumnCount();
273: final ArrayList header = new ArrayList(colcount);
274: for (int i = 0; i < colcount; i++)
275: {
276: if (labelMapping)
277: {
278: final String name = rsmd.getColumnLabel(i + 1);
279: header.add(name);
280: }
281: else
282: {
283: final String name = rsmd.getColumnName(i + 1);
284: header.add(name);
285: }
286: }
287: final ArrayList rows = new ArrayList();
288: while (rs.next())
289: {
290: final Object[] column = new Object[colcount];
291: for (int i = 0; i < colcount; i++)
292: {
293: column[i] = rs.getObject(i + 1);
294: if (rs.wasNull())
295: {
296: column[i] = null;
297: }
298: }
299: rows.add(column);
300: }
301:
302: final Object[] tempRows = rows.toArray();
303: final Object[][] rowMap = new Object[tempRows.length][];
304: for (int i = 0; i < tempRows.length; i++)
305: {
306: rowMap[i] = (Object[]) tempRows[i];
307: }
308: return new DefaultTableModel(rowMap, header.toArray());
309: }
310:
311:
318: public ReportDataFactory derive()
319: {
320: try
321: {
322: return (ReportDataFactory) clone();
323: }
324: catch (CloneNotSupportedException e)
325: {
326:
327: throw new IllegalStateException("Clone failed?");
328: }
329: }
330:
331: public Object clone () throws CloneNotSupportedException
332: {
333: final SimpleSQLReportDataFactory dataFactory = (SimpleSQLReportDataFactory) super.clone();
334: dataFactory.connection = null;
335: dataFactory.preparedStatements = (HashMap) preparedStatements.clone();
336: dataFactory.preparedStatements.clear();
337: return dataFactory;
338: }
339: }