View Javadoc

1   /***
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Exoffice Technologies.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Exoffice Technologies. Exolab is a registered
23   *    trademark of Exoffice Technologies.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 2001-2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42   *
43   * $Id: DBTool.java,v 1.4 2005/11/12 12:47:37 tanderson Exp $
44   */
45  package org.exolab.jms.tools.db;
46  
47  import java.sql.Connection;
48  import java.sql.SQLException;
49  
50  import org.apache.commons.logging.Log;
51  import org.apache.commons.logging.LogFactory;
52  import org.apache.log4j.xml.DOMConfigurator;
53  
54  import org.exolab.jms.config.Configuration;
55  import org.exolab.jms.config.ConfigurationReader;
56  import org.exolab.jms.config.RdbmsDatabaseConfiguration;
57  import org.exolab.jms.persistence.DBCPConnectionManager;
58  import org.exolab.jms.persistence.DBConnectionManager;
59  import org.exolab.jms.persistence.PersistenceException;
60  import org.exolab.jms.persistence.RDBMSAdapter;
61  import org.exolab.jms.util.CommandLine;
62  
63  
64  /***
65   * This class provides support for creating and destroying OpenJMS tables in
66   * RDBMS databases.
67   *
68   * @author <a href="mailto:tima@intalio.com">Tim Anderson</a>
69   * @version $Revision: 1.4 $ $Date: 2005/11/12 12:47:37 $
70   */
71  public class DBTool {
72  
73      /***
74       * The connection manager.
75       */
76      private DBConnectionManager _connections;
77  
78      /***
79       * The RDBMS tool.
80       */
81      private RDBMSTool _tool;
82  
83      /***
84       * The logger.
85       */
86      private static final Log _log = LogFactory.getLog(DBTool.class);
87  
88  
89      /***
90       * Construct a new <code>DBTool</code>.
91       *
92       * @param config the configuration to use.
93       * @throws PersistenceException for any error
94       */
95      public DBTool(Configuration config) throws PersistenceException {
96          if (config == null) {
97              throw new IllegalArgumentException("Argument 'config' is null");
98          }
99          init(config);
100     }
101 
102     /***
103      * Construct an instance with the path to an openjms XML configuration file.
104      *
105      * @param path the path to an openjms XML configuration file
106      * @throws PersistenceException if a connection cannot be established
107      */
108     public DBTool(String path) throws PersistenceException {
109         Configuration config;
110         try {
111             config = ConfigurationReader.read(path);
112         } catch (Exception exception) {
113             throw new PersistenceException(exception.getMessage());
114         }
115         DOMConfigurator.configure(config.getLoggerConfiguration().getFile());
116         init(config);
117     }
118 
119     /***
120      * Creates the database tables using the default schema.
121      *
122      * @throws PersistenceException if the tables cannot be created
123      */
124     public void create() throws PersistenceException {
125         Database schema = SchemaHelper.getSchema();
126         _tool.create(schema);
127     }
128 
129     /***
130      * Creates the database tables from the specified schema.
131      *
132      * @param path the path to an XML database schema file
133      * @throws PersistenceException if the tables cannot be created
134      */
135     public void create(String path) throws PersistenceException {
136         if (path == null) {
137             throw new IllegalArgumentException("Argument 'path' is null");
138         }
139         Database schema = SchemaHelper.getSchema(path);
140         _tool.create(schema);
141     }
142 
143     /***
144      * Drop the database tables from the default schema.
145      *
146      * @throws PersistenceException if the tables cannot be dropped
147      */
148     public void drop() throws PersistenceException {
149         Database schema = SchemaHelper.getSchema();
150         _tool.drop(schema);
151     }
152 
153     /***
154      * Drop the database tables from the specified schema.
155      *
156      * @param path the path to an XML database schema file
157      * @throws PersistenceException if the tables cannot be dropped
158      */
159     public void drop(String path) throws PersistenceException {
160         if (path == null) {
161             throw new IllegalArgumentException("Argument 'path' is null");
162         }
163         Database schema = SchemaHelper.getSchema(path);
164         _tool.drop(schema);
165     }
166 
167     /***
168      * Deletes all data from the database tables.
169      *
170      * @throws PersistenceException if the tables can't be deleted
171      */
172     public void delete() throws PersistenceException {
173         Database schema = SchemaHelper.getSchema();
174         _tool.delete(schema);
175     }
176 
177     /***
178      * Migrates the database tables to the latest version.
179      *
180      * @throws PersistenceException if the database cannot be migrated
181      */
182     public void migrate() throws PersistenceException {
183         Connection connection = _connections.getConnection();
184 
185         String fromVersion = SchemaHelper.getSchemaVersion(connection);
186         if (fromVersion == null) {
187             throw new PersistenceException(
188                     "Cannot migrate schema - existing schema version cannot be "
189                     + "determined");
190         }
191         String toVersion = RDBMSAdapter.SCHEMA_VERSION;
192         SchemaConverter converter =
193                 SchemaConverterFactory.create(fromVersion, toVersion,
194                                               connection);
195         if (converter != null) {
196             try {
197                 _log.info("Migrating schema from version=" +
198                           fromVersion + " to version=" + toVersion);
199                 converter.convert();
200                 _log.info("Successfully migrated schema");
201             } catch (PersistenceException exception) {
202                 _log.error("Schema migration from version=" + fromVersion +
203                            " to version=" + toVersion + " failed",
204                            exception);
205                 throw exception;
206             }
207         } else {
208             throw new PersistenceException(
209                     "Incompatible schema types. Expected schema version="
210                     + fromVersion + ", but got schema version=" + toVersion);
211         }
212     }
213 
214     /***
215      * Deallocate any resources.
216      *
217      * @throws SQLException if the database connection cannot be closed
218      */
219     public void close() throws SQLException {
220         _tool.close();
221     }
222 
223     public static void main(String args[]) {
224         CommandLine commands = new CommandLine(args);
225 
226         DBTool tool = null;
227         String config = commands.value("config");
228         if (config != null) {
229             try {
230                 tool = new DBTool(config);
231             } catch (Exception exception) {
232                 _log.error(exception, exception);
233                 System.exit(1);
234             }
235         } else {
236             usage();
237             System.exit(1);
238         }
239         boolean create = commands.exists("create");
240         boolean drop = commands.exists("drop");
241         boolean recreate = commands.exists("recreate");
242         boolean delete = commands.exists("delete");
243         boolean migrate = commands.exists("migrate");
244         String schema = commands.value("schema");
245         if (create) {
246             try {
247                 if (schema != null) {
248                     tool.create(schema);
249                 } else {
250                     tool.create();
251                 }
252                 System.out.println("Successfully created tables");
253             } catch (Exception exception) {
254                 _log.error(exception, exception);
255                 System.exit(1);
256             }
257         } else if (drop) {
258             try {
259                 if (schema != null) {
260                     tool.drop(schema);
261                 } else {
262                     tool.drop();
263                 }
264                 System.out.println("Successfully dropped tables");
265             } catch (Exception exception) {
266                 _log.error(exception, exception);
267                 System.exit(1);
268             }
269         } else if (recreate) {
270             try {
271                 if (schema != null) {
272                     tool.drop(schema);
273                     tool.create(schema);
274                 } else {
275                     tool.drop();
276                     tool.create();
277                 }
278                 System.out.println("Successfully recreated tables");
279             } catch (Exception exception) {
280                 _log.error(exception, exception);
281                 System.exit(1);
282             }
283         } else if (delete) {
284             try {
285                 tool.delete();
286             } catch (Exception exception) {
287                 _log.error(exception, exception);
288                 System.exit(1);
289             }
290             System.out.println("Sucessfully deleted data");
291         } else if (migrate) {
292             try {
293                 tool.migrate();
294             } catch (Exception exception) {
295                 _log.error(exception, exception);
296                 System.exit(1);
297             }
298             System.out.println("Sucessfully migrated database");
299         } else {
300             usage();
301             System.exit(1);
302         }
303         try {
304             tool.close();
305         } catch (Exception exception) {
306             _log.error(exception, exception);
307         }
308     }
309 
310     /***
311      * Initialise this.
312      *
313      * @param config the configuration to use
314      * @throws PersistenceException for any error
315      */
316     private void init(Configuration config) throws PersistenceException {
317         RdbmsDatabaseConfiguration rdbms =
318                 config.getDatabaseConfiguration()
319                 .getRdbmsDatabaseConfiguration();
320         if (rdbms == null) {
321             throw new PersistenceException(
322                     "Configuration not configured to use an RDBMS");
323         }
324         _connections = new DBCPConnectionManager();
325         _connections.setDriver(rdbms.getDriver());
326         _connections.setURL(rdbms.getUrl());
327         _connections.setUser(rdbms.getUser());
328         _connections.setPassword(rdbms.getPassword());
329         _connections.init();
330         _tool = new RDBMSTool(_connections.getConnection());
331     }
332 
333 
334     /***
335      * Displays usage information for this tool when invoked from the command
336      * line.
337      */
338     private static void usage() {
339         System.err.println(
340                 "usage: " + DBTool.class.getName()
341                 + " <arguments> [options]\n"
342                 + "arguments:\n"
343                 + "  -create -config <path>   creates the database tables\n"
344                 + "  -drop -config <path>     drops the database tables\n"
345                 + "  -recreate -config <path> recreates the database tables\n"
346                 + "  -delete -config <path>   deletes all data, leaving tables"
347                 + "\n"
348                 + "  -migrate -config <path>  migrates the database to the "
349                 + "latest schema version\n\n"
350                 + "options:\n"
351                 + "  -schema <schema>\n");
352         System.err.println(
353                 "where:\n"
354                 + "  path      is the path to an OpenJMS configuration file\n"
355                 + "  schema    is an XML document specifying the database "
356                 + "schema\n"
357                 + "            If not specified, the default schema will be "
358                 + "used");
359     }
360 
361 }