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;
48
49 import java.io.File;
50 import java.util.ArrayList;
51 import java.util.Enumeration;
52 import java.util.Iterator;
53 import java.util.Properties;
54 import java.util.Random;
55
56 import pl.kernelpanic.dbmonster.connection.ConnectionProvider;
57 import pl.kernelpanic.dbmonster.connection.Transaction;
58 import pl.kernelpanic.dbmonster.schema.Schema;
59 import pl.kernelpanic.dbmonster.util.Converter;
60 import pl.kernelpanic.dbmonster.util.ScriptReaderIterator;
61
62 import org.apache.commons.logging.Log;
63 import org.apache.commons.logging.LogFactory;
64
65 /***
66 * DBMonster is a test data generation tool for SQL databases.
67 *
68 * @author Piotr Maj <piotr.maj@kernelpanic.pl>
69 *
70 * @version $Id: DBMonster.html,v 1.1 2007/06/21 08:38:14 sbahloul Exp $
71 */
72 public class DBMonster {
73
74 /***
75 * DBMonster's version.
76 */
77 public static final String VERSION = "1.0.3";
78
79 /***
80 * A key under the logger is stored in DBMonsterContext.
81 */
82 public static final String LOGGER_KEY =
83 "pl.kernelpanic.dbmonster.LOGGER_KEY";
84
85 /***
86 * A key under the connection provider is stored in the
87 * DBMonsterContext.
88 */
89 public static final String CONNECTION_PROVIDER_KEY =
90 "pl.kernelpanic.dbmonster.CONNECTION_PROVIDER_KEY";
91
92 /***
93 * A key under the dictionaries manager is stored in
94 * context.
95 */
96 public static final String DICTIONARY_MANAGER_KEY =
97 "pl.kernelpanic.dbmonster.DICTIONARY_MANAGER_KEY";
98
99 /***
100 * A key under the random number generator is stored in context.
101 */
102 public static final String RANDOM_KEY =
103 "pl.kernelpanic.dbmonster.RANDOM_KEY";
104
105 /***
106 * A key under progress monitor (if any) is stored in the context.
107 */
108 public static final String PROGRESS_MONITOR_KEY =
109 "pl.kernelpanic.dbmonster.PROGRESS_MONITOR_KEY";
110
111 /***
112 * A connection provider used by DBMonster.
113 */
114 private ConnectionProvider connProvider = null;
115
116 /***
117 * A list of schemas that will be generated.
118 */
119 private ArrayList schemaList = new ArrayList();
120
121 /***
122 * A logger used.
123 */
124 private Log logger = LogFactory.getLog(DBMonster.class);
125
126 /***
127 * A context.
128 */
129 private DBMonsterContext context = new DBMonsterContext();
130
131 /***
132 * Progress monitor.
133 */
134 private ProgressMonitor progressMonitor = null;
135
136 /***
137 * Pre-generation script
138 */
139 private File preScript;
140
141 /***
142 * Post-generation script
143 */
144 private File postScript;
145
146 /***
147 * Random number generator.
148 */
149 private Random random = new Random();
150
151 /***
152 * Returns a connection provider used by this instance.
153 *
154 * @return connection provider
155 */
156 public ConnectionProvider getConnectionProvider() {
157 return connProvider;
158 }
159
160 /***
161 * Sets a connection provider.
162 *
163 * @param cp a connection provider
164 */
165 public void setConnectionProvider(final ConnectionProvider cp) {
166 connProvider = cp;
167 }
168
169 /***
170 * Adds a schema.
171 *
172 * @param schema a schema to add.
173 *
174 * @throws Exception if schema with the same name already exists
175 */
176 public void addSchema(final Schema schema) throws Exception {
177 if (schemaExists(schema)) {
178 throw new Exception(
179 "Schema named <" + schema.getName() + "> already exists.");
180 }
181 schemaList.add(schema);
182 }
183
184 /***
185 * Sets a logger for this DBMonster instance.
186 *
187 * @param log a logger
188 */
189 public void setLogger(final Log log) {
190 logger = log;
191 }
192
193 /***
194 * Returns logger.
195 *
196 * @return a logger.
197 */
198 public Log getLogger() {
199 return logger;
200 }
201
202 /***
203 * Sets the properties.
204 *
205 * @param props the properties
206 */
207 public void setProperties(final Properties props) {
208 Enumeration enum = props.propertyNames();
209 while (enum.hasMoreElements()) {
210 String key = (String) enum.nextElement();
211 context.setProperty(key, props.get(key));
212 }
213 }
214
215 /***
216 * Does the job. ;) Before calling this method ensure that:
217 * <ol>
218 * <li>Connection provider is set.</li>
219 * <li>Progress monitor (if any) is set.</li>
220 * <li>Valid schemas are added.</li>
221 * </ol>
222 *
223 * @throws Exception on errors.
224 */
225 public void doTheJob() throws Exception {
226 long t0 = System.currentTimeMillis();
227 context.setProperty(LOGGER_KEY, logger);
228 if (logger.isInfoEnabled()) {
229 logger.info("Let's feed this hungry database.");
230 }
231
232 if (logger.isDebugEnabled()) {
233 logger.debug("Checking the connection provider.");
234 }
235 if (connProvider == null) {
236 throw new Exception("No connection provider.");
237 }
238 connProvider.testConnection();
239 if (logger.isDebugEnabled()) {
240 logger.debug("Connection provider is OK.");
241 }
242 context.setProperty(CONNECTION_PROVIDER_KEY, connProvider);
243 context.setProperty(RANDOM_KEY, random);
244 context.setProperty(PROGRESS_MONITOR_KEY, progressMonitor);
245
246 DictionaryManager dm = new DictionaryManager();
247 dm.setRandom(random);
248 context.setProperty(DICTIONARY_MANAGER_KEY, dm);
249
250 if (preScript != null) {
251 executeScript(connProvider, preScript);
252 }
253 Iterator it = schemaList.iterator();
254 try {
255 if (progressMonitor != null) {
256 progressMonitor.setUp();
257 progressMonitor.setSchemaCount(schemaList.size());
258 }
259 while (it.hasNext()) {
260 Schema schema = (Schema) it.next();
261 if (progressMonitor != null) {
262 progressMonitor.setSchemaName(schema.getName());
263 }
264 schema.initialize(context);
265 schema.generate();
266 if (progressMonitor != null) {
267 progressMonitor.schemaComplete();
268 }
269 }
270 } catch (Exception e) {
271 throw e;
272 } finally {
273 if (progressMonitor != null) {
274 progressMonitor.tearDown();
275 }
276 }
277 if (postScript != null) {
278 executeScript(connProvider, postScript);
279 }
280
281 t0 = System.currentTimeMillis() - t0;
282 logger.info("Finished in " + Converter.formatTime(t0));
283 }
284
285 /***
286 * Returns the version.
287 *
288 * @return version
289 */
290 public static final String getVersion() {
291 return VERSION;
292 }
293
294 /***
295 * Check if schema of this name already exists.
296 *
297 * @param schema schema
298 *
299 * @return <code>true</code> if schema already exists.
300 */
301 private boolean schemaExists(final Schema schema) {
302 for (int i = 0; i < schemaList.size(); i++) {
303 if (schema.compareTo(schemaList.get(i)) == 0) {
304 return true;
305 }
306 }
307 return false;
308 }
309
310 /***
311 * Returns the progress monitor.
312 *
313 * @return progress monitor.
314 */
315 public ProgressMonitor getProgressMonitor() {
316 return progressMonitor;
317 }
318
319 /***
320 * Sets the progress monitor.
321 *
322 * @param monitor progress monitor.
323 */
324 public void setProgressMonitor(ProgressMonitor monitor) {
325 progressMonitor = monitor;
326 }
327
328 public void setPostScript(File postScript) {
329 this.postScript = postScript;
330 }
331
332 public void setPreScript(File preScript) {
333 this.preScript = preScript;
334 }
335
336 private void executeScript(ConnectionProvider cp, File scriptFile) throws Exception {
337 ScriptReaderIterator it = new ScriptReaderIterator(scriptFile);
338 Transaction tx = new Transaction(cp);
339 try {
340 tx.begin();
341 while (it.hasNext()) {
342 String query = (String) it.next();
343 if (logger.isDebugEnabled()) {
344 logger.debug("Executing query: " + query);
345 }
346 tx.prepareStatement(query);
347 tx.execute();
348 }
349 tx.commit();
350 } catch (Exception e) {
351 tx.abort();
352 throw e;
353 } finally {
354 tx.close();
355 }
356 }
357 }