View Javadoc

1   /* Version 1.0 based on Apache Software License 1.1
2    *
3    * Copyright (c) 2003 Piotr Maj and DBMonster developers. All rights
4    * reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are
8    * met:
9    *
10   * 1. Redistributions of source code must retain the above copyright
11   *    notice, this list of conditions and the following disclaimer.
12   *
13   * 2. Redistributions in binary form must reproduce the above copyright
14   *    notice, this list of conditions and the following disclaimer in the
15   *    documentation and/or other materials provided with the distribution.
16   *
17   * 3. The end-user documentation included with the redistribution, if any,
18   *    must include the following acknowledgment:
19   *
20   *    "This product includes software developed by DBMonster developers
21   *    (http://dbmonster.kernelpanic.pl/)."
22   *
23   *  Alternately, this acknowledgment may appear in the software itself,
24   *  if and wherever such third-party acknowledgments normally appear.
25   *
26   * 4. The name "DBMonster" must not be used to endorse or promote products
27   *    derived from this software without prior written permission. For
28   *    written permission, please contact pm@jcake.com.
29   *
30   * 5. Products derived from this software may not be called "DBMonster",
31   *    nor may "DBMonster" appear in their name, without prior written
32   *    permission of Piotr Maj.
33   *
34   * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
35   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
37   * IN NO EVENT SHALL THE DBMONSTER DEVELOPERS BE LIABLE FOR ANY DIRECT,
38   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
42   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
43   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44   * POSSIBILITY OF SUCH DAMAGE.
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 <pm@jcake.com>
69   *
70   * @version $Id: DBMonster.java,v 1.8 2006/01/05 16:29:37 majek Exp $
71   */
72  public class DBMonster {
73  
74      /***
75       * DBMonster's version.
76       */
77      public static final String VERSION = "1.0.4"; //$NON-NLS-1$
78  
79      /***
80       * A key under which the logger is stored in DBMonsterContext.
81       */
82      public static final String LOGGER_KEY =
83          "pl.kernelpanic.dbmonster.LOGGER_KEY"; //$NON-NLS-1$
84  
85      /***
86       * A key under which 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"; //$NON-NLS-1$
91  
92      /***
93       * A key under which the dictionaries manager is stored in
94       * context.
95       */
96      public static final String DICTIONARY_MANAGER_KEY =
97          "pl.kernelpanic.dbmonster.DICTIONARY_MANAGER_KEY"; //$NON-NLS-1$
98  
99      /***
100      * A key under which the random number generator is stored in context.
101      */
102     public static final String RANDOM_KEY =
103         "pl.kernelpanic.dbmonster.RANDOM_KEY"; //$NON-NLS-1$
104 
105     /***
106      * A key under which 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"; //$NON-NLS-1$
110 
111     /***
112      * A key under which transaction size is stored.
113      */
114     public static final String TRANSACTION_SIZE_KEY =
115         "pl.kernelpanic.dbmonster.TRANSACTION_SIZE_KEY"; //$NON-NLS-1$
116 
117     /***
118      * A connection provider used by DBMonster.
119      */
120     private ConnectionProvider connProvider = null;
121 
122     /***
123      * A list of schemas that will be generated.
124      */
125     private ArrayList schemaList = new ArrayList();
126 
127     /***
128      * A logger used.
129      */
130     private Log logger = LogFactory.getLog(DBMonster.class);
131 
132     /***
133      * A context.
134      */
135     private DBMonsterContext context = new DBMonsterContext();
136 
137     /***
138      * Progress monitor.
139      */
140     private ProgressMonitor progressMonitor = null;
141 
142     /***
143      * Pre-generation script
144      */
145     private File preScript;
146 
147     /***
148      * Post-generation script
149      */
150     private File postScript;
151 
152     /***
153      * Random number generator.
154      */
155     private Random random = new Random();
156 
157     /***
158      * The number of insert statements performed in a single transaction.
159      */
160     private int transactionSize;
161 
162     /***
163      * Returns a connection provider used by this instance.
164      *
165      * @return connection provider
166      */
167     public ConnectionProvider getConnectionProvider() {
168         return connProvider;
169     }
170 
171     /***
172      * Sets a connection provider.
173      *
174      * @param cp a connection provider
175      */
176     public void setConnectionProvider(ConnectionProvider cp) {
177         connProvider = cp;
178     }
179 
180     /***
181      * Adds a schema.
182      *
183      * @param schema a schema to add.
184      *
185      * @throws Exception if schema with the same name already exists
186      */
187     public void addSchema(Schema schema) throws Exception {
188         if (schemaExists(schema)) {
189             throw new Exception(
190                 "Schema named <" + schema.getName() + "> already exists."); //$NON-NLS-1$ //$NON-NLS-2$
191         }
192         schemaList.add(schema);
193     }
194 
195     /***
196      * Sets a logger for this DBMonster instance.
197      *
198      * @param log a logger
199      */
200     public void setLogger(Log log) {
201         logger = log;
202     }
203 
204     /***
205      * Returns logger.
206      *
207      * @return a logger.
208      */
209     public Log getLogger() {
210         return logger;
211     }
212 
213     /***
214      * Sets the properties.
215      *
216      * @param props the properties
217      */
218     public void setProperties(Properties props) {
219         Enumeration propertyKeys = props.propertyNames();
220         while (propertyKeys.hasMoreElements()) {
221             String key = (String) propertyKeys.nextElement();
222             context.setProperty(key, props.get(key));
223         }
224     }
225 
226     /***
227      * Does the job. ;) Before calling this method ensure that:
228      * <ol>
229      *  <li>Connection provider is set.</li>
230      *  <li>Progress monitor (if any) is set.</li>
231      *  <li>Valid schemas are added.</li>
232      * </ol>
233      *
234      * @throws Exception on errors.
235      */
236     public void doTheJob() throws Exception {
237         long t0 = System.currentTimeMillis();
238         context.setProperty(LOGGER_KEY, logger);
239         if (logger.isInfoEnabled()) {
240             logger.info("Let's feed this hungry database."); //$NON-NLS-1$
241         }
242 
243         if (logger.isDebugEnabled()) {
244             logger.debug("Checking the connection provider."); //$NON-NLS-1$
245         }
246         if (connProvider == null) {
247             throw new Exception("No connection provider."); //$NON-NLS-1$
248         }
249         connProvider.testConnection();
250 
251         if (logger.isDebugEnabled()) {
252             logger.debug("Connection provider is OK."); //$NON-NLS-1$
253         }
254 
255         if (transactionSize > 1) {
256             if (logger.isDebugEnabled()) {
257                 logger.debug("Transaction size is set to " + transactionSize + ". Turning autoCommit off..."); //$NON-NLS-1$
258             }
259             context.setProperty(TRANSACTION_SIZE_KEY, new Integer(transactionSize));
260             connProvider.setAutoCommit(false);
261         }
262 
263         context.setProperty(CONNECTION_PROVIDER_KEY, connProvider);
264         context.setProperty(RANDOM_KEY, random);
265         context.setProperty(PROGRESS_MONITOR_KEY, progressMonitor);
266 
267         DictionaryManager dm = new DictionaryManager();
268         dm.setRandom(random);
269         context.setProperty(DICTIONARY_MANAGER_KEY, dm);
270 
271         if (preScript != null) {
272             executeScript(connProvider, preScript);
273         }
274         Iterator it = schemaList.iterator();
275         try {
276             if (progressMonitor != null) {
277                 progressMonitor.setUp();
278                 progressMonitor.setSchemaCount(schemaList.size());
279             }
280             while (it.hasNext()) {
281                 Schema schema = (Schema) it.next();
282                 if (progressMonitor != null) {

283                     progressMonitor.setSchemaName(schema.getName());
284                 }
285                 schema.initialize(context);
286                 schema.generate();
287                 if (progressMonitor != null) {
288                     progressMonitor.schemaComplete();
289                 }
290             }
291         } catch (Exception e) {
292             throw e;
293         } finally {
294             if (progressMonitor != null) {
295                 progressMonitor.tearDown();
296             }
297         }
298         if (postScript != null) {
299             executeScript(connProvider, postScript);
300         }
301 
302         t0 = System.currentTimeMillis() - t0;
303         logger.info("Finished in " + Converter.formatTime(t0)); //$NON-NLS-1$
304     }
305 
306     /***
307      * Returns the version.
308      *
309      * @return version
310      */
311     public static final String getVersion() {
312         return VERSION;
313     }
314 
315     /***
316      * Check if schema of this name already exists.
317      *
318      * @param schema schema
319      *
320      * @return <code>true</code> if schema already exists.
321      */
322     private boolean schemaExists(Schema schema) {
323         for (int i = 0; i < schemaList.size(); i++) {
324             if (schema.compareTo(schemaList.get(i)) == 0) {
325                 return true;
326             }
327         }
328         return false;
329     }
330 
331     /***
332      * Returns the progress monitor.
333      *
334      * @return progress monitor.
335      */
336     public ProgressMonitor getProgressMonitor() {
337         return progressMonitor;
338     }
339 
340     /***
341      * Sets the progress monitor.
342      *
343      * @param monitor progress monitor.
344      */
345     public void setProgressMonitor(ProgressMonitor monitor) {
346         progressMonitor = monitor;
347     }
348 
349     public void setPostScript(File postScript) {
350         this.postScript = postScript;
351     }
352 
353     public void setPreScript(File preScript) {
354         this.preScript = preScript;
355     }
356 
357     public void setTransactionSize(int transactionSize) {
358         this.transactionSize = transactionSize;
359     }
360 
361     private void executeScript(ConnectionProvider cp, File scriptFile) throws Exception {
362         ScriptReaderIterator it = new ScriptReaderIterator(scriptFile);
363         Transaction tx = new Transaction(cp);
364         try {
365             tx.begin();
366             while (it.hasNext()) {
367                 String query = (String) it.next();
368                 if (logger.isDebugEnabled()) {
369                     logger.debug("Executing query: " + query);
370                 }
371                 tx.prepareStatement(query);
372                 tx.execute();
373             }
374             tx.commit();
375         } catch (Exception e) {
376             tx.abort();
377             throw e;
378         } finally {
379             tx.close();
380         }
381     }
382 }