BuildDb.java

/***************************************************************************
   Copyright 2014 Emily Estes

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
***************************************************************************/
package net.metanotion.sql;


import java.io.File;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.ServiceLoader;
import javax.inject.Named;

import net.metanotion.util.ArgsToStruct;
import net.metanotion.util.Description;

/** This is a utility class/mini-application that creates a database schema and/or create a database. The command line
arguments are as follows:
-url:<jdbc database url>
-user:<username>
-pass:<password>
-database:<database name>
-create
-dropFirst
-schema:<schema name>
-class:<class name to load the schema from>
-echo
-dryrun
*/
public final class BuildDb {
	/** This class represents the command line options used by BuildDb. */
	public static final class Args {
		@Description("The JDBC connection URL for the database server.")
		public String url;
		@Description("The username for the database server.")
		public String user;
		@Description("The password for the database server.")
		public String pass;
		@Description("The name of the database.")
		public String database;
		@Description("If this option is set, create the database first.")
		public boolean create;
		@Description("If this option is set along with -create, attempt to drop the database if it already exists "
			+ "before creating the database.")
		public boolean dropFirst;
		@Description("Create the schema and set the schema search path to this schema before running the database DDL.")
		public String schema;
		@Description("Echo the SQL statements to System.out.")
		public boolean echo;
		@Description("Do not actually excute any of the SQL statements.")
		public boolean dryrun;
		@Description("Load the class specified and generate the database DDL from the SchemaGenerator instance "
			+ "obtained from calling the zero argument static method 'schemaFactory()'")
		@Named("class") public String klazz;
		@Description("Generate the database DDL from the classpath resource specified.")
		public String resource;
		@Description("Generate the database DDL from the SQL contained in the file specified.")
		public File file;
	}

	/** Run the BuildDb application.
		@param args The command line arguments for the applcation(in order: JDBC URL, Username, Password, classname of the
			class to load the schema from.).
	*/
	public static void main(final String[] args) {
		try {
			final Args arg = (new ArgsToStruct<>(Args.class)).getInstance(args);

			final int ct = ((arg.klazz != null) ? 1 : 0) + ((arg.resource != null) ? 1 : 0) + ((arg.file != null) ? 1 : 0);
			if(ct>1) {
				System.out.println("FAIL: You must specify only one of -class, -resource, or -file");
				return;
			}


			if(arg.create) {
				try (final Connection conn = DriverManager.getConnection(arg.url, arg.user, arg.pass)) {
					DbUtil.createDatabase(conn, arg.database, arg.user, arg.dropFirst);
				}
			}

			final SchemaGenerator schemaGen = (ct == 0) ? ServiceLoader.load(SchemaGenerator.class).iterator().next() :
				((arg.klazz != null) ? DbUtil.reflectSchemaGenerator(Class.forName(arg.klazz)) :
					((arg.file != null) ? DbUtil.fileSchemaGenerator(arg.file) :
						DbUtil.resourceSchemaGenerator(BuildDb.class.getClassLoader(), arg.resource)));

			if(!arg.dryrun) {
				try (final Connection conn = DriverManager.getConnection(arg.url + arg.database, arg.user, arg.pass)) {
					if(arg.schema != null) {
						DbUtil.createSchema(conn, arg.schema, false);
						DbUtil.setSearchPath(conn, arg.schema);
					}
					DbUtil.runSchema(conn, schemaGen);
				}
			}
			if(arg.echo) {
				final PrintWriter out = new PrintWriter(System.out);
				DbUtil.printSchema(out, schemaGen, arg.schema);
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}
	}
}