/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.usergrid.tools;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.io.IOUtils;
/** Upserts data from files found in an S3 bucket. */
public class WarehouseUpsert extends ExportingToolBase {
private static final Logger logger = LoggerFactory.getLogger( WarehouseUpsert.class );
public static final String DBHOST_PROPNAME = "usergrid.warehouse-export-dbhost";
public static final String DBPORT_PROPNAME = "usergrid.warehouse-export-dbport";
public static final String DBNAME_PROPNAME = "usergrid.warehouse-export-dbname";
public static final String DBUSER_PROPNAME = "usergrid.warehouse-export-dbuser";
public static final String DBPASSWORD_PROPNAME = "usergrid.warehouse-export-dbpassword";
public static final String STAGING_TABLE_PROPNAME = "usergrid.warehouse-export-staging-table";
public static final String MAIN_TABLE_PROPNAME = "usergrid.warehouse-export-main-table";
String accessId;
String secretKey;
String bucketName;
String dbusername;
String dbpassword;
String dbhost;
String dbname;
String dbport;
String tableSchema;
@Override
public void runTool( CommandLine line ) throws Exception {
startSpring();
setVerbose( line );
accessId = ( String ) properties.get( WarehouseExport.ACCESS_ID_PROPNAME );
secretKey = ( String ) properties.get( WarehouseExport.SECRET_KEY_PROPNAME );
bucketName = ( String ) properties.get( WarehouseExport.BUCKET_PROPNAME );
dbusername = ( String ) properties.get( DBUSER_PROPNAME );
dbpassword = ( String ) properties.get( DBPASSWORD_PROPNAME );
dbhost = ( String ) properties.get( DBHOST_PROPNAME );
dbname = ( String ) properties.get( DBNAME_PROPNAME );
dbport = ( String ) properties.get( DBPORT_PROPNAME );
tableSchema = IOUtils.toString( getClass().getResourceAsStream( "/warehouse-schema.sql" ) );
String constr =
String.format( "jdbc:postgresql://%s:%s/%s?user=%s&password=%s", dbhost, dbport, dbname, dbusername,
dbpassword );
Class.forName( "org.postgresql.Driver" );
Connection con = DriverManager.getConnection( constr );
// create main table
String mainTableName = ( String ) properties.get( MAIN_TABLE_PROPNAME );
try {
con.createStatement().execute( createWarehouseTable( mainTableName ) );
logger.info( "Created main table " + mainTableName );
}
catch ( SQLException ex ) {
if ( !ex.getMessage().contains( "already exists" ) ) {
logger.error( "Error creating main table: " + ex.getMessage(), ex );
}
else {
logger.info( "Using existing main table " + mainTableName );
}
}
// drop any existing staging table
String stagingTableName = ( String ) properties.get( STAGING_TABLE_PROPNAME );
String dropStagingTable = String.format( "drop table %s", stagingTableName );
try {
con.createStatement().execute( dropStagingTable );
logger.info( "Dropped existing staging table " + stagingTableName );
}
catch ( SQLException ex ) {
if ( !ex.getMessage().contains( "does not exist" ) ) {
logger.error( "Error dropping staging table: " + ex.getMessage(), ex );
}
else {
logger.info( "Using existing staging table " + stagingTableName );
}
}
// create staging table
logger.info( "Creating new staging table" );
con.createStatement().execute( createWarehouseTable( stagingTableName ) );
// copy data from S3 into staging table
logger.info( "Copying data from S3" );
String copyFromS3 = String.format( "COPY %s FROM 's3://%s' "
+ "CREDENTIALS 'aws_access_key_id=%s;aws_secret_access_key=%s' IGNOREHEADER 2 EMPTYASNULL",
stagingTableName, bucketName, accessId, secretKey );
logger.debug( copyFromS3 );
con.createStatement().execute( copyFromS3 );
// run update portion of upsert process
logger.info( "Upsert: updating" );
String upsertUpdate =
String.format( "UPDATE %s SET id = s.id FROM %s s WHERE %s.created = s.created ", mainTableName,
stagingTableName, mainTableName );
logger.debug( upsertUpdate );
con.createStatement().execute( upsertUpdate );
// insert new values in staging table into main table
logger.info( "Upsert: inserting" );
String upsertInsert =
String.format( "INSERT INTO %s SELECT s.* FROM %s s LEFT JOIN %s n ON s.id = n.id WHERE n.id IS NULL",
mainTableName, stagingTableName, mainTableName );
logger.debug( upsertInsert );
con.createStatement().execute( upsertInsert );
// drop staging table
logger.info( "Dropping existing staging table" );
con.createStatement().execute( dropStagingTable );
// done!
}
String createWarehouseTable( String name ) {
String ddl = tableSchema.replaceAll( "\\{tableName\\}", name );
ddl = ddl.replaceAll( "\\{accessId\\}", accessId );
ddl = ddl.replaceAll( "\\{secretKey\\}", secretKey );
return ddl;
}
}