/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * 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 org.seasar.extension.jdbc.gen.internal.data; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.seasar.extension.jdbc.gen.desc.ColumnDesc; import org.seasar.extension.jdbc.gen.desc.TableDesc; import org.seasar.extension.jdbc.gen.dialect.GenDialect; import org.seasar.extension.jdbc.gen.internal.util.CloseableUtil; import org.seasar.extension.jdbc.gen.internal.util.DumpUtil; import org.seasar.extension.jdbc.gen.sqltype.SqlType; import org.seasar.framework.exception.IORuntimeException; import org.seasar.framework.log.Logger; import org.seasar.framework.util.CaseInsensitiveMap; import org.seasar.framework.util.FileOutputStreamUtil; /** * ダンプファイルのライタです。 * * @author taedium */ public class DumpFileWriter { /** ロガー */ protected static Logger logger = Logger.getLogger(DumpFileWriter.class); /** ダンプファイル */ protected File dumpFile; /** 方言 */ protected GenDialect dialect; /** テーブル記述 */ protected TableDesc tableDesc; /** エンコーディング */ protected String encoding; /** カラム名をキー、カラム記述を値とするマップ */ @SuppressWarnings("unchecked") protected Map<String, ColumnDesc> columnDescMap = new CaseInsensitiveMap(); /** 区切り文字 */ protected char delimiter; /** ライタ */ protected BufferedWriter writer; /** 行番号 */ protected int lineNumber; /** * インスタンスを構築します。 * * @param dumpFile * ダンプファイル * @param tableDesc * テーブル記述 * @param dialect * 方言 * @param encoding * エンコーディング * @param delimiter * 区切り文字 */ public DumpFileWriter(File dumpFile, TableDesc tableDesc, GenDialect dialect, String encoding, char delimiter) { if (dumpFile == null) { throw new NullPointerException("dumpFile"); } if (tableDesc == null) { throw new NullPointerException("tableDesc"); } if (dialect == null) { throw new NullPointerException("dialect"); } if (encoding == null) { throw new NullPointerException("encoding"); } this.dumpFile = dumpFile; this.dialect = dialect; this.tableDesc = tableDesc; this.encoding = encoding; this.delimiter = delimiter; setupColumnDescMap(); } /** * カラム記述のマップを用意します。 */ protected void setupColumnDescMap() { for (ColumnDesc columnDesc : tableDesc.getColumnDescList()) { if (isIgnoreColumn(columnDesc)) { continue; } columnDescMap.put(columnDesc.getName(), columnDesc); } } /** * ヘッダーのみを書き込みます。 */ public void writeHeaderOnly() { int size = tableDesc.getColumnDescList().size(); StringBuilder buf = new StringBuilder(size * 10); for (ColumnDesc columnDesc : tableDesc.getColumnDescList()) { if (isIgnoreColumn(columnDesc)) { continue; } String columnName = columnDesc.getName(); buf.append(DumpUtil.quote(columnName)); buf.append(delimiter); } if (buf.length() > 0) { buf.setLength(buf.length() - 1); } writeLine(buf.toString()); } /** * 無視するカラムの場合{@code true}を返します。 * * @param columnDesc * カラム記述 * @return 無視するカラムの場合{@code true} */ protected boolean isIgnoreColumn(ColumnDesc columnDesc) { return columnDesc.isIdentity() && !dialect.supportsIdentityInsert(); } /** * ヘッダーとデータ行を書き込みます。 * * @param rs * 結果セット * @throws SQLException * SQL例外が発生した場合 */ public void writeRows(ResultSet rs) throws SQLException { ResultSetMetaData metaData = rs.getMetaData(); Header header = createHeader(metaData); writeHeader(header); while (rs.next()) { writeRowData(rs, header); } } /** * ヘッダーを書き込みます。 * * @param header * ヘッダー */ protected void writeHeader(Header header) { StringBuilder buf = new StringBuilder(header.columnList.size() * 10); for (HeaderColumn headerColumn : header.columnList) { String columnName = headerColumn.columnDesc.getName(); buf.append(DumpUtil.quote(columnName)); buf.append(delimiter); } if (buf.length() > 0) { buf.setLength(buf.length() - 1); } writeLine(buf.toString()); } /** * データ行を書き込みます。 * * @param resultSet * 結果セット * @param header * ヘッダー * @throws SQLException * SQL例外が発生した場合 */ protected void writeRowData(ResultSet resultSet, Header header) throws SQLException { StringBuilder buf = new StringBuilder(header.columnList.size() * 10); for (HeaderColumn headerColumn : header.columnList) { String value = null; if (headerColumn.present) { SqlType sqlType = headerColumn.columnDesc.getSqlType(); value = sqlType.getValue(resultSet, headerColumn.index); } buf.append(DumpUtil.encode(value)); buf.append(delimiter); } if (buf.length() > 0) { buf.setLength(buf.length() - 1); } writeLine(buf.toString()); } /** * 行を書き込みます。 * * @param line * 行 */ protected void writeLine(String line) { if (writer == null) { writer = createBufferdWriter(); } try { writer.write(line); writer.newLine(); } catch (IOException e) { throw new IORuntimeException(e); } lineNumber++; } /** * {@link BufferedWriter}を作成します。 * * @return {@link BufferedWriter} */ protected BufferedWriter createBufferdWriter() { dumpFile.getParentFile().mkdirs(); Charset charset = Charset.forName(encoding); FileOutputStream fos = FileOutputStreamUtil.create(dumpFile); OutputStreamWriter osw = new OutputStreamWriter(fos, charset); return new BufferedWriter(osw); } /** * クローズします。 */ public void close() { CloseableUtil.close(writer); } /** * 行番号を返します。 * * @return 行番号 */ public int getLineNumber() { return lineNumber; } /** * ヘッダーを作成します。 * * @param metaData * 結果セットのメタデータ * @return ヘッダー * @throws SQLException * SQL例外が発生した場合 */ protected Header createHeader(ResultSetMetaData metaData) throws SQLException { Header header = new Header(); @SuppressWarnings("unchecked") Map<String, Integer> indexMap = new CaseInsensitiveMap(); for (int i = 0; i < metaData.getColumnCount(); i++) { int index = i + 1; String columnLabel = metaData.getColumnLabel(index); indexMap.put(columnLabel, index); } for (Map.Entry<String, ColumnDesc> entry : columnDescMap.entrySet()) { String columnLabel = entry.getKey(); if (indexMap.containsKey(columnLabel)) { int index = indexMap.get(columnLabel); HeaderColumn headerColumn = new HeaderColumn(); headerColumn.columnDesc = entry.getValue(); headerColumn.index = index; headerColumn.present = true; header.columnList.add(headerColumn); } else { HeaderColumn headerColumn = new HeaderColumn(); headerColumn.columnDesc = entry.getValue(); header.columnList.add(headerColumn); } } return header; } /** * ダンプファイルのヘッダーです。 * * @author taedium */ protected static class Header { /** ダンプファイルのヘッダーカラムのリスト */ protected List<HeaderColumn> columnList = new ArrayList<HeaderColumn>(); } /** * ダンプファイルのヘッダーのカラムです。 * * @author taedium */ protected static class HeaderColumn { /** カラム記述 */ protected ColumnDesc columnDesc; /** 対応するカラムがデータベースに存在する場合{@code true} */ protected boolean present; /** データベースのカラムのインデックス */ protected int index; } }