/*
* 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.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.seasar.extension.jdbc.gen.internal.data.DumpFileTokenizer.TokenType;
import org.seasar.extension.jdbc.gen.internal.exception.IllegalDumpColumnSizeRuntimeException;
import org.seasar.extension.jdbc.gen.internal.util.CloseableUtil;
import org.seasar.extension.jdbc.gen.internal.util.DumpUtil;
import org.seasar.framework.exception.IORuntimeException;
import org.seasar.framework.util.StringUtil;
/**
* ダンプファイルのリーダです。
*
* @author taedium
*/
public class DumpFileReader {
/** バッファのサイズ */
protected static final int BUF_SIZE = 8192;
/** ダンプファイル */
protected File dumpFile;
/** ダンプファイルのエンコーディング */
protected String dumpFileEncoding;
/** トークナイザ */
protected DumpFileTokenizer tokenizer;
/** リーダ */
protected BufferedReader reader;
/** バッファ */
protected char[] buf = new char[BUF_SIZE];
/** トークンタイプ */
protected TokenType tokenType = TokenType.END_OF_BUFFER;
/** 行番号 */
protected int lineNumber;
/** ヘッダーの列数 */
protected int headerColumnSize;
/** ファイルの終端の場合{@code true} */
protected boolean endOfFile;
/**
* インスタンスを構築します。
*
* @param dumpFile
* ダンプファイル
* @param dumpFileEncoding
* ダンプファイルのエンコーディング
* @param tokenizer
* トークナイザ
*/
public DumpFileReader(File dumpFile, String dumpFileEncoding,
DumpFileTokenizer tokenizer) {
if (dumpFile == null) {
throw new NullPointerException("dumpFile");
}
if (dumpFileEncoding == null) {
throw new NullPointerException("dumpFileEncoding");
}
if (tokenizer == null) {
throw new NullPointerException("tokenizer");
}
this.dumpFile = dumpFile;
this.dumpFileEncoding = dumpFileEncoding;
this.tokenizer = tokenizer;
}
/**
* 一行を読みます。
*
* @return ファイルの終端に達していなければ一行を表すリスト、ファイルの終端に達していれば{@code null}
*/
public List<String> readLine() {
if (endOfFile) {
return null;
}
try {
lineNumber++;
List<String> valueList = readLineInternal();
if (valueList == null) {
lineNumber--;
return null;
}
if (lineNumber == 1) {
headerColumnSize = valueList.size();
} else {
if (headerColumnSize != valueList.size()) {
throw new IllegalDumpColumnSizeRuntimeException(dumpFile
.getPath(), lineNumber, valueList.size(),
headerColumnSize);
}
}
return valueList;
} catch (IOException e) {
throw new IORuntimeException(e);
}
}
/**
* 内部的に一行を読みます。
*
* @return ファイルの終端に達していなければ一行を表すリスト、ファイルの終端に達していれば{@code null}
* @throws IOException
* 何らかのIO例外が発生した場合
*/
protected List<String> readLineInternal() throws IOException {
if (reader == null) {
reader = createBufferedReader();
}
Line line = new Line();
readLoop: for (;;) {
if (tokenType == TokenType.END_OF_BUFFER) {
int length = reader.read(buf);
tokenizer.addChars(buf, length);
}
for (;;) {
tokenType = tokenizer.nextToken();
String token = tokenizer.getToken();
switch (tokenType) {
case VALUE:
case NULL:
line.add(token);
break;
case END_OF_BUFFER:
continue readLoop;
case END_OF_LINE:
return line.toList();
case END_OF_FILE:
endOfFile = true;
if (!StringUtil.isEmpty(token)) {
line.add(token);
}
return line.toList();
default:
break;
}
}
}
}
/**
* {@link BufferedReader}を作成します。
*
* @return {@link BufferedReader}
* @throws IOException
* 何らかのIO例外が発生した場合
*/
protected BufferedReader createBufferedReader() throws IOException {
InputStream is = new FileInputStream(dumpFile);
return new BufferedReader(new InputStreamReader(is, dumpFileEncoding));
}
/**
* 読み込んだ行番号を返します。
* <p>
* 行番号は1から始まります。
* </p>
*
* @return 行番号
*/
public int getLineNumber() {
return lineNumber;
}
/**
* クローズします。
*/
public void close() {
CloseableUtil.close(reader);
}
/**
* 行を表すクラスです。
*
* @author taedium
*/
protected class Line {
/** 値のリスト */
protected List<String> valueList = new ArrayList<String>(30);
/**
* 値のリストを返します。
*
* @return 値のリスト
*/
public List<String> toList() {
return !valueList.isEmpty() ? valueList : null;
}
/**
* 値を追加します。
*
* @param value
* 値
*/
public void add(String value) {
valueList.add(DumpUtil.decode(value));
}
}
}