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 piotr.maj@kernelpanic.pl.
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 <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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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"; //$NON-NLS-1$
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."); //$NON-NLS-1$ //$NON-NLS-2$
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."); //$NON-NLS-1$
230         }
231 
232         if (logger.isDebugEnabled()) {
233             logger.debug("Checking the connection provider."); //$NON-NLS-1$
234         }
235         if (connProvider == null) {
236             throw new Exception("No connection provider."); //$NON-NLS-1$
237         }
238         connProvider.testConnection();
239         if (logger.isDebugEnabled()) {
240             logger.debug("Connection provider is OK."); //$NON-NLS-1$
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)); //$NON-NLS-1$
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 }