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.fukurou.process;
017
018import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
019import org.opengion.fukurou.util.Argument;
020import org.opengion.fukurou.util.HybsFileFilter;
021import org.opengion.fukurou.system.LogWriter;
022
023import java.io.File;
024import java.util.Map ;
025import java.util.LinkedHashMap ;
026import java.util.Stack;
027
028/**
029 * Process_FileSearch は、指定のフォルダ以下のファイルを一覧する、FirstProcess
030 * インターフェースと、ChainProcess インターフェースの実装クラスです。
031 *
032 * Fileリストは、FileLineModel オブジェクトを使用します。
033 * ファイル属性(Level,File,Length,Modify,LineCnt,Biko,MD5) と、
034 * オプションで、FILEPATH,ADDRESS,FILENAME 属性を文字列で準備できます。
035 *
036 * 指定の条件に合致するファイルを検索し、LineModel のサブクラスである、
037 * FileLineModel オブジェクトを作成して、下流に渡します。
038 * FileLineModel オブジェクトには、ファイル属性(Level,File,Length,Modify)
039 * が設定されます。
040 *
041 * 引数文字列中にスペースを含む場合は、ダブルコーテーション("") で括って下さい。
042 * 引数文字列の 『=』の前後には、スペースは挟めません。必ず、-key=value の様に
043 * 繋げてください。
044 *
045 * ※ 6.3.1.1 (2015/07/10)
046 *    ignoreCase の導入と同時に、初期値を、Grep , GrepChange , GrepChangeExcel と『異なる』
047 *    true:区別しない にしました。
048 *    これは、混乱する可能性が高いのですが、ファイル関連の検索において、通常は、大文字小文字の
049 *    区別なしで検索するのが、多く、Grep の区別するケースとは異なると判断しました。
050 *    実際は、ignoreCase 属性を毎回記述したくないというのが、本当の所です。
051 *
052 * ※ 6.4.0.2 (2015/12/11)
053 *    prefix,suffix,instr,equals に、("|"で複数指定可) の説明をJavaDocに追加。
054 *    useDIR 属性に、onlyパラメータを追加[false:File/true:File+Dir/only:Dir]。
055 *
056 * @og.formSample
057 *  Process_FileSearch -start=d:/ -suffix=jsp
058 *
059 *     -start=開始フォルダ         :検索を開始するフォルダ
060 *   [ -ignoreCase=[true/false]  ] :検索時に大文字小文字を区別しないかどうか(初期値:区別しない[true])
061 *   [ -preDir=接頭辞フォルダ       ] :File・・・・,View・・・・,など、指定の接頭辞で始まるフォルダを検索("|"で複数指定可)                      // 6.4.3.2 (2016/02/19)
062 *   [ -prefix=接頭辞            ] :File・・・・,View・・・・,など、指定の接頭辞で始まるファイルを検索("|"で複数指定可)
063 *   [ -unprefix=不接頭辞        ] :File・・・・,View・・・・,など、指定の接頭辞で始まらないファイルを検索("|"で複数指定可)
064 *   [ -suffix=接尾辞            ] :.txt|.java|.jsp.... など、指定の接尾辞で終わるファイルを検索("|"で複数指定可)
065 *   [ -unsuffix=不接尾辞        ] :.txt|.java|.jsp.... など、指定の接尾辞で終わらないファイルを検索("|"で複数指定可)
066 *   [ -instr=部分文字列         ] :ファイル名と一致する部分文字列を指定("|"で複数指定可)
067 *   [ -uninstr=不部分文字列     ] :ファイル名と一致しな部分文字列を指定("|"で複数指定可)
068 *   [ -equals=一致              ] :ファイル名と一致する文字列を指定("|"で複数指定可)
069 *   [ -notequals=不一致         ] :ファイル名と一致しない文字列を指定("|"で複数指定可)
070 *   [ -match=正規表現           ] :ファイル名と一致する正規表現を指定
071 *   [ -unmatch=正規表現         ] :ファイル名と一致しない正規表現を指定
072 *   [ -modify=YYYYMMDD          ] :指定日付け以降に変更されたファイルを検索
073 *             YYYYMMDD   : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻
074 *             TODAY      : 実行日の 00:00:00 を基準時刻
075 *             YESTERDAY  : 実行日前日の 00:00:00 を基準時刻
076 *             LAST_WEEK  : 実行日の先週(7日前) 00:00:00 を基準時刻
077 *             MONTH      : 実行月の 1日 00:00:00 を基準時刻
078 *             LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻
079 *             LAST_YEAR  : 実行前年の 同月同日 00:00:00 を基準時刻
080 *   [ -useDIR=[false/true/only] ] :判定をファイルだけでなく、ディレクトリでも行うかどうかを指定[false:File/true:File+Dir/only:Dir](初期値:false)
081 *   [ -larger=サイズ(Byte)      ] :ファイルの大きさが指定のバイト数と同じか大きいファイルを検索
082 *   [ -smaller=サイズ(Byte)     ] :ファイルの大きさが指定のバイト数より小さいファイルを検索
083 *   [ -isHidden=[true/false]    ] :true:HIDDENファイルのみ検索/false:NORMALファイルのみ検索(初期値:null)
084 *   [ -maxLevel=最大階層数      ] :ディレクトリの階層を下がる最大数(初期値:256)
085 *   [ -useLineCnt=行数計算      ] :ファイルの行数をカウントするかどうかを指定(初期値:false)
086 *   [ -useMD5=MD5計算値         ] :ファイルのMD5計算を行うかどうかを指定(初期値:false)
087 *   [ -useOmitCmnt=[false/true] ] :コメント部分を削除した行数と文字数計算を行うかどうかを指定(初期値:false)
088 *   [ -useFilePath=[false/true] ] :FILEPATH,ADDRESS,FILENAME 属性を文字列で準備します(初期値:false)
089 *   [ -modifyForm=日付フォーマット    ] :MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null)
090 *   [ -encode=エンコード名      ] :コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect)
091 *   [ -inPath=入力共通パス      ] :BIKO作成用のファイルパスから削除する部分(文字数のみ)
092 *   [ -outPath=出力追加パス     ] :BIKO作成用のファイルパスに追加する部分
093 *   [ -errAbend=[true/false]    ] :異常発生時に、処理を中断(true)するか、継続(false)するかを指定する(初期値:true[中断する])
094 *   [ -display=[false/true]     ] :trueは、検索状況を表示します(初期値:false)
095 *   [ -debug=[false/true]       ] :デバッグ情報を標準出力に表示する(true)かしない(false)か(初期値:false[表示しない])
096 *
097 * @version  4.0
098 * @author   Kazuhiko Hasegawa
099 * @since    JDK5.0,
100 */
101public class Process_FileSearch extends AbstractProcess implements FirstProcess , ChainProcess {
102
103        private Stack<FileListStack> dirs       ;
104        private File                    file            ;
105        private HybsFileFilter  filter          ;
106        private FileLineModel   newData         ;
107        private int                             level           = 1;
108
109        private String                  startDir        ;
110        private int                             maxLevel        = 256;
111        private int                             inCount         ;
112        private int                             outCount        ;
113        private int                             inPathLen       ;               // 4.2.3.0 (2008/05/26) BIKO欄用
114        private String                  outPath         ;               // 4.3.1.1 (2008/08/23) BIKO欄用
115        private boolean                 errAbend        = true; // 6.3.1.0 (2015/06/28) 中断する
116        private boolean                 display         ;               // false:表示しない
117        private boolean                 debug           ;               // 5.7.3.0 (2014/02/07) デバッグ情報
118
119        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
120        private static final Map<String,String> MUST_PROPARTY   ;               // [プロパティ]必須チェック用 Map
121        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
122        private static final Map<String,String> USABLE_PROPARTY ;               // [プロパティ]整合性チェック Map
123
124        static {
125                MUST_PROPARTY = new LinkedHashMap<>();
126                MUST_PROPARTY.put( "start",     "検索を開始するフォルダ(必須)" );
127
128                USABLE_PROPARTY = new LinkedHashMap<>();
129                USABLE_PROPARTY.put( "ignoreCase"       , "大文字小文字を区別しないかどうか(初期値:区別しない[true])" );                // 6.3.1.1 (2015/07/10)
130                USABLE_PROPARTY.put( "preDir"           , "File・・・・,View・・・・,など、指定の接頭辞で始まるフォルダを検索" );           // 6.4.3.2 (2016/02/19)
131                USABLE_PROPARTY.put( "prefix"           , "File・・・・,View・・・・,など、指定の接頭辞で始まるファイルを検索" );
132                USABLE_PROPARTY.put( "unprefix"         , "File・・・・,View・・・・,など、指定の接頭辞で始まらないファイルを検索" );
133                USABLE_PROPARTY.put( "suffix"           , ".txt|.java|.jsp.... など、指定の接尾辞で終わるファイルを検索" );
134                USABLE_PROPARTY.put( "unsuffix"         , ".txt|.java|.jsp.... など、指定の接尾辞で終わらないファイルを検索" );
135                USABLE_PROPARTY.put( "instr"            , "ファイル名と一致する部分文字列を指定" );
136                USABLE_PROPARTY.put( "uninstr"          , "ファイル名と一致しない部分文字列を指定" );
137                USABLE_PROPARTY.put( "equals"           , "ファイル名と一致する文字列を指定" );
138                USABLE_PROPARTY.put( "notequals"        , "ファイル名と一致しない文字列を指定" );
139                USABLE_PROPARTY.put( "match"            , "ファイル名と一致する正規表現を指定" );
140                USABLE_PROPARTY.put( "unmatch"          , "ファイル名と一致しない正規表現を指定" );
141                USABLE_PROPARTY.put( "modify"           , "指定日付け以降に変更されたファイルを検索" +
142                                                                                CR + "YYYYMMDD   : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻" +
143                                                                                CR + "TODAY      : 実行日の 00:00:00 を基準時刻" +
144                                                                                CR + "YESTERDAY  : 実行日前日の 00:00:00 を基準時刻" +
145                                                                                CR + "LAST_WEEK  : 実行日の先週(7日前) 00:00:00 を基準時刻" +
146                                                                                CR + "MONTH      : 実行月の 1日 00:00:00 を基準時刻" +
147                                                                                CR + "LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻" +
148                                                                                CR + "LAST_YEAR  : 実行前年の 同月同日 00:00:00 を基準時刻"
149                );
150                USABLE_PROPARTY.put( "useDIR"           , "判定をファイルだけでなく、ディレクトリでも行うかどうかを指定[false:File/true:File+Dir/only:Dir](初期値:false)" );
151                USABLE_PROPARTY.put( "larger"           , "ファイルの大きさが指定のバイト数と同じか大きいファイルを検索" );
152                USABLE_PROPARTY.put( "smaller"          , "ファイルの大きさが指定のバイト数より小さいファイルを検索" );
153                USABLE_PROPARTY.put( "isHidden"         , "true:HIDDENファイルのみ検索/false:NORMALファイルのみ検索(初期値:null)" );
154                USABLE_PROPARTY.put( "maxLevel"         , "ディレクトリの階層を下がる最大数(初期値:256)" );
155                USABLE_PROPARTY.put( "useLineCnt"       , "ファイルの行数をカウントするかどうかを指定(初期値:false)" );
156                USABLE_PROPARTY.put( "useMD5"           , "ファイルのMD5計算を行うかどうかを指定(初期値:false)" );          // 5.7.2.1 (2014/01/17)
157                USABLE_PROPARTY.put( "useOmitCmnt"      , "コメント部分を削除した行数と文字数計算を行うかどうかを指定(初期値:false)" );         // 5.7.4.0 (2014/03/07)
158                USABLE_PROPARTY.put( "useFilePath"      , "FILEPATH,ADDRESS,FILENAME 属性を文字列で準備します(初期値:false)" );                                // 6.3.1.0 (2015/06/28)
159                USABLE_PROPARTY.put( "modifyForm"       , "MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null)" );  // 6.3.1.1 (2015/07/10)
160                USABLE_PROPARTY.put( "encode"           , "コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect)" );  // 5.7.4.0 (2014/03/07)
161                USABLE_PROPARTY.put( "inPath"           , "BIKO作成用のファイルパスから削除する部分(文字数のみ)" );
162                USABLE_PROPARTY.put( "outPath"          , "BIKO作成用のファイルパスに追加する部分" );
163                USABLE_PROPARTY.put( "errAbend"         , "異常発生時に、処理を中断(true)するか、継続(false)するか" +
164                                                                                CR + "(初期値:true:中断する)" );                       // 6.3.1.0 (2015/06/28)
165                USABLE_PROPARTY.put( "display"          , "trueは、検索状況を表示します(初期値:false)" );
166                USABLE_PROPARTY.put( "debug"            , "デバッグ情報を標準出力に表示する(true)かしない(false)か" +
167                                                                                CR + "(初期値:false:表示しない)" );                     // 5.7.3.0 (2014/02/07) デバッグ情報
168        }
169
170        /**
171         * デフォルトコンストラクター。
172         * このクラスは、動的作成されます。デフォルトコンストラクターで、
173         * super クラスに対して、必要な初期化を行っておきます。
174         *
175         */
176        public Process_FileSearch() {
177                super( "org.opengion.fukurou.process.Process_FileSearch",MUST_PROPARTY,USABLE_PROPARTY );
178        }
179
180        /**
181         * プロセスの初期化を行います。初めに一度だけ、呼び出されます。
182         * 初期処理(ファイルオープン、DBオープン等)に使用します。
183         *
184         * @og.rev 4.2.2.0 (2008/05/10) 行数カウントの使用有無
185         * @og.rev 4.3.1.1 (2008/08/23) BIKO 欄にoutPath 属性を追加します。
186         * @og.rev 5.1.2.0 (2010/01/01) useDIR 属性を追加します。
187         * @og.rev 5.7.2.1 (2014/01/17) useMD5 属性を追加します。
188         * @og.rev 5.7.4.0 (2014/03/07) useOmitCmnt,encode 属性を追加します。
189         * @og.rev 5.7.4.3 (2014/03/28) larger,smaller属性を文字列に変更
190         * @og.rev 5.7.5.0 (2014/04/04) isHidden属性を追加します。
191         * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。
192         * @og.rev 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
193         * @og.rev 6.3.1.1 (2015/07/10) メソッドチェーン化と、大文字/小文字の区別なし(ignoreCase=true)対応
194         * @og.rev 6.3.1.1 (2015/07/10) Modify のフォーマットを、指定可能にします。
195         * @og.rev 6.4.0.2 (2015/12/11) useDIR 属性に、onlyパラメータを追加します[false:File/true:File+Dir/only:Dir]。
196         *
197         * @param   paramProcess データベースの接続先情報などを持っているオブジェクト
198         */
199        public void init( final ParamProcess paramProcess ) {
200                final Argument arg = getArgument();
201
202                startDir                = arg.getProparty( "start" );
203
204                final String inPath     = arg.getProparty( "inPath" );
205                if( inPath != null ) { inPathLen = inPath.length(); }
206
207                final boolean ignoreCase= arg.getProparty( "ignoreCase" ,true   );      // 6.3.1.1 (2015/07/10) 
208                final String preDir             = arg.getProparty( "preDir"             );              // 6.4.3.2 (2016/02/19)
209                final String prefix             = arg.getProparty( "prefix"             );
210                final String unprefix   = arg.getProparty( "unprefix"   );              // 5.1.2.0 (2010/01/01) 追加
211                final String suffix             = arg.getProparty( "suffix"             );
212                final String unsuffix   = arg.getProparty( "unsuffix"   );              // 5.1.2.0 (2010/01/01) 追加
213                final String instr              = arg.getProparty( "instr"              );
214                final String uninstr    = arg.getProparty( "uninstr"    );              // 5.1.2.0 (2010/01/01) 追加
215                final String equals             = arg.getProparty( "equals"             );
216                final String notequals  = arg.getProparty( "notequals"  );              // 5.1.2.0 (2010/01/01) 追加
217                final String match              = arg.getProparty( "match"              );
218                final String unmatch    = arg.getProparty( "unmatch"    );
219                final String modify             = arg.getProparty( "modify"             );
220                final String larger             = arg.getProparty( "larger"             );
221                final String smaller    = arg.getProparty( "smaller"    );
222                final String isHidden   = arg.getProparty( "isHidden"   );              // 5.7.5.0 (2014/04/04) 追加
223                maxLevel                                = arg.getProparty( "maxLevel",maxLevel);
224                outPath                                 = arg.getProparty( "outPath"    );
225                // 4.2.2.0 (2008/05/10) 行数カウントの使用有無
226                final boolean useLineCnt        = arg.getProparty( "useLineCnt",false );
227                // 5.7.2.1 (2014/01/17) ファイルのMD5の計算有無
228                final boolean useMD5            = arg.getProparty( "useMD5",false );
229                // 5.7.4.0 (2014/03/07) コメント部分を削除した行数と文字数計算を行うかどうか
230                final boolean useOmitCmnt       = arg.getProparty( "useOmitCmnt",false );
231                // 6.3.1.0 (2015/06/28) FILEPATH,ADDRESS,FILENAME 属性追加
232                final boolean useFilePath       = arg.getProparty( "useFilePath",false );
233                // 6.3.1.1 (2015/07/10) MODIFY 属性のDate型から文字列に変換するフォーマットを指定します
234                final String modifyForm = arg.getProparty( "modifyForm",null );
235                // 5.7.4.0 (2014/03/07) コメント削除時の文字数計算で利用するファイルのエンコード(初期値:JISAutoDetect)
236                final String encode                     = arg.getProparty( "encode" , "JISAutoDetect" );
237
238                // 5.1.2.0 (2010/01/01) 判定をディレクトリでも行うかどうか
239                // 6.4.0.2 (2015/12/11) useDIR 属性に、onlyパラメータを追加します[false:File/true:File+Dir/only:Dir]。
240                final String useDIR = arg.getProparty( "useDIR","false" );
241
242                errAbend= arg.getProparty( "errAbend"   , errAbend );                   // 6.3.1.0 (2015/06/28) errAbend属性追加
243                display = arg.getProparty( "display"    , display );
244                debug   = arg.getProparty( "debug"              , debug );                              // 5.7.3.0 (2014/02/07) デバッグ情報
245
246                // 6.3.1.1 (2015/07/10) メソッドチェーン化と、大文字/小文字の区別なし(ignoreCase=true)対応
247                filter = new HybsFileFilter( useDIR,ignoreCase )
248                        .startsDir(             preDir          )                       // 6.4.3.2 (2016/02/19)
249                        .startsWith(    prefix          )
250                        .startsWith(    unprefix        , true  )
251                        .endsWith(              suffix          )
252                        .endsWith(              unsuffix        , true  )
253                        .instr(                 instr           )
254                        .instr(                 uninstr         , true  )
255                        .fileEquals(    equals          )
256                        .fileEquals(    notequals       , true  )
257                        .matches(               match           )
258                        .matches(               unmatch         , true  )
259                        .lastModified(  modify          )
260                        .isLarger(              larger          )                       // 5.7.4.3 (2014/03/28) larger,smaller属性を文字列に変更
261                        .isSmaller(             smaller         )
262                        .isHidden(              isHidden        );                      // 5.7.5.0 (2014/04/04) 追加
263
264                final File tempFile = new File( startDir );
265                if( display ) { println( "start=[" + tempFile + "]" ); }                // 5.7.3.0 (2014/02/07)
266                if( tempFile.isDirectory() ) {
267                        dirs = new Stack<>();
268                        final File[] fileList = tempFile.listFiles( filter );
269                        dirs.push( new FileListStack( fileList, level ) );
270                }
271                else {
272                        dirs = new Stack<>();
273                        final File[] fileList = new File[] { tempFile };
274                        dirs.push( new FileListStack( fileList, level ) );
275                }
276
277                newData = new FileLineModel( useLineCnt,useMD5,useOmitCmnt,useFilePath );       // 6.3.1.0 (2015/06/28)
278                newData.setEncode( encode );
279                newData.setModifyForm( modifyForm );                                                                            // 6.3.1.1 (2015/07/10)
280        }
281
282        /**
283         * このデータの処理において、次の処理が出来るかどうかを問い合わせます。
284         * この呼び出し1回毎に、次のデータを取得する準備を行います。
285         *
286         * @og.rev 5.3.8.0 (2011/08/01) 処理中の状態を表示するための println を追加
287         *
288         * @return      処理できる:true / 処理できない:false
289         */
290        public boolean next() {
291                while( !dirs.empty() ) {
292                        final FileListStack fStack = dirs.pop();
293
294                        level = fStack.getLevel();
295                        if( level > maxLevel ) { continue; }
296
297                        final File[] fileList = fStack.getFileList();
298                        if( fileList == null ) { continue; }
299
300                        int address = fStack.getAddress();
301                        for( ; address<fileList.length; address++ ) {
302                                inCount++ ;
303                                if( fileList[address].isDirectory() ) {
304                                        if( debug ) { println( "file Add=" + fileList[address].getAbsolutePath() ); }                   // 5.7.3.0 (2014/02/07) デバッグ情報
305                                        final File[] newList = fileList[address].listFiles( filter );
306                                        dirs.push( new FileListStack( newList,level+1) );
307                                }
308                                else {
309                                        file = fileList[address];
310                                        if( debug ) { println( "file=" + file ); }                      // 5.7.3.0 (2014/02/07) デバッグ情報
311                                        fStack.setAddress( address+1 );
312                                        dirs.push( fStack );
313                                        return true;
314                                }
315                        }
316                }
317                return false;
318        }
319
320        /**
321         * 最初に、 行データである LineModel を作成します
322         * FirstProcess は、次々と処理をチェインしていく最初の行データを
323         * 作成して、後続の ChainProcess クラスに処理データを渡します。
324         *
325         * @og.rev 4.2.3.0 (2008/05/26) BIKO 欄に展開ファイル名を記述します。
326         * @og.rev 4.3.1.1 (2008/08/23) BIKO 欄にoutPath 属性を追加します。
327         * @og.rev 6.3.1.0 (2015/06/28) errAbend属性追加。
328         * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
329         *
330         * @param       rowNo   処理中の行番号
331         *
332         * @return      処理変換後のLineModel
333         */
334        public LineModel makeLineModel( final int rowNo ) {
335                outCount++ ;
336                // 6.3.1.0 (2015/06/28) 取りあえず、エラーの発生しそうな箇所で対応しておく。
337                try {
338                        newData.setFileVals( level,file );
339                }
340                catch( final RuntimeException ex ) {
341                        // 6.3.1.1 (2015/07/10) throwExceptionメソッドを使用
342                        final String errMsg = "rowNo=[" + rowNo + "] , file =[" + file + "]" ;
343                        throwException( errMsg,ex,errAbend );
344                }
345
346                // 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
347                if( file == null ) {
348                        final String errMsg = "#next() 実行しておかないと、file が初期化されません。" ;
349                        throw new OgRuntimeException( errMsg );
350                }
351
352                // 4.3.1.1 (2008/08/23)
353                String biko = null;
354                // 4.2.3.0 (2008/05/26) BIKO 欄追加
355                if( inPathLen > 0 ) {
356                        biko = file.getAbsolutePath().substring( inPathLen );
357                }
358
359                if( outPath != null ) {
360                        if( biko == null ) {
361                                biko = outPath + file.getName() ;
362                        }
363                        else {
364                                biko = outPath + biko ;
365                        }
366                }
367                if( biko != null ) {
368                        newData.setBiko( biko );
369                }
370
371                newData.setRowNo( rowNo );
372
373                return newData;
374        }
375
376        /**
377         * 引数の LineModel を処理するメソッドです。
378         * 変換処理後の LineModel を返します。
379         * 後続処理を行わない場合(データのフィルタリングを行う場合)は、
380         * null データを返します。つまり、null データは、後続処理を行わない
381         * フラグの代わりにも使用しています。
382         * なお、変換処理後の LineModel と、オリジナルの LineModel が、
383         * 同一か、コピー(クローン)かは、各処理メソッド内で決めています。
384         * ドキュメントに明記されていない場合は、副作用が問題になる場合は、
385         * 各処理ごとに自分でコピー(クローン)して下さい。
386         *
387         * @param       data    オリジナルのLineModel
388         *
389         * @return      処理変換後のLineModel
390         */
391        public LineModel action( final LineModel data ) {
392
393                final FileLineModel fileData ;
394                if( data instanceof FileLineModel ) {
395                        fileData = (FileLineModel)data ;
396                }
397                else {
398                        // これは、プログラマーの問題なので、errAbend 対象外
399                        final String errMsg = "データが FileLineModel オブジェクトではありません。" + CR ;
400                        throw new OgRuntimeException( errMsg );
401                }
402
403                if( debug ) { println( "Before:" + data.dataLine() ); }         // 5.1.2.0 (2010/01/01) display の条件変更
404
405                final File inFile = fileData.getFile() ;
406                final File[] fileList = inFile.listFiles( filter );
407
408                LineModel rtn = null;
409                if( fileList != null && fileList.length > 0 ) {
410                        rtn = data;
411                }
412
413                if( display && rtn != null ) { println( rtn.dataLine() ); }             // 5.1.2.0 (2010/01/01) display の条件変更
414                return rtn ;
415        }
416
417        /**
418         * プロセスの終了を行います。最後に一度だけ、呼び出されます。
419         * 終了処理(ファイルクローズ、DBクローズ等)に使用します。
420         *
421         * @param   isOK トータルで、OKだったかどうか[true:成功/false:失敗]
422         */
423        public void end( final boolean isOK ) {
424                dirs            = null;
425                file            = null;
426                filter          = null;
427                newData         = null;
428        }
429
430        /**
431         * プロセスの処理結果のレポート表現を返します。
432         * 処理プログラム名、入力件数、出力件数などの情報です。
433         * この文字列をそのまま、標準出力に出すことで、結果レポートと出来るような
434         * 形式で出してください。
435         *
436         * @return   処理結果のレポート
437         */
438        public String report() {
439                final String report = "[" + getClass().getName() + "]" + CR
440                                + TAB + "Start Folder : " + startDir  + CR
441                                + TAB + "Search Count : " + inCount   + CR
442                                + TAB + "Output Count : " + outCount ;
443
444                return report ;
445        }
446
447        /**
448         * このクラスの使用方法を返します。
449         *
450         * @return      このクラスの使用方法
451         * @og.rtnNotNull
452         */
453        public String usage() {
454                final StringBuilder buf = new StringBuilder( 3000 )
455                        .append( "Process_FileSearch は、指定のフォルダ以下のファイルを一覧する、FirstProcess"        ).append( CR )
456                        .append( "インターフェースと、ChainProcess インターフェースの実装クラスです。"                     ).append( CR )
457                        .append( CR )
458                        .append( "指定の条件に合致するファイルを検索し、ファイル属性(Level,File,Length,Modify)"  ).append( CR )
459                        .append( "を元に、LineModelを作成し、下流に渡します。"                                                                   ).append( CR )
460                        .append( CR )
461                        .append( "引数文字列中に空白を含む場合は、ダブルコーテーション(\"\") で括って下さい。"    ).append( CR )
462                        .append( "引数文字列の 『=』の前後には、空白は挟めません。必ず、-key=value の様に"           ).append( CR )
463                        .append( "繋げてください。"                                                                                                                             ).append( CR )
464                        .append( CR )
465                        .append( "  -start=開始フォルダ    :検索を開始するフォルダ"                                                              ).append( CR )
466                        .append( "[ -ignoreCase=true/false]:大文字小文字を区別しないかどうか(初期値:しない[true])" ).append( CR )
467                        .append( "[ -preDir=接頭辞フォルダ   ]:File・・・・,View・・・・,などの接頭辞で始まるフォルダ"              ).append( CR )                  // 6.4.3.2 (2016/02/19)
468                        .append( "[ -prefix=接頭辞        ]:File・・・・,View・・・・,などの接頭辞で始まるファイル"              ).append( CR )
469                        .append( "[ -unprefix=不接頭辞    ]:File・・・・,View・・・・,などの接頭辞で始まらないファイル"     ).append( CR )
470                        .append( "[ -suffix=接尾辞        ]:.txt|.java|.jsp.... などの接尾辞で終わるファイル"            ).append( CR )
471                        .append( "[ -unsuffix=不接尾辞    ]:.txt|.java|.jsp.... などの接尾辞で終わらないファイル"   ).append( CR )
472                        .append( "[ -instr=部分文字列     ]:ファイル名と一致する部分文字列"                                         ).append( CR )
473                        .append( "[ -uninstr=不部分文字列 ]:ファイル名と一致しな部分文字列"                                          ).append( CR )
474                        .append( "[ -equals=一致          ]:ファイル名と一致する文字列"                                                        ).append( CR )
475                        .append( "[ -notequals=不一致     ]:ファイル名と一致しない文字列"                                                        ).append( CR )
476                        .append( "[ -match=正規表現       ]:ファイル名と一致する正規表現"                                                 ).append( CR )
477                        .append( "[ -unmatch=正規表現     ]:ファイル名と一致しない正規表現"                                                ).append( CR )
478                        .append( "[ -modify=YYYYMMDD      ]:指定日付け以降に変更されたファイル"                                  ).append( CR )
479                        .append( "          YYYYMMDD   : YYYYMMDD 形式での指定日の 00:00:00 を基準時刻"                              ).append( CR )
480                        .append( "          TODAY      : 実行日の 00:00:00 を基準時刻"                                                           ).append( CR )
481                        .append( "          YESTERDAY  : 実行日前日の 00:00:00 を基準時刻"                                                 ).append( CR )
482                        .append( "          LAST_WEEK  : 実行日の先週(7日前) 00:00:00 を基準時刻"                                    ).append( CR )
483                        .append( "          MONTH      : 実行月の 1日 00:00:00 を基準時刻"                                                        ).append( CR )
484                        .append( "          LAST_MONTH : 実行前月の 同日 00:00:00 を基準時刻"                                               ).append( CR )
485                        .append( "          LAST_YEAR  : 実行前年の 同月同日 00:00:00 を基準時刻"                                     ).append( CR )
486                        .append( "[ -useDIR=[false/true/only]]:判定をディレクトリ名も含めて行うかどうか[false:File/true:File+Dir/only:Dir](初期値:false)").append( CR )
487                        .append( "[ -larger=サイズ(Byte)  ]:大きさが指定のバイト数と同じか大きいファイル"                        ).append( CR )
488                        .append( "[ -smaller=サイズ(Byte) ]:大きさが指定のバイト数より小さいファイル"                          ).append( CR )
489                        .append( "[ -isHidden=[false/true]]:true:HIDDENのみ検索/false:NORMALのみ検索(初期値:null)" ).append( CR )
490                        .append( "[ -maxLevel=最大階層数  ]:ディレクトリの階層を下がる最大数(初期値:256)"                       ).append( CR )
491                        .append( "[ -useLineCnt=行数計算  ]:ファイルの行数をカウントするかどうか(初期値:false)"  ).append( CR )
492                        .append( "[ -useMD5=MD5計算値     ]:ファイルのMD5計算を行うかどうかを指定(初期値:false)"       ).append( CR )
493                        .append( "[ -useOmitCmnt=[false/true] ]:コメント部分を削除した行数と文字数計算を行うかどうか(初期値:false)"  ).append( CR )
494                        .append( "[ -useFilePath=[false/true] ]:FILEPATH,ADDRESS,FILENAME 属性を準備(初期値:false)" ).append( CR )
495                        .append( "[ -modifyForm=日付フォーマット]:MODIFY 属性のDate型から文字列に変換するフォーマットを指定します(初期値:null)" ).append( CR )
496                        .append( "[ -inPath=入力共通パス  ]:BIKO作成用のファイルパスから削除する文字列"                  ).append( CR )
497                        .append( "[ -outPath=出力追加パス ]:BIKO作成用のファイルパスに追加する文字列"                           ).append( CR )
498                        .append( "[ -display=[false/true] ]:trueは、検索状況を表示(初期値:false)"                                   ).append( CR )
499                        .append( "[ -debug=[false/true]   ]:trueは、デバッグ状況を表示(初期値:false)"                         ).append( CR )
500                        .append( CR ).append( CR )
501                        .append( getArgument().usage() ).append( CR );
502
503                return buf.toString();
504        }
505
506        /**
507         * このクラスは、main メソッドから実行できません。
508         *
509         * @param       args    コマンド引数配列
510         */
511        public static void main( final String[] args ) {
512                LogWriter.log( new Process_FileSearch().usage() );
513        }
514
515        /**
516         * このクラスはファイルをスタックを使用して展開する場合の
517         * 個々の状態を保持する為のクラスです。
518         *
519         * @version  4.0
520         * @author   Kazuhiko Hasegawa
521         * @since    JDK5.0,
522         */
523        private static final class FileListStack {
524                private int address ;
525                private final File[] files;
526                private final int level;
527
528                /**
529                 * コンストラクター
530                 * 初期値を設定します。
531                 * ファイルの配列については、コピーせずそのまま内部配列にセットしています。
532                 *
533                 * @param files ファイルの配列(ファイルリスト)
534                 * @param       level   レベル(指定のstartフォルダからの階層数)
535                 */
536                FileListStack( final File[] files,final int level ) {
537                        this.files   = files;
538                        this.address = 0;
539                        this.level   = level;
540                }
541
542                /**
543                 * ファイルリストのアドレスを設定します。
544                 * スタックから取り出した後、配列を前回の続きからサーチする場合に使用します。
545                 *
546                 * @param       address ファイルリストのアドレス
547                 */
548                /* default */ void setAddress( final int address ) {
549                        this.address = address;
550                }
551
552                /**
553                 * ファイルリストのアドレスを取り出します。
554                 *
555                 * @return      ファイルリストのアドレス
556                 */
557                /* default */ int getAddress() {
558                        return address;
559                }
560
561                /**
562                 * ファイルリストを取り出します。
563                 * ファイルの配列については、コピーせずそのまま内部配列を返しています。
564                 *
565                 * @return ファイルリスト配列
566                 */
567                /* default */ File[] getFileList() {
568                        return files;
569                }
570
571                /**
572                 * 階層レベルを取り出します。
573                 *
574                 * @return      レベル
575                 */
576                /* default */ int getLevel() {
577                        return level;
578                }
579        }
580}