Package com.asakusafw.bulkloader.importer

Source Code of com.asakusafw.bulkloader.importer.ImportFileCreate

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* 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.
*/
package com.asakusafw.bulkloader.importer;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.List;

import com.asakusafw.bulkloader.bean.ImportBean;
import com.asakusafw.bulkloader.bean.ImportTargetTableBean;
import com.asakusafw.bulkloader.common.Constants;
import com.asakusafw.bulkloader.common.DBAccessUtil;
import com.asakusafw.bulkloader.common.DBConnection;
import com.asakusafw.bulkloader.common.FileNameUtil;
import com.asakusafw.bulkloader.common.ImportTableLockType;
import com.asakusafw.bulkloader.exception.BulkLoaderSystemException;
import com.asakusafw.bulkloader.log.Log;
import com.asakusafw.thundergate.runtime.cache.ThunderGateCacheSupport;

/**
* Importファイルを生成するクラス。
* @author yuta.shirai
*/
public class ImportFileCreate {

    static final Log LOG = new Log(ImportFileCreate.class);

    private static final String[] EMPTY = new String[0];

    /**
     * Importファイルを生成する。
     * Importファイルはテーブル毎に以下の通り出力される
<pre>
・出力ディレクトリ:[プロパティのimport.tsv-create-dir]
・ファイル名:IMP_[ターゲット名]_[ジョブフローID]_[ジョブフロー実行ID]_[インポート対象テーブル名].tsv
</pre>
     * @param bean パラメータを保持するBean
     * @param jobflowSid ジョブフローID (レコードロックを一つも行わない場合は{@code null}でもよい)
     * @return ファイル生成結果(成功した場合:true、失敗した場合:false)
     */
    public boolean createImportFile(ImportBean bean, String jobflowSid) {
        Connection conn = null;
        try {
            // コネクションを取得する
            conn = DBConnection.getConnection();

            // import対象テーブルの分繰り返してファイル作成を行う。
            List<String> list = bean.getImportTargetTableList();
            for (String tableName : list) {
                ImportTargetTableBean targetTable = bean.getTargetTable(tableName);
                ImportTableLockType lockType = targetTable.getLockType();

                // ファイル名を生成
                File importFile = FileNameUtil.createImportFilePath(
                        bean.getTargetName(), bean.getJobflowId(), bean.getExecutionId(), tableName);

                LOG.info("TG-IMPORTER-03003",
                        tableName,
                        lockType,
                        importFile.getAbsolutePath());

                // ファイルが既に存在する場合はファイルを削除する。
                if (importFile.exists()) {
                    if (!importFile.delete()) {
                        // ファイルの削除に失敗した場合は異常終了する
                        throw new BulkLoaderSystemException(getClass(), "TG-IMPORTER-03001",
                                importFile.getName());
                    }
                }

                // ロック取得有無に応じてレコードを抽出し、ファイルを生成する
                if (ImportTableLockType.TABLE.equals(lockType)) {
                    // ロック取得有無が「テーブルロック」の場合、検索条件でレコードを抽出する
                    createFileWithCondition(
                            conn,
                            tableName,
                            targetTable,
                            importFile);
                } else if (ImportTableLockType.RECORD.equals(lockType)) {
                    // ロック取得有無が「行ロック」の場合、ジョブフローIDを条件にレコードを抽出する
                    createFileWithJobFlowSid(
                            conn,
                            tableName,
                            targetTable,
                            jobflowSid,
                            importFile);
                } else if (ImportTableLockType.NONE.equals(lockType)) {
                    // ロック取得有無が「ロックを取得しない」の場合、検索条件でレコードを抽出する
                    createFileWithCondition(
                            conn,
                            tableName,
                            targetTable,
                            importFile);
                }
                // ファイルが生成出来なかった場合は0byteのファイルを作成する。
                if (!importFile.exists()) {
                    try {
                        if (!importFile.createNewFile()) {
                            throw new BulkLoaderSystemException(getClass(), "TG-IMPORTER-03002");
                        }
                        LOG.info("TG-IMPORTER-03005",
                                tableName,
                                lockType,
                                importFile.getAbsolutePath());
                    } catch (IOException e) {
                        throw new BulkLoaderSystemException(getClass(), "TG-IMPORTER-03002");
                    }
                } else {
                    LOG.info("TG-IMPORTER-03004",
                            tableName,
                            lockType,
                            importFile.getAbsolutePath());
                }

                // 生成したファイル名を追加
                targetTable.setImportFile(importFile);
            }

            // 正常終了
            return true;

        } catch (BulkLoaderSystemException e) {
            LOG.log(e);
            return false;
        } finally {
            DBConnection.closeConn(conn);
        }
    }

    /**
     * ジョブフローSIDを条件にレコードを抽出してファイルを生成する。
     * @param conn コネクション
     * @param tableName target table name
     * @param tableInfo target table information
     * @param jobflowSid ジョブフローID
     * @param importFileName importファイル
     * @throws BulkLoaderSystemException 処理に失敗した場合
     */
    private void createFileWithJobFlowSid(
            Connection conn,
            String tableName,
            ImportTargetTableBean tableInfo,
            String jobflowSid,
            File importFileName) throws BulkLoaderSystemException {
        String sql = createSQLWithJobFlowSid(tableName, tableInfo, importFileName);
        PreparedStatement stmt = null;

        String[] parameters = EMPTY;
        LOG.info("TG-IMPORTER-03006", sql, jobflowSid);
        try {
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, jobflowSid);
            if (tableInfo.getStartTimestamp() != null) {
                Calendar beginning = tableInfo.getStartTimestamp();
                Timestamp timestamp = new Timestamp(beginning.getTimeInMillis());
                LOG.info("TG-IMPORTER-13001", tableName, tableInfo.getCacheId(), timestamp);
                stmt.setTimestamp(2, timestamp, beginning);
                parameters = new String[] { jobflowSid, String.valueOf(timestamp) };
            } else {
                parameters = new String[] { jobflowSid };
            }
            DBConnection.executeQuery(stmt, sql, parameters);
        } catch (SQLException e) {
            throw BulkLoaderSystemException.createInstanceCauseBySQLException(e, getClass(), sql, parameters);
        } finally {
            DBConnection.closePs(stmt);
        }
    }
    /**
     * ジョブフローIDを条件にレコードを抽出する場合のSQLを組み立てる。
     * @param tableName target table name
     * @param tableInfo target table information
     * @param importFileName importファイル
     * @return 生成したSQL文
     * @throws BulkLoaderSystemException if failed to build SQL
     */
    private String createSQLWithJobFlowSid(
            String tableName,
            ImportTargetTableBean tableInfo,
            File importFileName) throws BulkLoaderSystemException {
        String rlTableName = DBAccessUtil.createRecordLockTableName(tableName);

        String baseSearchCondition = MessageFormat.format(
                "WHERE EXISTS (SELECT SID FROM {1} WHERE {1}.SID = {0}.{2} AND {1}.JOBFLOW_SID = ?)",
                tableName,
                rlTableName,
                Constants.getSidColumnName());
        String searchCondition = resolveSearchCondition(tableName, tableInfo, baseSearchCondition);

        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ");
        sql.append(DBAccessUtil.joinColumnArray(tableInfo.getImportTargetColumns()));
        sql.append(" FROM ");
        sql.append(tableName);
        sql.append(" ");
        sql.append(searchCondition);
        sql.append(" INTO OUTFILE ");
        sql.append("'");
        sql.append(importFileName.getAbsolutePath().replace(File.separatorChar, '/'));
        sql.append("'");
        sql.append(DBAccessUtil.getTSVFileFormat());

        return sql.toString();
    }
    /**
     * 検索条件でレコードを抽出してファイルを生成する。
     * @param conn コネクション
     * @param tableName target table name
     * @param tableInfo target table information
     * @param importFileName importファイル
     * @throws BulkLoaderSystemException SQL例外が発生した場合
     */
    private void createFileWithCondition(
            Connection conn,
            String tableName,
            ImportTargetTableBean tableInfo,
            File importFileName) throws BulkLoaderSystemException {
        String sql = createSQLWithCondition(tableName, tableInfo, importFileName);
        PreparedStatement stmt = null;

        LOG.info("TG-IMPORTER-03007", sql);
        String[] parameters = EMPTY;
        try {
            stmt = conn.prepareStatement(sql);
            if (tableInfo.getStartTimestamp() != null) {
                Calendar beginning = tableInfo.getStartTimestamp();
                Timestamp timestamp = new Timestamp(beginning.getTimeInMillis());
                LOG.info("TG-IMPORTER-13001", tableName, tableInfo.getCacheId(), timestamp);
                stmt.setTimestamp(1, timestamp, beginning);
                parameters = new String[] { String.valueOf(timestamp) };
            }
            DBConnection.executeQuery(stmt, sql, parameters);
        } catch (SQLException e) {
            throw BulkLoaderSystemException.createInstanceCauseBySQLException(e, getClass(), sql, parameters);
        } finally {
            DBConnection.closePs(stmt);
        }
    }
    /**
     * 検索条件でレコードを抽出する場合のSQLを組み立てる。
     * @param tableName target table name
     * @param tableInfo target table information
     * @param importFileName importファイル
     * @return 生成したSQL
     * @throws BulkLoaderSystemException if failed to build SQL
     */
    private String createSQLWithCondition(
            String tableName,
            ImportTargetTableBean tableInfo,
            File importFileName) throws BulkLoaderSystemException {
        StringBuilder sql = new StringBuilder();
        sql.append("SELECT ");
        sql.append(DBAccessUtil.joinColumnArray(tableInfo.getImportTargetColumns()));
        sql.append(" FROM ");
        sql.append(tableName);
        String searchCondition = resolveSearchCondition(tableName, tableInfo, tableInfo.getSearchCondition());
        if (searchCondition != null && !searchCondition.isEmpty()) {
            sql.append(" WHERE ");
            sql.append(searchCondition);
        }
        sql.append(" INTO OUTFILE ");
        sql.append("'");
        sql.append(importFileName.getAbsolutePath().replace(File.separatorChar, '/'));
        sql.append("'");
        sql.append(DBAccessUtil.getTSVFileFormat());

        return sql.toString();
    }

    /**
     * Creates condition expression for the target table.
     * If {@link ImportTargetTableBean#getStartTimestamp() cache is valid},
     * the search condition will include a placeholder ({@code ?}) in its tail.
     * @param tableName target table name (or alias name)
     * @param tableInfo target table information
     * @param expression the original condition expression (nullable)
     * @return the built string, or {@code null} if unconditioned
     * @throws BulkLoaderSystemException if failed to resolve search condition
     */
    private String resolveSearchCondition(
            String tableName,
            ImportTargetTableBean tableInfo,
            String expression) throws BulkLoaderSystemException {
        assert tableName != null;
        assert tableInfo != null;
        String original = expression;
        if (original == null || original.trim().isEmpty()) {
            original = null;
        }
        if (tableInfo.getStartTimestamp() == null) {
            return original;
        } else {
            ThunderGateCacheSupport support;
            try {
                support = tableInfo
                    .getImportTargetType()
                    .asSubclass(ThunderGateCacheSupport.class)
                    .newInstance();
            } catch (Exception e) {
                throw new BulkLoaderSystemException(e, getClass(), "TG-IMPORTER-13002",
                        tableName,
                        tableInfo.getCacheId(),
                        tableInfo.getImportTargetType().getName());
            }
            String timestampColumn = support.__tgc__TimestampColumn();
            if (original == null) {
                return MessageFormat.format(
                        "{0}.{1} >= ?",
                        tableName,
                        timestampColumn);
            } else {
                return MessageFormat.format(
                        "({0}) AND {1}.{2} >= ?",
                        original,
                        tableName,
                        timestampColumn);
            }
        }
    }
}
TOP

Related Classes of com.asakusafw.bulkloader.importer.ImportFileCreate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.