1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 package pl.kernelpanic.dbmonster.generator;
48
49 import java.sql.ResultSet;
50 import java.util.ArrayList;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Random;
54
55 import pl.kernelpanic.dbmonster.DBMonster;
56 import pl.kernelpanic.dbmonster.DBMonsterContext;
57 import pl.kernelpanic.dbmonster.connection.ConnectionProvider;
58 import pl.kernelpanic.dbmonster.connection.Transaction;
59 import pl.kernelpanic.dbmonster.schema.Column;
60 import pl.kernelpanic.dbmonster.schema.Key;
61 import pl.kernelpanic.dbmonster.schema.Schema;
62 import pl.kernelpanic.dbmonster.schema.SchemaException;
63 import pl.kernelpanic.dbmonster.schema.Table;
64
65 import org.apache.commons.logging.Log;
66
67 /***
68 * Foreign key generator.
69 *
70 * @author Piotr Maj <piotr.maj@kernelpanic.pl>
71 *
72 * @version $Id: ForeignKeyGenerator.html,v 1.1 2007/06/21 08:38:13 sbahloul Exp $
73 */
74 public class ForeignKeyGenerator extends BasicDataGenerator implements Initializable {
75
76 /***
77 * The name of the column.
78 */
79 private String columnName = null;
80
81 /***
82 * The name of the table.
83 */
84 private String tableName = null;
85
86 /***
87 * Turns on the fast mode.
88 */
89 private boolean fastMode = false;
90
91 /***
92 * A list of items stored in memmory in fast mode.
93 */
94 private List items = null;
95
96 /***
97 * Context.
98 */
99 private DBMonsterContext context = null;
100
101 /***
102 * Connection provider.
103 */
104 private ConnectionProvider connProv = null;
105
106 /***
107 * Logger.
108 */
109 private Log log = null;
110
111 /***
112 * Random number generator.
113 */
114 private Random random = null;
115
116 /***
117 * An SQL statement used to get values;
118 */
119 private String sql = null;
120
121 /***
122 * For internal use only.
123 */
124 private boolean dependencyGenerated = false;
125
126 /***
127 * For internal use only.
128 */
129 private boolean initialized = false;
130
131 /***
132 * Initializes the generator.
133 *
134 * @param ctx context
135 *
136 * @throws Exception if generator cannot be initialized
137 */
138 public final void initialize(final DBMonsterContext ctx) throws Exception {
139 if (columnName == null || tableName == null) {
140 throw new Exception("No columnName or tableName property set!");
141 }
142
143 context = ctx;
144 connProv = (ConnectionProvider) context.getProperty(
145 DBMonster.CONNECTION_PROVIDER_KEY);
146 log = (Log) context.getProperty(DBMonster.LOGGER_KEY);
147 random = (Random) context.getProperty(DBMonster.RANDOM_KEY);
148
149 StringBuffer buff = new StringBuffer();
150 buff.append("SELECT ");
151 buff.append(columnName);
152 buff.append(" FROM ");
153 buff.append(tableName);
154 sql = buff.toString();
155 }
156
157 /***
158 * Generates a value using foreign key.
159 *
160 * @return value
161 *
162 * @throws Exception if generation fails.
163 */
164 public final Object generate() throws Exception {
165 Schema schema = column.getTable().getSchema();
166 Table table = schema.findTable(tableName);
167 if (!dependencyGenerated) {
168 if (log.isDebugEnabled()) {
169 log.debug("Ensure that table <" + tableName
170 + "> is already generated.");
171 }
172 if (table == null) {
173 throw new SchemaException("No table <"
174 + tableName + "> in this schema!");
175 }
176 if (!table.getName().equals(getColumn().getTable().getName())) {
177 table.generate();
178 } else {
179 fastMode = false;
180 }
181 if (log.isDebugEnabled()) {
182 log.debug("Yup! The table <" + tableName
183 + "> is already generated.");
184 }
185 dependencyGenerated = true;
186 }
187
188 if (fastMode) {
189 if (!initialized) {
190 items = new ArrayList();
191 Transaction tx = null;
192 try {
193 tx = new Transaction(connProv);
194 tx.begin();
195 ResultSet rs = tx.executeQuery(sql);
196 while (rs.next()) {
197 items.add(rs.getObject(1));
198 }
199 tx.commit();
200 } catch (Exception e) {
201 tx.abort();
202 if (log.isDebugEnabled()) {
203 log.debug(e.getMessage());
204 }
205 throw e;
206 } finally {
207 tx.close();
208 }
209 initialized = true;
210 }
211
212 if (items.size() == 0) {
213 throw new Exception("No items in foreign key.");
214 }
215 return items.get(random.nextInt(items.size()));
216 }
217
218 Transaction tx = null;
219 int rowsCount = 0;
220 try {
221 tx = new Transaction(connProv);
222 tx.begin();
223 ResultSet rs = tx.executeQuery("SELECT count(*) FROM " + tableName);
224 rs.next();
225 rowsCount = rs.getInt(1);
226 tx.commit();
227
228 if (rowsCount == 0) {
229 if (table.getName().equals(tableName)) {
230
231 Column referencedColumn = null;
232
233 Key key = table.getKey();
234 if (key != null) {
235 List columns = key.getGenerator().getColumns();
236 for (int i = 0; i < columns.size(); i++) {
237 referencedColumn = (Column) columns.get(i);
238 if (referencedColumn.getName().equals(columnName)) {
239 break;
240 }
241 referencedColumn = null;
242 }
243 }
244 if (referencedColumn == null) {
245
246 Iterator it = table.columnIterator();
247 while (it.hasNext()) {
248 Column column = (Column) it.next();
249 if (column.getName().equals(columnName)) {
250 column.generate();
251 }
252 }
253 }
254
255 return referencedColumn.getValue();
256 }
257 throw new Exception("There are no rows in table "
258 + tableName);
259 }
260 rs = tx.executeQuery(sql);
261 int rowNum = random.nextInt(rowsCount);
262 int counter = 0;
263 while (counter <= rowNum) {
264 rs.next();
265 ++counter;
266 }
267 return rs.getObject(1);
268 } catch (Exception e) {
269 tx.abort();
270 if (log.isDebugEnabled()) {
271 log.debug(e.getMessage());
272 }
273 throw e;
274 } finally {
275 tx.close();
276 }
277 }
278
279 /***
280 * Returns column name.
281 *
282 * @return column name
283 */
284 public final String getColumnName() {
285 return columnName;
286 }
287
288 /***
289 * Sets the column name.
290 *
291 * @param name column name
292 */
293 public final void setColumnName(final String name) {
294 columnName = name;
295 }
296
297 /***
298 * Returns table name.
299 *
300 * @return table name
301 */
302 public final String getTableName() {
303 return tableName;
304 }
305
306 /***
307 * Sets the table name.
308 *
309 * @param name table name
310 */
311 public final void setTableName(final String name) {
312 tableName = name;
313 }
314
315 /***
316 * Returns fast mode parameter.
317 *
318 * @return fast mode
319 */
320 public final boolean getFastMode() {
321 return fastMode;
322 }
323
324 /***
325 * Sets the fast mode parameter.
326 *
327 * @param mode fast mode parameter
328 */
329 public final void setFastMode(final boolean mode) {
330 fastMode = mode;
331 }
332
333 /***
334 * @see pl.kernelpanic.dbmonster.generator.DataGenerator#reset()
335 */
336 public final void reset() {
337 initialized = false;
338 dependencyGenerated = false;
339 }
340 }