package com.linkedin.databus.util;
/*
*
* Copyright 2013 LinkedIn Corp. All rights reserved
*
* 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.
*
*/
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Map;
import org.apache.avro.specific.SpecificCompiler;
/**
* This tools is replaced by interactive schema generator tool, check InteractiveSchemaGenerator class for more details.
*/
@Deprecated
public class SchemaGeneratorMain
{
private static final String[] DEFAULT_JDBC_DRIVERS = {"oracle.jdbc.driver.OracleDriver"};
private static final String DEFAULT_DATABASE = "jdbc:oracle:thin:@devdb:1521:devdb";
private static final String DEFAULT_USERNAME = "system";
private static final String DEFAULT_PASSWORD = "manager";
private final String _database;
private final String _userName;
private final String _password;
private final String _viewName;
private final String _recordName;
private final String _namespace;
private final File _javaOutDir;
private final File _avroOutDir;
private final boolean _verbose;
private final String _driver;
private final int _avroOutVersion;
private String _primaryKey;
/**
* Command line: user/password@connect_string object_name [-driver foo] [-v]
*
* Like:
* java -classpath bin:/Users/jwesterm/.ivy2/lin-cache/ivy-cache/com.oracle/ojdbc14/10.2.0.2.0/ojdbc14-10.2.0.2.0.jar com.linkedin.databus.util.SchemaGenerator system/manager@jdbc:oracle:thin:@devdb:1521:db MEMBER2.SY\$MEMBER_PROFILE
* or
* java -classpath bin:/Users/jwesterm/.ivy2/lin-cache/ivy-cache/com.oracle/ojdbc14/10.2.0.2.0/ojdbc14-10.2.0.2.0.jar com.linkedin.databus.util.SchemaGenerator system/manager@jdbc:oracle:thin:@devdb:1521:db MEMBER2.DATABUS_PROF_EDU_T
*/
public static void main(String[] args)
throws Exception
{
CommandLineHelper commandLineParser = new CommandLineHelper();
commandLineParser.addArgument("database", false, "Database JDBC connection string (e.g. jdbc:oracle:thin:@devdb:1521:db).", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("userName", false, "User name used to connect to the database.", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("password", false, "Password used to connect to the database.", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("viewName", true, "Name of the databus view for which to generate a schema..", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("recordName", true, "Record name for the generated schema (will be the Java class name of the compiled schema).", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("namespace", true, "Namespace for the generated schema (will be the Java package of the compiled schema).", CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("javaOutDir", false, "Directory for generated Java source files (if absent, the files will not be generated).", CommandLineHelper.ArgumentType.DIRECTORY);
commandLineParser.addArgument("avroOutDir", false, "Directory for generated .avsc files (if absent, the files will not be generated).", CommandLineHelper.ArgumentType.DIRECTORY);
commandLineParser.addArgument("avroOutVersion", false, "Schema version for the avro output file (required if avroOutDir is specified).", CommandLineHelper.ArgumentType.INTEGER);
commandLineParser.addArgument("primaryKey", false, "Primary key name).",CommandLineHelper.ArgumentType.STRING);
commandLineParser.addArgument("verbose", false, "true to enable verbose output.", CommandLineHelper.ArgumentType.BOOLEAN);
commandLineParser.addArgument("driver", false, "JDBC driver (if absent, defaults to oracle.jdbc.driver.OracleDriver).", CommandLineHelper.ArgumentType.STRING);
Map<String, Object> parsedArgs = commandLineParser.parseCommandLine(args);
if(parsedArgs == null)
{
return;
}
if(parsedArgs.containsKey("avroOutDir") && !parsedArgs.containsKey("avroOutVersion"))
{
commandLineParser.showUsage("Bad command line. avroOutDir requires avroOutVersion to be specified as well.");
return;
}
String database = null != parsedArgs.get("database") ? (String)parsedArgs.get("database")
: DEFAULT_DATABASE;
String username = null != parsedArgs.get("userName") ? (String)parsedArgs.get("userName")
: DEFAULT_USERNAME;
String password = null != (String)parsedArgs.get("password") ? (String)(String)parsedArgs.get("password")
: DEFAULT_PASSWORD;
String primaryKey = null != (String) parsedArgs.get("primaryKey") ? (String) parsedArgs.get("primaryKey") : "";
// Show the arguments we read from the command line (helpful when running in an IDE, where you
// don't always see the command line)
commandLineParser.showParsedArguments("Processed command line arguments:", parsedArgs);
// Create the new SchemaGeneratorMain instance using the command line args
SchemaGeneratorMain generator = new SchemaGeneratorMain(
database,
username,
password,
(String)parsedArgs.get("viewName"),
(String)parsedArgs.get("recordName"),
(String)parsedArgs.get("namespace"),
(File)parsedArgs.get("javaOutDir"),
(File)parsedArgs.get("avroOutDir"),
(Boolean)parsedArgs.get("verbose"),
(String)parsedArgs.get("driver"),
(Integer)parsedArgs.get("avroOutVersion"),
primaryKey);
// Load JDBC drivers
generator.loadJdbcDrivers();
// Generate the schema
generator.generateSchema();
System.out.println("Done.");
}
public SchemaGeneratorMain(String database,
String userName,
String password,
String viewName,
String recordName,
String namespace,
File javaOutDir,
File avroOutDir,
Boolean verbose,
String driver,
Integer avroOutVersion,
String primaryKey)
{
_database = database;
_userName = userName;
_password = password;
_viewName = viewName;
_recordName = recordName;
_namespace = namespace;
_javaOutDir = javaOutDir;
_avroOutDir = avroOutDir;
_verbose = verbose != null && verbose;
_driver = driver;
_avroOutVersion = avroOutVersion != null ? avroOutVersion : 0;
_primaryKey = primaryKey;
}
public void loadJdbcDrivers()
{
// If a JDBC driver was specified then try to load it, otherwise load Oracle and MySQL if available
if(_driver != null)
{
try
{
if(_verbose)
{
System.out.println("Loading JDBC driver: " + _driver);
}
Class.forName(_driver);
if(_verbose)
{
System.out.println("JDBC driver loaded successfully.");
}
}
catch(ClassNotFoundException ex)
{
System.out.println("Could not load JDBC driver: " + _driver);
return;
}
}
else
{
boolean loadedAtLeastOneDriver = false;
for(int i=0; i < DEFAULT_JDBC_DRIVERS.length; i++)
{
String driver = DEFAULT_JDBC_DRIVERS[i];
try
{
if(_verbose)
{
System.out.println("Loading default JDBC driver: " + driver);
}
Class.forName(driver);
loadedAtLeastOneDriver = true;
if(_verbose)
{
System.out.println("JDBC driver loaded successfully.");
}
}
catch(ClassNotFoundException ex)
{
System.out.println("Could not load JDBC driver: " + driver);
}
}
if(!loadedAtLeastOneDriver)
{
System.out.println("Unable to load any of the default JDBC drivers. Please make sure one of the default drivers \n" +
"is available in the classpath, or specify a driver with [-driver com.foo.driver]. \n" +
"Default drivers are: " + Arrays.toString(DEFAULT_JDBC_DRIVERS));
}
}
}
public void generateSchema()
throws IOException
{
Connection con = null;
try
{
con = getConnection();
String owner;
String table;
String[] nameParts = _viewName.split("\\.");
if(nameParts.length == 1)
{
owner = _userName;
table = nameParts[0];
}
else
{
owner = nameParts[0];
table = nameParts[1];
}
System.out.println("Generating schema for " + _viewName);
if(_avroOutDir == null)
{
System.out.println("Avro schema will not be saved (use -avroOutDir if you want to save it).");
}
if(_javaOutDir == null)
{
System.out.println("Java files will not be generated (use -javaOutDir if you want to generate them).");
}
TableTypeInfo ti = (TableTypeInfo) new TypeInfoFactory().getTypeInfo(con, owner, table, 0, 0,_primaryKey);
String topRecordAvroName = _recordName + "_V" + _avroOutVersion;
String namespace = _namespace;
String topRecordDatabaseName = _viewName;
FieldToAvro fa = new FieldToAvro();
String schema = fa.buildAvroSchema(namespace, topRecordAvroName, topRecordDatabaseName, null, ti);
System.out.println("Generated Schema:\n" + schema);
if(_avroOutDir != null || _javaOutDir != null)
{
// We will write the schema out to a file. If an output directory was specified then we will
// write it there. Otherwise we write to a temp file that is deleted on exit.
File avroOutFile;
if(_avroOutDir != null)
{
avroOutFile = new File(_avroOutDir, _namespace + "." + _recordName + "." + _avroOutVersion + ".avsc");
System.out.println("Avro schema will be saved in the file: " + avroOutFile.getAbsolutePath());
}
else
{
avroOutFile = File.createTempFile(getClass().getName(), null);
avroOutFile.deleteOnExit();
}
// Write the schema to a file.
PrintWriter pw = new PrintWriter(new FileWriter(avroOutFile));
pw.println(schema);
pw.flush();
pw.close();
if(_javaOutDir != null)
{
System.out.println("Generating Java files in the directory: " + _javaOutDir.getAbsolutePath());
SpecificCompiler.compileSchema(avroOutFile, _javaOutDir);
}
}
}
catch(SQLException ex)
{
System.out.println(ex);
ex.printStackTrace();
}
finally
{
SchemaUtils.close(con);
}
}
public Connection getConnection()
throws SQLException
{
try
{
if(_verbose)
{
System.out.println("Connecting to database: " + _database);
}
Connection con = DriverManager.getConnection(_database, _userName, _password);
if(_verbose)
{
System.out.println("Connected successfully.");
}
return con;
}
catch(SQLException ex)
{
System.out.println("Could not connect to database: " + _database);
System.out.println(ex.getMessage());
if(_verbose)
{
ex.printStackTrace();
}
throw ex;
}
}
}