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