/*
* Copyright (c) 2011 NTT DATA Corporation
*
* 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 jp.terasoluna.fw.batch.util;
import java.lang.reflect.Array;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import jp.terasoluna.fw.batch.constants.LogId;
import jp.terasoluna.fw.batch.exception.IllegalClassTypeException;
import jp.terasoluna.fw.logger.TLogger;
import jp.terasoluna.fw.util.PropertyUtil;
import org.apache.commons.logging.Log;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* バッチ実装用ユーティリティ。<br>
* <br>
* 各種バッチ実装にて使用するユーティリティメソッドを定義する。
*/
public class BatchUtil {
/** ロガー. */
private static final TLogger LOGGER = TLogger.getLogger(BatchUtil.class);
/**
* コンストラクタ
*/
protected BatchUtil() {
}
/**
* 汎用文字列結合メソッド。
* @param args 任意の値
* @return 引数を結合した文字列
*/
public static String cat(Object... args) {
StringBuilder str = new StringBuilder();
if (args == null) {
return null;
}
for (Object o : args) {
if (o != null) {
str.append(o);
}
}
return str.toString();
}
/**
* インフォログの開始メッセージを取得する。
* @param jobCd ジョブ業務コード
* @return String メッセージ
*/
public static String getInfoLogStartMsg(String jobCd) {
return BatchUtil.cat("[", jobCd, "] ", "処理開始");
}
/**
* インフォログの終了メッセージを取得する。
* @param jobCd ジョブ業務コード
* @return String メッセージ
*/
public static String getInfoLogEndMsg(String jobCd) {
return BatchUtil.cat("[", jobCd, "] ", "処理終了");
}
/**
* デフォルトのTransactionDefinitionを取得する
* @return トランザクション定義オブジェクト
*/
public static TransactionDefinition getTransactionDefinition() {
return new DefaultTransactionDefinition();
}
/**
* デフォルトのTransactionDefinitionを取得する
* @param propagationBehavior トランザクション伝搬モード(@see TransactionDefinition) デフォルト:TransactionDefinition.PROPAGATION_REQUIRED
* @param isolationLevel トランザクション分離レベル(@see TransactionDefinition) デフォルト:TransactionDefinition.ISOLATION_DEFAULT
* @param timeout トランザクションタイムアウト(秒) デフォルト:TransactionDefinition.TIMEOUT_DEFAULT (タイムアウトなし)
* @param readOnly リードオンリートランザクション デフォルト:false
* @return トランザクション定義オブジェクト
*/
public static TransactionDefinition getTransactionDefinition(
int propagationBehavior, int isolationLevel, int timeout,
boolean readOnly) {
DefaultTransactionDefinition td = new DefaultTransactionDefinition();
td.setPropagationBehavior(propagationBehavior);
td.setIsolationLevel(isolationLevel);
td.setTimeout(timeout);
td.setReadOnly(readOnly);
return td;
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran) {
return startTransaction(tran, getTransactionDefinition(), null);
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @param log Log
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran, Log log) {
return startTransaction(tran, getTransactionDefinition(), log);
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @param propagationBehavior トランザクション伝搬モード(@see TransactionDefinition) デフォルト:TransactionDefinition.PROPAGATION_REQUIRED
* @param isolationLevel トランザクション分離レベル(@see TransactionDefinition) デフォルト:TransactionDefinition.ISOLATION_DEFAULT
* @param timeout トランザクションタイムアウト(秒) デフォルト:TransactionDefinition.TIMEOUT_DEFAULT (タイムアウトなし)
* @param readOnly リードオンリートランザクション デフォルト:false
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran, int propagationBehavior,
int isolationLevel, int timeout, boolean readOnly) {
return startTransaction(tran, getTransactionDefinition(
propagationBehavior, isolationLevel, timeout, readOnly), null);
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @param propagationBehavior トランザクション伝搬モード(@see TransactionDefinition) デフォルト:TransactionDefinition.PROPAGATION_REQUIRED
* @param isolationLevel トランザクション分離レベル(@see TransactionDefinition) デフォルト:TransactionDefinition.ISOLATION_DEFAULT
* @param timeout トランザクションタイムアウト(秒) デフォルト:TransactionDefinition.TIMEOUT_DEFAULT (タイムアウトなし)
* @param readOnly リードオンリートランザクション デフォルト:false
* @param log Log
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran, int propagationBehavior,
int isolationLevel, int timeout, boolean readOnly, Log log) {
return startTransaction(tran, getTransactionDefinition(
propagationBehavior, isolationLevel, timeout, readOnly), log);
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @param def TransactionDefinition
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran, TransactionDefinition def) {
return startTransaction(tran, def, null);
}
/**
* トランザクションを開始させる
* @param tran PlatformTransactionManager
* @param def TransactionDefinition
* @param log Log
* @return TransactionStatus
*/
public static TransactionStatus startTransaction(
PlatformTransactionManager tran, TransactionDefinition def, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025033, tran);
if (def != null) {
logDebug(log, LogId.DAL025034, def.getPropagationBehavior(), def
.getIsolationLevel(), def.getTimeout(), def
.isReadOnly(), def.getName());
}
}
TransactionStatus stat = null;
if (tran != null) {
stat = tran.getTransaction(def);
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025035, stat);
}
return stat;
}
/**
* トランザクションを開始させる
* @param tranDef TransactionDefinition
* @param tranMap PlatformTransactionManagerマップ
* @return TransactionStatusマップ
*/
public static Map<String, TransactionStatus> startTransactions(
TransactionDefinition tranDef, Map<?, ?> tranMap) {
return startTransactions(tranDef, tranMap, null);
}
/**
* トランザクションを開始させる
* @param tranDef TransactionDefinition
* @param tranMap PlatformTransactionManagerマップ
* @param log Log
* @return TransactionStatusマップ
*/
public static Map<String, TransactionStatus> startTransactions(
TransactionDefinition tranDef, Map<?, ?> tranMap, Log log) {
Map<String, TransactionStatus> statMap = new LinkedHashMap<String, TransactionStatus>();
if (!tranMap.isEmpty()) {
for (Map.Entry<?, ?> ent : tranMap.entrySet()) {
String key = null;
PlatformTransactionManager ptm = null;
// キー取り出し
if (ent.getKey() instanceof String) {
key = (String) ent.getKey();
}
// トランザクションマネージャ取り出し
if (ent.getValue() instanceof PlatformTransactionManager) {
ptm = (PlatformTransactionManager) ent.getValue();
}
if (ptm != null) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025033, key);
if (tranDef != null) {
logDebug(log, LogId.DAL025034, tranDef
.getPropagationBehavior(), tranDef
.getIsolationLevel(), tranDef
.getTimeout(), tranDef
.isReadOnly(),
tranDef.getName());
}
}
// トランザクション開始
TransactionStatus trnStat = null;
try {
trnStat = ptm.getTransaction(tranDef);
} catch (TransactionException e) {
if (log != null && log.isErrorEnabled()) {
logError(log, LogId.EAL025048, e, key);
}
endTransactions(tranMap, statMap, log);
throw e;
}
// トランザクションステータスを格納
if (statMap != null) {
statMap.put(key, trnStat);
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025035, key, trnStat);
}
}
}
}
return statMap;
}
/**
* トランザクションをコミットさせる コネクションのコミットを行う
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
*/
public static void commitTransaction(PlatformTransactionManager tran,
TransactionStatus stat) {
commitTransaction(tran, stat, null);
}
/**
* トランザクションをコミットさせる コネクションのコミットを行う
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param log Log
*/
public static void commitTransaction(PlatformTransactionManager tran,
TransactionStatus stat, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025037, stat);
}
if (tran != null && stat != null) {
tran.commit(stat);
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025038, stat);
}
}
/**
* トランザクションをコミットさせる
* @param tranMap トランザクションマップ
* @param statMap トランザクション状態マップ
*/
public static void commitTransactions(Map<?, ?> tranMap,
Map<String, TransactionStatus> statMap) {
commitTransactions(tranMap, statMap, null);
}
/**
* トランザクションをコミットさせる
* @param tranMap トランザクションマップ
* @param statMap トランザクション状態マップ
* @param log ロガー
*/
public static void commitTransactions(Map<?, ?> tranMap,
Map<String, TransactionStatus> statMap, Log log) {
Set<Entry<String, TransactionStatus>> statSet = statMap.entrySet();
if (statSet.isEmpty()) {
return;
}
Stack<Entry<String, TransactionStatus>> stack = new Stack<Entry<String, TransactionStatus>>();
for (Entry<String, TransactionStatus> stat : statSet) {
stack.push(stat);
}
while (!stack.isEmpty()) {
// トランザクション開始の逆順ステータスでコミットを実施する。
Entry<String, TransactionStatus> statEntry = stack.pop();
String key = statEntry.getKey();
TransactionStatus trnStat = statEntry.getValue();
if (trnStat == null) {
continue;
}
// トランザクションマネージャ取り出し
Object ptmObj = tranMap.get(key);
if (ptmObj == null || !(ptmObj instanceof PlatformTransactionManager)) {
continue;
}
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmObj;
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025038, trnStat);
}
// コミット
ptm.commit(trnStat);
}
}
/**
* トランザクションを終了させる(未コミット時ロールバック)
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
*/
public static void endTransaction(PlatformTransactionManager tran,
TransactionStatus stat) {
endTransaction(tran, stat, null);
}
/**
* トランザクションを終了させる(未コミット時ロールバック)
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param log Log
*/
public static void endTransaction(PlatformTransactionManager tran,
TransactionStatus stat, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025040, stat);
}
if (tran != null && stat != null && !stat.isCompleted()) {
tran.rollback(stat);
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025041, stat);
}
}
/**
* トランザクションを終了させる(未コミット時ロールバック)
* @param tranMap PlatformTransactionManagerマップ
* @param statMap TransactionStatusマップ
* @return 引数で与えられたPlatformTransactionManagerが全て正常に終了できた場合にtrueを返却する
*/
public static boolean endTransactions(Map<?, ?> tranMap,
Map<String, TransactionStatus> statMap) {
return endTransactions(tranMap, statMap, null);
}
/**
* トランザクションを終了させる(未コミット時ロールバック)
* @param tranMap PlatformTransactionManagerマップ
* @param statMap TransactionStatusマップ
* @param log Log
* @return 引数で与えられたPlatformTransactionManagerが全て正常に終了できた場合にtrueを返却する
*/
public static boolean endTransactions(Map<?, ?> tranMap,
Map<String, TransactionStatus> statMap, Log log) {
boolean isNormal = true;
Set<Entry<String, TransactionStatus>> statSet = statMap.entrySet();
if (statSet == null || statSet.isEmpty()) {
return isNormal;
}
Stack<Entry<String, TransactionStatus>> stack = new Stack<Entry<String, TransactionStatus>>();
for (Entry<String, TransactionStatus> stat : statSet) {
stack.push(stat);
}
while (!stack.isEmpty()) {
// トランザクション開始の逆順でトランザクションを終了する。
Entry<String, TransactionStatus> statEntry = stack.pop();
String key = statEntry.getKey();
TransactionStatus trnStat = statEntry.getValue();
if (trnStat == null) {
continue;
}
// トランザクションマネージャ取り出し
Object ptmObj = tranMap.get(key);
if (ptmObj == null || !(ptmObj instanceof PlatformTransactionManager)) {
continue;
}
PlatformTransactionManager ptm = (PlatformTransactionManager) ptmObj;
// トランザクション終了(トランザクションが未完了の場合はロールバックする)
if (trnStat.isCompleted()) {
continue;
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025041, trnStat);
}
// ロールバック
try {
ptm.rollback(trnStat);
} catch (TransactionException e) {
if (log != null && log.isErrorEnabled()) {
logError(log, LogId.EAL025045, e, key);
}
isNormal = false;
// 例外が発生しても途中終了せず、他のトランザクション終了を試みる
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025041, trnStat);
}
}
return isNormal;
}
/**
* セーブポイントを設定する
* @param stat TransactionStatus
* @return Object セーブポイント
*/
public static Object setSavepoint(TransactionStatus stat) {
return setSavepoint(stat, null);
}
/**
* セーブポイントを設定する
* @param stat TransactionStatus
* @param log Log
* @return Object セーブポイント
*/
public static Object setSavepoint(TransactionStatus stat, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025046, stat);
}
Object savepoint = stat.createSavepoint();
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025047, stat);
}
return savepoint;
}
/**
* セーブポイントをリリースする
* @param stat TransactionStatus
* @param savepoint セーブポイント
*/
public static void releaseSavepoint(TransactionStatus stat, Object savepoint) {
releaseSavepoint(stat, savepoint, null);
}
/**
* セーブポイントをリリースする
* @param stat TransactionStatus
* @param savepoint セーブポイント
* @param log Log
*/
public static void releaseSavepoint(TransactionStatus stat,
Object savepoint, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025048, stat);
}
stat.releaseSavepoint(savepoint);
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025049, stat);
}
}
/**
* セーブポイントまでロールバックさせる
* @param stat TransactionStatus
* @param savepoint セーブポイント
*/
public static void rollbackSavepoint(TransactionStatus stat,
Object savepoint) {
rollbackSavepoint(stat, savepoint, null);
}
/**
* セーブポイントまでロールバックさせる
* @param stat TransactionStatus
* @param savepoint セーブポイント
* @param log Log
*/
public static void rollbackSavepoint(TransactionStatus stat,
Object savepoint, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025050, stat);
}
stat.rollbackToSavepoint(savepoint);
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025051, stat);
}
}
/**
* トランザクション開始までロールバックする。
* @param tran トランザクションマネージャ
* @param stat TransactionStatus
*/
public static void rollbackTransaction(PlatformTransactionManager tran,
TransactionStatus stat) {
rollbackTransaction(tran, stat, null);
}
/**
* トランザクション開始までロールバックする。
* @param tran トランザクションマネージャ
* @param stat TransactionStatus
* @param log Log
*/
public static void rollbackTransaction(PlatformTransactionManager tran,
TransactionStatus stat, Log log) {
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025052, stat);
}
if (tran != null && stat != null && !stat.isCompleted()) {
tran.rollback(stat);
}
if (log != null && log.isDebugEnabled()) {
logDebug(log, LogId.DAL025053, stat);
}
}
/**
* トランザクションをコミットさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @return トランザクションステータス
*/
public static TransactionStatus commitRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat) {
commitTransaction(tran, stat, null);
endTransaction(tran, stat, null);
return startTransaction(tran);
}
/**
* トランザクションをコミットさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param log Log
*/
public static TransactionStatus commitRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat, Log log) {
commitTransaction(tran, stat, log);
endTransaction(tran, stat, log);
return startTransaction(tran, log);
}
/**
* トランザクションをコミットさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param def TransactionDefinition
*/
public static TransactionStatus commitRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat,
TransactionDefinition def) {
commitTransaction(tran, stat, null);
endTransaction(tran, stat, null);
return startTransaction(tran, def);
}
/**
* トランザクションをコミットさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param def TransactionDefinition
* @param log Log
*/
public static TransactionStatus commitRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat,
TransactionDefinition def, Log log) {
commitTransaction(tran, stat, log);
endTransaction(tran, stat, log);
return startTransaction(tran, def, log);
}
/**
* トランザクションをロールバックさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
*/
public static TransactionStatus rollbackRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat) {
rollbackTransaction(tran, stat, null);
endTransaction(tran, stat, null);
return startTransaction(tran);
}
/**
* トランザクションをロールバックさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param log Log
*/
public static TransactionStatus rollbackRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat, Log log) {
rollbackTransaction(tran, stat, log);
endTransaction(tran, stat, log);
return startTransaction(tran, log);
}
/**
* トランザクションをロールバックさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param def TransactionDefinition
*/
public static TransactionStatus rollbackRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat,
TransactionDefinition def) {
rollbackTransaction(tran, stat, null);
endTransaction(tran, stat, null);
return startTransaction(tran, def);
}
/**
* トランザクションをロールバックさせ、トランザクションを再度開始させる
* @param tran PlatformTransactionManager
* @param stat TransactionStatus
* @param def TransactionDefinition
* @param log Log
*/
public static TransactionStatus rollbackRestartTransaction(
PlatformTransactionManager tran, TransactionStatus stat,
TransactionDefinition def, Log log) {
rollbackTransaction(tran, stat, log);
endTransaction(tran, stat, log);
return startTransaction(tran, def, log);
}
/**
* Listを配列型に変換する Listの中に複数の型が混じっている場合は使用できない
* @param <E> 返却値の型
* @param list 入力データ
* @param clazz 返却値の型をあらわすClass型のインスタンス
* @return Listの中身を配列にしたもの
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static <E> E[] changeListToArray(List<E> list, Class clazz) {
if (clazz == null) {
throw new IllegalClassTypeException();
}
// SQLの実行:値の取得
List<E> castedList = list;
// 配列に変換
E[] retArray = (E[]) Array.newInstance(clazz, castedList.size());
try {
castedList.toArray(retArray);
} catch (ArrayStoreException e) {
throw new IllegalClassTypeException(e);
}
return retArray;
}
/**
* .propertiesファイルからグループキー指定で値を取り出す グループキーに合致したキーに対して昇順ソートを行ってから 返却リストへ値をセットしている
* @param propertyName .propertiesファイルの名前(.propertiesは必要ない)
* @param grpKey グループキー
* @return propertyNameに存在するgrpKeyPrefix
*/
public static List<String> getProperties(String propertyName, String grpKey) {
Properties properties = PropertyUtil.loadProperties(propertyName);
Enumeration<String> propNames = PropertyUtil.getPropertyNames(
properties, grpKey);
List<String> propNamesList = Collections.list(propNames);
Collections.sort(propNamesList);
List<String> resultList = new ArrayList<String>();
for (String key : propNamesList) {
resultList.add(PropertyUtil.getProperty(key));
}
return resultList;
}
/**
* Java 仮想マシンのメモリ総容量、使用量、 使用を試みる最大メモリ容量の情報を返します。
* @return Java 仮想マシンのメモリ情報
*/
public static String getMemoryInfo() {
DecimalFormat f1 = new DecimalFormat("#,###KB");
DecimalFormat f2 = new DecimalFormat("##.#");
Runtime rt = Runtime.getRuntime();
long free = rt.freeMemory() / 1024;
long total = rt.totalMemory() / 1024;
long max = rt.maxMemory() / 1024;
long used = total - free;
double ratio = used * 100 / (double) total;
StringBuilder sb = new StringBuilder();
sb.append("Java memory info : ");
sb.append("used=");
sb.append(f1.format(used));
sb.append(" (");
sb.append(f2.format(ratio));
sb.append("%), ");
sb.append("total=");
sb.append(f1.format(total));
sb.append(", ");
sb.append("max=");
sb.append(f1.format(max));
return sb.toString();
}
/**
* ログをデバッグレベル出力する。
* TLogger / commons.logging のどちらのロガーにも対応する
* @param log ロガー
* @param logId 出力するログID
* @param args ログの引数
*/
private static void logDebug(Log log, String logId, Object... args) {
if (log instanceof TLogger) {
TLogger logger = (TLogger) log;
logger.debug(logId, args);
} else {
String msg = LOGGER.getLogMessage(logId, args);
log.debug(msg);
}
}
/**
* ログをエラーレベルで出力する
* TLogger / commons.logging のどちらのロガーにも対応する
* @param log ロガー
* @param logId 出力するログID
* @param args ログの引数
*/
private static void logError(Log log, String logId, Object... args) {
if (log instanceof TLogger) {
TLogger logger = (TLogger) log;
logger.error(logId, args);
} else {
String msg = LOGGER.getLogMessage(logId, args);
log.error(msg);
}
}
}