org.jumpmind.symmetric.io.data.reader.ExtractDataReader.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.symmetric.io.data.reader.ExtractDataReader.java

Source

/**
 * Licensed to JumpMind Inc under one or more contributor
 * license agreements.  See the NOTICE file distributed
 * with this work for additional information regarding
 * copyright ownership.  JumpMind Inc licenses this file
 * to you under the GNU General Public License, version 3.0 (GPLv3)
 * (the "License"); you may not use this file except in compliance
 * with the License.
 *
 * You should have received a copy of the GNU General Public License,
 * version 3.0 (GPLv3) along with this library; if not, see
 * <http://www.gnu.org/licenses/>.
 *
 * 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.jumpmind.symmetric.io.data.reader;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.ArrayUtils;
import org.jumpmind.db.model.Column;
import org.jumpmind.db.model.Table;
import org.jumpmind.db.platform.DatabaseInfo;
import org.jumpmind.db.platform.IDatabasePlatform;
import org.jumpmind.db.sql.ISqlTemplate;
import org.jumpmind.db.util.BinaryEncoding;
import org.jumpmind.symmetric.io.data.Batch;
import org.jumpmind.symmetric.io.data.CsvData;
import org.jumpmind.symmetric.io.data.DataContext;
import org.jumpmind.symmetric.io.data.DataEventType;
import org.jumpmind.symmetric.io.data.IDataReader;
import org.jumpmind.util.CollectionUtils;
import org.jumpmind.util.FormatUtils;
import org.jumpmind.util.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExtractDataReader implements IDataReader {

    protected static final Logger log = LoggerFactory.getLogger(ExtractDataReader.class);

    public static final String DATA_CONTEXT_CURRENT_CSV_DATA = "csvData";

    protected Map<Batch, Statistics> statistics = new HashMap<Batch, Statistics>();

    protected IDatabasePlatform platform;

    protected List<IExtractDataReaderSource> sourcesToUse;

    protected IExtractDataReaderSource currentSource;

    protected Batch batch;

    protected Table table;

    protected CsvData data;

    protected DataContext dataContext;

    public ExtractDataReader(IDatabasePlatform platform, IExtractDataReaderSource source) {
        this.sourcesToUse = new ArrayList<IExtractDataReaderSource>();
        this.sourcesToUse.add(source);
        this.platform = platform;
    }

    public ExtractDataReader(IDatabasePlatform platform, List<IExtractDataReaderSource> sources) {
        this.sourcesToUse = new ArrayList<IExtractDataReaderSource>(sources);
        this.platform = platform;
    }

    public void open(DataContext context) {
        this.dataContext = context;
    }

    public Batch nextBatch() {
        closeCurrentSource();
        if (this.sourcesToUse.size() > 0) {
            this.currentSource = this.sourcesToUse.remove(0);
            this.batch = this.currentSource.getBatch();
        } else {
            this.batch = null;
        }
        return this.batch;

    }

    public Table nextTable() {
        this.table = null;
        if (this.currentSource != null) {
            if (this.data == null) {
                this.data = this.currentSource.next();
            }
            if (this.data != null) {
                this.table = this.currentSource.getTargetTable();
                if (this.table != null) {
                    this.table.setCatalog(substituteVariables(this.table.getCatalog()));
                    this.table.setSchema(substituteVariables(this.table.getSchema()));
                }
            }
        }

        if (this.table == null && this.batch != null) {
            this.batch.setComplete(true);
        }
        return this.table;
    }

    protected String substituteVariables(String sourceString) {
        if (sourceString != null && sourceString.indexOf("$(") != -1) {
            sourceString = FormatUtils.replace("sourceNodeId", (String) dataContext.get("sourceNodeId"),
                    sourceString);
            sourceString = FormatUtils.replace("sourceNodeExternalId",
                    (String) dataContext.get("sourceNodeExternalId"), sourceString);
            sourceString = FormatUtils.replace("sourceNodeGroupId", (String) dataContext.get("sourceNodeGroupId"),
                    sourceString);
            sourceString = FormatUtils.replace("targetNodeId", (String) dataContext.get("targetNodeId"),
                    sourceString);
            sourceString = FormatUtils.replace("targetNodeExternalId",
                    (String) dataContext.get("targetNodeExternalId"), sourceString);
            sourceString = FormatUtils.replace("targetNodeGroupId", (String) dataContext.get("targetNodeGroupId"),
                    sourceString);
        }
        return sourceString;
    }

    public CsvData nextData() {
        if (this.table != null) {
            if (this.data == null) {
                this.data = this.currentSource.next();
            }

            if (data == null) {
                closeCurrentSource();
            } else {
                Table targetTable = this.currentSource.getTargetTable();
                if (targetTable != null && targetTable.equals(this.table)) {
                    data = enhanceWithLobsFromSourceIfNeeded(this.currentSource.getSourceTable(), data);
                } else {
                    // the table has changed
                    return null;
                }
            }
        }

        CsvData dataToReturn = this.data;
        this.data = null;
        this.dataContext.put(DATA_CONTEXT_CURRENT_CSV_DATA, dataToReturn);
        return dataToReturn;
    }

    public void close() {
        closeCurrentSource();
        this.batch = null;
    }

    protected void closeCurrentSource() {
        if (this.currentSource != null) {
            this.currentSource.close();
            this.currentSource = null;
        }

        this.table = null;
        this.data = null;
    }

    public Map<Batch, Statistics> getStatistics() {
        return statistics;
    }

    protected CsvData enhanceWithLobsFromSourceIfNeeded(Table table, CsvData data) {
        if (this.currentSource.requiresLobsSelectedFromSource() && (data.getDataEventType() == DataEventType.UPDATE
                || data.getDataEventType() == DataEventType.INSERT)) {
            List<Column> lobColumns = platform.getLobColumns(table);
            if (lobColumns.size() > 0) {
                String[] columnNames = table.getColumnNames();
                String[] rowData = data.getParsedData(CsvData.ROW_DATA);
                Column[] orderedColumns = table.getColumns();
                Object[] objectValues = platform.getObjectValues(batch.getBinaryEncoding(), rowData,
                        orderedColumns);
                Map<String, Object> columnDataMap = CollectionUtils.toMap(columnNames, objectValues);
                Column[] pkColumns = table.getPrimaryKeyColumns();
                ISqlTemplate sqlTemplate = platform.getSqlTemplate();
                Object[] args = new Object[pkColumns.length];
                for (int i = 0; i < pkColumns.length; i++) {
                    args[i] = columnDataMap.get(pkColumns[i].getName());
                }

                for (Column lobColumn : lobColumns) {
                    String sql = buildSelect(table, lobColumn, pkColumns);
                    String valueForCsv = null;
                    if (platform.isBlob(lobColumn.getMappedTypeCode())) {
                        byte[] binaryData = sqlTemplate.queryForBlob(sql, lobColumn.getJdbcTypeCode(),
                                lobColumn.getJdbcTypeName(), args);
                        if (binaryData != null) {
                            if (batch.getBinaryEncoding() == BinaryEncoding.BASE64) {
                                valueForCsv = new String(Base64.encodeBase64(binaryData));
                            } else if (batch.getBinaryEncoding() == BinaryEncoding.HEX) {
                                valueForCsv = new String(Hex.encodeHex(binaryData));
                            } else {
                                valueForCsv = new String(binaryData);
                            }
                            binaryData = null;
                        }
                    } else {
                        valueForCsv = sqlTemplate.queryForClob(sql, lobColumn.getJdbcTypeCode(),
                                lobColumn.getJdbcTypeName(), args);
                    }

                    int index = ArrayUtils.indexOf(columnNames, lobColumn.getName());
                    rowData[index] = valueForCsv;

                }

                data.putParsedData(CsvData.ROW_DATA, rowData);
            }
        }
        return data;
    }

    protected String buildSelect(Table table, Column lobColumn, Column[] pkColumns) {
        StringBuilder sql = new StringBuilder("select ");
        DatabaseInfo dbInfo = platform.getDatabaseInfo();
        String quote = platform.getDdlBuilder().isDelimitedIdentifierModeOn() ? dbInfo.getDelimiterToken() : "";
        sql.append(quote);
        sql.append(lobColumn.getName());
        sql.append(quote);
        sql.append(",");
        sql.delete(sql.length() - 1, sql.length());
        sql.append(" from ");
        sql.append(table.getQualifiedTableName(quote, dbInfo.getCatalogSeparator(), dbInfo.getSchemaSeparator()));
        sql.append(" where ");
        for (Column col : pkColumns) {
            sql.append(quote);
            sql.append(col.getName());
            sql.append(quote);
            sql.append("=? and ");
        }
        sql.delete(sql.length() - 5, sql.length());
        return sql.toString();
    }

}