    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.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.db.DBTableModel;
    021import org.opengion.hayabusa.db.DBTableModelSorter;
    022import org.opengion.hayabusa.db.DBColumn;
    023import org.opengion.hayabusa.db.DBTableModelUtil;
    024import org.opengion.fukurou.system.DateSet;                                             // 6.4.2.0 (2016/01/29)
    025import org.opengion.fukurou.util.StringUtil;
    026import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    027import org.opengion.fukurou.security.HybsCryptography ;                 // 5.7.4.3 (2014/03/28)
    028import org.opengion.fukurou.model.POIUtil;                                              // 6.2.2.0 (2015/03/27)
    029import org.opengion.fukurou.util.FileInfo;                                              // 6.2.2.0 (2015/03/27)
    030import org.opengion.fukurou.util.FileUtil;                                              // 6.7.4.1 (2017/02/17)
    031import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    032
    033import static org.opengion.fukurou.util.StringUtil.nval ;
    034
    035import java.util.Arrays;
    036import java.io.File;
    037import java.io.FileFilter;
    038import java.io.IOException;
    039
    040/**
    041 * ファイルを検索し、DBTableModel にセットするタグです。
    042 *
    043 * ファイルの検索結果は、[WRITABLE],LEVEL,FILE_TYPE,PARENT,NAME,LASTMODIFIED,FILE_LENGTH,RWH,[MD5],[TO_PARENT,TO_NAME],[････]
    044 * のカラムを持つ DBTableModel にセット されます。このカラムは、固定です。
    045 * 並び替えについては、このタグで指定しますが、ファイルの選別(where 条件)は、
    046 * BODY 部に記述する fileWhere タグで指定します。(複数指定可能))
    047 *
    048 * [カラム名]      検索するファイルの属性は、以下のカラム名で作成されます。
    049 *     [WRITABLE]       useWritable=trueで、先頭カラムに、WRITABLE カラムが挿入されます。
    050 *      LEVEL           ディレクトリを展開する場合のレベル。
    051 *      FILE_TYPE       ファイル(F)かディレクトリ(D)であるか判定。
    052 *      PARENT          この抽象パス名の親のパス名文字列を返します。
    053 *      NAME            この抽象パス名が示すファイルまたはディレクトリの名前を返します。
    054 *      LASTMODIFIED    最後に変更された時刻を返します。
    055 *      FILE_LENGTH     ファイルの長さを返します。
    056 *      RWH             読み込み、書き込み、隠し属性をそれぞれ、ｒ,w,h で表します。
    057 *     [MD5]            useMD5=trueで、MD5 というカラムを追加したうえで、ファイルのMD5計算を行います。
    058 *     [TEXT]           useText=trueで、ファイルの内容を文字列にして、TEXTというカラムに設定します。
    059 *     [TO_PARENT]      useUpdateClms=trueで、fileUpdateタグでCOPYやMOVEを行う時に使用する必須となるカラム(TO_PARENT,TO_NAME)を追加します。
    060 *     [TO_NAME]        同上
    061 *     [････]           addClms属性で指定されたカラムを追加します。
    062 *
    063 * @og.formSample
    064 * ●形式：&lt;og:fileQuery from="…" multi="true/false" &gt;
    065 *             &lt;og:fileWhere … /&gt;
    066 *              …
    067 *         &lt;/og:fileQuery&gt;
    068 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    069 *
    070 * ●Tag定義：
    071 *   &lt;og:fileQuery
    072 *       from             ○【TAG】検索を開始するファイルまたはディレクトリを指定します(必須)。
    073 *       multi              【TAG】多段階展開するか、１レベル展開するかどうか[true:多段階/false:１レベル]を指定します(初期値:false:１レベル)。
    074 *       level              【TAG】多段階展開するレベルを指定します(初期値:100)。
    075 *       orderBy            【TAG】ソートするカラム名を指定します(一つのみ)。
    076 *       desc               【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。
    077 *       useWritable        【TAG】先頭カラムに、WRITABLE カラムを追加するかどうか[true/false]を指定します(初期値:false)。
    078 *       useMD5             【TAG】MD5カラムを追加したうえで、MD5計算を行うかどうか[true/false]を指定します(初期値:false)。
    079 *       useText            【TAG】TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    080 *       useUpdateClms      【TAG】TO_PARENT、TO_NAMEカラムを追加するかどうか[true/false]を指定します(初期値:false)。
    081 *       addClms            【TAG】検索結果のカラム列に追加するカラム名を、CSV形式で指定します。
    082 *       nameOnly           【TAG】ファイルの拡張子を除いた名前部分のみの値で行います。7.2.6.0 (2020/06/30)
    083 *       fileType           【TAG】選択対象[FILE/DIR]を指定します。下位展開は考慮(multi 属性準拠)されます。
    084 *       addFrom            【TAG】from属性で指定された基準ファイル/フォルダ自体をリストに追加するかどうか[true/false]を指定します(初期値:true)。
    085 *       fromBase           【TAG】検索結果のPARENT列から、fromBase指定のﾊﾟｽを削除した相対ﾊﾟｽを作成します。  (7.0.2.1 (2019/03/04))
    086 *       command            【TAG】コマンド (NEW,RENEW)をセットします("NEW" と "RENEW" 時のみ実行する(初期値:NEW))。
    087 *       maxRowCount        【TAG】(通常は使いません)データの最大読み込み件数を指定します (初期値:DB_MAX_ROW_COUNT[=1000])(0:[無制限])。
    088 *       displayMsg         【TAG】検索結果を画面上に表示するメッセージリソースIDを指定します (初期値:VIEW_DISPLAY_MSG[=])
    089 *       overflowMsg        【TAG】検索データが最大検索数をオーバーした場合に表示するメッセージリソースIDを指定します (初期値:MSG0007[検索結果が、制限行数を超えましたので、残りはカットされました])。
    090 *       notfoundMsg        【TAG】検索結果がゼロ件の場合に表示するメッセージリソースIDを指定します(初期値:MSG0077[対象データはありませんでした])。
    091 *       stopZero           【TAG】検索結果が０件のとき処理を続行するかどうか[true/false]を指定します(初期値:false[続行する])
    092 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    093 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)。
    094 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    095 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 6.8.0.0 (2017/06/02)
    096 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 6.8.0.0 (2017/06/02)
    097 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
    098 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
    099 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
    100 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)。
    101 *   &gt;   ... Body ...
    102 *   &lt;/og:fileQuery&gt;
    103 *
    104 * ●使用例
    105 *    ・一般的な属性でファイルの検索を行います。
    106 *         &lt;og:fileQuery
    107 *                from    = "d:/webapps/dbdef/jsp/"
    108 *                multi   = "true"
    109 *                command = "{&#064;command}"  &gt;
    110 *            &lt;og:fileWhere endWith=".jsp" /&gt;
    111 *      &lt;/og:fileQuery&gt;
    112 *
    113 *    ・最終変更日で逆順ソートする。対象は、2002/10/01 以降に変更されたファイル。
    114 *        &lt;og:fileQuery
    115 *                from    = "d:/webapps/dbdef/jsp/"
    116 *                multi   = "true"
    117 *                orderBy = "LASTMODIFIED"
    118 *                desc    = "true"
    119 *                command = "{&#064;command}"  &gt;
    120 *            &lt;og:fileWhere lastModified="20021001000000" /&gt;
    121 *        &lt;/og:fileQuery&gt;
    122 *
    123 * @og.rev 4.0.0.0 (2005/01/31) 内部ロジック改定
    124 * @og.group その他入力
    125 *
    126 * @version  4.0
    127 * @author       Kazuhiko Hasegawa
    128 * @since    JDK5.0,
    129 */
    130public class FileQueryTag extends QueryTag {
    131        /** このプログラムのVERSION文字列を設定します。   {@value} */
    132        private static final String VERSION = "7.2.6.0 (2020/06/30)" ;
    133        private static final long serialVersionUID = 726020200630L ;
    134
    135        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    136        private static final ArraySet<String> SELECT_SET = new ArraySet<>( "LEVEL","FILE_TYPE","PARENT","NAME","LASTMODIFIED","FILE_LENGTH","RWH" );
    137
    138        private static final String[] USE_UPDATE_CLM = { "TO_PARENT","TO_NAME" };       // 5.3.4.0 (2011/04/01)
    139
    140        private transient FileFilter filter     ;                                               // FileWhere で指定したフィルター
    141
    142        private boolean         multi                   ;                                               // 下位層展開ﾌﾗｸﾞ
    143        private int                     level                   = 100;                                                  // 展開ﾚﾍﾞﾙ
    144        private String      from                        = HybsSystem.sys( "FILE_URL" ); // 検索起点ﾌｧｲﾙ
    145        private String          orderBy                 ;                                               // 5.3.4.0 (2011/04/01) ソートカラム
    146        private boolean         desc                    ;                                               // 5.3.4.0 (2011/04/01) ソートの方向(true:逆順)
    147        private String[]        addClms                 = new String[0];                // 5.3.4.0 (2011/04/01) 追加カラム配列
    148        private String[]        defClms                 ;                                               // 5.7.4.3 (2014/03/28) 初期値のカラム配列
    149        private String          fileType                ;                                               // 5.3.4.0 (2011/04/01) 選択対象を指定(FILE,DIR)
    150        private boolean         useWritable             ;                                               // 5.7.4.3 (2014/03/28) 先頭カラムに、WRITABLE カラムを追加するかどうか[true/false](初期値:false)
    151        private boolean         useMD5                  ;                                               // 5.7.4.3 (2014/03/28) MD5カラムを追加したうえで、MD5計算を行うかどうか[true/false](初期値:false)
    152        private boolean         useText                 ;                                               // 6.2.2.0 (2015/03/27) TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    153        private boolean         useUpdateClms   ;                                               // 5.3.4.0 (2011/04/01) TO_PARENT、TO_NAMEカラムを追加(true:追加)
    154        private boolean         addFrom                 = true;                                 // 5.3.9.0 (2011/09/01) from属性で指定された基準ファイル/フォルダ自体をリストに追加するかどうか
    155        private int                     fromLen                 = -1;                                   // 7.0.2.1 (2019/03/04) fromBase の文字数をPARENTから削除するための数
    156        private boolean         nameOnly                ;                                               // 7.2.6.0 (2020/06/30) ファイルの拡張子を除いた名前部分のみの値で行います。
    157
    158        /**
    159         * デフォルトコンストラクター
    160         *
    161         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    162         */
    163        public FileQueryTag() { super(); }              // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    164
    165        /**
    166         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    167         *
    168         * タグ本体が空の場合は、呼ばれないので、従来の doAfterBody() 処理を、
    169         * doEndTag() に持っていきます。
    170         * よって、親クラスの doAfterBody() を実行させないため、このメソッドを用意しています。
    171         *
    172         * @og.rev 6.7.4.1 (2017/02/17) 親クラスの処理を、実行させない。
    173         *
    174         * @return      後続処理の指示(SKIP_BODY)
    175         */
    176        @Override
    177        public int doAfterBody() {
    178                return SKIP_BODY ;
    179        }
    180
    181        /**
    182         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    183         *
    184         * タグ本体が空の場合は、呼ばれないので、従来の doAfterBody() 処理を、
    185         * doEndTag() に持っていきます。
    186         *
    187         * @og.rev 6.7.4.1 (2017/02/17) 従来の doAfterBody() 処理を、doEndTag() に持ってくる。
    188         * @og.rev 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
    189         *
    190         * @return      後続処理の指示
    191         */
    192        @Override
    193        public int doEndTag() {
    194                if( !useTag() ) { return SKIP_BODY ; }  // 6.8.0.0 (2017/06/02)
    195
    196                executeCount = 0;
    197
    198                table = initDBTable();
    199                if( maxRowCount < 0 ) {
    200                        maxRowCount     = sysInt( "DB_MAX_ROW_COUNT" ) ;
    201                }
    202
    203                // 5.3.5.0 (2011/05/01) 最初のファイルが存在する場合のみ、実行する。
    204                final File fin = new File( from );
    205                if( fin.exists() ) {
    206                        // 7.0.2.1 (2019/03/04) 検索結果のPARENT列から、from指定のﾊﾟｽを削除した相対ﾊﾟｽを作成
    207
    208                        execute( fin,0 ) ;
    209
    210                        // 5.3.4.0 (2011/04/01) 指定カラムのソート処理
    211                        if( orderBy != null ) {
    212                                final int clmNo = table.getColumnNo( orderBy );
    213                                final DBTableModelSorter temp = new DBTableModelSorter();
    214                                temp.setModel( table );
    215                                temp.sortByColumn( clmNo,!desc );       // 注意 desc の値と ソート正逆は、反対です。
    216                                table = temp;
    217                        }
    218                }
    219                return super.doEndTag();
    220        }
    221
    222        /**
    223         * タグリブオブジェクトをリリースします。
    224         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    225         *
    226         * @og.rev 5.3.4.0 (2011/04/01) 指定カラムのソート処理機能、カラム追加機能、fileType追加
    227         * @og.rev 5.3.9.0 (2011/09/01) addFrom属性追加
    228         * @og.rev 5.7.4.3 (2014/03/28) useWritable,useMD5属性追加。valClms を defClms に置き換え。
    229         * @og.rev 6.2.2.0 (2015/03/27) useText属性追加。
    230         * @og.rev 7.0.2.1 (2019/03/04) fromBase属性追加に伴い、fromLen変数を用意。
    231         * @og.rev 7.2.6.0 (2020/06/30) nameOnly 属性 を追加します。
    232         */
    233        @Override
    234        protected void release2() {
    235                super.release2();
    236                filter                  = null;
    237                multi                   = false;
    238                level                   = 100;
    239                from                    = HybsSystem.sys( "FILE_URL" );
    240                orderBy                 = null;                         // 5.3.4.0 (2011/04/01) ソートカラム
    241                desc                    = false;                        // 5.3.4.0 (2011/04/01) 降順ﾌﾗｸﾞ
    242                addClms                 = new String[0];        // 5.3.4.0 (2011/04/01) 追加カラム配列
    243                defClms                 = null;                         // 5.7.4.3 (2014/03/28) 初期値のカラム配列
    244                fileType                = null;                         // 5.3.4.0 (2011/04/01) 選択対象を指定(FILE,DIR,ALL)
    245                useWritable             = false;                        // 5.7.4.3 (2014/03/28) 先頭カラムに、WRITABLE カラムを追加するかどうか[true/false](初期値:false)
    246                useMD5                  = false;                        // 5.7.4.3 (2014/03/28) MD5カラムを追加したうえで、MD5計算を行うかどうか[true/false](初期値:false)
    247                useText                 = false;                        // 6.2.2.0 (2015/03/27) TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    248                useUpdateClms   = false;                        // 5.3.4.0 (2011/04/01) TO_PARENT、TO_NAMEカラムを追加(true:追加)
    249                addFrom                 = true;                         // 5.3.9.0 (2011/09/01) addFrom属性追加
    250                fromLen                 = -1;                           // 7.0.2.1 (2019/03/04) fromBase の文字数をPARENTから削除するための数
    251                nameOnly                = false;                        // 7.2.6.0 (2020/06/30) ファイルの拡張子を除いた名前部分のみの値で行います。
    252        }
    253
    254        /**
    255         * FileQuery を実行します。
    256         *
    257         * @og.rev 5.3.4.0 (2011/04/01) fileType の条件に合致する場合だけ、データを作成する。
    258         * @og.rev 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、null となるのでその対応
    259         * @og.rev 7.0.2.1 (2019/03/04) fromBase属性追加に伴い、fromLen変数を用意。
    260         *
    261         * @param       fin     検索を開始するファイル/ディレクトリ
    262         * @param       lvl     階層展開レベル
    263         */
    264        protected void execute( final File fin,final int lvl ) {
    265                if( !multi && lvl > 1 || lvl > level ) { return; }                      // 階層展開する、しない   // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
    266                if( executeCount > maxRowCount ) { table.setOverflow( true ); return; }
    267
    268                final boolean isDIR = fin.isDirectory();
    269
    270                if(             fileType == null
    271                        ||  isDIR &&  "DIR".equalsIgnoreCase( fileType )
    272                        || !isDIR && "FILE".equalsIgnoreCase( fileType ) ) {
    273                                // 6.0.2.4 (2014/10/17) RpC:条件テストを繰り返しています。
    274                                if( addFrom || lvl > 0 ) {
    275                                        addFileData( executeCount++,lvl,fin );
    276                                }
    277                }
    278                if( isDIR ) {
    279                        final File[] list = fin.listFiles( filter );
    280                        // 5.3.7.0 (2011/07/01) フォルダにアクセスできない場合は、null となる。
    281                        if( list != null ) {
    282                                for( int i=0; i<list.length; i++ ) {
    283                                        execute( list[i],lvl+1 );
    284                                }
    285                        }
    286                }
    287        }
    288
    289        /**
    290         * 初期化された DBTableModel を返します。
    291         *
    292         * ここでは、useWritable、useMD5、useUpdateClms、addClms を加味した
    293         * DBTableModel と初期値データ(defClms)を作成します。
    294         * 以前は、TO_PARENT、TO_NAMEと、addClms 分のみ初期値を持っていましたが、
    295         * 5.7.4.3 (2014/03/28)で、先頭カラムのWRITABLEの初期値を、DBColumn の初期値ではなく
    296         * 手動設定する必要がある為、すべてのカラム列の初期値を持っておきます。
    297         *
    298         * @og.rev 5.3.4.0 (2011/04/01) 指定カラム追加機能追加
    299         * @og.rev 5.7.4.3 (2014/03/28) useWritable,useMD5属性追加
    300         * @og.rev 6.2.2.0 (2015/03/27) TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    301         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    302         * @og.rev 7.0.2.1 (2019/03/04) 追加カラムの位置のアドレス指定が間違っていた。
    303         *
    304         * @return       テーブルモデル
    305         */
    306        private DBTableModel initDBTable() {
    307                final DBTableModel tbl = DBTableModelUtil.newDBTable();
    308
    309                // 5.7.4.3 (2014/03/28) 以下の処理は、ほぼ全面見直し
    310                int size = SELECT_SET.size() ;                                                  // 6.4.3.4 (2016/03/11) 基本カラムの数
    311
    312                if( useWritable   ) { size++ ; }                                                // WRITABLE カラムを追加
    313                if( useMD5        ) { size++ ; }                                                // MD5 カラムを追加
    314                if( useText       ) { size++ ; }                                                // 6.2.2.0 (2015/03/27) TEXT カラムを追加
    315                if( useUpdateClms ) { size += USE_UPDATE_CLM.length; }  // TO_PARENT、TO_NAMEカラムを追加
    316                size += addClms.length ;                                                                // addClms(追加カラム)数を追加
    317
    318                // DBTableModel の初期化と、初期値配列の確保
    319                tbl.init( size );
    320                defClms = new String[size];
    321
    322                int ad=0;
    323                // 先頭は、WRITABLE
    324                if( useWritable ) {
    325                        final DBColumn dbColumn = getDBColumn( "WRITABLE" );
    326                        defClms[ad] = "1";                                                                      // WRITABLE を設定するときは、とりあえず 書き込み許可
    327                        tbl.setDBColumn( ad++,dbColumn );
    328                }
    329
    330                // SELECT の 基本カラムの設定。(初期値は不要)
    331                // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    332                // オリジナルの forEach。カウンタ初期値とラムダ式を与えると、ラムダ式の引数に、カウンタと値が設定される。
    333                SELECT_SET.forEach( ad , (i,v) -> {
    334                        final DBColumn dbColumn = getDBColumn( v );
    335                        tbl.setDBColumn( i,dbColumn );
    336                } );
    337
    338                ad += SELECT_SET.size();                                                                // 7.0.2.1 (2019/03/04)
    339
    340                // MD5 カラムを追加。
    341                if( useMD5 ) {
    342                        final DBColumn dbColumn = getDBColumn( "MD5" );
    343                        defClms[ad] = "";                                                                       // ディレクトリの場合は、MD5計算しません。
    344                        tbl.setDBColumn( ad++,dbColumn );
    345                }
    346
    347                // 6.2.2.0 (2015/03/27) TEXT カラムを追加
    348                if( useText ) {
    349                        final DBColumn dbColumn = getDBColumn( "TEXT" );
    350                        defClms[ad] = "";                                                                       // ディレクトリの場合は、TEXT計算しません。
    351                        tbl.setDBColumn( ad++,dbColumn );
    352                }
    353
    354                // TO_PARENT、TO_NAMEカラムを追加
    355                if( useUpdateClms ) {
    356                        for( int i=0; i<USE_UPDATE_CLM.length; i++ ) {
    357                                final DBColumn dbColumn = getDBColumn( USE_UPDATE_CLM[i] );
    358                                defClms[ad] = dbColumn.getDefault();                    // 初期値を指定しておく
    359                                tbl.setDBColumn( ad++,dbColumn );
    360                        }
    361                }
    362
    363                // 追加カラムのaddClmsカラムを追加
    364                for( int i=0; i<addClms.length; i++ ) {
    365                        final DBColumn dbColumn = getDBColumn( addClms[i] );
    366                        defClms[ad] = dbColumn.getDefault();                                    // 初期値を指定しておく
    367                        tbl.setDBColumn( ad++,dbColumn );
    368                }
    369
    370                return tbl ;
    371        }
    372
    373        /**
    374         * DBTableModel に、ファイル情報をセットします。
    375         * ファイル情報は、[WRITABLE],LEVEL,FILE_TYPE,PARENT,NAME,LASTMODIFIED,FILE_LENGTH,RWH,[MD5],[TO_PARENT,TO_NAME],[････] です。
    376         *
    377         * useWritable=true の場合、先頭カラムに、WRITABLE カラムを追加します。
    378         * useMD5=true の場合、MD5カラムを追加したうえで、MD5計算を行います(ファイルのみ計算します)。
    379         * useUpdateClms=true の場合TO_PARENT、TO_NAMEカラムを追加します。
    380         * addClms で指定されたカラムをその後ろに追加します。
    381         *
    382         * @og.rev 5.3.4.0 (2011/04/01) 指定カラム追加機能追加
    383         * @og.rev 5.7.4.3 (2014/03/28) useWritable,useMD5属性追加
    384         * @og.rev 6.2.2.0 (2015/03/27) TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    385         * @og.rev 6.2.3.0 (2015/05/01) POIUtil のメソッド名変更に伴う対応
    386         * @og.rev 6.2.4.2 (2015/05/29) POIUtil#extractor の判定方法変更
    387         * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します。
    388         * @og.rev 7.0.2.1 (2019/03/04) fromLen属性追加。
    389         * @og.rev 7.1.0.0 (2020/01/20) fromLen属性で、CanonicalFileで区切り文字'￥'が消えるため、そのため、PARENTに'￥'が残る現象の対応。
    390         * @og.rev 7.2.6.0 (2020/06/30) nameOnly 属性 を追加します。
    391         *
    392         * @param       rowNo   セットする行番号
    393         * @param       lvl     セットするレベル
    394         * @param       fin             ファイル情報の元となるファイルオブジェクト
    395         */
    396        private void addFileData( final int rowNo,final int lvl,final File fin ) {
    397                try {
    398                        final File file = fin.getCanonicalFile();
    399
    400                        final String rwh = (    file.canRead()  ? "r" : "-" )
    401                                                +       ( file.canWrite() ? "w" : "-" )
    402                                                +       ( file.isHidden() ? "h" : "-" );
    403
    404                        final String lastModified = DateSet.getDate( file.lastModified(),"yyyyMMddHHmmss" );                            // 6.4.2.0 (2016/01/29)
    405
    406                        final boolean isF = file.isFile();                                                      // File=true,それ以外=false
    407
    408                        final int size = table.getColumnCount() ;
    409                        String[] data = Arrays.copyOf( defClms,size );                          // JDK1.6
    410
    411                        int ad=0;
    412                        if( useWritable ) { ad++ ; }            // 単にひとつ進める。初期値はセット済み。
    413
    414                        // SELECT の 基本カラムの設定
    415                        data[ad++] = String.valueOf( lvl ) ;                                            // LEVEL
    416                        data[ad++] = isF ? "F" : "D" ;                                                          // FILE_TYPE
    417                        // 7.0.2.1 (2019/03/04) 検索結果のPARENT列から、from指定のﾊﾟｽを削除した相対ﾊﾟｽを作成
    418                        final String parent = file.getParent() ;                                                        // PARENTの元(正規パス)
    419//                      data[ad++] = fromLen > 0 ? parent.substring( fromLen ) : parent ;       // PARENT
    420                        data[ad++] = fromLen > 0 ? ( parent.length() < fromLen ? "" : parent.substring( fromLen ) ) : parent ;  // PARENT 7.1.0.0 (2020/01/20)
    421
    422                        // 7.2.6.0 (2020/06/30) nameOnly 属性 を追加します。
    423                        String fname = file.getName() ;                                                         // NAME
    424                        if( nameOnly ) {
    425                                final int idx = fname.lastIndexOf( '.' );
    426                                if( idx >= 0 ) { fname = fname.substring( 0,idx ); }
    427                        }
    428//                      data[ad++] = file.getName() ;                                                           // NAME
    429                        data[ad++] = fname ;                                                                            // NAME
    430                        data[ad++] = lastModified ;                                                                     // LASTMODIFIED
    431                        data[ad++] = String.valueOf( FileUtil.length( file ) );         // FILE_LENGTH 6.7.4.1 (2017/02/17) DIRの容量も計算する
    432                        data[ad++] = rwh ;                                                                                      // RWH
    433
    434                        // MD5 カラムを追加(ファイルの場合のみ計算します)
    435                        if( useMD5 && isF ) {
    436                                data[ad++] = HybsCryptography.getMD5( file );
    437                        }
    438
    439                        // 6.2.2.0 (2015/03/27) TEXT カラムを追加(ファイルの場合のみ取り込みます)
    440                        if( useText && isF ) {
    441                                final String sufix = FileInfo.getSUFIX( file ) ;
    442                                String val = "";
    443                                try {
    444                                        if( POIUtil.isPOI( file ) ) {                                           // 6.2.4.2 (2015/05/29)
    445                                                val = POIUtil.extractor( file );
    446                                        }
    447                                        else if( "txt,jsp,java,xml,css,js".contains( sufix ) ) {
    448                                                val = POIUtil.extractor( file , "UTF-8");                               // 6.2.3.0 (2015/05/01)
    449                                        }
    450                                        else {
    451                                                val = POIUtil.extractor( file , "Windows-31J");                 // 6.2.3.0 (2015/05/01)
    452                                        }
    453                                }
    454                                catch( final RuntimeException ex ) {
    455                                        // 変換に失敗しても、処理は継続する。
    456                                        final String errMsg = "ファイルのテキスト変換に失敗しました。[" + fin + "]"
    457                                                                + " ROW=[" + rowNo + "]"
    458                                                                + CR + ex.getMessage();
    459                                        System.err.println( errMsg );
    460                                }
    461                                data[ad++] = val;
    462                        }
    463
    464                        // useUpdateClms=true 時の TO_PARENT、TO_NAMEカラムや、addClmsの追加カラムは、初期値のみセット
    465                        // 初期値セットは、Arrays.copyOf で、defClms のコピーで完了。
    466
    467                        table.addColumnValues( data );
    468                }
    469                catch( final IOException ex ) {
    470                        final String errMsg = "正式なファイル名の取得に失敗しました。[" + fin + "]"
    471                                                + " ROW=[" + rowNo + "]"
    472                                                + CR + ex.getMessage();
    473                        throw new HybsSystemException( errMsg,ex );
    474                }
    475        }
    476
    477        /**
    478         * 【TAG】ファイルの検索元となるディレクトリを指定します
    479         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
    480         *
    481         * @og.tag ファイルの検索元となるディレクトリを指定します。
    482         *
    483         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
    484         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
    485         * @og.rev 6.4.2.1 (2016/02/05) HybsSystem.url2dir に引数追加。
    486         *
    487         * @param       url ファイルの検索元となるディレクトリ
    488         */
    489        public void setFrom( final String url ) {
    490                final String furl = nval( getRequestParameter( url ),null );
    491                from = HybsSystem.url2dir( from,furl,"." );                     // 6.4.2.1 (2016/02/05)
    492        }
    493
    494        /**
    495         * 【TAG】多段階展開するか、１レベル展開するかどうか[true/false]を指定します(初期値:false)。
    496         *
    497         * @og.tag
    498         * 初期値は、false (１レベル) です。
    499         *
    500         * @param       mlti 多段階展開するか [true:する/false:１レベル]
    501         */
    502        public void setMulti( final String mlti ) {
    503                multi = nval( getRequestParameter( mlti ),multi );
    504        }
    505
    506        /**
    507         * 【TAG】多段階展開するレベルを指定します(初期値:100)。
    508         *
    509         * @og.tag
    510         *
    511         * @param       lvl 多段階展開するレベル
    512         */
    513        public void setLevel( final String lvl ) {
    514                level = nval( getRequestParameter( lvl ),level );
    515        }
    516
    517        /**
    518         * 【TAG】ソートするカラム名を指定します(一つのみ)。
    519         *
    520         * @og.tag
    521         * ソートするカラム名を、"LEVEL","FILE_TYPE","PARENT","NAME","LASTMODIFIED","FILE_LENGTH","RWH"
    522         * から一つ選びます。
    523         * これは、複数カラムでのソートはできません。
    524         * 逆順にソートする場合は、desc属性を true にセットください。
    525         * + をつけても、無効(カラム名がないということ)でエラーになります。
    526         *
    527         * @og.rev 5.3.4.0 (2011/04/01) 新規追加
    528         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
    529         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    530         *
    531         * @param       clm ソートするカラム名 (一つのみ、逆順はマイナスを付ける)
    532         * @see         #setDesc( String )
    533         */
    534        public void setOrderBy( final String clm ) {
    535                orderBy = nval( getRequestParameter( clm ),orderBy );
    536
    537                if( orderBy != null && ! check( orderBy, SELECT_SET ) ) {
    538                        final String errMsg = "指定の orderBy は、指定できません。" + CR
    539                                                        + "orderBy=[" + orderBy + "] "                          + CR
    540                                                        + "orderByList=" + String.join( ", " , SELECT_SET ) ;
    541                        throw new HybsSystemException( errMsg );
    542                }
    543        }
    544
    545        /**
    546         * 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。
    547         *
    548         * @og.tag
    549         * orderBy 属性で指定した表示順を、逆順にするかどうかを指定できます。
    550         * 初期値は、false (昇順) です。
    551         *
    552         * @og.rev 5.3.4.0 (2011/04/01) 新規追加
    553         *
    554         * @param       flag 表示順逆順 [逆順:true/正順:false]
    555         * @see         #setOrderBy( String )
    556         */
    557        public void setDesc( final String flag ) {
    558                desc = nval( getRequestParameter( flag ),desc );
    559        }
    560
    561        /**
    562         * 【TAG】先頭カラムに、WRITABLE カラムを追加するかどうか[true/false]を指定します(初期値:false)。
    563         *
    564         * @og.tag
    565         * ファイル検索結果の１レコード単位に、書き込み許可/禁止属性を付けるには、
    566         * カラム列の先頭に、WRITABLE カラムを追加する必要があります。
    567         * 初期値は、false (追加しない) です。
    568         *
    569         * @og.rev 5.7.4.3 (2014/03/28) 新規追加
    570         *
    571         * @param       flag WRITABLEカラム追加 [true:する/false:しない]
    572         */
    573        public void setUseWritable( final String flag ) {
    574                useWritable = nval( getRequestParameter( flag ),useWritable );
    575        }
    576
    577        /**
    578         * 【TAG】MD5カラムを追加したうえで、MD5計算を行うかどうか[true/false]を指定します(初期値:false)。
    579         *
    580         * @og.tag
    581         * ファイルの改変等をチェックするには、ファイルのハッシュ値を拾う必要があります。
    582         * タイムスタンプとサイズ（LASTMODIFIED,FILE_LENGTH）でも、類似の処理は可能ですが、
    583         * より、厳密な一致をみるなら、MD5でハッシュした結果を突き合わせるのがベストです。
    584         * useMD5=true に設定すると、MD5 というカラムを追加したうえで、MD5計算結果をセットします。
    585         * 初期値は、false (追加しない) です。
    586         *
    587         * @og.rev 5.7.4.3 (2014/03/28) 新規追加
    588         *
    589         * @param       flag MD5カラム追加 [true:する/false:しない]
    590         */
    591        public void setUseMD5( final String flag ) {
    592                useMD5 = nval( getRequestParameter( flag ),useMD5 );
    593        }
    594
    595        /**
    596         * 【TAG】TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    597         *
    598         * @og.tag
    599         * ファイルの内容を取得する場合に、true に設定します。
    600         * 初期値は、false (追加しない) です。
    601         *
    602         * @og.rev 6.2.2.0 (2015/03/27) TEXTカラムを追加したうえで、ファイルの内容を読み込むかどうか[true/false]を指定します(初期値:false)。
    603         *
    604         * @param       flag TEXTカラム追加 [true:する/false:しない]
    605         */
    606        public void setUseText( final String flag ) {
    607                useText = nval( getRequestParameter( flag ),useText );
    608        }
    609
    610        /**
    611         * 【TAG】TO_PARENT、TO_NAMEカラムを追加するかどうか[true/false]を指定します(初期値:false)。
    612         *
    613         * @og.tag
    614         * fileUpdateタグでは、ファイルのCOPYやMOVEが出来ますが、そのコピー先、移動先の
    615         * ファイルを行ごとに指定する場合、TO_PARENT、TO_NAMEカラムという固定名のカラムが
    616         * 必要です。
    617         * これを、addClms 属性で指定する代わりに、この属性で、true をセットすることで、
    618         * 自動的に追加されます。
    619         * 初期値は、false (追加しない) です。
    620         *
    621         * @og.rev 5.3.4.0 (2011/04/01) 新規追加
    622         *
    623         * @param       flag TO_PARENT、TO_NAMEカラム追加 [true:追加する/false:追加しない]
    624         * @see         #setAddClms( String )
    625         * @see         org.opengion.hayabusa.taglib.FileUpdateTag
    626         */
    627        public void setUseUpdateClms( final String flag ) {
    628                useUpdateClms = nval( getRequestParameter( flag ),useUpdateClms );
    629        }
    630
    631        /**
    632         * 【TAG】検索結果のカラム列に追加するカラム名を、CSV形式で指定します。
    633         *
    634         * @og.tag
    635         * デフォルトのカラム名、[WRITABLE],LEVEL,FILE_TYPE,PARENT,NAME,LASTMODIFIED,FILE_LENGTH,RWH,[MD5],[TO_PARENT,TO_NAME]
    636         * 以外に、指定のカラム名を追加することが可能です。
    637         * これは、ファイル検索結果以外の項目を追加して、データベースに書き込む場合に、利用できます。
    638         * 並び順は、デフォルトカラムの後ろに、指定のカラムの順番で付きます。
    639         * ここで追加したカラムには、カラムリソースの初期値がセットされます。
    640         *
    641         * @og.rev 5.3.4.0 (2011/04/01) 新規追加
    642         *
    643         * @param       clms 追加するカラム名(CSV形式)
    644         * @see         #setUseUpdateClms( String )
    645         */
    646        public void setAddClms( final String clms ) {
    647                final String tmpClms = nval( getRequestParameter( clms ),null );
    648                if( tmpClms != null && tmpClms.length() > 0 ) {
    649                        addClms = StringUtil.csv2Array( tmpClms );
    650                }
    651        }
    652
    653        /**
    654         * 【TAG】ファイル名が、指定されたファイルタイプ[DIR/FILE]と一致した場合、スルー(選択)されます(初期値:null)。
    655         * @og.tag
    656         * 大文字小文字は区別しません。
    657         * ファイルタイプ は、DIR,FILE が指定できます。
    658         * DIR は、ディレクトリのみ検索します。(階層下がりも行います)
    659         * FILEは、ファイルのみ検索します。(階層下がりも行います)
    660         * 引数が null の場合は、追加しません。(つまり、すべてスルーされます。)
    661         *
    662         * @og.rev 5.3.4.0 (2011/04/01) fileType メソッドで選択対象指定の追加
    663         *
    664         * @param    str ファイルタイプ [null:スルー/DIR:ディレクトリのみ検索/FILE:ファイルのみ検索]
    665         */
    666        public void setFileType( final String str ) {
    667                final String tmp = nval( getRequestParameter( str ),fileType );
    668                if( tmp == null                                         ||
    669                        "DIR".equalsIgnoreCase( tmp )   ||
    670                        "FILE".equalsIgnoreCase( tmp ) ) {
    671                                fileType = tmp;
    672                }
    673                else {
    674                        // ファイルタイプに不正な値が設定された場合は、エラーになる。
    675                        final String errMsg = "この、fileType 属性には、DIR,FILE 以外は指定できません。["
    676                                                + tmp + "]";
    677                        throw new HybsSystemException( errMsg );
    678                }
    679        }
    680
    681        /**
    682         * 【TAG】from属性で指定された基準ファイル/フォルダ自体をリストに追加するかどうか[true/false]を指定します(初期値:true)。
    683         * @og.tag
    684         * 初期値はtrue(追加する)です。
    685         *
    686         * @og.rev 5.3.9.0 (2011/09/01) 新規作成
    687         *
    688         * @param    flag 基準をリストに追加するかどうか [true:追加する/false:追加しない]
    689         */
    690        public void setAddFrom( final String flag ) {
    691                addFrom = nval( getRequestParameter( flag ),addFrom );
    692        }
    693
    694        /**
    695         * 【TAG】検索結果のPARENT列から、fromBase指定のﾊﾟｽを削除した相対ﾊﾟｽを作成します。
    696         * @og.tag
    697         * 実ﾌｧｲﾙをURL化する場合に、階層をスキャンしたPARENTから、fromBase分の文字列を削除します。
    698         * PARENTに相対ﾊﾟｽを指定することが可能になります。
    699         * 元となるﾌｧｲﾙﾊﾟｽは、getCanonicalFile() で作成した正規パス名になるため、
    700         * fromBase のﾊﾟｽの文字数も、同様に正規パス名から作成します。
    701         *
    702         * @og.rev 7.0.2.1 (2019/03/04) fromBase属性追加に伴い、fromLen変数を用意。
    703         * @og.rev 7.0.5.0 (2019/09/16) fromBase のﾊﾟｽの文字数も、正規パス名から作成。
    704         * @og.rev 7.1.0.0 (2020/01/20) fromLen属性で、CanonicalFileで区切り文字'￥'が消えるため、そのため、PARENTに'￥'が残る現象の対応。
    705         *
    706         * @param    base PARENT列から、fromBase指定のﾊﾟｽを削除した相対ﾊﾟｽを作成
    707         */
    708        public void setFromBase( final String base ) {
    709                final String fromBase = nval( getRequestParameter( base ),null );
    710                if( fromBase != null ) {
    711                        // 7.0.5.0 (2019/09/16) fromBase のﾊﾟｽの文字数も、正規パス名から作成。
    712//                      fromLen = fromBase.length();
    713                        try {
    714                                fromLen = new File(fromBase).getCanonicalPath().length();               // 7.0.5.0 (2019/09/16)
    715                                // 7.1.0.0 (2020/01/20)
    716                                final char ch = fromBase.charAt( fromBase.length()-1 );
    717                                if( ch == '\\' || ch == '/' ) { fromLen++; }                                    // getCanonicalPathでは、最後の区切り記号が消える
    718                        }
    719                        catch( final IOException ex ) {
    720                                final String errMsg = "fromBaseの正式なファイル名の取得に失敗しました。[" + base + "]"
    721                                                        + CR + ex.getMessage();
    722                                throw new HybsSystemException( errMsg,ex );
    723                        }
    724                }
    725        }
    726
    727        /**
    728         * 【TAG】ファイルの拡張子を除いた名前部分のみの値で行います(初期値:false)。
    729         *
    730         * @og.tag
    731         * ファイル検索の値を、ファイルの拡張子を取り除いた値のみで、作成します。
    732         * 初期値は、false (拡張子付きファイル名でリスト) です。
    733         *
    734         * @og.rev 7.2.6.0 (2020/06/30) nameOnly 属性 を追加します。
    735         *
    736         * @param       flag ファイルの拡張子を除いた名前部分のみで作成するかどうか [true:名前部分のみ/false:ファイル名]
    737         */
    738        public void setNameOnly( final String flag ) {
    739                nameOnly = nval( getRequestParameter( flag ),nameOnly );
    740        }
    741
    742        /**
    743         * FileFilterオブジェクトをセットします。
    744         * これは、BODY 部に登録した、FileWhereタグによって設定された
    745         * ファイルフィルターです。
    746         *
    747         * @param       filter  オブジェクト
    748         */
    749        protected void setFileFilter( final FileFilter filter ) {
    750                this.filter = filter;
    751        }
    752
    753        /**
    754         * このオブジェクトの文字列表現を返します。
    755         * 基本的にデバッグ目的に使用します。
    756         *
    757         * @return このクラスの文字列表現
    758         * @og.rtnNotNull
    759         */
    760        @Override
    761        public String toString() {
    762                return ToString.title( this.getClass().getName() )
    763                                .println( "VERSION"                     ,VERSION                )
    764                                .println( "multi"                       ,multi                  )
    765                                .println( "level"                       ,level                  )
    766                                .println( "from"                        ,from                   )
    767                                .println( "orderBy"                     ,orderBy                )
    768                                .println( "desc"                        ,desc                   )
    769                                .println( "addClms"                     ,Arrays.toString( addClms )     )
    770                                .println( "defClms"                     ,Arrays.toString( defClms )     )
    771                                .println( "fileType"            ,fileType               )
    772                                .println( "useWritable"         ,useWritable    )
    773                                .println( "useMD5"              ,useMD5                 )
    774                                .println( "useText"                     ,useText                )
    775                                .println( "useUpdateClms"       ,useUpdateClms  )
    776                                .println( "addFrom"                     ,addFrom                )
    777                                .println( "filter"                      ,filter                 )                               // 6.8.0.0 (2017/06/02)
    778                                .fixForm().toString()
    779                        + CR
    780                        + super.toString() ;
    781        }
    782}