    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.plugin.develop;
    017
    018import java.util.ArrayList;
    019import java.util.List;
    020import java.util.Map;
    021import java.util.HashMap;
    022import java.util.regex.Matcher;
    023import java.util.regex.Pattern;
    024
    025import org.opengion.hayabusa.develop.AbstractJspCreate;
    026import org.opengion.hayabusa.develop.JspEnumeration.GROUPING_FUNCTIONS ;
    027import org.opengion.hayabusa.develop.JspEnumeration.WHERE_OPERATORS ;
    028import org.opengion.hayabusa.develop.JspConvertEntity;
    029import org.opengion.fukurou.xml.OGElement;
    030import static org.opengion.fukurou.util.StringUtil.isNull;
    031
    032/**
    033 * result.jspの&lt;og:query &gt;タグを作成します。
    034 *
    035 * ●使用例
    036 *      &lt;og:query
    037 *              command     = "{&#064;command}"
    038 *              debug       = "{&#064;debug}
    039 *              dbid        = "{&#064;FROM_DBID}"
    040 *              maxRowCount = "{&#064;maxRowCount}" &gt;
    041 *          select A1.xx , A1.xx ,・・・
    042 *          from   xxx A1 inner join xxx B1
    043 *          where  ・・・
    044 *          group by  ・・・
    045 *          having    ・・・
    046 *          ORDER BY  ・・・
    047 *      &lt;/og:query&gt;
    048 *
    049 * @og.rev 5.6.1.2 (2013/02/22) 文字列連結から、XML処理するように変更します。
    050 * @author Takeshi.Takada
    051 *
    052 */
    053public class JspCreate_QUERY extends AbstractJspCreate {
    054        //* このプログラムのVERSION文字列を設定します。   {@value} */
    055        private static final String VERSION = "5.6.4.4 (2013/05/31)" ;
    056
    057        private List<JspConvertEntity> QUERY_ROWS ;
    058        private List<JspConvertEntity> RESULT_ROWS ;
    059        private List<JspConvertEntity> CONST_ROWS ;
    060        private List<JspConvertEntity> JOIN_ROWS ;
    061        private List<JspConvertEntity> JOIN_ON_ROWS ;
    062        private List<JspConvertEntity> HAVING_ROWS ;
    063
    064        private String ns = "";         // 5.2.1.0 (2010/10/01) 名前空間
    065
    066        /**
    067         * 初期化メソッド
    068         *
    069         * 内部で使用する JspConvertEntity の リスト のマップを受け取り、初期化を行います。
    070         *
    071         * @og.rev 5.2.1.0 (2010/10/01) 名前空間を、og 決め打ちから、名前空間指定無しに変更します。
    072         *
    073         * @param       master  JspConvertEntityのリストのマップ
    074         */
    075        @Override
    076        protected void init( final Map<String,List<JspConvertEntity>> master ) {
    077                QUERY_ROWS      = master.get( "QUERY" );
    078                RESULT_ROWS     = master.get( "RESULT" );
    079                CONST_ROWS      = master.get( "CONST" );
    080                JOIN_ROWS       = master.get( "JOIN" );
    081                JOIN_ON_ROWS= master.get( "JOIN_ON" );
    082                HAVING_ROWS     = master.get( "HAVING" );
    083
    084                KEY  = ":query";                // 5.2.1.0 (2010/10/01) 名前空間指定無し
    085                NAME = "result";
    086        }
    087
    088        /**
    089         * JSPに出力するタグの内容を作成します。
    090         * 引数より作成前のタグの属性内容を確認するする事が出来ます。
    091         *
    092         * @og.rev 5.2.1.0 (2010/10/01) メソッドの引数を、OGAttributes から OGElement に変更します。
    093         * @og.rev 5.2.1.0 (2010/10/01) 名前空間を、og 決め打ちから、引数を使用するように変更します。
    094         * @og.rev 5.6.4.4 (2013/05/31) select カラムに、コメントを付与します。
    095         *
    096         * @param ele OGElementエレメントオブジェクト
    097         * @param       nameSpace       このドキュメントのnameSpace( og とか mis とか )
    098         *
    099         * @return      変換された文字列
    100         * @throws Throwable 変換時のエラー
    101         */
    102        @Override
    103        protected String execute( final OGElement ele , final String nameSpace )  throws Throwable {
    104                ns = (nameSpace.length() == 0) ? "" : nameSpace + ":" ; // 5.2.1.0 (2010/10/01) 名前空間
    105
    106                // この OGElement の階層の深さを探ります。
    107                // ele.getText( para ) とすることでXML全体を階層表示できる。
    108        //      int para = ele.getParentCount();
    109
    110                // TODO Auto-generated method stub
    111                //書き出す文字列を作成開始。
    112
    113                List<String> selects    = new ArrayList<String>();
    114                List<String> clmCmnt    = new ArrayList<String>();              // 5.6.4.4 (2013/05/31) select カラムに、コメントを付与します。
    115                List<String> tables             = new ArrayList<String>();
    116                List<String> orders             = new ArrayList<String>();
    117                List<String> group              = new ArrayList<String>();
    118                List<String> having_part = new ArrayList<String>();
    119                List<String> having_grouping_column = new ArrayList<String>();
    120
    121                //HAVING情報から<og:query>タグのテキスト部を生成する準備をします。
    122                if ( isNotEmpty(HAVING_ROWS) ){
    123                        for( JspConvertEntity row : HAVING_ROWS ){
    124                                having_part.add(row.getRemarks());
    125                                if( GROUPING_FUNCTIONS.search( row.getRemarks() ) ){
    126                                        having_grouping_column.add( row.getFullColumnName() );
    127                                }
    128                        }
    129                }
    130                //RESULT情報から<og:query>タグのテキスト部を生成する準備をします。
    131                boolean grouping = false;
    132                if ( isNotEmpty(RESULT_ROWS) ){
    133                        for(int i = 0 ; i < RESULT_ROWS.size() ; i++){
    134                                JspConvertEntity result = RESULT_ROWS.get(i);
    135                                //Select句の情報を作成
    136                                selects.add( result.getSelectPartColumnName() );
    137                                // 5.6.4.4 (2013/05/31) select カラムに、コメントを付与します。
    138                                clmCmnt.add( result.getTableName() + "." + result.getColumnCommentName() );
    139                                //テーブル名を検証して、テーブル数のみの情報にします。
    140                                if( tables != null && !tables.contains( result.getTableName() ) ) {
    141                                        tables.add( result.getFromPartTableName() );
    142                                }
    143                                //並び順に利用するカラムを取得する。
    144                                if ("1".equals( result.getUseOrder() )) {
    145                                        orders.add(Integer.toString( i + 1 ));
    146                                }
    147                                //GROUP BYに必要な情報を取得します。
    148                                if( GROUPING_FUNCTIONS.contains( result.getRemarks() ) ){
    149                                        grouping = true;
    150                //              }else if(having_grouping_column.indexOf( result.getFullColumnName() ) > -1 ){
    151                //                      group.add( result.getFullColumnName() );
    152                                }else{
    153                                        group.add( result.getFullColumnName() );
    154                                }
    155                        }
    156                }
    157
    158                //JOIN情報から<og:query>タグのテキスト部(join句)を生成する準備をします。
    159                JspConvertEntity join_on = null;
    160                if ( isNotEmpty(JOIN_ON_ROWS) ){
    161                        join_on = JOIN_ON_ROWS.get( 0 );
    162                }
    163                //JOIN情報から<og:query><og:where><og:and>タグの検索句を生成する準備をします。
    164                if ( QUERY_ROWS != null && isNotEmpty(CONST_ROWS) ){
    165                        QUERY_ROWS.addAll( CONST_ROWS );
    166                }
    167
    168                OGElement queryEle  = new OGElement( ns + "query" );
    169                queryEle.addAttr( "command"             ,"{@command}" );
    170                queryEle.addAttr( "debug"               ,"{@debug}" );
    171                queryEle.addAttr( "dbid"                ,"{@FROM_DBID}" );
    172                queryEle.addAttr( "maxRowCount" ,"{@maxRowCount}" );
    173
    174                queryEle.addNode( queryText(selects , clmCmnt , tables , JOIN_ROWS , join_on ) );       // 5.6.4.4 (2013/05/31) select カラムに、コメントを付与
    175
    176                if ( isNotEmpty(QUERY_ROWS) ){
    177
    178                        OGElement whereEle = new OGElement( ns + "where" );
    179
    180                        for ( JspConvertEntity where : QUERY_ROWS ) {
    181                                if ("QUERY".equals(where.getType())){
    182                                        whereEle.addNode( andWhereQuery(where.getFullColumnName() , where.getRemarks() ,"{@"+ where.getColumnName() +"}" ,where.isNumber()) );
    183                                }
    184                                if ("CONST".equals(where.getType())) {
    185                                        whereEle.addNode( andWhereConst( where.getFullColumnName(), where.getRemarks() , where.isNumber()) );
    186                                }
    187                        }
    188                        queryEle.addNode( whereEle );
    189                }
    190                if ( grouping || !having_grouping_column.isEmpty() ) {
    191                        queryEle.addNode( T2 + "group by " + chainChar(group,",") + CR );
    192                }
    193                if ( !having_grouping_column.isEmpty() ){
    194                        queryEle.addNode( T2 + "having " + chainChar(having_part ," and ") + CR );
    195                }
    196                if ( !orders.isEmpty() ){
    197                        queryEle.addNode( apperEle( "ORDER BY" , "ORDER_BY" , orders ) );
    198                }
    199
    200                return queryEle.getText(0);
    201        }
    202
    203        private static final String SPACE = "                              " ;  // カラムの位置合わせ用
    204
    205        /**
    206         * result.jspのog:queryタグのテキスト部を生成します。
    207         *
    208         * 補足１
    209         * 引数のjoin_onがnullでないときは、優先的にjoin_onの内容でJOIN句を生成します。
    210         *
    211         * @og.rev 5.6.4.4 (2013/05/31) select カラムに、コメントを付与します。
    212         *
    213         * @param       selects 検索SQLのリスト
    214         * @param       clmCmnt カラムコメントのリスト
    215         * @param       tables  テーブル名のリスト
    216         * @param       joins   JspConvertEntityのリスト
    217         * @param       join_on JspConvertEntityオブジェクト
    218         *
    219         * @return      og:queryタグのテキスト部
    220         */
    221//      protected String queryText( final List<String> selects , final List<String> tables ,
    222//                                                              final List<JspConvertEntity> joins ,final JspConvertEntity join_on ) {
    223        protected String queryText( final List<String> selects , final List<String> clmCmnt , final List<String> tables ,
    224                                                                final List<JspConvertEntity> joins ,final JspConvertEntity join_on ) {
    225                StringBuilder sb = new StringBuilder();
    226//              sb.append( CR ).append( "\t\tselect" ).append( CR );
    227                sb.append( CR ).append( T2 ).append( "select" ).append( CR );
    228//              sb.append( "\t\t\t" );
    229//              sb.append( T3 );
    230//              sb.append( chainChar( selects , "," ) );        // 5.6.4.4 (2013/05/31) 以前は、カラムをカンマで単純につなげていただけ。
    231                // 5.6.4.4 (2013/05/31) select カラムに、コメントを付与します。
    232                int size = selects.size();
    233                for( int i=0; i<size; i++ ) {
    234                        sb.append( T3 );
    235                        if( i == 0 ) { sb.append( " " ); }
    236                        else         { sb.append( "," ); }
    237                        String clm = selects.get(i) ;
    238                        sb.append( clm ).append( SPACE.substring( clm.length() ) ).append( T3 ).append( T3 ).append( T3 ).append( T3 );
    239                        sb.append( "<!-- " ).append( clmCmnt.get(i) ).append( " -->" ).append( CR );
    240                }
    241
    242//              sb.append( CR );
    243//              sb.append( "\t\tfrom " );
    244                sb.append( T2 ).append( "from " );
    245
    246                if ( join_on != null ) {
    247                        //JOIN_ONが存在する場合は、直接SQLを組み立てて処理を終了する。
    248//                      sb.append( "\t\t" );
    249                        sb.append( T2 );
    250                        sb.append( join_on.getRemarks() );
    251                        return sb.toString();
    252                }
    253
    254//              if( joins == null || joins.isEmpty() ) {
    255                if( !isNotEmpty( joins ) ) {
    256                        sb.append( tables.get(0) );
    257                        return sb.toString();
    258                }
    259
    260                //テーブルの内容を構造化します。
    261                TableStruct structs = createStruct(joins);
    262
    263                String before_left = "";
    264                String before_right = "";
    265                StringBuilder sbPre = new StringBuilder("");
    266
    267                Map<String,String> mapJoinParts = new HashMap<String,String>();
    268
    269                boolean isStartJoin = false;
    270
    271                for(int i = 0 ; i < joins.size() ; i++){
    272                        //join句を作るのとネスト構造を作るのは処理を分離させる。
    273                        JspConvertEntity join = joins.get( i );
    274
    275                        if(before_left.equals(join.getFromPartTableName())){
    276                                //前の処理と左側のテーブルは同じ
    277//                              if( before_right.equals(join.getJoinColumn().getFromPartTableName()) == false ) {
    278                                if( ! before_right.equals(join.getJoinColumn().getFromPartTableName()) ) {
    279                                        //前の処理と右側のテーブルが違う
    280                                        sbPre.append( sqlJoinOn( "", join.getJoinColumn().getFromPartTableName() , join.getJoinType()) );
    281                                        isStartJoin = true;
    282                                }
    283                        }else {
    284                                //前の処理と左側のテーブルが違う
    285//                              if( before_right.equals(join.getJoinColumn().getFromPartTableName()) == false ) {
    286                                if( ! before_right.equals(join.getJoinColumn().getFromPartTableName()) ) {
    287                                        //前の処理と右側のテーブルが違う
    288                                        //前の処理のJoin句をテーブル名別にセット
    289                                        String str = sbPre.toString();
    290                                        mapJoinParts.put( before_left, str );
    291                                        //バッファを初期化
    292                                        sbPre = new StringBuilder();
    293                                        sbPre.append( sqlJoinOn( join.getFromPartTableName() , join.getJoinColumn().getFromPartTableName() , join.getJoinType()) );
    294                                        isStartJoin = true;
    295                                }
    296                        }
    297//                      if ( isStartJoin == false ) {
    298                        if ( !isStartJoin  ) {
    299//                              sbPre.append( " and").append( CR );
    300//                              sbPre.append( CR ).append( "\t\t\tand\t");
    301                                sbPre.append( CR ).append( T3 ).append( "and").append( T1 );
    302                        }
    303//                      sbPre.append( "\t\t\t" );
    304                        sbPre.append( join.getFullColumnName() );
    305//                      sbPre.append( "\t\t=\t" );
    306                        sbPre.append( T2 ).append( "=" ).append( T1 );
    307                        sbPre.append( join.getJoinColumn().getFullColumnName() );
    308                        before_left = join.getFromPartTableName();
    309                        before_right = join.getJoinColumn().getFromPartTableName();
    310                        isStartJoin = false;
    311                }
    312                //最終分
    313                mapJoinParts.put( before_left, sbPre.toString() );
    314
    315                StringBuilder sbJoin = new StringBuilder();
    316                //Join句を組み立てます。
    317//              sb.append( createJoinPart(structs.getJoinTables(),mapJoinParts,sbJoin).toString() );
    318                createJoinPart(structs.getJoinTables(),mapJoinParts,sbJoin);
    319                sb.append( sbJoin.toString() );
    320
    321                return sb.toString();
    322        }
    323
    324        /**
    325         * join句の一部を作成する。
    326         *
    327         * @param       left            join句のレフト
    328         * @param       right           join句のライト
    329         * @param       join_type       [1:inner join/その他:left outer join]
    330         *
    331         * @return      join句の一部
    332         */
    333        private String sqlJoinOn(final String left , final String right ,final String join_type){
    334                StringBuilder sb = new StringBuilder();
    335//              sb.append( " " ).append( CR );
    336                sb.append( " " );
    337                sb.append( left );
    338                if("1".equals( join_type )){
    339                        sb.append( " inner join " );
    340                }else{
    341                        sb.append( " left outer join " );
    342                }
    343                sb.append( right );
    344//              sb.append( " on" ).append( CR );
    345//              sb.append( CR ).append( "\t\t\ton\t" );
    346                sb.append( CR ).append( T3 ).append( "on" ).append( T1 );
    347                return sb.toString();
    348        }
    349
    350        /**
    351         * JOIN句を組み立てます。
    352         *
    353         * JOIN句は、内部で再帰処理されます。引数の StringBuilder に最終的な JOIN句が格納されます。
    354         *
    355         * @param       structs テーブル内容の構造化TableStructのリスト
    356         * @param       join    JOIN句マップ
    357         * @param       buff    StringBuilderオブジェクト
    358         */
    359        private void createJoinPart( final List<TableStruct> structs , final Map<String,String> join ,final StringBuilder buff ) {
    360                Matcher matcher = null;
    361                for(int i = 0 ; i < structs.size() ; i++){
    362                        TableStruct struct = structs.get(i);
    363                        String part = join.get(struct.getTableName());
    364                        if ( part != null ){
    365//                              matcher = Pattern.compile( "join " + struct.getTableName() + " on").matcher( buff );
    366                                matcher = Pattern.compile( "join " + struct.getTableName() ).matcher( buff );
    367                                if( matcher.find()) {
    368                                        int start = matcher.start();
    369                                        buff.delete(start,matcher.end());
    370//                                      buff.insert(start , "join ( " + part + " ) on");
    371                                        buff.insert(start , "join ( " + part + " )" );
    372                                }else{
    373                                        buff.append( part );
    374                                }
    375                        }
    376                        createJoinPart(struct.getJoinTables(),join,buff);
    377                }
    378        }
    379
    380        /**
    381         * result.jspの og:query og:appear タグを生成します。
    382         *
    383         * @og.rev 5.2.1.0 (2010/10/01) 名前空間を、og 決め打ちから、引数を使用するように変更します。
    384         *
    385         * @param start_key             開始キー
    386         * @param value                 値
    387         * @param default_value 初期値リスト
    388         *
    389         * @return      og:query og:appear タグ
    390         */
    391//      protected String apperText( final String start_key , final String value , final List<String> default_value ){
    392        protected OGElement apperEle( final String start_key , final String value , final List<String> default_value ){
    393//              StringBuilder sb = new StringBuilder();
    394//              sb.append( "\t<").append( ns ).append( "appear startKey = \"" );
    395//              sb.append( start_key );
    396//              sb.append( "\" value = \"{@" );
    397//              sb.append( value );
    398//              sb.append( "}\"" ).append( CR );
    399//              sb.append( "\t\t\tdefaultVal = \"" );
    400//              sb.append( chainChar( default_value , "," ) );
    401//              sb.append( "\" />" ).append( CR );
    402//              return sb.toString();
    403
    404                OGElement apper = new OGElement( ns + "appear" );
    405                apper.addAttr( "startKey"               ,start_key );
    406                apper.addAttr( "value"                  ,"{@" + value + "}" );
    407                apper.addAttr( "defaultVal"             ,chainChar( default_value , "," ) );
    408                return apper;
    409        }
    410
    411        /**
    412         * result.jspの og:query og:where og:and タグを生成します。
    413         * 処理グループ：QUERY
    414         *
    415         * @param       left            左側式
    416         * @param       operator        オペレーター
    417         * @param       right           右側式
    418         * @param       is_number       数字かどうか[true/false]
    419         *
    420         * @return      og:and タグ
    421         */
    422//      protected String andWhereQuery( final String left , final String operator , final String right , final boolean is_number){
    423        protected OGElement andWhereQuery( final String left , final String operator , final String right , final boolean is_number){
    424//              StringBuilder sb = new StringBuilder();
    425//              if ( operator == null || operator.trim().length() == 0 ){
    426//              if ( operator == null || operator.trim().isEmpty() ){
    427//                      operator = "eq";
    428//              }
    429
    430                String ope = isNull(operator) ? "eq" : operator ;
    431
    432                WHERE_OPERATORS wrOpe = WHERE_OPERATORS.valueOf( ope );
    433//              sb.append( "\t\t<og:and value = \"" ).append( wrOpe.apply( left , right , is_number )).append( "\"\t/>" ).append( CR );
    434//              sb.append( "\t\t<").append( ns ).append( "and value = \"" ).append( wrOpe.apply( left , right , is_number )).append( "\"\t/>" ).append( CR );
    435//              return sb.toString();
    436
    437                OGElement and = new OGElement( ns + "and" );
    438                and.addAttr( "value" , wrOpe.apply( left , right , is_number ) );
    439                return and;
    440        }
    441
    442        /**
    443         * result.jspのog:query og:where og:and タグを生成します。
    444         * 処理グループ：CONST
    445         *
    446         * @param       left            左側式
    447         * @param       right           右側式
    448         * @param       is_number       数字かどうか[true/false]
    449         *
    450         * @return      og:and タグ
    451         */
    452        protected OGElement andWhereConst( final String left , final String right , final boolean is_number ){
    453                String operator = ( right.indexOf( ',' ) >= 0 ) ? "in" : "eq";
    454                return  andWhereQuery( left , operator , right , is_number );
    455        }
    456
    457        /**
    458         * query.jspの og:column タグを生成します。
    459         *
    460         * @param name                  タグのname
    461         * @param default_value 初期値
    462         *
    463         * @return      og:columnタグ
    464         */
    465//      protected String columnText( final String name , final String default_value ){
    466//              StringBuilder sb = new StringBuilder();
    467// //           sb.append( "\t<og:column name=\"" );
    468//              sb.append( "\t<").append( ns ).append( "column name=\"" );
    469//              sb.append( name );
    470//              sb.append( "\"" );
    471//              if ( default_value != null ) {
    472//                      sb.append( " defaultVal=\"" );
    473//                      sb.append( default_value );
    474//                      sb.append( "\" " );
    475//              }
    476//              sb.append("/>");
    477//              return sb.toString();
    478//      }
    479
    480        /**
    481         * テーブルの結合関係を再現する構造体につめ直すメソッド
    482         *
    483         * @param       joins   JspConvertEntityのリスト
    484         *
    485         * @return      テーブルの結合関係を再現する構造体
    486         */
    487        private TableStruct createStruct( final List<JspConvertEntity> joins ) {
    488                TableStruct st = new TableStruct();
    489                for(int i = 0 ; i < joins.size() ; i++){
    490                        JspConvertEntity join = joins.get( i );
    491                        String left_name = join.getFromPartTableName();
    492                        String right_name = join.getJoinColumn().getFromPartTableName();
    493
    494                        TableStruct left = st.getJoinTable( left_name );
    495                        TableStruct right = st.getJoinTable( right_name );
    496
    497                        if (left == null && right == null) {
    498                                //全くの新規。
    499                                left = new TableStruct();
    500                                left.setTableName( left_name );
    501                                right = new TableStruct();
    502                                right.setTableName(right_name);
    503                                left.addJoinTable( right );
    504                                st.addJoinTable( left );
    505                        }else{
    506                                if( left != null && right == null ){
    507                                        right = new TableStruct();
    508                                        right.setTableName(right_name);
    509                                        left.addJoinTable( right );
    510                                }
    511                        }
    512                }
    513                return st;
    514        }
    515
    516        /**
    517         * テーブルの結合状態を階層構図にする為のオブジェクト
    518         *
    519         * @author Administrator
    520         *
    521         */
    522        private static class TableStruct {
    523
    524                private final List<TableStruct> _joins = new ArrayList<TableStruct>();
    525                private String _table_name;
    526
    527                /**
    528                 * テーブル名を設定
    529                 *
    530                 * @param table_name String
    531                 */
    532                public void setTableName( final String table_name ) {
    533                        _table_name = table_name;
    534                }
    535
    536                /**
    537                 * テーブル名を取得
    538                 *
    539                 * @return テーブル名
    540                 */
    541                public String getTableName() {
    542                        return _table_name;
    543                }
    544
    545                /**
    546                 * 結合テーブルを追加
    547                 *
    548                 * @param join_table String
    549                 */
    550                public void addJoinTable( final TableStruct join_table ) {
    551                        _joins.add(join_table);
    552                }
    553
    554                /**
    555                 * 結合テーブルを全て取得
    556                 *
    557                 * @return 全ての結合テーブル
    558                 */
    559                public List<TableStruct> getJoinTables() {
    560                        return _joins;
    561                }
    562
    563                /**
    564                 * 指定したテーブルを取得
    565                 *
    566                 * @param table_name String
    567                 * @return 指定したテーブル
    568                 */
    569                public TableStruct getJoinTable( final String table_name ) {
    570                        return search(_joins,table_name);
    571                }
    572
    573                /**
    574                 * テーブル同士が一致しているか検証する。
    575                 *
    576                 * @param table_name String
    577                 * @return 検証した結果の真偽
    578                 */
    579                public boolean equalTable( final String table_name ) {
    580                        return _table_name != null && _table_name.equals( table_name ) ;
    581                }
    582
    583                /**
    584                 * 指定したテーブルが存在しているか検証する。
    585                 *
    586                 * @param table_name String
    587                 * @return  検証した結果の真偽
    588                 */
    589                public boolean constains( final String table_name ) {
    590                        for(int i = 0; i < _joins.size() ; i++){
    591                                TableStruct join = _joins.get( i );
    592//                              if(join.equals(table_name)){
    593                                if(join.equalTable(table_name)){
    594                                        return true;
    595                                }
    596                        }
    597                        return false;
    598                }
    599
    600                /**
    601                 * 結合先を含めて指定したテーブルを取得する。
    602                 *
    603                 * @param joins List<TableStruct>
    604                 * @param table_name String
    605                 * @return 指定したテーブル
    606                 */
    607                private TableStruct search( final List<TableStruct> joins , final String table_name ) {
    608                        TableStruct join =  null;
    609                        for(int i = 0; i < joins.size() ; i++){
    610                                join = joins.get( i );
    611//                              if(join.equals(table_name)){
    612                                if(join.equalTable(table_name)){
    613                                        return join;
    614                                }else{
    615                                        join = search(join.getJoinTables(),table_name);
    616                                }
    617                        }
    618                        return join;
    619                }
    620        }
    621}