All Downloads are FREE. Search and download functionalities are using the official Maven repository.

es.accenture.flink.Sink.KuduOutputFormat Maven / Gradle / Ivy

package es.accenture.flink.Sink;

import es.accenture.flink.Utils.Exceptions.KuduClientException;
import es.accenture.flink.Utils.Exceptions.KuduTableException;
import es.accenture.flink.Utils.RowSerializable;
import es.accenture.flink.Utils.Utils;
import org.apache.flink.api.common.io.RichOutputFormat;
import org.apache.flink.configuration.Configuration;
import org.apache.kudu.client.*;
import org.apache.log4j.Logger;

import java.io.IOException;


public class KuduOutputFormat extends RichOutputFormat {

    private String host, tableName;
    private Integer tableMode;
    private String[] fieldsNames;
    private transient Utils utils;

    //Kudu variables
    private transient KuduTable table;

    //Modes
    public static final Integer CREATE = 1;
    public static final Integer APPEND = 2;
    public static final Integer OVERRIDE = 3;


    //LOG4J
    private final static Logger logger = Logger.getLogger(KuduOutputFormat.class);
    private static final Object lock = new Object();
    /**
     * Builder to use when you want to create a new table
     *
     * @param host        Kudu host
     * @param tableName   Kudu table name
     * @param fieldsNames List of column names in the table to be created
     * @param tableMode   Way to operate with table (CREATE, APPEND, OVERRIDE)
     * @throws KuduClientException In case of exception caused by Kudu Client
     * @throws KuduTableException In case of exception caused by Kudu Tablet
     * @throws KuduException In case of exception caused by Kudu
     */
    public KuduOutputFormat(String host, String tableName, String[] fieldsNames, Integer tableMode) throws KuduException, KuduTableException, KuduClientException {
        if (tableMode == null || ((!tableMode.equals(CREATE)) && (!tableMode.equals(APPEND)) && (!tableMode.equals(OVERRIDE)))) {
            throw new IllegalArgumentException("ERROR: Param \"tableMode\" not valid (null or empty)");

        } else if (!(tableMode.equals(CREATE) || tableMode.equals(APPEND) || tableMode.equals(OVERRIDE))) {
            throw new IllegalArgumentException("ERROR: Param \"tableMode\" not valid (must be CREATE, APPEND or OVERRIDE)");

        } else if (tableMode.equals(CREATE)) {
            if (fieldsNames == null || fieldsNames.length == 0)
                throw new IllegalArgumentException("ERROR: Missing param \"fieldNames\". Can't create a table without column names");

        } else if (host == null || host.isEmpty()) {
            throw new IllegalArgumentException("ERROR: Param \"host\" not valid (null or empty)");

        } else if (tableName == null || tableName.isEmpty()) {
            throw new IllegalArgumentException("ERROR: Param \"tableName\" not valid (null or empty)");
        }

        this.host = host;
        this.tableName = tableName;
        this.fieldsNames = fieldsNames;
        this.tableMode = tableMode;

    }

    /**
     * Builder to be used when using an existing table
     *
     * @param host      Kudu host
     * @param tableName Kudu table name to be used
     * @param tableMode Way to operate with table (CREATE, APPEND, OVERRIDE)
     * @throws KuduClientException In case of exception caused by Kudu Client
     * @throws KuduTableException In case of exception caused by Kudu Tablet
     * @throws KuduException In case of exception caused by Kudu

     */
    public KuduOutputFormat(String host, String tableName, Integer tableMode) throws KuduException, KuduTableException, KuduClientException {
        if (tableMode == null || ((!tableMode.equals(CREATE)) && (!tableMode.equals(APPEND)) && (!tableMode.equals(OVERRIDE)))) {
            throw new IllegalArgumentException("ERROR: Param \"tableMode\" not valid (null or empty)");

        } else if (tableMode.equals(CREATE)) {
            throw new IllegalArgumentException("ERROR: Param \"tableMode\" can't be CREATE if missing \"fieldNames\". Use other builder for this mode");

        } else if (!(tableMode.equals(APPEND) || tableMode.equals(OVERRIDE))) {
            throw new IllegalArgumentException("ERROR: Param \"tableMode\" not valid (must be APPEND or OVERRIDE)");

        } else if (host == null || host.isEmpty()) {
            throw new IllegalArgumentException("ERROR: Param \"host\" not valid (null or empty)");

        } else if (tableName == null || tableName.isEmpty()) {
            throw new IllegalArgumentException("ERROR: Param \"tableName\" not valid (null or empty)");
        }

        this.host = host;
        this.tableName = tableName;
        this.tableMode = tableMode;

    }


    @Override
    public void configure(Configuration configuration) {

    }

    @Override
    public void open(int i, int i1) throws IOException {

        // Establish connection with Kudu
        this.utils = new Utils(host);
        if(this.utils.getClient().tableExists(tableName)){
            logger.info("Mode is CREATE and table already exist. Changed mode to APPEND. Warning, parallelism may be less efficient");
            tableMode = APPEND;
        }

        // Case APPEND (or OVERRIDE), with builder without column names, because otherwise it throws a NullPointerException
        if(tableMode.equals(APPEND) || tableMode.equals(OVERRIDE)) {
            this.table = utils.useTable(tableName, tableMode);

            if (fieldsNames == null || fieldsNames.length == 0) {
                fieldsNames = utils.getNamesOfColumns(table);
            } else {
                // When column names provided, and table exists, must check if column names match
                utils.checkNamesOfColumns(utils.getNamesOfColumns(this.table), fieldsNames);
            }

        }

    }

    @Override
    public void close() throws IOException {
        this.utils.getClient().close();
    }

    /**
     * It's responsible to insert a row into the indicated table by the builder (Batch)
     *
     * @param row   Data of a row to insert
     * */
    @Override
    public void writeRecord(RowSerializable row) throws IOException {

        if(tableMode.equals(CREATE)){
            if (!utils.getClient().tableExists(tableName)) {
                createTable(utils, tableName, fieldsNames, row);
            }else{
                this.table = utils.getClient().openTable(tableName);
            }
        }
        if(table!=null)
            utils.insert(table, row, fieldsNames);
        //logger.info("Inserted the Row: | " + utils.printRow(row) + "at the table \"" + this.tableName + "\"");
    }

    private synchronized void createTable(Utils utils, String tableName, String[] fieldsNames, RowSerializable row) throws KuduException, KuduTableException {
        synchronized (lock){
               this.table = utils.useTable(tableName, fieldsNames, row);
               if(fieldsNames == null || fieldsNames.length == 0){
                    this.fieldsNames = utils.getNamesOfColumns(table);
               } else {
                    // When column names provided, and table exists, must check if column names match
                    utils.checkNamesOfColumns(utils.getNamesOfColumns(this.table), fieldsNames);
               }
            }
        }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy