KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > prefuse > data > Schema


1 package prefuse.data;
2
3 import java.util.HashMap JavaDoc;
4
5 import prefuse.util.PrefuseLib;
6
7 /**
8  * <p>The Schema class represents a description of a Table's columns, including
9  * column names, data types, and default values. New Table
10  * instances can be created directly from Schema objects through the use of
11  * the {@link #instantiate()} method. If a schema is subsequently changed,
12  * instantiated table instances are not affected, keeping their original
13  * schema.</p>
14  *
15  * <p>Schema instances can be locked to prevent further changes. Any attempt
16  * to alter a locked schema will result in a runtime exception being thrown.
17  * If a schema is not locked, clients are free to add new columns and
18  * edit default values.</p>
19  *
20  * @author <a HREF="http://jheer.org">jeffrey heer</a>
21  */

22 public class Schema implements Cloneable JavaDoc {
23
24     private String JavaDoc[] m_names;
25     private Class JavaDoc[] m_types;
26     private Object JavaDoc[] m_dflts;
27     private HashMap JavaDoc m_lookup;
28     private int m_size;
29     private boolean m_locked;
30     
31     // ------------------------------------------------------------------------
32
// Constructors
33

34     /**
35      * Creates a new empty schema.
36      */

37     public Schema() {
38         this(10);
39     }
40     
41     /**
42      * Creates a new empty schema with a starting capacity for a given number
43      * of columns.
44      * @param ncols the number of columns in this schema
45      */

46     public Schema(int ncols) {
47         m_names = new String JavaDoc[ncols];
48         m_types = new Class JavaDoc[ncols];
49         m_dflts = new Object JavaDoc[ncols];
50         m_size = 0;
51         m_locked = false;
52     }
53     
54     /**
55      * Create a new schema consisting of the given column names and types.
56      * @param names the column names
57      * @param types the column types (as Class instances)
58      */

59     public Schema(String JavaDoc[] names, Class JavaDoc[] types) {
60         this(names.length);
61         
62         // check the schema validity
63
if ( names.length != types.length ) {
64             throw new IllegalArgumentException JavaDoc(
65                 "Input arrays should be the same length");
66         }
67         for ( int i=0; i<names.length; ++i ) {
68             addColumn(names[i], types[i], null);
69         }
70     }
71     
72     /**
73      * Create a new schema consisting of the given column names, types, and
74      * default column values.
75      * @param names the column names
76      * @param types the column types (as Class instances)
77      * @param defaults the default values for each column
78      */

79     public Schema(String JavaDoc[] names, Class JavaDoc[] types, Object JavaDoc[] defaults) {
80         this(names.length);
81         
82         // check the schema validity
83
if ( names.length != types.length ||
84              types.length != defaults.length )
85         {
86             throw new IllegalArgumentException JavaDoc(
87                 "Input arrays should be the same length");
88         }
89         for ( int i=0; i<names.length; ++i ) {
90             addColumn(names[i], types[i], defaults[i]);
91         }
92     }
93     
94     /**
95      * Creates a copy of this Schema. This might be useful for creating
96      * extended schemas from a shared base schema. Cloned copies
97      * of a locked Schema will not inherit the locked status.
98      * @see java.lang.Object#clone()
99      */

100     public Object JavaDoc clone() {
101         Schema s = new Schema(m_size);
102         for ( int i=0; i<m_size; ++i ) {
103             s.addColumn(m_names[i], m_types[i], m_dflts[i]);
104         }
105         return s;
106     }
107     
108     /**
109      * Lazily construct the lookup table for this schema. Used to
110      * accelerate name-based lookups of schema information.
111      */

112     protected void initLookup() {
113         m_lookup = new HashMap JavaDoc();
114         for ( int i=0; i<m_names.length; ++i ) {
115             m_lookup.put(m_names[i], new Integer JavaDoc(i));
116         }
117     }
118     
119     // ------------------------------------------------------------------------
120
// Accessors / Mutators
121

122     /**
123      * Locks the schema, preventing any additional changes. Locked schemas
124      * can not be unlocked! Cloned copies of a locked schema will not inherit
125      * this locked status.
126      * @return a pointer to this schema
127      */

128     public Schema lockSchema() {
129         m_locked = true;
130         return this;
131     }
132     
133     /**
134      * Indicates if this schema is locked. Locked schemas can not be edited.
135      * @return true if this schema is locked, false otherwise
136      */

137     public boolean isLocked() {
138         return m_locked;
139     }
140     
141     /**
142      * Add a column to this schema.
143      * @param name the column name
144      * @param type the column type (as a Class instance)
145      * @throws IllegalArgumentException is either name or type are null or
146      * the name already exists in this schema.
147      */

148     public void addColumn(String JavaDoc name, Class JavaDoc type) {
149         addColumn(name, type, null);
150     }
151     
152     /**
153      * Add a column to this schema.
154      * @param name the column name
155      * @param type the column type (as a Class instance)
156      * @throws IllegalArgumentException is either name or type are null or
157      * the name already exists in this schema.
158      */

159     public void addColumn(String JavaDoc name, Class JavaDoc type, Object JavaDoc defaultValue) {
160         // check lock status
161
if ( m_locked ) {
162             throw new IllegalStateException JavaDoc(
163                 "Can not add column to a locked Schema.");
164         }
165         // check for validity
166
if ( name == null ) {
167             throw new IllegalArgumentException JavaDoc(
168                 "Null column names are not allowed.");
169         }
170         if ( type == null ) {
171             throw new IllegalArgumentException JavaDoc(
172                 "Null column types are not allowed.");
173         }
174         for ( int i=0; i<m_size; ++i ) {
175             if ( m_names[i].equals(name) ) {
176                 throw new IllegalArgumentException JavaDoc(
177                     "Duplicate column names are not allowed: "+m_names[i]);
178             }
179         }
180         
181         // resize if necessary
182
// TODO put resizing functionality into library routines?
183
if ( m_names.length == m_size ) {
184             int capacity = (3*m_names.length)/2 + 1;
185             String JavaDoc[] names = new String JavaDoc[capacity];
186             Class JavaDoc[] types = new Class JavaDoc[capacity];
187             Object JavaDoc[] dflts = new Object JavaDoc[capacity];
188             System.arraycopy(m_names, 0, names, 0, m_size);
189             System.arraycopy(m_types, 0, types, 0, m_size);
190             System.arraycopy(m_dflts, 0, dflts, 0, m_size);
191             m_names = names;
192             m_types = types;
193             m_dflts = dflts;
194         }
195         
196         m_names[m_size] = name;
197         m_types[m_size] = type;
198         m_dflts[m_size] = defaultValue;
199         
200         if ( m_lookup != null )
201             m_lookup.put(name, new Integer JavaDoc(m_size));
202         
203         ++m_size;
204     }
205     
206     /**
207      * <p>Add a new interpolated column to this data schema. This actually adds
208      * three columns to the schema: a column for the current value of the
209      * field, and columns for starting and ending values. During animation or
210      * operations spread over a time span, the current value can be
211      * interpolated between the start and end values.</p>
212      *
213      * <p>The name for the current value column is the name parameter provided
214      * to the method. The name for the start and end columns will be determined
215      * by the return value of {@link PrefuseLib#getStartField(String)} and
216      * {@link PrefuseLib#getEndField(String)}. The default behavior for these
217      * methods is to append ":start" to the name of a stating value column
218      * and append ":end" to the the name of an ending value column.</p>
219      *
220      * @param name the name of the interpolated column to add
221      * @param type the data type the columns will contain
222      * @param dflt the default value for each of the columns
223      */

224     public void addInterpolatedColumn(String JavaDoc name, Class JavaDoc type, Object JavaDoc dflt) {
225         addColumn(name, type, dflt);
226         addColumn(PrefuseLib.getStartField(name), type, dflt);
227         addColumn(PrefuseLib.getEndField(name), type, dflt);
228     }
229     
230     /**
231      * Add an interpolated column with a null default value.
232      * @see #addInterpolatedColumn(String, Class, Object)
233      * @param name the name of the interpolated column to add
234      * @param type the data type the columns will contain
235      */

236     public void addInterpolatedColumn(String JavaDoc name, Class JavaDoc type) {
237         addInterpolatedColumn(name, type, null);
238     }
239     
240     /**
241      * Get the number of columns in this schema.
242      * @return the number of columns
243      */

244     public int getColumnCount() {
245         return m_size;
246     }
247     
248     /**
249      * The name of the column at the given position.
250      * @param col the column index
251      * @return the column name
252      */

253     public String JavaDoc getColumnName(int col) {
254         return m_names[col];
255     }
256     
257     /**
258      * The column index for the column with the given name.
259      * @param field the column name
260      * @return the column index
261      */

262     public int getColumnIndex(String JavaDoc field) {
263         if ( m_lookup == null )
264             initLookup();
265         
266         Integer JavaDoc idx = (Integer JavaDoc)m_lookup.get(field);
267         return ( idx==null ? -1 : idx.intValue() );
268     }
269     
270     /**
271      * The type of the column at the given position.
272      * @param col the column index
273      * @return the column type
274      */

275     public Class JavaDoc getColumnType(int col) {
276         return m_types[col];
277     }
278
279     /**
280      * The type of the column with the given name.
281      * @param field the column name
282      * @return the column type
283      */

284     public Class JavaDoc getColumnType(String JavaDoc field) {
285         int idx = getColumnIndex(field);
286         return ( idx<0 ? null : m_types[idx] );
287     }
288     
289     /**
290      * The default value of the column at the given position.
291      * @param col the column index
292      * @return the column's default value
293      */

294     public Object JavaDoc getDefault(int col) {
295         return m_dflts[col];
296     }
297     
298     /**
299      * The default value of the column with the given name.
300      * @param field the column name
301      * @return the column's default value
302      */

303     public Object JavaDoc getDefault(String JavaDoc field) {
304         int idx = getColumnIndex(field);
305         return ( idx<0 ? null : m_dflts[idx] );
306     }
307     
308     /**
309      * Set the default value for the given field.
310      * @param col the column index of the field to set the default for
311      * @param val the new default value
312      */

313     public void setDefault(int col, Object JavaDoc val) {
314         // check lock status
315
if ( m_locked ) {
316             throw new IllegalStateException JavaDoc(
317                 "Can not update default values of a locked Schema.");
318         }
319         m_dflts[col] = val;
320     }
321     
322     /**
323      * Set the default value for the given field.
324      * @param field the name of column to set the default for
325      * @param val the new default value
326      */

327     public void setDefault(String JavaDoc field, Object JavaDoc val) {
328         // check lock status
329
if ( m_locked ) {
330             throw new IllegalStateException JavaDoc(
331                 "Can not update default values of a locked Schema.");
332         }
333         int idx = getColumnIndex(field);
334         m_dflts[idx] = val;
335     }
336     
337     /**
338      * Set the default value for the given field as an int.
339      * @param field the name of column to set the default for
340      * @param val the new default value
341      */

342     public void setDefault(String JavaDoc field, int val) {
343         setDefault(field, new Integer JavaDoc(val));
344     }
345     
346     /**
347      * Set the default value for the given field as a long.
348      * @param field the name of column to set the default for
349      * @param val the new default value
350      */

351     public void setDefault(String JavaDoc field, long val) {
352         setDefault(field, new Long JavaDoc(val));
353     }
354     
355     /**
356      * Set the default value for the given field as a float.
357      * @param field the name of column to set the default for
358      * @param val the new default value
359      */

360     public void setDefault(String JavaDoc field, float val) {
361         setDefault(field, new Float JavaDoc(val));
362     }
363     
364     /**
365      * Set the default value for the given field as a double.
366      * @param field the name of column to set the default for
367      * @param val the new default value
368      */

369     public void setDefault(String JavaDoc field, double val) {
370         setDefault(field, new Double JavaDoc(val));
371     }
372     
373     /**
374      * Set the default value for the given field as a boolean.
375      * @param field the name of column to set the default for
376      * @param val the new default value
377      */

378     public void setDefault(String JavaDoc field, boolean val) {
379         setDefault(field, val ? Boolean.TRUE : Boolean.FALSE);
380     }
381     
382     /**
383      * Set default values for the current, start, and end columns of an
384      * interpolated column.
385      * @param field the field name of the interpolated column
386      * @param val the new default value for all three implicated columns
387      */

388     public void setInterpolatedDefault(String JavaDoc field, Object JavaDoc val) {
389         setDefault(field, val);
390         setDefault(PrefuseLib.getStartField(field), val);
391         setDefault(PrefuseLib.getEndField(field), val);
392     }
393     
394     /**
395      * Set default values for the current, start, and end columns of an
396      * interpolated column as an int.
397      * @param field the field name of the interpolated column
398      * @param val the new default value for all three implicated columns
399      */

400     public void setInterpolatedDefault(String JavaDoc field, int val) {
401         setInterpolatedDefault(field, new Integer JavaDoc(val));
402     }
403     
404     /**
405      * Set default values for the current, start, and end columns of an
406      * interpolated column as a long.
407      * @param field the field name of the interpolated column
408      * @param val the new default value for all three implicated columns
409      */

410     public void setInterpolatedDefault(String JavaDoc field, long val) {
411         setInterpolatedDefault(field, new Long JavaDoc(val));
412     }
413     
414     /**
415      * Set default values for the current, start, and end columns of an
416      * interpolated column as a float.
417      * @param field the field name of the interpolated column
418      * @param val the new default value for all three implicated columns
419      */

420     public void setInterpolatedDefault(String JavaDoc field, float val) {
421         setInterpolatedDefault(field, new Float JavaDoc(val));
422     }
423     
424     /**
425      * Set default values for the current, start, and end columns of an
426      * interpolated column as a double.
427      * @param field the field name of the interpolated column
428      * @param val the new default value for all three implicated columns
429      */

430     public void setInterpolatedDefault(String JavaDoc field, double val) {
431         setInterpolatedDefault(field, new Double JavaDoc(val));
432     }
433     
434     /**
435      * Set default values for the current, start, and end columns of an
436      * interpolated column as a boolean.
437      * @param field the field name of the interpolated column
438      * @param val the new default value for all three implicated columns
439      */

440     public void setInterpolatedDefault(String JavaDoc field, boolean val) {
441         setInterpolatedDefault(field, val ? Boolean.TRUE : Boolean.FALSE);
442     }
443     
444     
445     // ------------------------------------------------------------------------
446
// Comparison and Hashing
447

448     /**
449      * Compares this schema with another one for equality.
450      */

451     public boolean equals(Object JavaDoc o) {
452         if ( !(o instanceof Schema) )
453             return false;
454         
455         Schema s = (Schema)o;
456         if ( m_size != s.getColumnCount() )
457             return false;
458         
459         for ( int i=0; i<m_size; ++i ) {
460             if ( !(m_names[i].equals(s.getColumnName(i)) &&
461                    m_types[i].equals(s.getColumnType(i)) &&
462                    m_dflts[i].equals(s.getDefault(i))) )
463             {
464                 return false;
465             }
466         }
467         return true;
468     }
469     
470     /**
471      * Indicates if values from a given Schema can be safely assigned to
472      * data using this Schema. The input Schema must be less than or
473      * equal in length to this Schema, and all contained columns in the
474      * given Schema must have matching names and types to this Schema.
475      * This method does not consider default values settings or the
476      * locked status of the Schemas. For example, if the given Schema
477      * has different default values than this one, this will have no
478      * impact on the assignability of the two.
479      * @param s the input Schema
480      * @return true if data models using this Schema could be assigned values
481      * directly from data using the input Schema, false otherwise.
482      */

483     public boolean isAssignableFrom(Schema s) {
484         int ssize = s.getColumnCount();
485         
486         if ( ssize > m_size )
487             return false;
488         
489         for ( int i=0; i<ssize; ++i ) {
490             int idx = getColumnIndex(s.getColumnName(i));
491             if ( idx < 0 )
492                 return false;
493             
494             if ( !m_types[idx].equals(s.getColumnType(i)) )
495                 return false;
496         }
497         return true;
498     }
499     
500     /**
501      * Computes a hashcode for this schema.
502      */

503     public int hashCode() {
504         int hashcode = 0;
505         for ( int i=0; i<m_size; ++i ) {
506             int idx = i+1;
507             int code = idx*m_names[i].hashCode();
508             code ^= idx*m_types[i].hashCode();
509             if ( m_dflts[i] != null )
510                 code ^= m_dflts[i].hashCode();
511             hashcode ^= code;
512         }
513         return hashcode;
514     }
515     
516     /**
517      * Returns a descriptive String for this schema.
518      */

519     public String JavaDoc toString() {
520         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
521         sbuf.append("Schema[");
522         for ( int i=0; i<m_size; ++i ) {
523             if ( i > 0 ) sbuf.append(' ');
524             sbuf.append('(').append(m_names[i]).append(", ");
525             sbuf.append(m_types[i].getName()).append(", ");
526             sbuf.append(m_dflts[i]).append(')');
527         }
528         sbuf.append(']');
529         return sbuf.toString();
530     }
531     
532     // ------------------------------------------------------------------------
533
// Table Operations
534

535     /**
536      * Instantiate this schema as a new Table instance.
537      * @return a new Table with this schema
538      */

539     public Table instantiate() {
540         return instantiate(0);
541     }
542     
543     /**
544      * Instantiate this schema as a new Table instance.
545      * @param nrows the number of starting rows in the table
546      * @return a new Table with this schema
547      */

548     public Table instantiate(int nrows) {
549         Table t = new Table(nrows, m_size);
550         for ( int i=0; i<m_size; ++i ) {
551             t.addColumn(m_names[i], m_types[i], m_dflts[i]);
552         }
553         return t;
554     }
555     
556 } // end of class Schema
557
Popular Tags