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 }