intra-mart Accel Kaiden! プログラミングガイド 第4版 2016-08-01

3.1. 事前準備

本項では、intra-mart Accel Kaiden!でプログラミングする際の準備内容を説明します。
本書では、本項の事前準備が完了していることを前提に記載しています。

3.1.1. 開発環境構築

本書のプログラミング方法は、intra-mart e Builder for Accel Platformを前提としています。
本項では、intra-mart e Builder for Accel Platformのインストール、および開発プロジェクトの準備を行います。

3.1.1.1. intra-mart e Builder for Accel Platformの準備

intra-mart e Builder for Accel Platformのインストール、およびデバッグサーバの構築を行います。
構築手順の詳細は、『intra-mart e Builder for Accel Platform セットアップガイド』を参照してください。

コラム

デバッグサーバの構築時(WARファイルの作成時)には、利用するintra-mart Accel Kaiden!のモジュールを追加してください。
また、WARファイルのデプロイ後、テナント環境の構築まで完了させてください。

3.1.1.2. モジュール・プロジェクトの作成

intra-mart e Builder for Accel Platform上にモジュール・プロジェクトを作成し、プロジェクトの設定を行います。
プロジェクトの作成・設定の方法に関しては、『intra-mart e Builder for Accel Platform ユーザ操作ガイド』のモジュール・プロジェクト作成、およびプロジェクトの設定を参照してください。

コラム

モジュール・プロジェクト作成ウィザードでは次の情報を参考に入力してください。
あくまで参考値ですので、別の値を入力していただいても問題ありません。
  • プロジェクト名 :tutorial
  • グループID :jp.co.slcs.kaiden2
  • アーティファクトID:tutorial
  • バージョン :1.0.0

3.1.1.3. convention.diconの設定

モジュール・プロジェクトの作成後、convention.dicon でルートパッケージの設定をします。
SAStruts フレームワークでは、ルートパッケージを設定することで、「ルートパッケージ.action」パッケージに配置されたJavaクラスにアクセスすることができます。

コラム

ルートパッケージを「jp.co.xxx.yyy」と設定した場合に、Javaクラス「jp.co.xxx.yyy.action.foo.BarAction」にアクセスするためのURLは「http://ホスト名/war名/foo/bar/」となります。
「convention.dicon」を「src/main/resource」に配置し、「addRootPackageName」を追加します。
本項以降のチュートリアルでは、ルートパッケージを”jp.co.slcs.kaiden2.tutorial.feature”と設定したものとして記載しています。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<components>
  <component class="jp.co.intra_mart.framework.extension.seasar.convention.IMNamingConventionImpl">
    <initMethod name="addRootPackageName">
      <arg>"org.seasar.framework.container.warmdeploy"</arg>
    </initMethod>
    <initMethod name="addRootPackageName">
      <arg>"jp.co.slcs.kaiden2.tutorial.feature"</arg>
    </initMethod>
  </component>
  <component class="org.seasar.framework.convention.impl.PersistenceConventionImpl"/>
</components>

コラム

convention.diconなどの各種設定を行うdiconファイルの仕様に関しては、seasar2のホームページを参照してください。

3.1.1.4. kaiden_tutorial.diconの作成

チュートリアルで使用する「kaiden_tutorial.dicon」を作成します。
「kaiden_tutorial.dicon」を「src/main/resource」に作成し、次の様に編集します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
  "http://www.seasar.org/dtd/components24.dtd">

<components>

  <!-- manager -->

  <!-- helper -->

  <!-- validator -->

  <!-- service -->

</components>

3.1.1.5. kaiden.diconの編集

「kaiden_tutorial.dicon」を作成後、「kaiden.dicon」に設定を追加します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<components xmlns:xi="http://www.w3.org/2001/XInclude">
  <include path="s2jdbc.dicon"/>
  <component name="kaidenSqlLogRegistry" class="org.seasar.extension.jdbc.SqlLogRegistry">@org.seasar.extension.jdbc.SqlLogRegistryLocator@getInstance()</component>

  <xi:include href="/kaiden_base.dicon" />
  <xi:include href="/kaiden_extension_imw.dicon" />
  <xi:include href="/kaiden_product_workflow.dicon" />
  <xi:include href="/kaiden_product_labormgr.dicon" />

  <!-- ↓を追加します -->
  <xi:include href="/kaiden_tutorial.dicon" />
  <!-- ↑を追加します -->
</components>

コラム

環境構築時に「kaiden.dicon」以外を利用している場合は、利用したdiconファイルに設定を追加してください。
設定するdiconファイルの設定は『intra-mart Accel Kaiden! セットアップガイド』のSAStruts用設定ファイルを参照してください。
  • intra-mart Accel Kaiden! Core Moduleのみを利用する場合
    kaiden_framework.diconを編集します。
  • intra-mart Accel Kaiden! 経費旅費を利用する場合
    kaiden_workflow.diconを編集します。
  • intra-mart Accel Kaiden! 勤務管理を利用する場合
    kaiden_labormgr.diconを編集します。
  • intra-mart Accel Kaiden!の全てのモジュールを利用する場合
    kaiden.diconを編集します。

3.1.2. S2JDBC

intra-mart Accel Kaiden!のデータベースプログラミング方法は、S2JDBCを前提としています。
本項では、S2JDBCのエンティティやサービスクラスを自動生成するS2JDBC-Genの準備を行います。

3.1.2.1. S2JDBC-Genのセットアップ

S2JDBC-Genのダウンロード、およびセットアップを行います。
セットアップの詳細はSeasarプロジェクトのサイト(http://s2container.seasar.org/2.4/ja/s2jdbc_gen/)を参照してください。
  • エンティティ
    intra-mart Accel Kaiden!が使用するエンティティは、S2JDBC-Genを使ってデータベース上のテーブル定義から自動生成します。
    自動生成時にエンティティのスーパークラスに「jp.co.slcs.kaiden2.base.foundation.model.entity.GenerateEntity」を指定してください。

    注意

    エンティティを自動生成する際には、必ずスーパークラス「GenerateEntity」を指定する必要がありますが、
    自動生成時に「GenerateEntity」がない場合、ビルドエラーが発生する場合があります。
    次項の「GenerateEntity」をS2JDBC-Genのプロジェクト内に配置し、エンティティの自動生成を行うようにしてください。

    コラム

    intra-mart Accel Kaiden!のエンティティはOracle Database上のテーブルから自動生成しています。
    本書でも、エンティティを自動生成する際のデータベースは、Oracle Databaseを推奨します。

    自動生成されるエンティティのプロパティの型は、各データベースのデータ型により生成される内容が変わります。
    詳細はSeasarプロジェクトのサイトのデータベースのデータ型とJavaの型の対応表(http://s2container.seasar.org/2.4/ja/s2jdbc_gen/tasks/gen_entity.html)を参照してください。
  • サービス
    エンティティに対する操作を格納するクラスをサービスと呼びます。
    intra-mart Accel Kaiden!が使用するサービスは、S2JDBC-Genを使ってエンティティから自動生成します。
    自動生成時後にサービスのスーパークラスを「jp.co.slcs.kaiden2.base.foundation.model.service.GenerateService」に変更してください。

    コラム

    サービス生成時に「GenerateService」を自動設定する場合は、S2JDBC-Genのカスタマイズが必要です。
    サービス生成時に抽象サービスクラスが出力される場合がありますが、スーパークラスを「GenerateService」にする場合は生成された抽象サービスクラスは不要です。

3.1.2.2. 補足

S2JDBC-Genプロジェクトへ配置するソースや設定ファイルは次の項を参照してください。
src
└─main
    └─java
        └─jp
            └─co
                └─slcs
                    └─kaiden2
                        └─base
                            └─foundation
                                └─model
                                    ├─annotation
                                    │      AutoTimestamp.java
                                    │      AutoUpdateUser.java
                                    ├─entity
                                    │      GenerateEntity.java
                                    └─service
                                            GenerateService.java

3.1.2.2.1. GenerateEntity

  • Path
    src/main/java/jp/co/slcs/kaiden2/base/foundation/model/entity/GenerateEntity.java
package jp.co.slcs.kaiden2.base.foundation.model.entity;

import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import jp.co.slcs.kaiden2.base.foundation.model.annotation.AutoTimestamp;
import jp.co.slcs.kaiden2.base.foundation.model.annotation.AutoUpdateUser;

/**
 * s2jdbc-genを利用して自動生成したEntityのスーパークラス.
 * 
 * @author Sumitomo Life Information Systems Co.,Ltd.
 */
@MappedSuperclass
public abstract class GenerateEntity {
    
    /** 登録日時. */
    @AutoTimestamp(insert = true, update = false)
    @Column(name = "entry_ts", columnDefinition = "timestamp(6)", nullable = false, unique = false)
    public Timestamp entryTs;
    
    /** 登録者コード. */
    @AutoUpdateUser(insert = true, update = false)
    @Column(name = "entry_user_cd", columnDefinition = "varchar2(100)", nullable = false, unique = false)
    public String entryUserCd;
    
    /** 更新カウンタ. */
    @Version
    @Column(name = "renew_cnt", columnDefinition = "number(18,0)", nullable = false, unique = false)
    public Long renewCnt;
    
    /** 更新日時. */
    @AutoTimestamp(insert = true, update = true)
    @Column(name = "renew_ts", columnDefinition = "timestamp(6)", nullable = false, unique = false)
    public Timestamp renewTs;
    
    /** 更新者コード. */
    @AutoUpdateUser(insert = true, update = true)
    @Column(name = "renew_user_cd", columnDefinition = "varchar2(100)", nullable = false, unique = false)
    public String renewUserCd;
}

3.1.2.2.2. GenerateService

  • Path
    src/main/java/jp/co/slcs/kaiden2/base/foundation/model/service/GenerateService.java
package jp.co.slcs.kaiden2.base.foundation.model.service;

import org.seasar.extension.jdbc.AutoSelect;
import org.seasar.extension.jdbc.DbmsDialect;
import org.seasar.extension.jdbc.IterationCallback;
import org.seasar.extension.jdbc.IterationContext;
import org.seasar.extension.jdbc.JdbcManager;
import org.seasar.extension.jdbc.OrderByItem;
import org.seasar.extension.jdbc.SqlFileSelect;
import org.seasar.extension.jdbc.SqlFileUpdate;
import org.seasar.extension.jdbc.SqlLogRegistry;
import org.seasar.extension.jdbc.manager.JdbcManagerImpl;
import org.seasar.extension.jdbc.manager.JdbcManagerImplementor;
import org.seasar.extension.jdbc.operation.Operations;
import org.seasar.extension.jdbc.service.S2AbstractService;
import org.seasar.extension.jdbc.util.LikeUtil;
import org.seasar.extension.jdbc.where.SimpleWhere;
import org.seasar.extension.sql.Node;
import org.seasar.extension.sql.SqlParser;
import org.seasar.extension.sql.node.BindVariableNode;
import org.seasar.extension.sql.node.EmbeddedValueNode;
import org.seasar.extension.sql.node.ParenBindVariableNode;
import org.seasar.extension.sql.parser.SqlParserImpl;
import org.seasar.util.beans.util.BeanMap;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.persistence.Id;
import jp.co.slcs.kaiden2.base.foundation.conf.OrderType;
import jp.co.slcs.kaiden2.base.foundation.exception.KaidenIllegalParametersException;
import jp.co.slcs.kaiden2.base.foundation.exception.KaidenRuntimeException;
import jp.co.slcs.kaiden2.base.foundation.model.conf.EntityCommonFieldNames;
import jp.co.slcs.kaiden2.base.foundation.model.dto.OrderDto;
import jp.co.slcs.kaiden2.base.foundation.model.entity.GenerateEntity;
import jp.co.slcs.kaiden2.base.foundation.model.util.AutoFieldSetter;
import jp.co.slcs.kaiden2.base.foundation.util.BeanUtil;
import jp.co.slcs.kaiden2.base.foundation.util.CollectionUtil;
import jp.co.slcs.kaiden2.base.foundation.util.StringUtil;
import jp.co.slcs.kaiden2.base.foundation.util.log.KaidenLogger;

/**
 * s2jdbc-genを利用して自動生成したServiceのスーパークラス.
 * <p>
 * 当クラスで実行されたSQL文はすべてログファイルにレベルDebugで出力されます。<br>
 * </p>
 * 
 * @author Sumitomo Life Information Systems Co.,Ltd.
 * @param <ENTITY> エンティティの型
 */
public abstract class GenerateService<ENTITY> extends S2AbstractService<ENTITY> {
    
    /** SQLファイル読込時に使用する文字エンコーディング. */
    private static final String SQL_READ_CHARSET_STR = "UTF-8";
    /**
     * ログリポジトリ.
     */
    @Resource
    public SqlLogRegistry kaidenSqlLogRegistry;
    
    /**
     * {@inheritDoc}
     */
    @Override
    protected final void setEntityClass(Class<ENTITY> entityClass) {
        super.setEntityClass(entityClass);
        super.sqlFilePathPrefix = "META-INF/sql/" + StringUtil.replace(this.getClass().getName(), ".", "/") + "/";
    }
    
    /**
     * エンティティのクラスを返却.
     * 
     * @return エンティティクラス
     */
    public Class<ENTITY> getEntityClass() {
        return super.entityClass;
    }
    
    /**
     * エンティティにフィールドが含まれるかを判定.
     * 
     * @param fieldName フィールド名
     * @return 判定結果 true:含まれる、false:含まれない
     */
    public boolean hasField(String fieldName) {
        return BeanUtil.hasField(entityClass, fieldName);
    }
    
    /**
     * PKフィールドを返却.
     * 
     * @return PKフィールド
     */
    public List<String> getPkFiled() {
        List<String> result = new ArrayList<String>();
        Field[] fields = entityClass.getFields();
        for (Field fld : fields) {
            Id id = fld.getAnnotation(Id.class);
            if (id != null) {
                result.add(fld.getName());
            }
        }
        return result;
    }
    
    /**
     * dtoから主キー条件のkey-value(MAP)を返却.
     * <p>
     * すべてイコール条件になります。主キー項目がDTOに存在しない、または主キー条件がnull(空文字)の場合は、RuntimeExceptionをスローします。
     * </p>
     * 
     * @param dto 対象dto
     * @return 主キーのkey-value(MAP)
     */
    public Map<String, Object> getPkCriteria(Object dto) {
        Map<String, Object> params = new HashMap<String, Object>();
        Field[] fields = entityClass.getFields();
        
        for (Field fld : fields) {
            Id id = fld.getAnnotation(Id.class);
            if (id != null) {
                try {
                    Field dtoField = BeanUtil.getField(dto, fld.getName());
                    if (dtoField == null) {
                        throw KaidenIllegalParametersException.makeInstance();
                    }
                    
                    // フィールドの値
                    Object value = dtoField.get(dto);
                    if (value instanceof String && StringUtil.isEmpty((String) value)) {
                        throw KaidenIllegalParametersException.makeInstance();
                    } else if (value == null) {
                        throw KaidenIllegalParametersException.makeInstance();
                    }
                    params.put(fld.getName(), value);
                    
                } catch (IllegalArgumentException e) {
                    throw KaidenRuntimeException.makeInstance(e);
                } catch (IllegalAccessException e) {
                    throw KaidenRuntimeException.makeInstance(e);
                } catch (SecurityException e) {
                    throw KaidenRuntimeException.makeInstance(e);
                }
            }
        }
        return params;
    }
    
    /**
     * dtoから検索条件のkey-value(MAP)を返却.
     * <p>
     * エンティティのフィールドと名称のフィールドのみ条件が作成されます。 <br />
     * すべてイコール条件になります。条件値がnull(空文字)の場合は、無視されます。
     * </p>
     * 
     * @param dto 対象dto
     * @return 検索条件のMap
     */
    public Map<String, Object> getCriteria(Object dto) {
        Map<String, Object> params = new HashMap<String, Object>();
        Field[] fields = entityClass.getFields();
        
        for (Field fld : fields) {
            Field dtoField;
            try {
                dtoField = BeanUtil.getField(dto, fld.getName());
                if (dtoField != null) {
                    
                    // フィールドの値
                    Object value = dtoField.get(dto);
                    if (value != null) {
                        params.put(fld.getName(), value);
                    }
                }
            } catch (SecurityException e) {
                throw KaidenRuntimeException.makeInstance(e);
            } catch (IllegalArgumentException e) {
                throw KaidenRuntimeException.makeInstance(e);
            } catch (IllegalAccessException e) {
                throw KaidenRuntimeException.makeInstance(e);
            }
        }
        return params;
    }
    
    /**
     * ORDER BYをAutoSelectで利用できる形式で作成.
     * 
     * @param order ORDER BY条件
     * @return ORDER BY
     */
    private OrderByItem[] makeOrderBy(List<OrderDto> order) {
        List<OrderByItem> rv = new ArrayList<OrderByItem>();
        
        for (OrderDto that : order) {
            if (that.orderType == OrderType.ASC) {
                rv.add(Operations.asc(that.fieldName));
            } else {
                rv.add(Operations.desc(that.fieldName));
            }
        }
        
        return rv.toArray(new OrderByItem[rv.size()]);
    }
    
    /**
     * ORDER BYをSqlFileSelectで利用できる形式で作成.
     * 
     * @param order ORDER BY条件
     * @return ORDER BY
     */
    private String makeOrderByString(List<OrderDto> order) {
        List<String> rv = new ArrayList<String>();
        
        for (OrderDto that : order) {
            if (that.orderType == OrderType.ASC) {
                rv.add(Operations.asc(StringUtil.camelToSnake(that.fieldName)).getCriteria());
            } else {
                rv.add(Operations.desc(StringUtil.camelToSnake(that.fieldName)).getCriteria());
            }
        }
        
        if (rv.size() > 0) {
            return StringUtil.join(rv.toArray(new String[rv.size()]), ",");
        }
        return null;
    }
    
    /**
     * generalSelect用のAtutoSelectを返却.
     * 
     * @param criteria 検索条件
     * @param order ORDER BY
     * @return AtutoSelect
     */
    public AutoSelect<ENTITY> getAutoSelect(Map<String, Object> criteria, List<OrderDto> order) {
        AutoSelect<ENTITY> autoSelect = select().where(criteria);
        OrderByItem[] orderby = makeOrderBy(order);
        
        if (orderby.length > 0) {
            autoSelect = autoSelect.orderBy(orderby);
        }
        return autoSelect;
    }
    
    /**
     * 汎用検索.
     * 
     * @param criteria 検索条件
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList(Map<String, Object> criteria) {
        return genericSelectList(criteria, new ArrayList<OrderDto>());
    }
    
    /**
     * 汎用検索.
     * 
     * @param criteria 検索条件
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList(Map<String, Object> criteria, List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(criteria, order).getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * 汎用検索(ロック).
     * 
     * @param criteria 検索条件
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList4Update(Map<String, Object> criteria, List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(criteria, order).forUpdate().getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * generalSelect用のAtutoSelectを返却.
     * 
     * @param where 検索条件
     * @param order ORDER BY
     * @return AtutoSelect
     */
    private AutoSelect<ENTITY> getAutoSelect(SimpleWhere where, List<OrderDto> order) {
        AutoSelect<ENTITY> autoSelect = select().where(where);
        OrderByItem[] orderby = makeOrderBy(order);
        
        if (orderby.length > 0) {
            autoSelect = autoSelect.orderBy(orderby);
        }
        return autoSelect;
    }
    
    /**
     * 汎用検索.
     * 
     * @param where 検索条件
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList(SimpleWhere where) {
        return genericSelectList(where, new ArrayList<OrderDto>());
    }
    
    /**
     * 汎用検索.
     * 
     * @param where 検索条件
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList(SimpleWhere where, List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(where, order).getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * 汎用検索(ロック).
     * 
     * @param where 検索条件
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectList4Update(SimpleWhere where, List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(where, order).forUpdate().getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * generalSelectAll用のAtutoSelectを返却.
     * 
     * @param order ORDER BY
     * @return AtutoSelect
     */
    private AutoSelect<ENTITY> getAutoSelect(List<OrderDto> order) {
        AutoSelect<ENTITY> autoSelect = select();
        OrderByItem[] orderby = makeOrderBy(order);
        
        if (orderby.length > 0) {
            autoSelect = autoSelect.orderBy(orderby);
        }
        return autoSelect;
    }
    
    /**
     * 汎用検索(全検索).
     * 
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectAll(List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(order).getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * 汎用検索(全検索)(ロック).
     * 
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<ENTITY> genericSelectAll4Update(List<OrderDto> order) {
        List<ENTITY> ret = getAutoSelect(order).forUpdate().getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * SQLファイルを利用して検索条件から、limitとoffsetを除外.
     * <p>
     * S2JDBCにてlimitやoffsetは予約であり、SQL検索条件にあると自動的にlimitやoffsetを利用してページングをするため、意図しないページングが行われないよう無害化します
     * </p>
     * 
     * @param criteria 検索条件
     * @return 無害化した検索条件
     */
    private Map<String, Object> sanitizeCriteria4SqlFile(Map<String, Object> criteria) {
        if (criteria != null) {
            if (criteria.containsKey("limit")) {
                criteria.remove("limit");
            }
            if (criteria.containsKey("offset")) {
                criteria.remove("offset");
            }
        }
        return criteria;
    }
    
    /**
     * SqlFileSelectを返却.
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @param resultClass 検索結果のクラス
     * @param order ORDER BY
     * @param <T> 検索結果のクラス
     * @return SqlFileSelect
     */
    public <T> SqlFileSelect<T> getSqlFileSelect(Class<T> resultClass, String sqlfile, Map<String, Object> criteria,
            List<OrderDto> order) {
        String orderby = makeOrderByString(order);
        if (StringUtil.isNotEmpty(orderby)) {
            criteria.put("orderBy", orderby);
        }
        
        Map<String, String> args = getSqlArguments("/" + super.sqlFilePathPrefix + sqlfile);
        for (Map.Entry<String, String> e : args.entrySet()) {
            if (!criteria.containsKey(e.getKey())) {
                criteria.put(e.getKey(), null);
            }
            
        }
        
        return selectBySqlFile(resultClass, sqlfile, sanitizeCriteria4SqlFile(criteria));
    }
    
    /**
     * SQLファイルを解析し、SQLファイルで指定されている変数(検索条件)を返却.
     * 
     * @param sqlPath SQLファイル
     * @return 引数リスト(valueにはnullが設定されています。キーのみ利用してください)
     */
    private Map<String, String> getSqlArguments(String sqlPath) {
        
        StringBuffer sql = new StringBuffer();
        String sqlPathDialect = null;
        if (super.jdbcManager instanceof JdbcManagerImplementor) {
            DbmsDialect dialect = ((JdbcManagerImplementor) super.jdbcManager).getDialect();
            if ((StringUtil.isNotEmpty(sqlPath)) && (dialect != null) && (StringUtil.isNotEmpty(dialect.getName()))) {
                int posDot = sqlPath.lastIndexOf(".");
                if (posDot > 0) {
                    sqlPathDialect = sqlPath.substring(0, posDot) + "_" + dialect.getName() + sqlPath.substring(posDot);
                } else {
                    sqlPathDialect = sqlPath + "_" + dialect.getName();
                }
            }
        }
        URL sqlFile = null;
        if (StringUtil.isNotEmpty(sqlPathDialect)) {
            sqlFile = GenerateService.class.getResource(sqlPathDialect);
        }
        if (null == sqlFile) {
            sqlFile = GenerateService.class.getResource(sqlPath);
        }
        InputStream is = null;
        BufferedReader br = null;
        try {
            is = sqlFile.openStream();
            br = new BufferedReader(new InputStreamReader(is, SQL_READ_CHARSET_STR));
            while (br.ready()) {
                sql.append(br.readLine());
            }
        } catch (IOException e) {
            throw KaidenRuntimeException.makeInstance(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    throw KaidenRuntimeException.makeInstance(e);
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    throw KaidenRuntimeException.makeInstance(e);
                }
            }
        }
        Map<String, String> argMap = new HashMap<String, String>();
        SqlParser parser = new SqlParserImpl(sql.toString());
        Node sqlNode = parser.parse();
        sqlNodeParse(sqlNode, argMap);
        return argMap;
    }
    
    /**
     * SQLを解析する.
     * 
     * @param node SQL解析Node
     * @param argMap 変数MAP ※当メソッド内で追加します。
     */
    private void sqlNodeParse(Node node, Map<String, String> argMap) {
        
        if (BindVariableNode.class.isInstance(node)) {
            argMap.put(((BindVariableNode) node).getExpression(), null);
        } else if (ParenBindVariableNode.class.isInstance(node)) {
            argMap.put(((ParenBindVariableNode) node).getExpression(), null);
        } else if (EmbeddedValueNode.class.isInstance(node)) {
            argMap.put(((EmbeddedValueNode) node).getExpression(), null);
        }
        for (int i = 0; i < node.getChildSize(); i++) {
            sqlNodeParse(node.getChild(i), argMap);
        }
        
    }
    
    /**
     * SQLファイル検索.
     * <p>
     * Like条件の%等はエスケープされます
     * </p>
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @param resultClass 検索結果のクラス
     * @param order ORDER BY
     * @param <T> 検索結果のクラス
     * @return 検索結果
     */
    public <T> List<T> selectBySql(Class<T> resultClass, String sqlfile, Map<String, Object> criteria,
            List<OrderDto> order) {
        List<T> ret = getSqlFileSelect(resultClass, sqlfile, criteria, order).getResultList();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * SQLファイル検索.
     * <p>
     * Like条件の%等はエスケープされます
     * </p>
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @return 検索結果
     */
    public List<BeanMap> selectBySql(String sqlfile, Map<String, Object> criteria) {
        return selectBySql(BeanMap.class, sqlfile, criteria, new ArrayList<OrderDto>());
    }
    
    /**
     * SQLファイル検索.
     * <p>
     * Like条件の%等はエスケープされます
     * </p>
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @param order ORDER BY
     * @return 検索結果
     */
    public List<BeanMap> selectBySql(String sqlfile, Map<String, Object> criteria, List<OrderDto> order) {
        return selectBySql(BeanMap.class, sqlfile, criteria, order);
    }
    
    /**
     * SQLファイル検索後、Filterクラスによって内容をフィルタリングし返却.
     * <p>
     * 引数「limit」が0より大きい場合は以下のように動作します。
     * <p>
     * <ul>
     * <li>返却データは「limit」の数までです</li>
     * <li>「numberOfPage」が指定されている場合にはそのページ番号のデータのみを返却します。</li>
     * </ul>
     * 
     * @param sqlfile sqlファイル名
     * @param criteria SQL検索条件 ※Like条件の%等はエスケープされます
     * @param resultClass 検索結果のクラス
     * @param order ORDER BY
     * @param filterClasses フィルタリングクラス
     * @param limit フィルタリング結果の返却最大数
     * @param numberOfPage フィルタリング結果の返却ページ
     * @param <T> 検索結果(リスト)のクラス
     * @return 検索結果
     */
    @SuppressWarnings("unchecked")
    public <T> Map<String, Object> selectBySqlFilter(Class<T> resultClass, String sqlfile,
            Map<String, Object> criteria, List<OrderDto> order, SqlResultFilterIF[] filterClasses, long limit,
            long numberOfPage) {
        
        if (criteria.containsKey("limit")) {
            criteria.remove("limit");
        }
        numberOfPage = numberOfPage <= 1 ? 1L : numberOfPage;
        
        FilterIterationCallBack filterIterationCallBack = new FilterIterationCallBack(filterClasses, limit,
                numberOfPage);
        Map<String, Object> ret = getSqlFileSelect(resultClass, sqlfile, criteria, order).iterate(
                (IterationCallback<T, Map<String, Object>>) filterIterationCallBack);
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        
        // 結果なし
        if (ret == null) {
            return this.getSelectBySqlFilterNoDataResult();
        }
        
        if (limit > 0) {
            Long matchCount = (Long) ret.get("matchCount");
            long pageTtl = (matchCount / limit) + ((matchCount % limit) > 0 ? 1 : 0);
            
            if (matchCount >= (limit * (numberOfPage - 1) + 1)) {
                // 指定ページが存在する
                ret.put("resultPage", numberOfPage);
            } else {
                // 指定ページが存在しないため、最大ページ番号で再検索
                FilterIterationCallBack reFilterIterationCallBack = new FilterIterationCallBack(filterClasses, limit,
                        pageTtl);
                ret = getSqlFileSelect(resultClass, sqlfile, criteria, order).iterate(
                        (IterationCallback<T, Map<String, Object>>) reFilterIterationCallBack);
                ret.put("resultPage", Long.valueOf(pageTtl));
                
            }
            
            matchCount = (Long) ret.get("matchCount");
            pageTtl = (matchCount / limit) + ((matchCount % limit) > 0 ? 1 : 0);
            
            // 返却ページ総数の計算
            if (ret.get("matchCount") != null) {
                ret.put("resultPageTotal", Long.valueOf(pageTtl));
            }
        } else {
            // limitが0以下なら全件返却のため、総ページ数、ページ番号とも1を返却
            ret.put("resultPageTotal", Long.valueOf(1L));
            ret.put("resultPage", Long.valueOf(1L));
        }
        
        return ret;
    }
    
    /**
     * SQLファイル検索後、Filterクラスによって内容をフィルタリングし返却.
     * <p>
     * {@link #selectBySqlFilter(Class, String, Map, List, SqlResultFilterIF[], long, long)}
     * と同様の機能で、戻り値を特定のDTOでなくBeanMapで返却します。
     * </p>
     * 
     * @param sqlfile sqlファイル名
     * @param criteria SQL検索条件 ※Like条件の%等はエスケープされます
     * @param order ORDER BY
     * @param filterClasses フィルタリングクラス
     * @param limit フィルタリング結果の返却最大数
     * @param numberOfPage フィルタリング結果の返却ページ
     * @param <T> 検索結果(リスト)のクラス
     * @return 検索結果
     * @return
     */
    public <T> Map<String, Object> selectBySqlFilter(String sqlfile, Map<String, Object> criteria,
            List<OrderDto> order, SqlResultFilterIF[] filterClasses, long limit, long numberOfPage) {
        return selectBySqlFilter(BeanMap.class, sqlfile, criteria, order, filterClasses, limit, numberOfPage);
    }
    
    /**
     * 検索後、Filterクラスによって内容をフィルタリングし返却.
     * 
     * @param resultClass 検索結果のクラス
     * @param criteria SQL検索条件 ※Like条件の%等はエスケープされます
     * @param order ORDER BY
     * @param filterClasses フィルタリングクラス
     * @param limit フィルタリング結果の返却最大数
     * @param numberOfPage フィルタリング結果の返却ページ
     * @param <T> 検索結果(リスト)のクラス
     * @return 検索結果
     */
    @SuppressWarnings("unchecked")
    public <T> Map<String, Object> selectListByFilter(Class<T> resultClass, Map<String, Object> criteria,
            List<OrderDto> order, SqlResultFilterIF[] filterClasses, long limit, long numberOfPage) {
        
        if (criteria.containsKey("limit")) {
            criteria.remove("limit");
        }
        numberOfPage = numberOfPage <= 1 ? 1L : numberOfPage;
        
        FilterIterationCallBack filterIterationCallBack = new FilterIterationCallBack(filterClasses, limit,
                numberOfPage);
        
        Map<String, Object> ret = getAutoSelect(criteria, order).iterate(
                (IterationCallback<ENTITY, Map<String, Object>>) filterIterationCallBack);
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        
        // 結果なし
        if (ret == null) {
            return this.getSelectBySqlFilterNoDataResult();
        }
        
        if (limit > 0) {
            Long matchCount = (Long) ret.get("matchCount");
            long pageTtl = (matchCount / limit) + ((matchCount % limit) > 0 ? 1 : 0);
            
            if (matchCount >= (limit * (numberOfPage - 1) + 1)) {
                // 指定ページが存在する
                ret.put("resultPage", numberOfPage);
            } else {
                // 指定ページが存在しないため、最大ページ番号で再検索
                FilterIterationCallBack reFilterIterationCallBack = new FilterIterationCallBack(filterClasses, limit,
                        pageTtl);
                ret = getAutoSelect(criteria, order).iterate(
                        (IterationCallback<ENTITY, Map<String, Object>>) reFilterIterationCallBack);
                ret.put("resultPage", Long.valueOf(pageTtl));
                
            }
            
            matchCount = (Long) ret.get("matchCount");
            pageTtl = (matchCount / limit) + ((matchCount % limit) > 0 ? 1 : 0);
            
            // 返却ページ総数の計算
            if (ret.get("matchCount") != null) {
                ret.put("resultPageTotal", Long.valueOf(pageTtl));
            }
        } else {
            // limitが0以下なら全件返却のため、総ページ数、ページ番号とも1を返却
            ret.put("resultPageTotal", Long.valueOf(1L));
            ret.put("resultPage", Long.valueOf(1L));
        }
        
        List<ENTITY> resultList = (List<ENTITY>) ret.get("resultList");
        if (CollectionUtil.isNotEmpty(resultList)) {
            ret.put("resultList", CollectionUtil.changeDtoListClass(resultClass, resultList));
        }
        return ret;
        
    }
    
    /**
     * 検索条件で、Like検索のワイルドカードをエスケープします.
     * <p>
     * % → $%
     * </p>
     * 
     * @param criteria 検索条件
     * @param likeTarget LIKE検索対象カラム
     */
    public void escapeWildcard(Map<String, Object> criteria, String[] likeTarget) {
        
        if (likeTarget == null || likeTarget.length == 0) {
            return;
        }
        
        for (String that : likeTarget) {
            if (criteria.containsKey(that)) {
                Object value = criteria.get(that);
                
                if (value instanceof String) {
                    criteria.put(that, LikeUtil.escapeWildcard((String) value));
                }
            }
        }
    }
    
    /**
     * {@inheritDoc}
     * <p>
     * {@link AutoFieldSetter#autoTimestampByUpdate(Object)}、 {@link AutoFieldSetter#autoUpdateuserByUpdate(Object)}
     * を実行後に、<code>super.update(entity)</code>を実行します
     * </p>
     */
    @Override
    public int update(ENTITY entity) {
        AutoFieldSetter.autoTimestampByUpdate(entity);
        AutoFieldSetter.autoUpdateuserByUpdate(entity);
        int ret = super.update(entity);
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * エンティティを更新.
     * <p>
     * 指定のプロパティを更新対象から除外します。<br>
     * {@link AutoFieldSetter#autoTimestampByUpdate(Object)}、 {@link AutoFieldSetter#autoUpdateuserByUpdate(Object)}
     * を実行後に、 <br>
     * <code>super.jdbcManager.update(entity).excludes(propertyNames).execute()</code>を実行します
     * </p>
     * 
     * @param entity 更新対象エンティティ
     * @param propertyNames 更新対象から除外するプロパティ名の配列
     * @return 更新件数
     */
    public int updateExcludes(ENTITY entity, String[] propertyNames) {
        AutoFieldSetter.autoTimestampByUpdate(entity);
        AutoFieldSetter.autoUpdateuserByUpdate(entity);
        int ret = super.jdbcManager.update(entity).excludes(this.adjustExcludesPropertyNames(propertyNames)).execute();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * エンティティを更新.
     * <p>
     * 指定のプロパティのみを更新対象とします。<br>
     * {@link AutoFieldSetter#autoTimestampByUpdate(Object)}、 {@link AutoFieldSetter#autoUpdateuserByUpdate(Object)}
     * を実行後に、 <br>
     * <code>super.jdbcManager.update(entity).excludes(propertyNames).execute()</code>を実行します
     * </p>
     * 
     * @param entity 更新対象エンティティ
     * @param propertyNames 更新対象とするプロパティ名の配列
     * @return 更新件数
     */
    public int updateIncludes(ENTITY entity, String[] propertyNames) {
        AutoFieldSetter.autoTimestampByUpdate(entity);
        AutoFieldSetter.autoUpdateuserByUpdate(entity);
        int ret = super.jdbcManager.update(entity).includes(adjustInludesPropertyNames(propertyNames)).execute();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * {@inheritDoc}
     * <p>
     * {@link AutoFieldSetter#autoTimestampByInsert(Object)}、 {@link AutoFieldSetter#autoUpdateuserByInsert(Object)}
     * を実行後に、<code>super.insert(entity)</code>を実行します
     * </p>
     */
    @Override
    public int insert(ENTITY entity) {
        AutoFieldSetter.autoTimestampByInsert(entity);
        AutoFieldSetter.autoUpdateuserByInsert(entity);
        int ret = super.insert(entity);
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * 一括挿入.
     * 
     * @param dataList 挿入対象リスト
     * @return 挿入件数の配列 ※S2AbstractService#insert(ENTITY)の仕様に準じる
     */
    public int[] insertBatch(List<ENTITY> dataList) {
        List<Integer> rvList = new ArrayList<Integer>();
        for (ENTITY entity : dataList) {
            rvList.add(this.insert(entity));
        }
        
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 一括更新.
     * <p>
     * 指定のプロパティを更新対象から除外します。<br>
     * </p>
     * 
     * @param dataList 更新対象リスト
     * @return 更新件数(Ingeger)の配列
     */
    public int[] updateBatch(List<ENTITY> dataList) {
        List<Integer> rvList = new ArrayList<Integer>();
        for (ENTITY entity : dataList) {
            rvList.add(this.update(entity));
        }
        
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 一括更新.
     * <p>
     * 指定のプロパティのみを更新対象とします。<br>
     * </p>
     * 
     * @param dataList 更新対象リスト
     * @param propertyNames 更新対象から除外するプロパティ名の配列
     * @return 更新件数(Ingeger)の配列
     */
    public int[] updateExcludesBatch(List<ENTITY> dataList, String[] propertyNames) {
        List<Integer> rvList = new ArrayList<Integer>();
        for (ENTITY entity : dataList) {
            rvList.add(this.updateExcludes(entity, propertyNames));
        }
        
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 一括更新.
     * 
     * @param dataList 更新対象リスト
     * @param propertyNames 更新対象とするプロパティ名の配列
     * @return 更新件数(Ingeger)の配列
     */
    public int[] updateIncludesBatch(List<ENTITY> dataList, String[] propertyNames) {
        List<Integer> rvList = new ArrayList<Integer>();
        for (ENTITY entity : dataList) {
            rvList.add(this.updateIncludes(entity, propertyNames));
        }
        
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 一括削除.
     * 
     * @param dataList 更新対象リスト
     * @return 削除数(Ingeger)の配列
     */
    public int[] deleteBatch(List<ENTITY> dataList) {
        List<Integer> rvList = new ArrayList<Integer>();
        for (ENTITY entity : dataList) {
            rvList.add(delete(entity));
            KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        }
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 内容に応じて挿入/更新を切り替えて実行.
     * <p>
     * エンティティのrenewCntがnullの場合はinsert、そうでない場合はupdateを行います
     * </p>
     * 
     * @param data 更新対象
     * @return 挿入/更新件数.
     */
    public int autoInsUpd(ENTITY data) {
        if (((GenerateEntity) data).renewCnt == null) {
            return this.insert(data);
        } else {
            return this.update(data);
        }
        
    }
    
    /**
     * 内容に応じて挿入/更新を一括実行.
     * <p>
     * エンティティのrenewCntがnullの場合はinsert、そうでない場合はupdateを行います
     * </p>
     * <p>
     * エラーが発生した場合はnullを返却
     * </p>
     * 
     * @param dataList 更新対象リスト
     * @return 挿入/更新件数.
     */
    public int[] autoInsUpdBatch(List<ENTITY> dataList) {
        List<Integer> rvList = new ArrayList<Integer>();
        genericLock(dataList);
        for (ENTITY data : dataList) {
            rvList.add(this.autoInsUpd(data));
        }
        return CollectionUtil.toIntArray(rvList);
    }
    
    /**
     * 汎用ロック.
     * <p>
     * 注意&#65281;引数のリストを主キーの昇順にソートしますので、注意してください
     * </p>
     * 
     * @param dataList 対象エンティティのリスト
     */
    public void genericLock(List<ENTITY> dataList) {
        // PKでソート
        List<String> pk = this.getPkFiled();
        List<OrderDto> order = new ArrayList<OrderDto>();
        for (String fld : pk) {
            OrderDto that = new OrderDto();
            that.fieldName = fld;
            that.orderType = OrderType.ASC;
            order.add(that);
        }
        CollectionUtil.dtoSort(dataList, order);
        
        // PKキー順にロック
        for (ENTITY that : dataList) {
            this.genericSelectList4Update(getPkCriteria(that), new ArrayList<OrderDto>());
        }
    }
    
    /**
     * 主キーの昇順でソート定義を生成.
     * 
     * @return ソート定義(主キーの昇順)
     */
    public List<OrderDto> makeOrderListFromPk() {
        List<String> pk = this.getPkFiled();
        List<OrderDto> order = new ArrayList<OrderDto>();
        for (String fld : pk) {
            OrderDto that = new OrderDto();
            that.fieldName = fld;
            that.orderType = OrderType.ASC;
            order.add(that);
        }
        return order;
    }
    
    /**
     * getSelectBySqlFilter時の返却値なしの状態のMapを返却.
     * <p>
     * 主にSQL実行前に戻り値を返却する場合に利用してください
     * </p>
     * 
     * @return 返却値なしの状態のMap
     */
    public Map<String, Object> getSelectBySqlFilterNoDataResult() {
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("resultList", new ArrayList<Object>()); // フィルター結果(データ) ※最大でもlimit数まで
        result.put("matchCount", Long.valueOf(0L)); // フィルターにマッチした数 ※limit以上もカウント
        result.put("sqlTotal", Long.valueOf(0L)); // フィルター前のカウント
        result.put("resultPageTotal", Long.valueOf(0L)); // 返却ページtotal
        result.put("resultPage", Long.valueOf(0L)); // 返却ページ番号
        return result;
    }
    
    /**
     * selectListFilter用コールバック.
     * <p>
     * 返却値(MAP)には以下の情報が格納されています。
     * <table border="1">
     * <tr>
     * <th>key</th>
     * <th>value</th>
     * </tr>
     * <tr>
     * <td>reusltList</td>
     * <td>List&lt;Object&gt; フィルター結果(指定ページのデータのみ)</td>
     * </tr>
     * <tr>
     * <td>matchCount</td>
     * <td>Long フィルター一致数</td>
     * </tr>
     * <tr>
     * <td>sqlTotal</td>
     * <td>Long SQLヒット数</td>
     * </tr>
     * <tr>
     * <td>resultPageTotal</td>
     * <td>Long 返却ページ総数</td>
     * </tr>
     * <tr>
     * <td>resultPage</td>
     * <td>Long 返却ページ番号</td>
     * </tr>
     * </table>
     * 
     * @author Sumitomo Life Information Systems Co.,Ltd.
     */
    private class FilterIterationCallBack implements IterationCallback<Object, Map<String, Object>> {
        
        /** フィルタークラス. */
        private final SqlResultFilterIF[] filters;
        /** 返却結果の最大数. */
        private final long limit;
        /** 返却ページ番号. */
        private final long numberOfPage;
        
        /** 戻り値. */
        private final Map<String, Object> result = new HashMap<String, Object>();
        
        /**
         * コンストラクタ.
         * 
         * @param filters フィルタークラス配列
         * @param limit 返却最大件数
         * @param numberOfPage 返却ページ番号
         */
        public FilterIterationCallBack(SqlResultFilterIF[] filters, long limit, long numberOfPage) {
            this.filters = filters;
            this.limit = limit;
            this.numberOfPage = numberOfPage <= 1 ? Long.valueOf(1L) : numberOfPage;
            // 戻り値の準備
            result.put("resultList", new ArrayList<Object>()); // フィルター結果(データ) ※最大でもlimit数まで
            result.put("matchCount", Long.valueOf(0L)); // フィルターにマッチした数 ※limit以上もカウント
            result.put("sqlTotal", Long.valueOf(0L)); // フィルター前のカウント
            result.put("resultPageTotal", Long.valueOf(0L)); // 返却ページtotal
            result.put("resultPage", Long.valueOf(0L)); // 返却ページ番号
        }
        
        /**
         * {@inheritDoc}
         */
        @Override
        public Map<String, Object> iterate(Object selectEntity, IterationContext ctx) {
            boolean match = true;
            for (SqlResultFilterIF sqlFilter : this.filters) {
                match = sqlFilter.filter(selectEntity) && match;
                if (!match) {
                    break;
                }
            }
            
            // インクリメント
            this.result.put("sqlTotal", ((Long) this.result.get("sqlTotal")) + 1);
            if (match) {
                Long matchCount = ((Long) this.result.get("matchCount")) + 1;
                this.result.put("matchCount", (matchCount));
                
                if (limit <= 0
                        || (matchCount <= (limit * numberOfPage) && matchCount >= (limit * (numberOfPage - 1) + 1))) {
                    @SuppressWarnings("unchecked")
                    List<Object> lst = (List<Object>) this.result.get("resultList");
                    lst.add(selectEntity);
                }
            }
            return this.result;
        }
    }
    
    /**
     * 更新除外対象プロパティ配列補正.
     * <p>
     * 更新除外対象プロパティ配列に下記プロパティを含む場合、当該要素を削除します。
     * </p>
     * <li>{@link EntityCommonFieldNames.RENEW_USER_CD 更新者コード}</li> <br>
     * <li>{@link EntityCommonFieldNames.TS 更新日時}</li>
     * 
     * @param arg 更新除外対象プロパティ
     * @return 補正後プロパティ配列
     */
    private String[] adjustExcludesPropertyNames(String[] arg) {
        List<String> list = new ArrayList<String>(Arrays.asList(arg));
        int targetIdx = list.lastIndexOf(EntityCommonFieldNames.RENEW_USER_CD);
        if (targetIdx != -1) {
            list.remove(targetIdx);
        }
        targetIdx = list.lastIndexOf(EntityCommonFieldNames.RENEW_TS);
        if (targetIdx != -1) {
            list.remove(targetIdx);
        }
        return list.toArray(new String[list.size()]);
    }
    
    /**
     * 更新対象プロパティ配列補正.
     * <p>
     * 更新対象プロパティ配列に下記プロパティを含まない場合、当該要素を追加します。
     * </p>
     * <li>{@link EntityCommonFieldNames.RENEW_USER_CD 更新者コード}</li> <br>
     * <li>{@link EntityCommonFieldNames.TS 更新日時}</li>
     * 
     * @param arg 更新対象プロパティ
     * @return 補正後プロパティ配列
     */
    private String[] adjustInludesPropertyNames(String[] arg) {
        List<String> list = new ArrayList<String>(Arrays.asList(arg));
        int targetIdx = list.lastIndexOf(EntityCommonFieldNames.RENEW_USER_CD);
        if (targetIdx == -1) {
            list.add(EntityCommonFieldNames.RENEW_USER_CD);
        }
        targetIdx = list.lastIndexOf(EntityCommonFieldNames.RENEW_TS);
        if (targetIdx == -1) {
            list.add(EntityCommonFieldNames.RENEW_TS);
        }
        return list.toArray(new String[list.size()]);
    }
    
    /**
     * SQLフィイル更新.
     * 
     * @param sqlfile sqlファイル名
     * @return 更新件数
     */
    public int updateBySql(String sqlfile) {
        return updateBySql(sqlfile, null);
    }
    
    /**
     * SQLフィイル更新.
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 更新条件
     * @return 更新件数
     */
    public int updateBySql(String sqlfile, Map<String, Object> criteria) {
        int ret = getSqlFileUpdate(sqlfile, criteria).execute();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * SqlFileUpdateを返却.
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @return SqlFileUpdate
     */
    public SqlFileUpdate getSqlFileUpdate(String sqlfile, Map<String, Object> criteria) {
        
        Map<String, String> args = getSqlArguments("/" + super.sqlFilePathPrefix + sqlfile);
        for (Map.Entry<String, String> e : args.entrySet()) {
            if (!criteria.containsKey(e.getKey())) {
                criteria.put(e.getKey(), null);
            }
            
        }
        
        return updateBySqlFile(sqlfile, criteria);
    }
    
    /**
     * 汎用検索結果件数取得.
     * 
     * @return 検索結果件数
     */
    @Override
    public long getCount() {
        return getCount(new HashMap<String, Object>());
    }
    
    /**
     * 汎用検索結果件数取得.
     * 
     * @param criteria 検索条件
     * @return 検索結果件数
     */
    public long getCount(Map<String, Object> criteria) {
        long ret = select().where(criteria).getCount();
        KaidenLogger.debug(kaidenSqlLogRegistry.getLast().getCompleteSql()); // SQL文をログに出力
        return ret;
    }
    
    /**
     * Sqlファイルの検索結果件数を返却.
     * 
     * @param sqlfile sqlファイル名
     * @return Sqlファイルの検索結果件数
     * @see #getCountBySql(String, Map)
     */
    public long getCountBySql(String sqlfile) {
        return getCountBySql(sqlfile, null);
    }
    
    /**
     * Sqlファイルの検索結果件数を返却.
     * 
     * @param sqlfile sqlファイル名
     * @param criteria 検索条件
     * @return Sqlファイルの検索結果件数
     */
    public long getCountBySql(String sqlfile, Map<String, Object> criteria) {
        
        if (null == criteria || criteria.isEmpty()) {
            return jdbcManager.getCountBySqlFile(sqlFilePathPrefix + sqlfile);
        }
        
        Map<String, String> args = getSqlArguments("/" + super.sqlFilePathPrefix + sqlfile);
        
        for (Map.Entry<String, String> e : args.entrySet()) {
            if (!criteria.containsKey(e.getKey())) {
                criteria.put(e.getKey(), null);
            }
            
        }
        return jdbcManager.getCountBySqlFile(sqlFilePathPrefix + sqlfile, criteria);
    }
    
    /**
     * JdbcManagerを設定.
     * 
     * @param jdbcManager JdbcManager
     */
    public void setJdbcManager(JdbcManager jdbcManager) {
        this.jdbcManager = jdbcManager;
        // @formatter:off
        KaidenLogger.info(getClass().getSimpleName() + "に jdbcManagerが設定されました。[" + ((JdbcManagerImpl) jdbcManager).getDialect().getName() + "]");
        // @formatter:on
        
    }
    
}

3.1.2.2.3. AutoTimestamp

  • Path
    src/main/java/jp/co/slcs/kaiden2/base/foundation/model/annotation/AutoTimestamp.java
package jp.co.slcs.kaiden2.base.foundation.model.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jp.co.slcs.kaiden2.base.foundation.model.service.GenerateService;

/**
 * 自動現在時刻設定.
 * <p>
 * S2JDBCのエンティティにアノテーションを付与することで、insert時/update時に自動的に現在日付時刻を設定します。<br >
 * ただし自動的に設定されるのは、{@link GenerateService}の{@link GenerateService#insert(Object) insert}/
 * {@link GenerateService#update(Object) update}を利用した場合のみです。
 * <p>
 * 
 * @author Sumitomo Life Information Systems Co.,Ltd.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AutoTimestamp {
    
    /** insert時に現在日付時刻を設定. */
    boolean insert();
    
    /** update時に現在日付時刻を設定. */
    boolean update();
}

3.1.2.2.4. AutoUpdateUser

  • Path
    src/main/java/jp/co/slcs/kaiden2/base/foundation/model/annotation/AutoUpdateUser.java
package jp.co.slcs.kaiden2.base.foundation.model.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import jp.co.slcs.kaiden2.base.foundation.model.service.GenerateService;

/**
 * 自動ログインユーザ設定.
 * <p>
 * S2JDBCのエンティティにアノテーションを付与することで、insert時/update時に自動的にログインユーザを設定します。<br >
 * ただし自動的に設定されるのは、{@link GenerateService}の{@link GenerateService#insert(Object) insert}/
 * {@link GenerateService#update(Object) update}を利用した場合のみです。
 * <p>
 * 
 * @author Sumitomo Life Information Systems Co.,Ltd.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AutoUpdateUser {
    
    /** insert時にログインユーザを設定. */
    boolean insert();
    
    /** update時にログインユーザを設定. */
    boolean update();
}

3.1.2.2.5. s2jdbc-gen-build.xml/s2jdbc-gen-build.properties

  • 次ファイルは参考としてお使いください。
    ご利用中の環境によっては、動作しない場合がありますので、ご注意ください。
  • s2jdbc-gen-build.xml

<project name="example-s2jdbc-gen" default="generate-src" basedir=".">
	<property file="s2jdbc-gen-build.properties" />
	
	<path id="classpath">
		<pathelement location="${classpathdir}"/>
		<pathelement location="${resourcesdir}"/>
		<fileset dir="${librarydir}"/>
	</path>
	<taskdef resource="s2jdbc-gen-task.properties" classpathref="classpath"/>
	<property name="templateFilePrimaryDir" value="resources/tempaltes"/>
	<property name="pluralFormFile" value="${templateFilePrimaryDir}/plural.properties"/>
	
	<target name="generate-src">
		<gen-entity 
			tableNamePattern="${tableNamePattern}"
			ignoreTableNamePattern="${ignoreTableNamePattern}"
			entitySuperclassName="jp.co.slcs.kaiden2.base.foundation.model.entity.GenerateEntity"
			pluralFormFile="${pluralFormFile}"
			useTemporalType="false"
			useAccessor="false"
			applyDbCommentToJava="true"
			showTableName="true"
			showColumnName="true"
			showColumnDefinition="true"
			showJoinColumn="true"
			rootPackageName="${rootPackageName}"
			entityPackageName="entity"
			templateFilePrimaryDir="${templateFilePrimaryDir}"
			overwrite="true"
			classpathref="classpath"
		/>
		<javac 
			srcdir="${srcdir}"
			destdir="${classpathdir}"
			encoding="UTF-8"
			fork="true"
			debug="on"
			includeantruntime=""
			classpathref="classpath" 
		/>
		<gen-names
			classpathDir="${classpathdir}"
			rootPackageName="${rootPackageName}"
			namesPackageName="entity"
			templateFilePrimaryDir="${templateFilePrimaryDir}"
			generateNamesAggregateClass="false"
			overwrite="true"
			classpathref="classpath"
		/>
		<gen-service
			classpathDir="${classpathdir}"
			rootPackageName="${rootPackageName}"
			servicePackageName="service"
			templateFilePrimaryDir="${templateFilePrimaryDir}"
			overwrite="true"
			classpathref="classpath"
		/>
		<gen-condition
			classpathDir="${classpathdir}"
			rootPackageName="${rootPackageName}"
			conditionPackageName="service"
			templateFilePrimaryDir="${templateFilePrimaryDir}"
			overwrite="true"
			classpathref="classpath"
		/>
		<javac 
			srcdir="${srcdir}"
			destdir="${classpathdir}"
			encoding="UTF-8"
			fork="true"
			debug="on"
			includeantruntime=""
			classpathref="classpath" 
		/>
	</target>
</project>
  • s2jdbc-gen-build.properties
# classpath
srcdir=src/main/java
classpathdir=target/classes
resourcesdir=resources
librarydir=lib

# 対象とするテーブル名の正規表現です。
# (デフォルト値:「".*"」)
tableNamePattern=.*

# 対象としないテーブル名の正規表現です。
# (デフォルト値:「"(SCHEMA_INFO|.*\$.*)"」)
ignoreTableNamePattern=

# ルートパッケージ名です。
# エンティティクラスは、ルートパッケージ名と「entity」をピリオドで連結したパッケージに配置します。
# 名前クラスは、ルートパッケージ名と「entity」をピリオドで連結したパッケージに配置します。
# サービスクラスは、ルートパッケージ名と「service」をピリオドで連結したパッケージに配置します。
# 条件クラスは、ルートパッケージ名と「service」をピリオドで連結したパッケージに配置します。
rootPackageName=aaa.bbb.ccc.foundation.model