/*******************************************************************************
* Copyright (c) 2010-2011 VIVO Harvester Team. For full list of contributors, please see the AUTHORS file provided.
* All rights reserved.
* This program and the accompanying materials are made available under the terms of the new BSD license which accompanies this distribution, and is available at http://www.opensource.org/licenses/bsd-license.html
******************************************************************************/
package org.vivoweb.harvester.fetch;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vivoweb.harvester.util.InitLog;
import org.vivoweb.harvester.util.SpecialEntities;
import org.vivoweb.harvester.util.args.ArgDef;
import org.vivoweb.harvester.util.args.ArgList;
import org.vivoweb.harvester.util.args.ArgParser;
import org.vivoweb.harvester.util.args.UsageException;
import org.vivoweb.harvester.util.repo.RecordHandler;
/**
* Fetches rdf data from a JDBC database placing the data in the supplied record handler.
* @author Christopher Haines (hainesc@ctrip.ufl.edu)
*/
public class JDBCFetch {
/**
* SLF4J Logger
*/
private static Logger log = LoggerFactory.getLogger(JDBCFetch.class);
/**
* Record Handler to write records to
*/
private RecordHandler rh;
/**
* Statement processor for the database
*/
private Statement cursor;
/**
* Mapping of tablename to idField name
*/
private Map<String, List<String>> idFields = null;
/**
* Mapping of tablename to mapping of fieldname to tablename
*/
private Map<String, Map<String, String>> fkRelations = null;
/**
* Mapping of tablename to list of datafields
*/
private Map<String, List<String>> dataFields = null;
/**
* Set of table names
*/
private Set<String> tableNames = null;
/**
* List of conditions
*/
private Map<String, List<String>> whereClauses;
/**
* Mapping of extra tables for the from section
*/
private Map<String, String> fromClauses;
/**
* Namespace for RDF made from this database
*/
private String uriNS;
/**
* Prefix each field in query with this
*/
private String queryPre;
/**
* Suffix each field in query with this
*/
private String querySuf;
/**
* The user defined SQL Query string
*/
private Map<String, String> queryStrings;
/**
* accepted table types
*/
private String[] tableTypes;
/**
* Constructor
* @param dbConn connection to the database
* @param output RecordHandler to write data to
* @param uriNameSpace namespace base for rdf records
* @throws IOException error talking with database
*/
public JDBCFetch(Connection dbConn, RecordHandler output, String uriNameSpace) throws IOException {
this(dbConn, output, uriNameSpace, null, null, null, null, null, null, null, null, null);
}
/**
* Constructor
* @param driverClass the jdbc driver
* @param connLine the jdbc connection line
* @param username the username
* @param password the password
* @param output RecordHandler to write data to
* @param uriNameSpace namespace base for rdf records
* @throws IOException error talking with database
*/
public JDBCFetch(String driverClass, String connLine, String username, String password, RecordHandler output, String uriNameSpace) throws IOException {
this(driverClass, connLine, username, password, output, uriNameSpace, null, null, null, null, null, null, null, null, null);
}
/**
* Command line Constructor
* @param args commandline arguments
* @throws IOException error creating task
* @throws UsageException user requested usage message
*/
private JDBCFetch(String[] args) throws IOException, UsageException {
this(getParser().parse(args));
}
/**
* Arglist Constructor
* @param args option set of parsed args
* @throws IOException error creating task
*/
private JDBCFetch(ArgList args) throws IOException {
this(
args.get("d"),
args.get("c"),
args.get("u"),
args.get("p"),
RecordHandler.parseConfig(args.get("o"), args.getValueMap("O")),
(args.has("n")?args.get("n"):(args.get("c")+"/")),
args.get("delimiterPrefix"),
args.get("delimiterSuffix"),
new TreeSet<String>(args.getAll("t")),
(args.has("T")?args.getValueMap("T"):null),
(args.has("F")?splitCommaList(args.getValueMap("F")):null),
(args.has("I")?splitCommaList(args.getValueMap("I")):null),
(args.has("W")?splitCommaList(args.getValueMap("W")):null),
(args.has("R")?splitTildeMap(args.getValueMap("R")):null),
(args.has("Q")?args.getValueMap("Q"):null),
args.getAll("v").toArray(new String[]{})
);
}
/**
* Library style Constructor
* @param dbConn The database Connection
* @param rh Record Handler to write records to
* @param uriNS the uri namespace to use
* @param queryPre Query prefix often "["
* @param querySuf Query suffix often "]"
* @param tableNames set of the table names
* @param fromClauses Mapping of extra tables for the from section
* @param dataFields Mapping of tablename to list of datafields
* @param idFields Mapping of tablename to idField name
* @param whereClauses List of conditions
* @param relations Mapping of tablename to mapping of fieldname to tablename
* @param queryStrings Mapping of tablename to query
* @param tableTypes accepted table types
* @throws IOException error accessing database
*/
public JDBCFetch(Connection dbConn, RecordHandler rh, String uriNS, String queryPre, String querySuf, Set<String> tableNames, Map<String, String> fromClauses, Map<String, List<String>> dataFields, Map<String, List<String>> idFields, Map<String, List<String>> whereClauses, Map<String, Map<String, String>> relations, Map<String, String> queryStrings, String... tableTypes) throws IOException {
try {
this.cursor = dbConn.createStatement();
} catch(SQLException e) {
throw new IOException(e);
}
this.rh = rh;
Set<String> argTables = tableNames;
this.fromClauses = fromClauses;
this.dataFields = dataFields;
this.idFields = idFields;
this.whereClauses = whereClauses;
this.fkRelations = relations;
this.uriNS = uriNS;
this.queryPre = queryPre;
this.querySuf = querySuf;
this.queryStrings = queryStrings;
if(tableTypes.length > 0 && tableTypes[0] != null) {
this.tableTypes = tableTypes;
for(int x=0; x<this.tableTypes.length; x++) {
this.tableTypes[x] = this.tableTypes[x].toUpperCase();
}
} else {
this.tableTypes = new String[]{"TABLE"};
}
if(this.rh == null) {
throw new IllegalArgumentException("Must provide output recordhandler!");
}
if(argTables == null) {
argTables = new TreeSet<String>();
}
if(this.fromClauses != null) {
argTables.addAll(this.fromClauses.keySet());
}
if(this.dataFields != null) {
argTables.addAll(this.dataFields.keySet());
}
if(this.idFields != null) {
argTables.addAll(this.idFields.keySet());
}
if(this.whereClauses != null) {
argTables.addAll(this.whereClauses.keySet());
}
if(this.fkRelations != null) {
argTables.addAll(this.fkRelations.keySet());
}
if(this.queryStrings != null) {
// tablenames for queries are arbitrary
argTables.removeAll(this.queryStrings.keySet());
}
this.tableNames = new TreeSet<String>();
try {
this.tableNames = getTableNames();
} catch(SQLException e) {
throw new IOException(e);
}
Set<String> realDBTables = this.tableNames;
this.tableNames = new TreeSet<String>();
//TODO: this is required as getTableNames loads data in and we want this to be a fresh start
// there should be a nicer way to do all of this, as this is very hacky at the moment
for(String argTable : argTables) {
boolean found = false;
for(String realTableName : realDBTables) {
realTableName = realTableName.trim();
if(argTable.trim().equalsIgnoreCase(realTableName)) {
this.tableNames.add(realTableName);
// fix the tablename in all the other structures >.>
if(this.fromClauses != null) {
Map<String, String> tempMap = new HashMap<String, String>();
for(String fromClausesTable : this.fromClauses.keySet()) {
if(fromClausesTable.trim().equalsIgnoreCase(realTableName)) {
tempMap.put(realTableName, this.fromClauses.get(fromClausesTable));
} else {
tempMap.put(fromClausesTable, this.fromClauses.get(fromClausesTable));
}
}
this.fromClauses = tempMap;
}
if(this.dataFields != null) {
Map<String, List<String>> tempMap = this.dataFields;
for(String dataFieldsTable : this.dataFields.keySet()) {
if(dataFieldsTable.trim().equalsIgnoreCase(realTableName)) {
tempMap.put(realTableName, this.dataFields.get(dataFieldsTable));
} else {
tempMap.put(dataFieldsTable, this.dataFields.get(dataFieldsTable));
}
}
this.dataFields = tempMap;
}
if(this.idFields != null) {
Map<String, List<String>> tempMap = this.idFields;
for(String idFieldsTable : this.idFields.keySet()) {
if(idFieldsTable.trim().equalsIgnoreCase(realTableName)) {
tempMap.put(realTableName, this.idFields.get(idFieldsTable));
} else {
tempMap.put(idFieldsTable, this.idFields.get(idFieldsTable));
}
}
this.idFields = tempMap;
}
if(this.whereClauses != null) {
Map<String, List<String>> tempMap = this.whereClauses;
for(String whereClausesTable : this.whereClauses.keySet()) {
if(whereClausesTable.trim().equalsIgnoreCase(realTableName)) {
tempMap.put(realTableName, this.whereClauses.get(whereClausesTable));
} else {
tempMap.put(whereClausesTable, this.whereClauses.get(whereClausesTable));
}
}
this.whereClauses = tempMap;
}
if(this.fkRelations != null) {
Map<String, Map<String, String>> tempMap = this.fkRelations;
for(String fkRelationsTable : this.fkRelations.keySet()) {
if(fkRelationsTable.trim().equalsIgnoreCase(realTableName)) {
tempMap.put(realTableName, this.fkRelations.get(fkRelationsTable));
} else {
tempMap.put(fkRelationsTable, this.fkRelations.get(fkRelationsTable));
}
}
this.fkRelations = tempMap;
}
found = true;
break;
}
}
if(!found) {
throw new IllegalArgumentException("Database Does Not Contain A Table Named '"+argTable+"'");
}
}
if(this.queryStrings != null) {
this.tableNames.addAll(this.queryStrings.keySet());
}
}
/**
* Library style Constructor
* @param driverClass the jdbc driver
* @param connLine the jdbc connection line
* @param username the username
* @param password the password
* @param rh Record Handler to write records to
* @param uriNS the uri namespace to use
* @param queryPre Query prefix often "["
* @param querySuf Query suffix often "]"
* @param tableNames set of the table names
* @param fromClauses Mapping of extra tables for the from section
* @param dataFields Mapping of tablename to list of datafields
* @param idFields Mapping of tablename to idField name
* @param whereClauses List of conditions
* @param relations Mapping of tablename to mapping of fieldname to tablename
* @param queryStrings Mapping of tablename to query
* @param tableTypes accepted table types
* @throws IOException error accessing database
*/
public JDBCFetch(String driverClass, String connLine, String username, String password, RecordHandler rh, String uriNS, String queryPre, String querySuf, Set<String> tableNames, Map<String, String> fromClauses, Map<String, List<String>> dataFields, Map<String, List<String>> idFields, Map<String, List<String>> whereClauses, Map<String, Map<String, String>> relations, Map<String, String> queryStrings, String... tableTypes) throws IOException {
this(createConnection(driverClass, connLine, username, password), rh, uriNS, queryPre, querySuf, tableNames, fromClauses, dataFields, idFields, whereClauses, relations, queryStrings, tableTypes);
}
/**
* Split the values of a comma separated list mapping
* @param list the original mapping
* @return the split mapping
*/
private static Map<String, List<String>> splitCommaList(Map<String, String> list) {
Map<String, List<String>> splitList = new HashMap<String, List<String>>();
for(String tableName : list.keySet()) {
splitList.put(tableName, Arrays.asList(list.get(tableName).split("\\s?,\\s?")));
}
return splitList;
}
/**
* Split the values of comma separated ~ maps mapping
* @param list the original mapping
* @return the split mappings
*/
private static Map<String, Map<String, String>> splitTildeMap(Map<String, String> list) {
Map<String, List<String>> splitList = splitCommaList(list);
Map<String, Map<String, String>> splitMaps = new HashMap<String, Map<String, String>>();
for(String tableName : splitList.keySet()) {
if(!splitMaps.containsKey(tableName)) {
splitMaps.put(tableName, new HashMap<String, String>());
}
for(String relLine : splitList.get(tableName)) {
String[] relPair = relLine.split("\\s?~\\s?", 2);
if(relPair.length != 2) {
throw new IllegalArgumentException("Bad Relation Line: " + relLine);
}
splitMaps.get(tableName).put(relPair[0], relPair[1]);
}
}
return splitMaps;
}
/**
* Create a connection
* @param driverClass the jdbc driver
* @param connLine the jdbc connection line
* @param username the username
* @param password the password
* @return the connection
* @throws IOException error connecting or loading driver
*/
private static Connection createConnection(String driverClass, String connLine, String username, String password) throws IOException {
try {
Class.forName(driverClass);
return DriverManager.getConnection(connLine, username, password);
} catch(SQLException e) {
throw new IOException(e);
} catch(ClassNotFoundException e) {
throw new IOException(e);
}
}
/**
* Get the field prefix
* @return the field prefix
*/
private String getFieldPrefix() {
if(this.queryPre == null) {
this.queryPre = getParser().getOptMap().get("delimiterPrefix").getDefaultValue();
}
return this.queryPre;
}
/**
* Set the field prefix
* @param fieldPrefix the field prefix to use
*/
public void setFieldPrefix(String fieldPrefix) {
this.queryPre = fieldPrefix;
}
/**
* Get the field suffix
* @return the field suffix
*/
private String getFieldSuffix() {
if(this.querySuf == null) {
this.querySuf = getParser().getOptMap().get("delimiterSuffix").getDefaultValue();
}
return this.querySuf;
}
/**
* Set the field suffix
* @param fieldSuffix the field suffix to use
*/
public void setFieldSuffix(String fieldSuffix) {
this.querySuf = fieldSuffix;
}
/**
* Get the data field information for a table from the database
* @param tableName the table to get the data field information for
* @return the data field list
* @throws SQLException error connecting to DB
*/
private List<String> getDataFields(String tableName) throws SQLException {
// TODO: the part after the OR looks like it should be on the next if statement, look into this
if((this.dataFields == null) || ((this.queryStrings != null) && this.queryStrings.containsKey(tableName))) {
this.dataFields = new HashMap<String, List<String>>();
}
if(!this.dataFields.containsKey(tableName)) {
log.debug("Finding data column names for table: "+tableName);
this.dataFields.put(tableName, new LinkedList<String>());
if((this.queryStrings == null) || !this.queryStrings.containsKey(tableName)) {
ResultSet columnData = this.cursor.getConnection().getMetaData().getColumns(this.cursor.getConnection().getCatalog(), null, tableName, "%");
while(columnData.next()) {
String colName = columnData.getString("COLUMN_NAME");
log.trace("Found data column: "+colName);
if(!getFkRelationFields(tableName).containsKey(colName)) {
this.dataFields.get(tableName).add(colName);
}
}
}
}
return this.dataFields.get(tableName);
}
/**
* Get the relation field information for a table from the database
* @param tableName the table to get the relation field information for
* @return the relation field mapping
* @throws SQLException error connecting to DB
*/
private Map<String, String> getFkRelationFields(String tableName) throws SQLException {
// TODO: the part after the OR looks like it should be on the next if statement, look into this
if(this.fkRelations == null) {
this.fkRelations = new HashMap<String, Map<String, String>>();
}
if(!this.fkRelations.containsKey(tableName)) {
this.fkRelations.put(tableName, new HashMap<String, String>());
}
if((this.queryStrings == null || !this.queryStrings.containsKey(tableName)) && this.fkRelations.get(tableName).isEmpty()) {
log.debug("Finding relation column names for table: "+tableName);
if((this.queryStrings == null) || !this.queryStrings.containsKey(tableName)) {
ResultSet foreignKeys = this.cursor.getConnection().getMetaData().getImportedKeys(this.cursor.getConnection().getCatalog(), null, tableName);
while(foreignKeys.next()) {
String colName = foreignKeys.getString("FKCOLUMN_NAME");
String foreignTable = foreignKeys.getString("PKTABLE_NAME");
log.trace("Found relation column: "+colName);
log.trace("links to table: "+foreignTable);
this.fkRelations.get(tableName).put(colName, foreignTable);
}
}
}
return this.fkRelations.get(tableName);
}
/**
* Get the where clauses for a table from the database
* @param tableName the table to get the where clauses for
* @return the where clauses
*/
private List<String> getWhereClauses(String tableName) {
if(this.whereClauses == null) {
this.whereClauses = new HashMap<String, List<String>>();
}
if(!this.whereClauses.containsKey(tableName)) {
this.whereClauses.put(tableName, new LinkedList<String>());
}
return this.whereClauses.get(tableName);
}
/**
* Get the id field list for a table from the database
* @param tableName the table to get the id field list for
* @return the id field list
* @throws SQLException error connecting to DB
*/
private List<String> getIDFields(String tableName) throws SQLException {
if(this.idFields == null) {
this.idFields = new HashMap<String, List<String>>();
}
if(!this.idFields.containsKey(tableName)) {
log.debug("Finding id column names for table: "+tableName);
this.idFields.put(tableName, new LinkedList<String>());
ResultSet primaryKeys = this.cursor.getConnection().getMetaData().getPrimaryKeys(this.cursor.getConnection().getCatalog(), null, tableName);
while(primaryKeys.next()) {
String colName = primaryKeys.getString("COLUMN_NAME");
log.trace("Found id column: "+colName);
this.idFields.get(tableName).add(colName);
}
}
if(this.idFields.get(tableName).isEmpty()) {
throw new IllegalArgumentException("ID fields for table '" + tableName + "' were not provided and no primary keys are present... please provide an ID field set for this table");
}
return this.idFields.get(tableName);
}
/**
* Gets the tablenames in database
* @return set of tablenames
* @throws SQLException error connecting to DB
*/
private Set<String> getTableNames() throws SQLException {
if(this.tableNames.isEmpty()) {
ResultSet tableData = this.cursor.getConnection().getMetaData().getTables(this.cursor.getConnection().getCatalog(), null, "%", this.tableTypes);
while(tableData.next()) {
this.tableNames.add(tableData.getString("TABLE_NAME"));
}
}
return this.tableNames;
}
/**
* Builds a select statement against the table using configured fields
* @param tableName the table to build the select statement for
* @return the select statement
* @throws SQLException error connecting to db
*/
private String buildSelect(String tableName) throws SQLException {
if((this.queryStrings != null) && this.queryStrings.containsKey(tableName)) {
String query = this.queryStrings.get(tableName);
log.trace("User defined SQL Query:\n" + query);
return query;
}
boolean multiTable = (this.fromClauses != null) && this.fromClauses.containsKey(tableName);
StringBuilder sb = new StringBuilder();
sb.append("SELECT ");
for(String dataField : getDataFields(tableName)) {
sb.append(getFieldPrefix());
if(multiTable && (dataField.split("\\.").length <= 1)) {
sb.append(tableName);
sb.append(".");
}
sb.append(dataField);
sb.append(getFieldSuffix());
sb.append(", ");
}
for(String relField : getFkRelationFields(tableName).keySet()) {
sb.append(getFieldPrefix());
if(multiTable && (relField.split("\\.").length <= 1)) {
sb.append(tableName);
sb.append(".");
}
sb.append(relField);
sb.append(getFieldSuffix());
sb.append(", ");
}
for(String idField : getIDFields(tableName)) {
sb.append(getFieldPrefix());
if(multiTable && (idField.split("\\.").length <= 1)) {
sb.append(tableName);
sb.append(".");
}
sb.append(idField);
sb.append(getFieldSuffix());
sb.append(", ");
}
sb.delete(sb.lastIndexOf(", "), sb.length());
sb.append(" FROM ");
sb.append(tableName);
if(multiTable) {
sb.append(", ");
sb.append(this.fromClauses.get(tableName));
}
if(getWhereClauses(tableName).size() > 0) {
sb.append(" WHERE ");
sb.append(StringUtils.join(getWhereClauses(tableName), " AND "));
}
log.trace("Generated SQL Query:\n" + sb.toString());
return sb.toString();
}
/**
* Builds a table's record namespace
* @param tableName the table to build the namespace for
* @return the namespace
*/
private String buildTableRecordNS(String tableName) {
return this.uriNS + tableName;
}
/**
* Builds a table's field description namespace
* @param tableName the table to build the namespace for
* @return the namespace
*/
private String buildTableFieldNS(String tableName) {
return this.uriNS + "fields/" + tableName + "/";
}
/**
* Builds a table's type description namespace
* @param tableName the table to build the namespace for
* @return the namespace
*/
private String buildTableType(String tableName) {
return this.uriNS + "types#" + tableName;
}
/**
* Get the fields from a result set
* @param rs the resultset
* @return the list of fields
* @throws SQLException error reading resultset
*/
private List<String> getResultSetFields(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
List<String> fields = new ArrayList<String>(count);
for(int x = 1; x <= count; x++) {
fields.add(rsmd.getColumnLabel(x));
}
return fields;
}
/**
* Executes the task
* @throws IOException error processing record handler or jdbc connection
*/
public void execute() throws IOException {
int count = 0;
// For each Table
try {
for(String tableName : getTableNames()) {
StringBuilder sb = new StringBuilder();
// For each Record
ResultSet rs = this.cursor.executeQuery(buildSelect(tableName));
// ResultSetMetaData rsmd = rs.getMetaData();
// int ColumnCount = rsmd.getColumnCount();
// Map<String,String> columnData = new HashMap<String,String>();
while(rs.next()) {
StringBuilder recID = new StringBuilder();
recID.append("id");
for(String idField : getIDFields(tableName)) {
recID.append("_-_");
String id = rs.getString(idField);
if(id != null) {
id = id.trim();
}
id = SpecialEntities.xmlEncode(id);
recID.append(id);
}
// log.trace("Creating RDF for "+tableName+": "+recID);
// Build RDF BEGIN
// Header info
String tableNS = "db-" + tableName;
sb = new StringBuilder();
sb.append("<?xml version=\"1.0\"?>\n");
sb.append("<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n");
sb.append(" xmlns:");
sb.append(tableNS);
sb.append("=\"");
sb.append(buildTableFieldNS(tableName));
sb.append("\"\n");
sb.append(" xml:base=\"");
sb.append(buildTableRecordNS(tableName));
sb.append("\">\n");
// Record info BEGIN
sb.append(" <rdf:Description rdf:ID=\"");
sb.append(recID);
sb.append("\">\n");
// insert type value
sb.append(" <rdf:type rdf:resource=\"");
sb.append(buildTableType(tableName));
sb.append("\"/>\n");
// DataFields
List<String> dataFieldList;
if((this.queryStrings != null) && this.queryStrings.containsKey(tableName)) {
dataFieldList = getResultSetFields(rs);
} else {
dataFieldList = getDataFields(tableName);
}
for(String dataField : dataFieldList) {
// Field BEGIN
String field = tableNS + ":" + dataField.replaceAll(" ", "_");
sb.append(" <");
sb.append(SpecialEntities.xmlEncode(field));
sb.append(">");
// insert field value
if(rs.getString(dataField) != null) {
sb.append(SpecialEntities.xmlEncode(rs.getString(dataField).trim()));
}
// Field END
sb.append("</");
sb.append(SpecialEntities.xmlEncode(field));
sb.append(">\n");
}
// Relation Fields
for(String relationField : getFkRelationFields(tableName).keySet()) {
// Field BEGIN
String field = tableNS + ":" + relationField.replaceAll(" ", "_");
sb.append(" <");
sb.append(SpecialEntities.xmlEncode(field));
sb.append(" rdf:resource=\"");
sb.append(buildTableRecordNS(getFkRelationFields(tableName).get(relationField)));
// insert field value
sb.append("#id_-_" + rs.getString(relationField).trim());
// Field END
sb.append("\"/>\n");
}
// Record info END
sb.append(" </rdf:Description>\n");
// Footer info
sb.append("</rdf:RDF>");
// Build RDF END
// Write RDF to RecordHandler
log.trace("Adding record: " + tableName + "_" + recID);
this.rh.addRecord(tableName + "_" + recID, sb.toString(), this.getClass());
count++;
}
}
} catch(SQLException e) {
throw new IOException(e);
}
log.info("Added " + count + " Records");
}
/**
* Get the ArgParser for this task
* @return the ArgParser
*/
private static ArgParser getParser() {
ArgParser parser = new ArgParser("JDBCFetch");
parser.addArgument(new ArgDef().setShortOption('d').setLongOpt("driver").withParameter(true, "JDBC_DRIVER").setDescription("jdbc driver class").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('c').setLongOpt("connection").withParameter(true, "JDBC_CONN").setDescription("jdbc connection string").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('u').setLongOpt("username").withParameter(true, "USERNAME").setDescription("database username").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('p').setLongOpt("password").withParameter(true, "PASSWORD").setDescription("database password").setRequired(true));
parser.addArgument(new ArgDef().setShortOption('o').setLongOpt("output").withParameter(true, "CONFIG_FILE").setDescription("RecordHandler config file path").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('t').setLongOpt("tableName").withParameters(true, "TABLE_NAME").setDescription("a single database table name [have multiple -t for more table names]").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('v').setLongOpt("validTableType").withParameters(true, "TABLE_TYPE").setDescription("a single table type (TABLE, VIEW, etc) [have multiple -v for more table types]").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('Q').setLongOpt("query").withParameterValueMap("TABLE_NAME", "SQL_QUERY").setDescription("use SQL_QUERY to select from TABLE_NAME").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('I').setLongOpt("id").withParameterValueMap("TABLE_NAME", "ID_FIELD_LIST").setDescription("use columns in ID_FIELD_LIST[comma separated] as identifier for TABLE_NAME").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('F').setLongOpt("fields").withParameterValueMap("TABLE_NAME", "FIELD_LIST").setDescription("fetch columns in FIELD_LIST[comma separated] for TABLE_NAME").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('R').setLongOpt("relations").withParameterValueMap("TABLE_NAME", "RELATION_PAIR_LIST").setDescription("fetch columns in RELATION_PAIR_LIST[comma separated] for TABLE_NAME").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('W').setLongOpt("whereClause").withParameterValueMap("TABLE_NAME", "CLAUSE_LIST").setDescription("filter TABLE_NAME records based on conditions in CLAUSE_LIST[comma separated]").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('T').setLongOpt("tableFromClause").withParameterValueMap("TABLE_NAME", "TABLE_LIST").setDescription("add tables to use in from clauses for TABLE_NAME").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('O').setLongOpt("outputOverride").withParameterValueMap("RH_PARAM", "VALUE").setDescription("override the RH_PARAM of output recordhandler using VALUE").setRequired(false));
parser.addArgument(new ArgDef().setShortOption('n').setLongOpt("namespaceBase").withParameter(true, "NAMESPACE_BASE").setDescription("the base namespace to use for each node created").setRequired(false));
parser.addArgument(new ArgDef().setLongOpt("delimiterPrefix").withParameter(true, "DELIMITER").setDescription("Prefix each field in the query with this character").setDefaultValue("").setRequired(false));
parser.addArgument(new ArgDef().setLongOpt("delimiterSuffix").withParameter(true, "DELIMITER").setDescription("Suffix each field in the query with this character").setDefaultValue("").setRequired(false));
return parser;
}
/**
* Main method
* @param args commandline arguments
*/
public static void main(String... args) {
Exception error = null;
try {
InitLog.initLogger(args, getParser());
log.info(getParser().getAppName() + ": Start");
new JDBCFetch(args).execute();
} catch(IllegalArgumentException e) {
log.error(e.getMessage());
log.debug("Stacktrace:",e);
System.out.println(getParser().getUsage());
error = e;
} catch(UsageException e) {
log.info("Printing Usage:");
System.out.println(getParser().getUsage());
error = e;
} catch(Exception e) {
log.error(e.getMessage());
log.debug("Stacktrace:",e);
error = e;
} finally {
log.info(getParser().getAppName() + ": End");
if(error != null) {
System.exit(1);
}
}
}
}