KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > swing > data > TableModelExtTextLoader


1 /*
2  * $Id: TableModelExtTextLoader.java,v 1.1 2005/01/27 14:40:25 kleopatra Exp $
3  *
4  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
5  * Santa Clara, California 95054, U.S.A. All rights reserved.
6  */

7
8 package org.jdesktop.swing.data;
9
10 import org.jdesktop.swing.event.ProgressEvent;
11
12 import java.io.BufferedReader JavaDoc;
13 import java.io.InputStream JavaDoc;
14 import java.io.InputStreamReader JavaDoc;
15 import java.io.IOException JavaDoc;
16
17 import java.text.ParseException JavaDoc;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Collections JavaDoc;
22
23 import javax.swing.SwingUtilities JavaDoc;
24
25
26 /**
27  * Data loader class which reads data from a text input stream and loads
28  * it into a DefaultTableModelExt instance. Common examples of tabular text data
29  * are comma-separated-values (CSV) and tab-separated-values (TSV) files.
30  * <p>
31  * Each line of text in the data stream is treated as a single row of data in
32  * the tabular data model. A line is considered to be terminated by any one
33  * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
34  * followed immediately by a linefeed. Within each row, column values are
35  * delimited by a regular expression string, which is a configurable
36  * &quot;columnDelimiter&quot; property on the Loader class. The default
37  * column delimiter is a <code>tab ('\t')</code> character.</p>
38  * <p>
39  * Some text files encode the column names as the first row of data, thus
40  * this loader class supports a configurable &quot;columnNamesInFirstRow&quot;
41  * boolean property.</p>
42  * <p>
43  * This class supports loading the data into the model in increments so that
44  * it may be displayed immediately, rather than waiting until the entire stream
45  * has been read. The number of rows in an increment can be specified via
46  * the &quot;blockIncrementSize&quot; property.</p>
47  * <p>
48  * The following example configures a TableModelExtTextLoader to read CSV
49  * formatted data at the URL location, &quot;http://myapp/employees.csv&quot;,
50  * and load the data by roughly 75 line increments:
51  * <pre><code>
52  * DefaultTableModelExt data = new DefaultTableModelExt("http://myapp/employees.csv");
53  * TableModelExtTextLoader loader = new TableModelExtTextLoader(",", false, 75);
54  * data.setLoader(loader);
55  * data.startLoading();
56  * </code></pre>
57  * </p>
58  * <p>
59  * Note that properties on a TableModelExtTextLoader instance should not be modified
60  * while a load operation is executing, else synchronization errors will occur.
61  * </p>
62  */

63
64 public class TableModelExtTextLoader extends DataLoader {
65
66     private String JavaDoc columnDelimiter;
67     private boolean firstRowHeader;
68     private int blockSize;
69
70     private int columnCount = 0;
71     private MetaData columnMetaData[];
72     private List JavaDoc rows;
73     private boolean complete = false;
74
75     /**
76      * Creates a TableModelExtTextLoader object with a default tab ('\t') column delimeter,
77      * &quot;columnNameInFirstRow&quot; set to <code>false</code>, and
78      * a default block increment size of 50.
79      */

80     public TableModelExtTextLoader() {
81         this("\t", false, 50);
82     }
83
84     /**
85      * Creates a TableModelExtTextLoader object with the specified column delimiter,
86      * &quot;columnNamesInFirstRow&quot; value, and block increment size.
87      * @param columnDelimiter regular expression string used to delimit column
88      * values within a row
89      * @param isFirstRowHeader boolean indicating whether the first row
90      * should be treated as the column header names
91      * @param blockIncrementSize integer indicating the number of rows to be read
92      * between incremental load requests
93      */

94     public TableModelExtTextLoader(String JavaDoc columnDelimiter,
95                                  boolean isFirstRowHeader,
96                                  int blockIncrementSize) {
97         super();
98         this.columnDelimiter = columnDelimiter;
99         this.firstRowHeader = isFirstRowHeader;
100         this.blockSize = blockIncrementSize;
101     }
102
103     /**
104      *
105      * @return regular expression string used to delimit column
106      * values within a row
107      */

108     public String JavaDoc getColumnDelimiter() {
109         return columnDelimiter;
110     }
111
112     /**
113      * Sets the &quot;columnDelimiter&quot; property.
114      * @param regex regular expression string used to delimit column
115      * values within a row
116      */

117     public void setColumnDelimiter(String JavaDoc regex) {
118         this.columnDelimiter = regex;
119     }
120
121     /**
122      *
123      * @return boolean indicating whether the first row should be treated
124      * as header column names
125      */

126     public boolean isFirstRowHeader() {
127         return firstRowHeader;
128     }
129
130     /**
131      * Sets the &quot;isFirstRowHeader&quot; property.
132      * @param isFirstRowHeader boolean indicating whether the first row
133      * should be treated as header column names
134      */

135     public void setFirstRowHeader(boolean isFirstRowHeader) {
136         this.firstRowHeader = isFirstRowHeader;
137     }
138
139     /**
140      *
141      * @return integer indicating the number of rows to be read
142      * between incremental load requests
143      */

144     public int getBlockIncrementSize() {
145         return blockSize;
146     }
147
148     /**
149      * Sets the &quot;blockIncrementSize&quot; property.
150      * @param blockIncrementSize integer indicating the number of rows to be read
151      * between incremental load requests
152      */

153     public void setBlockIncrementSize(int blockIncrementSize) {
154         this.blockSize = blockIncrementSize;
155     }
156
157     /**
158      * Initializes the the number of columns in the tabular data model by
159      * reading the first line in the stream and counting the columns.
160      * If &quot;columnNamesInFirstRow&quot; is <code>true</code> then this
161      * method will also initialize the column names for the tabular data model
162      * with the column values contained in the first line of the stream.
163      * This method is synchronous and may be invoked from the event dispatch thread.
164      *
165      * @param model the tabular data model being loaded from the input stream
166      * @param is the input stream containing the meta-data
167      * @throws IOException if errors occur while reading from the stream
168      * @throws ClassCastException if the model is not an instance of DefaultTableModelExt
169      */

170     public void loadMetaData(Object JavaDoc model, InputStream JavaDoc is) throws IOException JavaDoc {
171         DefaultTableModelExt dataModel = (DefaultTableModelExt)model;
172         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is));
173         String JavaDoc firstLine = reader.readLine();
174         String JavaDoc columns[] = firstLine.split(columnDelimiter);
175         dataModel.setColumnCount(columns.length);
176         if (firstRowHeader) {
177             for(int i = 0; i < columns.length; i++) {
178                 MetaData metaData = dataModel.getColumnMetaData(i);
179                 metaData.setName(columns[i]);
180             }
181         }
182         reader.close();
183     }
184
185     /**
186      * {@inheritDoc}
187      */

188     public void startLoading(final Object JavaDoc model, final InputStream JavaDoc is) {
189         DefaultTableModelExt dataModel = (DefaultTableModelExt)model;
190         columnCount = dataModel.getColumnCount();
191         columnMetaData = dataModel.getMetaData();
192         super.startLoading(model, is);
193     }
194
195   /**
196     * Invoked by the <code>startLoading</code> method. This method will be
197     * called on a separate &quot;reader&quot; thread. This method will invoke
198     * <code>scheduleLoad</code> between reading each incremental block of rows.
199     * This reader will use the &quot;elementClass&quot; and &quot;Converter&quot;
200     * properties on a given column's meta-data object in order to convert the
201     * data from string to object values.
202     * @param is the input stream containing the data
203     * @throws IOException if errors occur while reading data from the input stream
204     * @throws ConversionException if errors occur while converting data values from
205     * string to object
206     */

207     protected void readData(InputStream JavaDoc is) throws IOException JavaDoc,
208         ConversionException {
209         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(is));
210         StringBuffer JavaDoc strbuf = new StringBuffer JavaDoc();
211         if (columnCount == 0) {
212             throw new IOException JavaDoc("cannot read data when column count is 0");
213         }
214
215         int colIndex = 0;
216         int rowCount = 0;
217         Object JavaDoc row[] = null;
218         rows = Collections.synchronizedList(new ArrayList JavaDoc());
219
220         String JavaDoc line = reader.readLine();
221         if (firstRowHeader) {
222             // throw away first line
223
line = reader.readLine();
224         }
225         while (line != null) {
226             String JavaDoc columns[] = line.split(columnDelimiter);
227             row = new Object JavaDoc[columnCount];
228             for (int i = 0; i < columnCount; i++) {
229                 if (i < columns.length) {
230                     row[i] = convertToValue(i, columns[i]);
231                 }
232             }
233             synchronized (rows) {
234                 rows.add(row);
235                 rowCount++;
236                 if (rowCount % blockSize == 0) {
237                     scheduleLoad();
238                 }
239             }
240             line = reader.readLine();
241         }
242         complete = true;
243         scheduleLoad();
244         reader.close();
245     }
246
247     /**
248      * Invoked internally once the <code>readData</code> method calls
249      * <code>scheduleLoad</code> to schedule the loading of an increment of
250      * data to the model. This method is called on the event dispatch
251      * thread, therefore it will add the current list of rows read to the
252      * tabular data model. After the data is added to the model, it will
253      * fire a progress event to indicate whether the load operation is complete.
254      *
255      * @param model the data model being loaded from the input stream
256      * @throws ClassCastException if model is not an instance of DefaultTableModelExt
257      */

258     protected void loadData(Object JavaDoc model) {
259         DefaultTableModelExt dataModel = (DefaultTableModelExt)model;
260         boolean done = false;
261         synchronized (rows) {
262             dataModel.loadRows(rows);
263             rows.clear();
264             done = complete;
265         }
266         if (done) {
267             // don't want to hold lock while listeners fire
268
fireProgressEnded();
269         }
270     }
271
272     private Object JavaDoc convertToValue(int colIndex, String JavaDoc stringValue) throws ConversionException {
273         Object JavaDoc value = null;
274         if (stringValue.length() == 0) {
275             return null;
276         }
277         Converter converter = columnMetaData[colIndex].getConverter();
278         if (converter == null) {
279             // defaults to String
280
value = stringValue;
281         } else {
282             value = converter.decode(stringValue, columnMetaData[colIndex].getDecodeFormat());
283         }
284         return value;
285     }
286 }
287
Popular Tags