
nablarch.common.code.BasicCodeLoader Maven / Gradle / Ivy
The newest version!
package nablarch.common.code;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import nablarch.common.code.schema.CodeNameSchema;
import nablarch.common.code.schema.CodePatternSchema;
import nablarch.core.cache.StaticDataLoader;
import nablarch.core.db.connection.AppDbConnection;
import nablarch.core.db.statement.SqlPStatement;
import nablarch.core.db.statement.SqlResultSet;
import nablarch.core.db.statement.SqlRow;
import nablarch.core.db.transaction.SimpleDbTransactionExecutor;
import nablarch.core.db.transaction.SimpleDbTransactionManager;
import nablarch.core.repository.initialization.Initializable;
import nablarch.core.util.I18NUtil;
import nablarch.core.util.map.CaseInsensitiveMap;
/**
* データベースからコードをロードするクラス。
*
* @author Koichi Asano
*/
public class BasicCodeLoader implements StaticDataLoader, Initializable {
/** 使用するテーブル名/カラム名 */
private Map dbSchema = new HashMap();
/** パターンカラム名 */
private String[] patternColumnNames;
/** オプション名称のカラム名 */
private String[] optionNameColumnNames;
/** データベーストランザクションマネージャ */
private SimpleDbTransactionManager dbManager;
/**
* 全てのコードをロードするSQL文。
*/
private String selectAllStatement;
/**
* 1つのコードをロードするSQL文。
*/
private String selectOneCodeStatement;
/**
* コード名称テーブルのスキーマ情報を設定する。
*
* @param codeNameSchema コード名称テーブルのスキーマ情報
*/
public void setCodeNameSchema(CodeNameSchema codeNameSchema) {
dbSchema.put("codeName", codeNameSchema.getTableName());
dbSchema.put("codeNameId", codeNameSchema.getIdColumnName());
dbSchema.put("codeNameValue", codeNameSchema.getValueColumnName());
dbSchema.put("codeNameLang", codeNameSchema.getLangColumnName());
dbSchema.put("codeNameSortOrder", codeNameSchema.getSortOrderColumnName());
dbSchema.put("codeNameName", codeNameSchema.getNameColumnName());
dbSchema.put("codeNameShortName", codeNameSchema.getShortNameColumnName());
optionNameColumnNames = codeNameSchema.getOptionNameColumnNames();
}
/**
* コードパターンテーブルのスキーマ情報を設定する。
*
* @param codePatternSchema コードパターンテーブルのスキーマ情報
*/
public void setCodePatternSchema(CodePatternSchema codePatternSchema) {
dbSchema.put("codePattern", codePatternSchema.getTableName());
dbSchema.put("codePatternId", codePatternSchema.getIdColumnName());
dbSchema.put("codePatternValue", codePatternSchema.getValueColumnName());
patternColumnNames = codePatternSchema.getPatternColumnNames();
}
/**
* データベーストランザクションマネージャを設定する。
*
* @param dbManager データベーストランザクションマネージャ
*/
public void setDbManager(SimpleDbTransactionManager dbManager) {
this.dbManager = dbManager;
}
/**
* {@inheritDoc}
*
*
* 本機能ではインデックスは提供しないためnullを返す。
*/
public Object generateIndexKey(String indexName, Code value) {
return null;
}
/**
* {@inheritDoc}
*/
public Object getId(Code value) {
return value.getCodeId();
}
/**
* {@inheritDoc}
*
*
* 本機能ではインデックスは提供しないためnullを返す。
*/
public List getIndexNames() {
return null;
}
/**
* {@inheritDoc}
*/
public Code getValue(final Object id) {
SqlResultSet resultSet = new SimpleDbTransactionExecutor(
dbManager) {
@Override
public SqlResultSet execute(AppDbConnection connection) {
SqlPStatement statement = connection.prepareStatement(
selectOneCodeStatement);
statement.setString(1, id.toString());
return statement.retrieve();
}
}.doTransaction();
List createdCodes = createResult(resultSet);
if (createdCodes.size() == 1) {
return createdCodes.get(0);
} else {
return null;
}
}
/**
* {@inheritDoc}
*
*
* 本機能ではインデックスは提供しないためnullを返す。
*/
public List getValues(String indexName, Object key) {
return null;
}
/**
* {@inheritDoc}
*/
public List loadAll() {
SqlResultSet resultSet = new SimpleDbTransactionExecutor(
dbManager) {
@Override
public SqlResultSet execute(AppDbConnection connection) {
SqlPStatement statement = connection.prepareStatement(
selectAllStatement);
SqlResultSet results = statement.retrieve();
return results;
}
}.doTransaction();
return createResult(resultSet);
}
/**
* データベースの検索結果からBasicCodeのListを作成する。
*
* @param queryResults データベースの検索結果
* @return BasicCodeのList
*/
private List createResult(SqlResultSet queryResults) {
List basicCodeList = new ArrayList();
String codeId = "";
List data = new ArrayList();
for (SqlRow row : queryResults) {
String currentCodeId = row.getString(dbSchema.get("codeNameId"));
if (!codeId.equals(currentCodeId)) {
if (data.size() > 0) {
basicCodeList.add(new BasicCode(codeId, data));
data.clear();
}
codeId = currentCodeId;
}
data.add(row);
}
if (data.size() > 0) {
basicCodeList.add(new BasicCode(codeId, data));
}
return Collections.unmodifiableList(basicCodeList);
}
/**
* SQL文を初期化する。
*/
private void initializeStatements() {
StringBuilder codePatternColumns = new StringBuilder();
for (String patternColumnName : patternColumnNames) {
codePatternColumns.append("$codePattern$.");
codePatternColumns.append(patternColumnName);
codePatternColumns.append(", ");
}
StringBuilder optionNameColumns = new StringBuilder();
for (String optionNameColumn : optionNameColumnNames) {
codePatternColumns.append("$codeName$.");
codePatternColumns.append(optionNameColumn);
codePatternColumns.append(", ");
}
String preSelectStatement =
"SELECT "
+ codePatternColumns
+ optionNameColumns
+ "$codeName$.$codeNameId$, "
+ "$codeName$.$codeNameValue$, "
+ "$codeName$.$codeNameLang$, "
+ "$codeName$.$codeNameName$, "
+ "$codeName$.$codeNameShortName$ "
+ "FROM $codePattern$ "
+ "INNER JOIN $codeName$ "
+ "ON $codePattern$.$codePatternId$ = $codeName$.$codeNameId$ "
+ "AND $codePattern$.$codePatternValue$ = $codeName$.$codeNameValue$ ";
String preWhereStatement =
"WHERE "
+ "$codePattern$.$codePatternId$ = ? ";
String preOrderByStatement =
"ORDER BY "
+ "$codeName$.$codeNameId$, "
+ "$codeName$.$codeNameLang$, "
+ "$codeName$.$codeNameSortOrder$ ";
String selectStatement = replaceStatement(preSelectStatement);
String whereStatement = replaceStatement(preWhereStatement);
String orderByStatement = replaceStatement(preOrderByStatement);
selectAllStatement = selectStatement + orderByStatement;
selectOneCodeStatement = selectStatement + whereStatement + orderByStatement;
}
/**
* {@inheritDoc}
*/
public void initialize() {
initializeStatements();
}
/**
* SQL文の置き換え文字の置き換えを行う。
*
* @param statement 置き換え対象の文字
* @return 置き換え文字を置き換えた文字列。
*/
private String replaceStatement(String statement) {
Matcher m = Pattern.compile("\\$([_0-9a-zA-Z]+)\\$").matcher(statement);
StringBuffer sb = new StringBuffer();
while (m.find()) {
String replacement = m.group(1);
m.appendReplacement(sb, dbSchema.get(replacement));
}
m.appendTail(sb);
String createdSelectStatement = sb.toString();
return createdSelectStatement;
}
/**
* ロードするコードの実装。
*
*/
private final class BasicCode implements Code {
/**
* コンストラクタ。
*
*
* @param codeId コードID
* @param data コードを構成するデータのList。
* データは言語を第1の条件としてソートされている必要がある。
*/
private BasicCode(String codeId, List data) {
this.codeId = codeId;
parLangValuesMap = new HashMap();
List langData = new ArrayList();
String lang = "";
for (SqlRow row : data) {
String currentLang = row.getString(dbSchema.get("codeNameLang"));
if (!lang.equals(currentLang)) {
if (langData.size() > 0) {
PerLangValues value = new PerLangValues(langData);
parLangValuesMap.put(I18NUtil.createLocale(lang), value);
langData.clear();
}
lang = currentLang;
}
langData.add(row);
}
PerLangValues value = new PerLangValues(langData);
parLangValuesMap.put(I18NUtil.createLocale(lang), value);
// containsの情報は、全言語文取得
values = new HashSet();
patternValuesMap = new CaseInsensitiveMap>();
for (PerLangValues parLangValues : parLangValuesMap.values()) {
values.addAll(parLangValues.values);
for (String pattern : patternColumnNames) {
pattern = pattern.toLowerCase();
if (!patternValuesMap.containsKey(pattern)) {
patternValuesMap.put(pattern, new HashSet());
}
patternValuesMap.get(pattern).addAll(parLangValues.patternMap.get(pattern));
}
}
}
/** コードID */
private final String codeId;
/** 言語と言語毎に持つ値のMap */
private final Map parLangValuesMap;
/** コードに含まれるコード値のセット */
private final Set values;
/** パターンに含まれる値のセット */
private final Map> patternValuesMap;
/**
* {@inheritDoc}
*/
public String getCodeId() {
return codeId;
}
/**
* {@inheritDoc}
*/
public boolean contains(String value) {
return values.contains(value);
}
/**
* {@inheritDoc}
*/
public boolean contains(String pattern, String value) {
Set patternValues = patternValuesMap.get(pattern);
if (patternValues == null) {
throw new IllegalArgumentException("pattern was not found. "
+ "code id = " + codeId
+ ", pattern = " + pattern);
}
return patternValues.contains(value);
}
/**
* {@inheritDoc}
*/
public String getName(String value, Locale locale) {
PerLangValues perLangValues = parLangValuesMap.get(locale);
if (perLangValues == null) {
throw new IllegalArgumentException("locale was not found. "
+ "code id = " + codeId
+ ", locale = " + locale);
}
String name = perLangValues.names.get(value);
if (name == null) {
throw new IllegalArgumentException("name was not found. "
+ "code id = " + codeId
+ ", locale = " + locale
+ ", value = " + value);
}
return name;
}
/**
* {@inheritDoc}
*/
public String getShortName(String value, Locale locale) {
PerLangValues parLangValues = parLangValuesMap.get(locale);
if (parLangValues == null) {
throw new IllegalArgumentException("locale was not found. "
+ "code id = " + codeId
+ ", locale = " + locale);
}
String shortName = parLangValues.shortNames.get(value);
if (shortName == null) {
throw new IllegalArgumentException("short name was not found. "
+ "code id = " + codeId
+ ", locale = " + locale
+ ", value = " + value);
}
return shortName;
}
/**
* {@inheritDoc}
*/
public String getOptionalName(String value, String optionColumnName,
Locale locale) {
PerLangValues parLangValues = parLangValuesMap.get(locale);
if (parLangValues == null) {
throw new IllegalArgumentException("locale was not found. "
+ "code id = " + codeId
+ ", locale = " + locale);
}
Map valueMap = parLangValues.optionNamesMap.get(optionColumnName);
if (valueMap == null) {
throw new IllegalArgumentException("option name was not found. "
+ "code id = " + codeId
+ ", locale = " + locale
+ ", value = " + value);
}
String optionName = valueMap.get(value);
if (optionName == null) {
throw new IllegalArgumentException("option name was not found. "
+ "code id = " + codeId
+ ", locale = " + locale
+ ", value = " + value
+ ", option name = " + optionColumnName);
}
return optionName;
}
/**
* {@inheritDoc}
*/
public List getValues(Locale locale) {
PerLangValues parLangValues = parLangValuesMap.get(locale);
if (parLangValues == null) {
throw new IllegalArgumentException("locale was not found. "
+ "code id = " + codeId
+ ", locale = " + locale);
}
return parLangValues.values;
}
/**
* {@inheritDoc}
*/
public List getValues(String pattern, Locale locale) {
PerLangValues parLangValues = parLangValuesMap.get(locale);
if (parLangValues == null) {
throw new IllegalArgumentException("locale was not found. "
+ "code id = " + codeId
+ ", locale = " + locale);
}
List values = parLangValues.patternMap.get(pattern);
if (values == null) {
throw new IllegalArgumentException("pattern was not found. "
+ "code id = " + codeId
+ ", locale = " + locale
+ ", pattern = " + pattern);
}
return values;
}
}
/**
* 言語毎に持つ値を保持するクラス。
*/
private final class PerLangValues {
/**
* 全てのコード値のList。
*/
private final List values;
/**
* パターン毎のコード値のListを保持するMap。
*/
private final Map> patternMap;
/**
* 名称を保持するMap。
*
* key:コード値
* value:コード名称
*
*/
private final Map names;
/**
* 略称を保持するMap。
*
* key:コード値
* value:コードの略称
*
*/
private final Map shortNames;
/**
* コードのオプション名称を保持するMap。
*
* key:コード値
* value:コードのオプション名称
*
*/
private final Map> optionNamesMap;
/**
* コンストラクタ。
*
* @param data コードを構成するデータのList。
* データはソート順を第1の条件としてソートされている必要がある。
*/
private PerLangValues(List data) {
List tmpValues = new ArrayList();
Map tmpNames = new HashMap();
Map tmpShortNames = new HashMap();
Map> tmpOptionNamesMap = new CaseInsensitiveMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy