View Javadoc

1   /* $Id: Table.java,v 1.15 2006/01/10 21:33:33 psionides Exp $ */
2   package net.sourceforge.jdbdump.dump;
3   
4   import java.io.IOException;
5   import java.io.ObjectInputStream;
6   import java.io.Serializable;
7   import java.sql.SQLException;
8   import java.util.Vector;
9   
10  import org.apache.log4j.Logger;
11  
12  /***
13   * Represents a table in a database. Objects of this class should be created either by a
14   * DatabaseConnector during the execution of dump() method, or by a DumpFileManager
15   * while recreating a Dump from a saved backup file.
16   * A table must have its name assigned, and should also have a number of columns (handled by
17   * Column class). Optionally a table can also have one or more Triggers.
18   * <br /><br />
19   * Table is different from other classes in this package in that it is the only one which 
20   * has the ability to download more information from the database after the Dump structure
21   * is created. This is done to let a DumpFileManager download parts of data and immediately
22   * store them in a file (or, in the same way, load data from a file and insert them into
23   * database). Otherwise the entire contents of a database (often many megabytes or even
24   * gigabytes) would have to be kept in memory.
25   * <br /><br />
26   * Database data is loaded using methods initializeData() and getDataLine(). The former is
27   * executed once per table to prepare the data stream, and the latter is called for each
28   * record of data. Data can be saved to a dump file just after they are downloaded, so
29   * only one record occupies the memory at the same time.   
30  * <br /><br />
31   * Example code:
32   * <pre>
33   * DatabaseConnectorFactory factory = DatabaseConnectorFactory.getInstance();
34   * if (connectorTypes.length > 0) {
35   *     DatabaseConnector connector = factory.createConnector(
36   *         "net.sourceforge.jdbdump.connect.connectors.MysqlConnector");
37   *     connector.connect("jdbc:mysql://localhost/base", "admin", "qwerty");
38   *     Dump dump = connector.dump();
39   *     File dumpFile = new File("dump.bin");
40   *     // ...write the structure to a file...
41   *     for (Table t : dump.getTables()) {
42   *         t.initializeData();
43   *         while (true) {
44   *             String record[] = t.getDataLine();
45   *             if (record == null) break;
46   *             // ...write one line with an insert command...
47   *         }
48   *     }
49   *     connector.disconnect();
50   * } else {
51   *     // error - no connectors
52   * }
53   * </pre>
54   *
55   * @author jsuder
56   */
57  
58  public class Table implements Serializable {
59  	
60  	/*** ID used in serialization process. */
61  	private static final long serialVersionUID = -5780410768401074139L;
62  
63  	/*** Name of the table. */
64  	private String name;
65  	
66  	/*** A list of table's columns. */
67  	private Vector<Column> columns;
68  	
69  	/*** A list of table's constraints (primary/foreign keys, etc.). */
70  	private Vector<Constraint> constraints;
71  
72  	/*** A log4j logger for this class. */
73  	private static Logger logger = Logger.getLogger(Table.class);
74  	
75  	/*** A reference to a Dump object in which this Table is contained. */
76  	private transient Dump dump;
77  	
78  	/*** Tells if initializeData() and getDataLine() methods should operate on a database,
79  	 * or a backup file. */  
80  	private transient boolean readFromDatabase;
81  
82  	
83  	/***
84  	 * Creates a new table with specified name.
85  	 * @param name table's name
86  	 * @param connection database connection which will be used to dump table's data
87  	 */
88  	
89  	public Table(String name, Dump dump) {
90  		this.name = name;
91  		this.dump = dump;
92  		columns = new Vector<Column>();
93  		constraints = new Vector<Constraint>();
94  	}
95  	
96  	/***
97  	 * Sets a reference to a Dump object which contains this Table.
98  	 * @param dump a database dump
99  	 */
100 	
101 	public void setDump(Dump dump) {
102 		this.dump = dump;
103 	}
104 	
105 	/***
106 	 * Returns table's name.
107 	 * @return table's name
108 	 */
109 	
110 	public String getName() {
111 		return name;
112 	}
113 	
114 	/***
115 	 * Sets table's name.
116 	 * @return table's new name
117 	 */
118 
119 	public void setName(String name) {
120 		this.name = name;
121 	}
122 	
123 	/***
124 	 * Returns a list of this table's constraints (including primary and foreign keys).
125 	 * @return a list of table's constraints
126 	 */
127 	
128 	public Vector<Constraint> getConstraints() {
129 		return constraints;
130 	}
131 	
132 	/***
133 	 * Adds a new constraint to this table.
134 	 * @param constraint a constraint to be added to the list
135 	 */
136 	
137 	public void addConstraint(Constraint constraint) {
138 		constraints.add(constraint);
139 	}
140 	
141 	/***
142 	 * Prepares table's data for downloading using getDataLine().
143 	 * @throws SQLException if data download can't be initialized because of a connection
144 	 *     error or an error in the database
145 	 */
146 
147 	public void initializeData() throws SQLException {
148 		readFromDatabase = dump.isReadingFromDatabase();
149 		if (readFromDatabase) {
150 			dump.getDatabaseReader().initializeTableData(name);
151 			logger.info("initializeData(): data from table " + name + " is ready for downloading.");
152 		} else {
153 			// nothing has to be done to prepare reading from file
154 		}
155 	}
156 
157 	/***
158 	 * Downloads one record of data from this table in database or from a file (depending
159 	 * on the value of readFromDatabase attribute).
160 	 * @return next record from the table, or null if there are no more records
161 	 * @throws Exception if data record can't be downloaded because of a connection error
162 	 *     or an error in the database, or because of an IO error during the reading from
163 	 *     a backup file 
164 	 */
165 
166 	public String[] getDataLine() throws Exception {
167 		if (readFromDatabase) {
168 			return getDataLineFromDatabase();
169 		} else {
170 			return getDataLineFromFile();
171 		}
172 	}
173 	
174 	/***
175 	 * Downloads one record of data from this table in database.
176 	 * @return next record from the table, or null if there are no more records
177 	 * @throws SQLException if data record can't be downloaded because of a connection error
178 	 *     or an error in the database
179 	 */
180 
181 	public String[] getDataLineFromDatabase() throws SQLException {
182 		return dump.getDatabaseReader().getTableDataLine();
183 	}
184 	
185 	/***
186 	 * Reads one record of data from a backup file.
187 	 * @return next record from the table, or null if there are no more records
188 	 * @throws IOException if data can't be read from the file
189 	 * @throws ClassNotFoundException if the read object doesn't match the required class
190 	 */
191 
192 	public String[] getDataLineFromFile() throws IOException, ClassNotFoundException {
193 		String[] dataLine = (String[]) dump.getFileReader().readObject();
194 		return dataLine;
195 	}
196 
197 	/***
198 	 * Returns number of columns in the table.
199 	 * @return number of columns in the table
200 	 */
201 	
202 	public Vector<Column> getColumns() {
203 		return columns;
204 	}
205 	
206 	/***
207 	 * Reads an object from a file using serialization and initializes it.
208 	 * @param in an input stream from which the object will be read
209 	 * @throws IOException if the object can't be read from the file
210 	 * @throws ClassNotFoundException if the saved object format doesn't match this class 
211 	 */
212 	
213 	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
214 		in.defaultReadObject();
215 		this.dump = null;
216 		this.readFromDatabase = false;
217 	}
218 }