いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

iBatis奮闘記-0020 (ユーティリティクラスの作成)

今回、SqlMapの時と同じようにユーティリティクラスを定義してみます。

以下、ソースです。
ここに出てこないソースなどは、以下の記事を参照してみてください。

[DAO実行用インターフェース]

// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.interfaces.dao;

import gsf.interfaces.*;

import com.ibatis.dao.client.*;

/**
 * iBatis Daoオブジェクトの実行のシンタックスを定義しているインターフェースです.<br/>
 * このインターフェースを実装したクラスは、特定のDaoオブジェクトを受け取り、そのDao内の各メソッドを<br/>
 * 適切な順序で実行することを担当します(テンプレートメソッド, ファサード).<br/>
 * どのDaoのどのメソッドを順に実行していくかは、各実装によります.<br/>
 *
 * @author gsf_zero1
 *
 * @see gsf.interfaces.Executor
 *
 */
public interface DaoExecutor extends Executor{

    /**
     * 実行する.<br/>
     * 
     * @return 実行結果
     *
     * @throws DaoExecuteFailureRuntimeException Dao実行中にエラーが発生した場合
     *
     */
    Object execute();

}

[各例外クラス(実行時例外)]

// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.exception;

/**
 * Dao関連でエラーが発生した場合に発生する実行時例外クラス.<br/>
 *
 * @author gsf_zero1
 *
 */
public class DaoExecuteFailureRuntimeException extends RuntimeException{

    /**
     * コンストラクタ.<br/>
     *
     */
    public DaoExecuteFailureRuntimeException(){
        super();
    }

    /**
     * コンストラクタ.<br/>
     *
     * @param message メッセージ
     *
     */
    public DaoExecuteFailureRuntimeException(String message){
        super(message);
    }

    /**
     * コンストラクタ.<br/>
     *
     * @param cause 元原因例外オブジェクト
     *
     */
    public DaoExecuteFailureRuntimeException(Throwable cause){
        super(cause);
    }

    /**
     * コンストラクタ.<br/>
     *
     * @param message メッセージ
     * @param cause   元原因例外オブジェクト
     *
     */
    public DaoExecuteFailureRuntimeException(String message, Throwable cause){
        super(message, cause);
    }
}


// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.exception;

/**
 * DaoManagerの生成に失敗した場合に発生する実行時例外クラス.<br/>
 *
 * @author gsf_zero1
 *
 */
public class DaoManagerInitializeFailureRuntimeException extends RuntimeException{
    
    /**
     * コンストラクタ.<br/>
     *
     */
    public DaoManagerInitializeFailureRuntimeException(){
        super();
    }

    /**
     * コンストラクタ.<br/>
     *
     * @param message メッセージ
     *
     */
    public DaoManagerInitializeFailureRuntimeException(String message){
        super(message);
    }

    /**
     * コンストラクタ.<br/>
     *
     * @param cause 元原因例外オブジェクト
     *
     */
    public DaoManagerInitializeFailureRuntimeException(Throwable cause){
        super(cause);
    }
    
    /**
     * コンストラクタ.<br/>
     *
     * @param message メッセージ
     * @param cause   元原因例外オブジェクト
     *
     */
    public DaoManagerInitializeFailureRuntimeException(String message, Throwable cause){
        super(message, cause);
    }

}

[ユーティティクラス]

// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.utils.dao;

import java.lang.reflect.*;
import java.io.*;
import java.util.*;

import gsf.interfaces.dao.*;
import gsf.exception.*;
import gsf.utils.sqlmap.SqlMapExecuteMode;
import static gsf.utils.sqlmap.SqlMapExecuteMode.NO_TRANSACTION;
import static gsf.utils.sqlmap.SqlMapExecuteMode.WITH_TRANSACTION;
import static gsf.utils.sqlmap.SqlMapExecuteMode.BATCH_EXECUTE;

import org.apache.commons.lang.*;

import com.ibatis.common.resources.*;
import com.ibatis.dao.client.*;
import com.ibatis.dao.client.template.*;

/**
 * iBatis Data Access Objectフレームワークのユーティリティクラスです.<br/>
 * DaoManager取得の為のショートカットメソッドなどを備えています.<br/>
 *
 * @author gsf_zero1
 *
 */
public class DaoManagerUtils{

    /** DaoManagerのプール */
    protected static Map<String, DaoManager> POOL_DAO_MANAGER = new HashMap<String, DaoManager>();

    /** デフォルトのDaoManager設定ファイル */
    protected static final String DAO_CONFIG_DEFAULT = "DaoManagerConfig.xml";

    /**
     * DaoManagerオブジェクトをプールから取得します.<br/>
     * プールに存在しない場合、新規に作成しそれをプーリングしてから返します.<br/>
     *
     * @param resource DaoManager設定ファイルへのリソースパス
     *
     * @return DaoManagerオブジェクト
     *
     * @throws DaoManagerInitializeFailureRuntimeException DaoManagerの生成に失敗した場合
     *
     */
    protected static DaoManager getDaoManagerFromPool(String resource){

        DaoManager daoManager = POOL_DAO_MANAGER.get(resource);

        if(daoManager == null){

            try{

                daoManager = DaoManagerBuilder.buildDaoManager(Resources.getResourceAsReader(resource));

            }catch(IOException ex){
                throw new DaoManagerInitializeFailureRuntimeException(ex);
            }

            POOL_DAO_MANAGER.put(resource, daoManager);

        }

        return daoManager;

    }

    /**
     * デフォルトの設定ファイル(DaoManagerConfig.xml)を使用してDaoManagerオブジェクトを取得します.<br/>
     * 
     * @return DaoManagerオブジェクト
     *
     * @throws DaoManagerInitializeFailureRuntimeException DaoManagerの生成に失敗した場合
     *
     */
    public static DaoManager getDaoManager(){

        return getDaoManagerFromPool(DAO_CONFIG_DEFAULT);

    }

    /**
     * 指定された設定ファイルを使用してDaoManagerオブジェクトを取得します.<br/>
     * 
     * @return DaoManagerオブジェクト
     *
     * @throws DaoManagerInitializeFailureRuntimeException DaoManagerの生成に失敗した場合
     *
     */
    public static DaoManager getDaoManager(String resource){

        return getDaoManagerFromPool(resource);

    }

    /**
     * 第一引数で渡されたDaoExecutorの実装オブジェクトと、第二引数で渡されたマップを用いて<br/>
     * 本クラスのexecuteメソッドをトランザクション無しモードで実行するショートカットメソッドです。<br/>
     * 詳細は、本クラスのexecuteメソッドの説明を参照してください。<br/>
     *
     * @param executor         DaoExecutorインターフェースの実装
     * @param daoInterfacesMap キーがセット対象のプロパティ名で、値がDAOインターフェースのマップ.
     *
     * @return DaoExecutorオブジェクトのexecute()メソッド実行後の戻り値.
     *
     * @throws DaoExecuteFailureRuntimeException メソッド実行中にエラーが発生した場合.
     *
     * @see gsf.interfaces.dao.DaoExecutor
     * @see gsf.utils.dao.DaoManagerUtils#execute(com.ibatis.dao.client.DaoManager, gsf.interfaces.dao.DaoExecutor, java.util.Map, gsf.utils.sqlmap.SqlMapExecuteMode)
     *
     */
    public static Object executeNoTransaction(DaoExecutor executor, Map<String, Class> daoInterfacesMap){

        return execute(getDaoManager(), executor, daoInterfacesMap, NO_TRANSACTION);

    }

    /**
     * 指定されたDaoManagerを利用し、第ニ引数で渡されたDaoExecutorの実装オブジェクトと、第三引数で渡されたマップを用いて<br/>
     * 本クラスのexecuteメソッドをトランザクション無しモードで実行するショートカットメソッドです。<br/>
     * 詳細は、本クラスのexecuteメソッドの説明を参照してください。<br/>
     *
     * @param daoManager       DaoManagerオブジェクト
     * @param executor         DaoExecutorインターフェースの実装
     * @param daoInterfacesMap キーがセット対象のプロパティ名で、値がDAOインターフェースのマップ.
     *
     * @return DaoExecutorオブジェクトのexecute()メソッド実行後の戻り値.
     *
     * @throws DaoExecuteFailureRuntimeException メソッド実行中にエラーが発生した場合.
     *
     * @see gsf.interfaces.dao.DaoExecutor
     * @see gsf.utils.dao.DaoManagerUtils#execute(com.ibatis.dao.client.DaoManager, gsf.interfaces.dao.DaoExecutor, java.util.Map, gsf.utils.sqlmap.SqlMapExecuteMode)
     *
     */
    public static Object executeNoTransaction(DaoManager daoManager, DaoExecutor executor, Map<String, Class> daoInterfacesMap){

        return execute(daoManager, executor, daoInterfacesMap, NO_TRANSACTION);

    }

    /**
     * 第一引数で渡されたDaoExecutorの実装オブジェクトと、第二引数で渡されたマップを用いて<br/>
     * 本クラスのexecuteメソッドをトランザクション無しモードで実行するショートカットメソッドです。<br/>
     * 詳細は、本クラスのexecuteメソッドの説明を参照してください。<br/>
     *
     * @param executor         DaoExecutorインターフェースの実装
     * @param daoInterfacesMap キーがセット対象のプロパティ名で、値がDAOインターフェースのマップ.
     *
     * @return DaoExecutorオブジェクトのexecute()メソッド実行後の戻り値.
     *
     * @throws DaoExecuteFailureRuntimeException メソッド実行中にエラーが発生した場合.
     *
     * @see gsf.interfaces.dao.DaoExecutor
     * @see gsf.utils.dao.DaoManagerUtils#execute(com.ibatis.dao.client.DaoManager, gsf.interfaces.dao.DaoExecutor, java.util.Map, gsf.utils.sqlmap.SqlMapExecuteMode)
     *
     */
    public static Object executeWithTransaction(DaoExecutor executor, Map<String, Class> daoInterfacesMap){

        return execute(getDaoManager(), executor, daoInterfacesMap, WITH_TRANSACTION);

    }

    /**
     * 指定されたDaoManagerを利用し、第ニ引数で渡されたDaoExecutorの実装オブジェクトと、第三引数で渡されたマップを用いて<br/>
     * 本クラスのexecuteメソッドをトランザクション無しモードで実行するショートカットメソッドです。<br/>
     * 詳細は、本クラスのexecuteメソッドの説明を参照してください。<br/>
     *
     * @param daoManager       DaoManagerオブジェクト
     * @param executor         DaoExecutorインターフェースの実装
     * @param daoInterfacesMap キーがセット対象のプロパティ名で、値がDAOインターフェースのマップ.
     *
     * @return DaoExecutorオブジェクトのexecute()メソッド実行後の戻り値.
     *
     * @throws DaoExecuteFailureRuntimeException メソッド実行中にエラーが発生した場合.
     *
     * @see gsf.interfaces.dao.DaoExecutor
     * @see gsf.utils.dao.DaoManagerUtils#execute(com.ibatis.dao.client.DaoManager, gsf.interfaces.dao.DaoExecutor, java.util.Map, gsf.utils.sqlmap.SqlMapExecuteMode)
     *
     */
    public static Object executeWithTransaction(DaoManager daoManager, DaoExecutor executor, Map<String, Class> daoInterfacesMap){

        return execute(daoManager, executor, daoInterfacesMap, WITH_TRANSACTION);

    }

    /**
     * 指定されたDaoManagerからDAO具象オブジェクトを取得し、それをDaoExecutorにセットした後、DaoExecutor#execute()メソッドをコールします。
     * その際、指定されたSqlMapExecuteModeの値にしたがって、トランザクション制御を行います.<br/>
     * <br/>
     * <p>
     * DaoExecutorにセットされるDAOは、引数daoInterfacesMapのキー名を対象プロパティとし、<br/>
     * そこから、セッターメソッド名を生成して、DaoManagerから取得したDAO具象オブジェクトを<br/>
     * セットします.<br/>
     * 該当するDAO具象クラスに定義するセッターメソッドは、以下の規則を守る必要があります.<br/>
     * <b>
     *      <ol>
     *          <li>メソッド名の命名規則はsetXXXXXXX.</li>
     *          <li>メソッドの引数は、DAOインターフェース一つである必要がある.</li>
     *          <li>メソッドの返り値の型は、void.</li>
     *          <li>メソッドのスコープは(public, protected, private, デフォルト)の全て自由.</li>
     *      </ol>
     *      つまり、通常のセッターメソッドであれば問題ないという事になります.<br/>
     *      <br/>
     *      (例:<br/>
     *          public void setTestTableDao(TestTableDao dao)の場合は、<br/>
     *          マップにdaoInterfacesMap.put("testTableDao", TestTableDao.class)<br/>
     *          と設定します.)<br/>
     * </b>
     * </p>
     * なお、gsf.utils.sqlmap.SqlMapUtilsと違い、こちらは、バッチモードをサポートしません。<br/>
     * バッチ処理が必要な場合は、各DAO内にて、startBatch,executeBatchメソッドを使用してください。<br/>
     * <br/>
     * メソッドの実行中にエラーが発生した場合、DaoExecuteFailureRuntimeException(実行時例外)がスローされます.<br/>
     * <br/>
     * また、メソッドの戻り値はDaoExecutor#execute()メソッドの戻り値をそのままObject型として返却します。<br/>
     * キャストして特定の型に変換してください.<br/>
     * <br/>
     * このメソッドは、トランザクションモードが指定されている場合、メソッドの実行が成功した場合は、<br/>
     * コミットを、失敗した場合は、ロールバックを行います。<br/>
     *
     * @param daoManager       DaoManagerオブジェクト
     * @param executor         DaoExecutorオブジェクト
     * @param daoInterfacesMap キーがセット対象のプロパティ名で、値がDAOインターフェースのマップ.
     * @param mode             実行モード
     *
     * @return メソッド実行後の戻り値.
     *
     * @throws IllegalArgumentException          SqlMapExecuteModeにバッチモードが指定されている場合
     * @throws DaoExecuteFailureRuntimeException メソッド実行中にエラーが発生した場合.
     *
     * @see gsf.interfaces.dao.DaoExecutor
     * @see gsf.utils.sqlmap.SqlMapExecuteMode
     *
     */
    public static Object execute(DaoManager daoManager, DaoExecutor executor, Map<String, Class> daoInterfacesMap, SqlMapExecuteMode mode){

        Object result = null;
        
        try{

            if(mode == BATCH_EXECUTE){
                throw new IllegalArgumentException("バッチモードはサポートしていません。DAO内にて個別にバッチ処理をおこなってください.");
            }

            for(Map.Entry<String, Class> entry : daoInterfacesMap.entrySet()){
                
                String methodName   = String.format("set%s", StringUtils.capitalize(entry.getKey()));

                Method targetMethod = executor.getClass().getDeclaredMethod(methodName, new Class{entry.getValue()});
                targetMethod.setAccessible(true);

                targetMethod.invoke(executor, new Object{daoManager.getDao(entry.getValue())});

            }

            if(mode == NO_TRANSACTION){

                result = executor.execute();

            }else if(mode == WITH_TRANSACTION){

                try{

                    daoManager.startTransaction();

                    result = executor.execute();

                    daoManager.commitTransaction();

                }finally{
                    daoManager.endTransaction();
                }

            }

        }catch(InvocationTargetException ex){
            throw new DaoExecuteFailureRuntimeException("メソッド実行中にエラー.", ex);
        }catch(IllegalAccessException ex){
            throw new DaoExecuteFailureRuntimeException("メソッドへのアクセスが不正です.", ex);
        }catch(NoSuchMethodException ex){
            throw new DaoExecuteFailureRuntimeException("該当するsetterメソッドが見つかりません.", ex);
        }catch(DaoException ex){
            throw new DaoExecuteFailureRuntimeException(ex);
        }

        return result;
    }

}

次は、前回作成したDAOの動作確認クラスを上記の
ユーティリティクラスを使用した版で書き直してみます。