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