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 }