    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.hayabusa.taglib;
    017
    018import org.opengion.fukurou.system.OgRuntimeException ;                 // 6.4.2.0 (2016/01/29)
    019import org.opengion.hayabusa.common.HybsSystem;
    020import org.opengion.hayabusa.common.HybsSystemException;
    021import org.opengion.hayabusa.db.DBTableModel;
    022import org.opengion.hayabusa.develop.JspCreateFactory;
    023import org.opengion.hayabusa.develop.JspConvertEntity;
    024import org.opengion.fukurou.system.ThrowUtil;                                   // 6.4.2.0 (2016/01/29)
    025import org.opengion.fukurou.util.ErrorMessage;
    026import org.opengion.fukurou.util.StringUtil;
    027import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    028import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    029import org.opengion.fukurou.xml.JspSaxParser;
    030
    031import static org.opengion.fukurou.util.StringUtil.nval ;
    032
    033import java.io.File;
    034import java.util.Map;
    035import java.util.HashMap;
    036import java.util.List;
    037import java.util.ArrayList;
    038import java.util.Locale ;
    039import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
    040
    041/**
    042 * JspCreateTag は、画面定義情報より、JSP画面を自動作成するツールです。
    043 *
    044 * 画面作成するにあたり、３箇所の参照元が存在します。
    045 *
    046 *   １．画面属性の設定 ： 雛形   → 仮画面   ・・・ hpgid で指定の画面ID
    047 *   ２．仮画面修正     ： 仮画面 → 仮画面   ・・・ jsp/customUserDef/画面ID
    048 *   ３．本環境修正     ： 本画面 → 本画面   ・・・ jsp/画面ID
    049 *
    050 * それぞれ、作成先の画面IDフォルダが存在する場合は、取込元を作成先に設定します。
    051 * つまり、一度作成すると、それ以降は、作成された画面を基準に処理を行います。
    052 *
    053 * @og.formSample
    054 * ●形式：&lt;og:jspCreate outdir="…" pgid="…" /&gt;
    055 * ●body：なし
    056 *
    057 * ●Tag定義：
    058 *   &lt;og:jspCreate
    059 *       pgid             ○【TAG】プログラムIDを指定します(必須)。
    060 *       outdir             【TAG】作成先のディレクトリを指定します(初期値:HybsSystem#REAL_PATH + "jsp/")
    061 *       hpgid              【TAG】雛形のプログラムIDを指定します
    062 *       useUserDef         【TAG】仮環境を使用するかどうか[true/false]を指定します(初期値:true:使用する)
    063 *       tagNames           【TAG】処理を行うタグを部分指定します(初期値:内部登録タグすべて)
    064 *       tableId            【TAG】(通常は使いません)DBTableModel が登録されているメモリのキーを指定します
    065 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
    066 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    067 *   /&gt;
    068 *
    069 * ●使用例
    070 *    ・先に、query タグでDBTableModel が作成済み
    071 *          &lt;og:jspCreate
    072 *              outdir      = "{&#064;SYS.REAL_PATH}jsp/"    ：出力先フォルダ
    073 *              pgid        = "{&#064;PGID}"                 ：作成画面ID
    074 *              hpgid       = "{&#064;HPGID}"                ：雛形画面ID
    075 *              useUserDef  = "true/false"                   ：仮環境の使用可否(初期値:true 使用する)
    076 *          /&gt;
    077 *
    078 * @og.group 開発補助
    079 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    080 *
    081 * @version  0.9.0  2000/10/17
    082 * @author   Kazuhiko Hasegawa
    083 * @since    JDK1.6,
    084 */
    085public class JspCreateTag extends CommonTagSupport {
    086        /** このプログラムのVERSION文字列を設定します。   {@value} */
    087        private static final String VERSION = "6.5.0.1 (2016/10/21)" ;
    088        private static final long serialVersionUID = 650120161021L ;
    089
    090        private static final String JSP_DIR = HybsSystem.sys( "REAL_PATH" ) + "jsp/" ;          // 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)
    091
    092        private static final String CUST_DEF = "customUserDef/" ;
    093
    094        private transient DBTableModel  table   ;
    095
    096        private String          tableId         = HybsSystem.TBL_MDL_KEY;
    097        private String          outdir          = JSP_DIR;                                              // 出力先フォルダ
    098        private String          pgid            ;                                                               // 作成画面ID
    099        private String          hpgid           ;                                                               // 雛形画面ID
    100        private String[]        tagNames        ;                                                               // 5.6.8.0 (2013/09/06) 処理を行うタグを部分指定
    101        private boolean         useUserDef      = true;                                                 // 仮環境の使用可否(初期値:true 使用する)
    102
    103        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    104        private static final Set<String> JCF_SET = new ArraySet<>( "COMMENT" , "HIDEMENU" , "COLUMN" , "ORDER_BY" , "QUERY" , "VIEW" , "TABLE_UPDATE" );
    105
    106        /**
    107         * デフォルトコンストラクター
    108         *
    109         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    110         */
    111        public JspCreateTag() { super(); }              // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    112
    113        /**
    114         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    115         *
    116         * @return      後続処理の指示(SKIP_BODY)
    117         */
    118        @Override
    119        public int doStartTag() {
    120                table = (DBTableModel)getObject( tableId );
    121
    122                return SKIP_BODY ;                              // Body を評価しない
    123        }
    124
    125        /**
    126         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    127         *
    128         * @return      後続処理の指示
    129         */
    130        @Override
    131        public int doEndTag() {
    132                // デバッグ時には、オブジェクト内部情報を表示する。
    133                if( isDebug() ) {
    134                        debugPrint();
    135                }
    136
    137                final boolean okFlag = execute();
    138
    139                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    140                return okFlag ? EVAL_PAGE : SKIP_PAGE ;
    141
    142        }
    143
    144        /**
    145         * タグリブオブジェクトをリリースします。
    146         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    147         *
    148         * @og.rev 5.6.8.0 (2013/09/06) tagNames 追加
    149         */
    150        @Override
    151        protected void release2() {
    152                super.release2();
    153                table           = null;
    154                tableId         = HybsSystem.TBL_MDL_KEY;
    155                outdir          = JSP_DIR;
    156                pgid            = null;
    157                hpgid           = null;
    158                useUserDef      = true;
    159                tagNames        = null;                                                 // 5.6.8.0 (2013/09/06) 処理を行うタグを部分指定
    160        }
    161
    162        /**
    163         * DBTableModel処理を実行します。
    164         *
    165         * @og.rev 5.2.1.0 (2010/10/01) 実行クラスのクラス名を変更します。 _OG_ を削除
    166         * @og.rev 5.5.2.6 (2012/05/25) findbugs対応。JspConvertEntity.DBKEY を、JspConvertEntity.getDBKEY() に変更。
    167         * @og.rev 5.6.8.0 (2013/09/06) 処理対象タグの部分指定対応 (tagNames 追加)
    168         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    169         * @og.rev 6.4.2.0 (2016/01/29) ex.printStackTrace() を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
    170         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    171         * @og.rev 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    172         *
    173         * @return      処理の実行結果
    174         */
    175        public boolean execute() {
    176
    177                // 出力先(セーブ先)のフォルダ
    178                final File saveDir = useUserDef ? new File( outdir + CUST_DEF , pgid ) : new File( outdir , pgid ) ;
    179
    180                // 雛形(参照元)のフォルダ
    181                final File refDir ;
    182                if( saveDir.exists() ) {                // 出力先フォルダが存在した場合
    183                        refDir = saveDir ;                      // 出力先フォルダが、雛形フォルダになる。
    184                }
    185                else {                                                  // 出力先フォルダが存在しない場合
    186                        refDir = new File( outdir , hpgid );                    // 雛形画面IDをそのまま使用します。
    187                        if( ! saveDir.mkdirs() ) {
    188                                final String errMsg = "出力先のフォルダが作成できませんでした。[" + saveDir + "]" ;
    189                                throw new HybsSystemException( errMsg );
    190                        }
    191                }
    192
    193                if( ! refDir.exists() ) {       // 雛形(参照元)フォルダが存在しない場合、エラー
    194                        final String errMsg = "雛形(参照元)フォルダが存在しません。[" + refDir + "]" ;
    195                        throw new HybsSystemException( errMsg );
    196                }
    197
    198                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
    199                if( table == null ) {
    200                        final String errMsg = "DBTableModel が取得できていません。" + CR
    201                                                        + "   tableId=[" + tableId + "] や、scope=[" + getScope() + "] の確認を行ってください。" ;
    202                        throw new OgRuntimeException( errMsg );
    203                }
    204
    205                final int[] clmNo = getTableColumnNo( JspConvertEntity.getDBKEY() );            // 5.5.2.6 (2012/05/25) findbugs対応
    206                final int rowCnt  = table.getRowCount();
    207
    208                int row = 0;
    209                boolean unCmntSet = true;
    210                String[] data = null;
    211                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
    212                boolean okFlag = false;
    213                try {
    214                        //JSPを書く為に必要な情報を設定
    215                        final Map<String,List<JspConvertEntity>> jceLstMap = new HashMap<>();
    216
    217                        for( row=0; row<rowCnt; row++ ) {
    218                                data = table.getValues( row );
    219                                final JspConvertEntity entry = JspConvertEntity.newInstance( data, clmNo );
    220
    221                                if( entry != null ) {
    222                                        List<JspConvertEntity> array = jceLstMap.get( entry.getType() );
    223                                        if( array == null ) { array = new ArrayList<>(); }
    224                                        array.add( entry );
    225                                        jceLstMap.put( entry.getType(),array );
    226                                        if( unCmntSet ) {
    227                                                jceLstMap.put( "COMMENT",array );
    228                                                unCmntSet = false;
    229                                        }
    230                                }
    231                        }
    232
    233                        // 参照先フォルダから、出力先フォルダに、XMLコピー処理を行います。
    234                        final JspSaxParser spar = new JspSaxParser();
    235
    236                        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    237                        if( tagNames == null ) {
    238                                // tagnames が null の場合は、全項目を使用します。
    239                                for( final String jcf : JCF_SET ) {
    240                                        spar.addFilter( JspCreateFactory.newInstance( jcf , jceLstMap ) );
    241                                }
    242                        }
    243                        else {
    244                                for( final String jcf : tagNames ) {
    245                                        spar.addFilter( JspCreateFactory.newInstance( jcf , jceLstMap ) );
    246                                }
    247                        }
    248
    249                        spar.copyDirectry( refDir,saveDir );
    250
    251                        okFlag = true;
    252                }
    253                catch( final RuntimeException ex ) {
    254                        System.err.println( ThrowUtil.ogStackTrace( ex ) );                             // 6.4.2.0 (2016/01/29)
    255                        // 6.5.0.1 (2016/10/21) ErrorMessage をまとめるのと、直接 Throwable を渡します。
    256                        final ErrorMessage errMessage = new ErrorMessage( "JspCreateTag Error" )
    257                                .addMessage( row+1,ErrorMessage.NG,"JSPOUT"
    258                                        , "PRGID=[" + pgid + "]"
    259                                        , StringUtil.array2csv( data )
    260                                        )
    261                                        .addMessage( ex );
    262                        // BAT から呼び出す場合があるため、標準エラー出力にも情報を出しておきます。
    263                        System.out.println( errMessage );
    264                }
    265
    266                return okFlag;
    267        }
    268
    269        /**
    270         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    271         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    272         *
    273         * @og.tag
    274         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    275         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    276         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    277         * この tableId 属性を利用して、メモリ空間を分けます。
    278         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    279         *
    280         * @param       id テーブルID (sessionに登録する時のID)
    281         */
    282        public void setTableId( final String id ) {
    283                tableId = nval( getRequestParameter( id ),tableId );
    284        }
    285
    286        /**
    287         * 【TAG】作成先のディレクトリを指定します(初期値:HybsSystem#REAL_PATH + "jsp/")。
    288         * @og.tag
    289         * 作成先のディレクトリを指定します。
    290         * 初期値は、実際に実行しているアプリケーションの REAL_PATH + jsp フォルダ以下です。
    291         * 作成先のフォルダも、useUserDef の設定によって異なります。
    292         *
    293         * @og.rev 6.0.2.4 (2014/10/17) メソッド名の統一の為
    294         *
    295         * @param       dir     出力先のディレクトリ
    296         */
    297        public void setOutDir( final String dir ) {
    298                outdir = nval( getRequestParameter( dir ),outdir );
    299        }
    300
    301        /**
    302         * 【TAG】プログラムIDを指定します。
    303         *
    304         * @og.tag
    305         * 作成先のプログラムIDを指定します。
    306         * ただし、作成先の実際のフォルダは、useUserDef の設定によって異なります。
    307         *
    308         * @param       id      プログラムID
    309         */
    310        public void setPgid( final String id ) {
    311                pgid = nval( getRequestParameter( id ),pgid );
    312        }
    313
    314        /**
    315         * 【TAG】雛形のプログラムIDを指定します。
    316         *
    317         * @og.tag
    318         * 雛形のプログラムIDをパースして、実際のプログラムを作成します。
    319         * ただし、作成先の実際のフォルダは、useUserDef の設定によって異なります。
    320         * また、パースするのは、作成先の画面IDのフォルダが存在しない場合のみです。
    321         * すでに、存在している場合は、元の画面IDのフォルダを読み取って、パースを
    322         * 行います。基本的に、作成先のソースを手で修正した場合でも、パースと
    323         * 無関係な箇所の修正はそのまま反映のこされます。
    324         *
    325         * @param       id      雛形のプログラムID
    326         */
    327        public void setHpgid( final String id ) {
    328                hpgid = nval( getRequestParameter( id ),hpgid );
    329        }
    330
    331        /**
    332         * 【TAG】仮環境を使用するかどうか[true/false]を指定します(初期値:true:使用する)。
    333         *
    334         * @og.tag
    335         * true:使用する を設定すると、"customUserDef" フォルダの下に、画面IDの
    336         * フォルダを作成します。
    337         * false:使用しない を設定すると、実際の リアルパス(REAL_PATH/jsp)の下に、
    338         * 画面IDのフォルダを作成します。こちらは、実際の画面と同様に、画面リソース等を
    339         * 作成してアクセスすることになります。
    340         *
    341         * @param       flag    仮環境の使用 [true:使用する/false:使用しない]
    342         */
    343        public void setUseUserDef( final String flag ) {
    344                useUserDef = nval( getRequestParameter( flag ),useUserDef );
    345        }
    346
    347        /**
    348         * 【TAG】処理を行うタグを部分指定します(初期値:内部登録タグすべて)。
    349         *
    350         * @og.tag
    351         * 処理を行うタグは、内部的に、COMMENT,HIDEMENU,COLUMN,ORDER_BY,QUERY,VIEW,TABLE_UPDATE だけ
    352         * 予約されており、初期値は、すべてのタグを処理します。
    353         * ここでは、その一部のみ実行できるように、CSV形式で指定できるようにします。
    354         * 実行不可のタグ名を指定すると、エラーになります。
    355         *
    356         * @og.rev 5.6.8.0 (2013/09/06) 新規追加
    357         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
    358         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    359         *
    360         * @param       tags    処理を行うタグを部分指定
    361         */
    362        public void setTagNames( final String tags ) {
    363                final String tagNms = nval( getRequestParameter( tags ),null );
    364
    365                if( tagNms != null ) {
    366                        tagNames = tagNms.split( "," );
    367
    368                        for( int i=0; i<tagNames.length; i++ ) {
    369                                final String tag = tagNames[i].trim().toUpperCase(Locale.JAPAN);
    370                                if( ! check( tag, JCF_SET ) ) {
    371                                        final String errMsg = "指定の tagNames は、下記の範囲で指定してください。"  + CR
    372                                                                        + "tagNames=[" + tagNms + "] "                                                          + CR
    373                                                                        + "tagNames List=" + String.join( ", " , JCF_SET ) ;
    374                                        throw new HybsSystemException( errMsg );
    375
    376                                }
    377                                tagNames[i] = tag ;             // 大文字に変換した値を戻す。
    378                        }
    379                }
    380        }
    381
    382        /**
    383         *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
    384         *
    385         * @param       nameArray カラム名配列
    386         *
    387         * @return      カラムNo配列(可変長引数)
    388         */
    389        private int[] getTableColumnNo( final String... nameArray ) {
    390                int[] clmNo = new int[nameArray.length];
    391                for( int i=0; i<clmNo.length; i++ ) {
    392                        clmNo[i] = table.getColumnNo( nameArray[i] );
    393                }
    394                return clmNo;
    395        }
    396
    397        /**
    398         * このオブジェクトの文字列表現を返します。
    399         * 基本的にデバッグ目的に使用します。
    400         *
    401         * @return このクラスの文字列表現
    402         * @og.rtnNotNull
    403         */
    404        @Override
    405        public String toString() {
    406                return ToString.title( this.getClass().getName() )
    407                                .println( "VERSION"                     ,VERSION                )
    408                                .println( "tableId"                     ,tableId                )
    409                                .println( "outdir"                      ,outdir                 )
    410                                .println( "pgid"                        ,pgid                   )
    411                                .println( "hpgid"                       ,hpgid                  )
    412                                .println( "useUserDef"          ,useUserDef             )
    413                                .fixForm().toString() ;
    414        }
    415}