KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > db > sql > execute > ResultSetTableModelSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.db.sql.execute;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.Reader JavaDoc;
25 import java.math.BigDecimal JavaDoc;
26 import java.sql.Blob JavaDoc;
27 import java.sql.Clob JavaDoc;
28 import java.sql.ResultSet JavaDoc;
29 import java.sql.ResultSetMetaData JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.sql.Time JavaDoc;
32 import java.sql.Timestamp JavaDoc;
33 import java.sql.Types JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Date JavaDoc;
36 import java.util.HashMap JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Map JavaDoc;
39
40 /**
41  * This class is used to create a TableModel for a ResultSet.
42  *
43  * @author Andrei Badea
44  */

45 public class ResultSetTableModelSupport {
46     
47     /**
48      * Holds the ColumnTypeDef for all the types in java.sql.Types.
49      * Not private because of unit tests.
50      */

51     static final Map JavaDoc<Integer JavaDoc,ColumnTypeDef> TYPE_TO_DEF = new HashMap JavaDoc<Integer JavaDoc,ColumnTypeDef>();
52     
53     /**
54      * The default implementation of ColumnTypeDef used for SQL types for which
55      * there is no value in {@link #TYPE_TO_DEF}.
56      */

57     private static ColumnTypeDef DEFAULT_COLUMN_DEF;
58     
59     static {
60         // editable types
61

62         ColumnTypeDef booleanTypeDef = new GenericWritableColumnDef(Boolean JavaDoc.class);
63         
64         TYPE_TO_DEF.put(Integer.valueOf(Types.BOOLEAN), booleanTypeDef);
65         TYPE_TO_DEF.put(Integer.valueOf(Types.BIT), booleanTypeDef);
66         
67         ColumnTypeDef integerTypeDef = new GenericWritableColumnDef(Integer JavaDoc.class);
68         
69         TYPE_TO_DEF.put(Integer.valueOf(Types.TINYINT), integerTypeDef);
70         TYPE_TO_DEF.put(Integer.valueOf(Types.SMALLINT), integerTypeDef);
71         TYPE_TO_DEF.put(Integer.valueOf(Types.INTEGER), integerTypeDef);
72         
73         ColumnTypeDef charTypeDef = new GenericWritableColumnDef(String JavaDoc.class);
74         
75         TYPE_TO_DEF.put(Integer.valueOf(Types.CHAR), charTypeDef);
76         TYPE_TO_DEF.put(Integer.valueOf(Types.VARCHAR), charTypeDef);
77         
78         ColumnTypeDef longTypeDef = new GenericWritableColumnDef(Long JavaDoc.class);
79         
80         TYPE_TO_DEF.put(Integer.valueOf(Types.BIGINT), longTypeDef);
81         
82         ColumnTypeDef floatTypeDef = new GenericWritableColumnDef(Double JavaDoc.class);
83         
84         TYPE_TO_DEF.put(Integer.valueOf(Types.FLOAT), floatTypeDef);
85         TYPE_TO_DEF.put(Integer.valueOf(Types.DOUBLE), floatTypeDef);
86         
87         ColumnTypeDef decimalTypeDef = new GenericWritableColumnDef(BigDecimal JavaDoc.class);
88         
89         TYPE_TO_DEF.put(Integer.valueOf(Types.REAL), decimalTypeDef);
90         TYPE_TO_DEF.put(Integer.valueOf(Types.NUMERIC), decimalTypeDef);
91         TYPE_TO_DEF.put(Integer.valueOf(Types.DECIMAL), decimalTypeDef);
92         
93         ColumnTypeDef dateTypeDef = new GenericWritableColumnDef(Date JavaDoc.class);
94         
95         TYPE_TO_DEF.put(Integer.valueOf(Types.DATE), dateTypeDef);
96         
97         // TIME type must displayed as time -- issue 72607
98

99         ColumnTypeDef timeTypeDef = new ColumnTypeDef() {
100             public boolean isWritable() {
101                 return true;
102             }
103             public Class JavaDoc getColumnClass() {
104                 return Time JavaDoc.class;
105             }
106             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
107                 return rs.getTime(column);
108             }
109         };
110         
111         TYPE_TO_DEF.put(Integer.valueOf(Types.TIME), timeTypeDef);
112         
113         // TIMESTAMP type -- ensure that it is displayed as date and time
114
// issue 64165, issue 70521
115

116         TYPE_TO_DEF.put(Integer.valueOf(Types.TIMESTAMP), new ColumnTypeDef() {
117             public boolean isWritable() {
118                 return true;
119             }
120             public Class JavaDoc getColumnClass() {
121                 return Timestamp JavaDoc.class;
122             }
123             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
124                 return rs.getTimestamp(column);
125             }
126         });
127         
128         // binary types -- we can't edit them, and
129
// we display them like "0xdeadbeef..."
130

131         ColumnTypeDef binaryTypeDef = new ColumnTypeDef() {
132             public boolean isWritable() {
133                 return false;
134             }
135             public Class JavaDoc getColumnClass() {
136                 return Object JavaDoc.class;
137             }
138             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
139                 return BinaryColumnValue.forBinaryColumn(rs, column);
140             }
141         };
142         
143         TYPE_TO_DEF.put(Integer.valueOf(Types.BINARY), binaryTypeDef);
144         TYPE_TO_DEF.put(Integer.valueOf(Types.VARBINARY), binaryTypeDef);
145         TYPE_TO_DEF.put(Integer.valueOf(Types.LONGVARBINARY), binaryTypeDef);
146         
147         // blob type -- we can't edit it, and
148
// we display it like "0xdeadbeef..."
149

150         ColumnTypeDef blobTypeDef = new ColumnTypeDef() {
151             public boolean isWritable() {
152                 return false;
153             }
154             public Class JavaDoc getColumnClass() {
155                 return Object JavaDoc.class;
156             }
157             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
158                 return BinaryColumnValue.forBlobColumn(rs, column);
159             }
160         };
161         
162         TYPE_TO_DEF.put(Integer.valueOf(Types.BLOB), blobTypeDef);
163         
164         // long varchar type -- we don't retrieve the full contents (it is too
165
// long), and we display only the first n characters
166

167         ColumnTypeDef longVarCharTypeDef = new ColumnTypeDef() {
168             public boolean isWritable() {
169                 return false;
170             }
171             public Class JavaDoc getColumnClass() {
172                 return Object JavaDoc.class;
173             }
174             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
175                 return LongVarCharColumnValue.forCharColumn(rs, column);
176             }
177         };
178         
179         TYPE_TO_DEF.put(Integer.valueOf(Types.LONGVARCHAR), longVarCharTypeDef);
180         
181         // clob type -- we don't retrieve the full contents (it is are too
182
// long), and we display only the first n characters
183

184         ColumnTypeDef clobTypeDef = new ColumnTypeDef() {
185             public boolean isWritable() {
186                 return false;
187             }
188             public Class JavaDoc getColumnClass() {
189                 return Object JavaDoc.class;
190             }
191             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
192                 return LongVarCharColumnValue.forClobColumn(rs, column);
193             }
194         };
195         
196         TYPE_TO_DEF.put(Integer.valueOf(Types.CLOB), clobTypeDef);
197         
198         // other types -- we can hardly edit them
199

200         ColumnTypeDef otherTypeDef = new ColumnTypeDef() {
201             public boolean isWritable() {
202                 return false;
203             }
204             public Class JavaDoc getColumnClass() {
205                 return Object JavaDoc.class;
206             }
207             public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc {
208                 return rs.getObject(column);
209             }
210         };
211         
212         TYPE_TO_DEF.put(Integer.valueOf(Types.NULL), otherTypeDef);
213         TYPE_TO_DEF.put(Integer.valueOf(Types.OTHER), otherTypeDef);
214         TYPE_TO_DEF.put(Integer.valueOf(Types.JAVA_OBJECT), otherTypeDef);
215         TYPE_TO_DEF.put(Integer.valueOf(Types.DISTINCT), otherTypeDef);
216         TYPE_TO_DEF.put(Integer.valueOf(Types.STRUCT), otherTypeDef);
217         TYPE_TO_DEF.put(Integer.valueOf(Types.ARRAY), otherTypeDef);
218         TYPE_TO_DEF.put(Integer.valueOf(Types.REF), otherTypeDef);
219         TYPE_TO_DEF.put(Integer.valueOf(Types.DATALINK), otherTypeDef);
220     }
221     
222     /**
223      * Describes how we handle columns.
224      */

225     private interface ColumnTypeDef {
226         
227         /**
228          * Do we know how to edit this column?
229          */

230         public boolean isWritable();
231         
232         /**
233          * The class used in the table model.
234          */

235         public Class JavaDoc getColumnClass();
236         
237         /**
238          * The value displayed in the table.
239          */

240         public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc;
241     }
242     
243     /**
244      * Helper ColumnTypeDef for writable types.
245      */

246     private static final class GenericWritableColumnDef implements ColumnTypeDef {
247         
248         private Class JavaDoc columnClass;
249         
250         public GenericWritableColumnDef(Class JavaDoc columnClass) {
251             this.columnClass = columnClass;
252         }
253         
254         public boolean isWritable() {
255             return true;
256         }
257         
258         public Class JavaDoc getColumnClass() {
259             return columnClass;
260         }
261         
262         public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
263             return rs.getObject(column);
264         }
265     }
266     
267     /**
268      * Default ColumnTypeDef implementation: not writable and using
269      * ResultSet.getObject() to read column values.
270      */

271     private static final class DefaultColumnDef implements ColumnTypeDef {
272         
273         public boolean isWritable() {
274             return false;
275         }
276         
277         public Class JavaDoc getColumnClass() {
278             return Object JavaDoc.class;
279         }
280         
281         public Object JavaDoc getColumnValue(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
282             return rs.getObject(column);
283         }
284     }
285     
286     /**
287      * Represents the value of a long varchar or clob column. Instances of this
288      * class are placed in the table model for the result set.
289      */

290     private static final class LongVarCharColumnValue {
291
292         private static final int COUNT = 100;
293
294         private String JavaDoc data;
295         
296         public static LongVarCharColumnValue forCharColumn(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
297             Reader JavaDoc reader = rs.getCharacterStream(column);
298             if (reader == null) {
299                 return null;
300             }
301             try {
302                 return new LongVarCharColumnValue(reader);
303             } finally {
304                 reader.close();
305             }
306         }
307         
308         public static LongVarCharColumnValue forClobColumn(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
309             Clob JavaDoc clob = rs.getClob(column);
310             if (clob == null) {
311                 return null;
312             }
313             Reader JavaDoc reader = clob.getCharacterStream();
314             if (reader == null) {
315                 return null;
316             }
317             try {
318                 return new LongVarCharColumnValue(reader);
319             } finally {
320                 reader.close();
321             }
322         }
323
324         private LongVarCharColumnValue(Reader JavaDoc reader) throws SQLException JavaDoc, IOException JavaDoc {
325             char[] charData = new char[COUNT];
326             int read = reader.read(charData, 0, charData.length);
327
328             if (read >= 0) {
329                 data = new String JavaDoc(charData, 0, read);
330
331                 // display an ellipsis if there are more characters in the stream
332
if (reader.read() != -1) {
333                     data += "..."; // NOI18N
334
}
335             } else {
336                 data = ""; // NOI18N
337
}
338         }
339
340         public String JavaDoc toString() {
341             return data;
342         }
343     }
344
345     /**
346      * Represents the value of a binary or blob column. Instances of this
347      * class are placed in the table model for the result set.
348      */

349     private static final class BinaryColumnValue {
350
351         private static final int COUNT = 100;
352
353         private String JavaDoc data;
354         
355         public static BinaryColumnValue forBinaryColumn(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
356             InputStream JavaDoc input = rs.getBinaryStream(column);
357             if (input == null) {
358                 return null;
359             }
360             try {
361                 return new BinaryColumnValue(input);
362             } finally {
363                 input.close();
364             }
365         }
366         
367         public static BinaryColumnValue forBlobColumn(ResultSet JavaDoc rs, int column) throws SQLException JavaDoc, IOException JavaDoc {
368             Blob JavaDoc blob = rs.getBlob(column);
369             if (blob == null) {
370                 return null;
371             }
372             InputStream JavaDoc input = blob.getBinaryStream();
373             if (input == null) {
374                 return null;
375             }
376             try {
377                 return new BinaryColumnValue(input);
378             } finally {
379                 input.close();
380             }
381         }
382
383         private BinaryColumnValue(InputStream JavaDoc input) throws SQLException JavaDoc, IOException JavaDoc {
384             byte[] byteData = new byte[COUNT];
385             int read = input.read(byteData, 0, byteData.length);
386             
387             if (read > 0) {
388                 StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(2 + 2 * read);
389
390                 buffer.append("0x"); // NOI18N
391
for (int i = 0; i < read; i++) {
392                     int b = byteData[i];
393                     if (b < 0) {
394                         b += 256;
395                     }
396                     if (b < 16) {
397                         buffer.append('0');
398                     }
399                     buffer.append(Integer.toHexString(b).toUpperCase());
400                 }
401
402                 // display an ellipsis if there are more characters in the stream
403
if (input.read() != -1) {
404                     buffer.append("..."); // NOI18N
405
}
406
407                 data = buffer.toString();
408             } else {
409                 data = ""; // NOI18N
410
}
411         }
412
413         public String JavaDoc toString() {
414             return data;
415         }
416     }
417     
418     /**
419      * Not private because of unit tests.
420      */

421     static ColumnTypeDef getColumnTypeDef(int type) {
422         ColumnTypeDef result = (ColumnTypeDef)TYPE_TO_DEF.get(Integer.valueOf(type));
423         if (result != null) {
424             return result;
425         }
426         
427         synchronized (ResultSetTableModelSupport.class) {
428             if (DEFAULT_COLUMN_DEF == null) {
429                 DEFAULT_COLUMN_DEF = new DefaultColumnDef();
430             }
431             return DEFAULT_COLUMN_DEF;
432         }
433     }
434     
435     /**
436      * Returns a List of ColumnDef objects or null if the calling thread was
437      * interrupted.
438      */

439     public static List JavaDoc<ColumnDef> createColumnDefs(ResultSetMetaData JavaDoc rsmd) throws SQLException JavaDoc {
440         int count = rsmd.getColumnCount();
441         List JavaDoc<ColumnDef> columns = new ArrayList JavaDoc<ColumnDef>(count);
442
443         for (int i = 1; i <= count; i++) {
444             if (Thread.currentThread().isInterrupted()) {
445                 return null;
446             }
447             
448             int type = rsmd.getColumnType(i);
449             ColumnTypeDef ctd = getColumnTypeDef(type);
450             
451             // TODO: does writable depend on the result set type (updateable?)
452

453             // issue 75700: the demo version of the Teradata DB throws SQLException on RSMD.isWritable()
454
boolean writable = false;
455             try {
456                 writable = rsmd.isWritable(i) && ctd.isWritable();
457             } catch (SQLException JavaDoc e) {
458                 // ignore
459
}
460
461             ColumnDef column = new ColumnDef(
462                     rsmd.getColumnName(i),
463                     writable,
464                     ctd.getColumnClass());
465             
466             columns.add(column);
467         }
468         return columns;
469     }
470     
471     public static List JavaDoc<List JavaDoc<Object JavaDoc>> retrieveRows(ResultSet JavaDoc rs, ResultSetMetaData JavaDoc rsmd, FetchLimitHandler handler) throws SQLException JavaDoc, IOException JavaDoc {
472         List JavaDoc<List JavaDoc<Object JavaDoc>> rows = new ArrayList JavaDoc<List JavaDoc<Object JavaDoc>>();
473         int columnCount = rsmd.getColumnCount();
474         int fetchLimit = handler.getFetchLimit();
475
476         while (rs.next()) {
477             if (Thread.currentThread().isInterrupted()) {
478                 return null;
479             }
480             
481             int fetchCount = rows.size();
482             if (fetchLimit > 0 && fetchCount >= fetchLimit) {
483                 fetchLimit = handler.fetchLimitReached(fetchCount);
484                 if (fetchLimit != 0 && fetchLimit <= fetchCount) {
485                     break;
486                 }
487             }
488
489             List JavaDoc<Object JavaDoc> row = new ArrayList JavaDoc<Object JavaDoc>();
490             for (int i = 1; i <= columnCount; i++) {
491                 if (Thread.currentThread().isInterrupted()) {
492                     return null;
493                 }
494                 
495                 int type = rsmd.getColumnType(i);
496                 ColumnTypeDef ctd = getColumnTypeDef(type);
497                 Object JavaDoc value = ctd.getColumnValue(rs, i);
498                 row.add(value != null ? value : NullValue.getDefault());
499             }
500             rows.add(row);
501         }
502         return rows;
503     }
504 }
505
Popular Tags