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     */
016    package org.opengion.fukurou.process;
017    
018    import org.opengion.fukurou.util.FileUtil;
019    import org.opengion.fukurou.util.Closer;
020    import org.opengion.fukurou.util.HybsDateUtil;
021    import org.opengion.fukurou.util.CommentLineParser;
022    
023    import org.opengion.fukurou.security.HybsCryptography ;         // 5.7.2.1 (2014/01/17)
024    
025    import java.io.File;
026    import java.io.BufferedReader;
027    import java.io.PrintWriter;
028    import java.io.IOException;
029    
030    /**
031     * FileLineModel は、LineModel を継承した ファイルリスト専用の
032     * LineModel の実è£?‚¯ラスですã?
033     *
034     * FileLineModel オブジェクトには、ファイル属æ?(Level,File,Length,Modify,LineCnt,Biko,MD5)
035     * が設定されますã?
036     * LineCnt と、MD5 は、それぞれã?計算するかどã�?�‹のフラグを設定するå¿?¦�がありますã?
037     *
038     * ※ useLineCnt=false の場合ã?Length(æ–?­—数)は、File#length() メソãƒ?ƒ‰で求めますã?
039     *    ä¸?–¹、useLineCnt=true にすると、行単位に、String#length() を加算するためã?
040     *    先ã?Length(æ–?­—数)値とは異なりますã?でご注意くã�?�•ã�??
041     *
042     * omitCmnt=true にすると、コメント部åˆ?‚’削除した行数とæ–?­—数を求めますã?
043     * これはã€?* から */ の間ã?// から改行までですã?
044     * ただしã?"(二重引用符)で囲まれたæ–?­—å?は、コメントとみなしませんã€?
045     *
046     * ãƒ??タの?‘行å?ã‚?FileLineModel に割り当てますã?
047     * カラãƒ?•ª号はã€? から始まりますã?カラãƒ?��よりカラãƒ?•ª号を求めるå?合にã€?
048     * 存在しなã�??合ã?ã€?1 を返しますã?
049     * カラãƒ?•ª号ã�?-1 の場合ã?、å?ç�?‚’行いませんã€?
050     *
051     * 注意:このクラスは、同期å?ç�?�•れてã�?�¾せんã€?
052     *
053     * @version  4.0
054     * @author   Kazuhiko Hasegawa
055     * @since    JDK5.0,
056     */
057    public class FileLineModel extends LineModel {
058            // 5.7.2.1 (2014/01/17) MD5 é ?›®追åŠ?
059            private static final String[] KEYS = new String[] { "Level","File","Length","Modify","LineCnt","Biko","MD5" };
060    
061            private static final int LEVEL    = 0;
062            private static final int FILE     = 1;
063            private static final int LENGTH   = 2;
064            private static final int MODIFY   = 3;
065            private static final int LINECNT  = 4;
066            private static final int BIKO     = 5;
067            private static final int MD5      = 6;          // 5.7.2.1 (2014/01/17)
068    
069            private final boolean useLineCnt ;
070            private final boolean useMD5 ;                          // 5.7.2.1 (2014/01/17) MD5 é ?›®追åŠ?
071            private final boolean omitCmnt ;                        // 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?
072            private String encode = "JISAutoDetect";        // 5.7.4.0 (2014/03/07) コメント削除時ã?æ–?­—数計算で利用するファイルのエンコーãƒ?
073    
074            /**
075             * コンストラクターですã?
076             * useLineCnt=false , useMD5=false , omitCmnt=false で初期化されますã?
077             *
078             * @og.rev 5.7.2.1 (2014/01/17) MD5対å¿?
079             * @og.rev 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?対å¿?
080             *
081             */
082            public FileLineModel() {
083                    this( false,false,false );                              // 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?
084            }
085    
086            /**
087             * ラインカウントã?有無を指定したã?コンストラクターですã?
088             * useMD5=false , omitCmnt=false で初期化されますã?
089             *
090             * @og.rev 4.2.2.0 (2008/05/10) 行数カウントã?使用有無
091             * @og.rev 5.7.2.1 (2014/01/17) MD5対å¿?
092             * @og.rev 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?対å¿?
093             *
094             * @param       isLineCnt       行数カウントã?使用有無
095             */
096            public FileLineModel( final boolean isLineCnt ) {
097                    this( isLineCnt,false,false );                  // 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?
098            }
099    
100            /**
101             * ラインカウントã?有無と、MD5計算ã?有無を指定したã?コンストラクターですã?
102             * omitCmnt=false で初期化されますã?
103             *
104             * @og.rev 5.7.2.1 (2014/01/17) 新規追åŠ?MD5対å¿?
105             * @og.rev 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?対å¿?
106             *
107             * @param       isLineCnt       行数カウントã?使用有無
108             * @param       isMD5           ファイルのMD5の使用有無
109             */
110            public FileLineModel( final boolean isLineCnt,final boolean isMD5 ) {
111                    this( isLineCnt,isMD5,false );                          // 5.7.4.0 (2014/03/07) コメント除å¤?
112            }
113    
114            /**
115             * ラインカウントã?有無と、MD5計算ã?有無と、コメント除外ã?可否を指定したã?コンストラクターですã?
116             *
117             * @og.rev 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?
118             *
119             * @param       isLineCnt       行数カウントã?使用有無
120             * @param       isMD5           ファイルのMD5の使用有無
121             * @param       isOmit          コメント除外ã?可否(true:除外すã‚?
122             */
123            public FileLineModel( final boolean isLineCnt,final boolean isMD5,final boolean isOmit ) {
124                    // 4.3.4.4 (2009/01/01)
125                    useLineCnt = isLineCnt;
126                    useMD5     = isMD5;                             // 5.7.2.1 (2014/01/17)
127                    omitCmnt   = isOmit;                    // 5.7.4.0 (2014/03/07)
128                    init( KEYS );
129            }
130    
131            /**
132             * LineModel をå?に、FileLineModel を構築しますã?
133             * これは、ä¸?—¦ファイル等にセーブされた FileLineModel 形式を
134             * å…?�«戻す簡易コンストラクタですã?
135             *
136             * @og.rev 4.2.3.0 (2008/05/26) 新規追åŠ?
137             * @og.rev 5.7.2.1 (2014/01/17) MD5の設定å?ç�?¿½åŠ?
138             *
139             * @param       model   å…??LineModel
140             */
141            public FileLineModel( final LineModel model ) {
142                    // 4.3.4.4 (2009/01/01)
143                    init( model.getNames() );
144    
145                    Object[] obj = model.getValues();
146    
147                    setValue( LEVEL   ,Integer.valueOf( (String)obj[LEVEL] ) );
148                    setValue( FILE    ,new File((String)obj[FILE]) );
149                    setValue( LENGTH  ,Long.valueOf( (String)obj[LENGTH] ) );
150                    setValue( MODIFY  ,(String)obj[MODIFY] );
151    
152                    String cnt = (String)obj[LINECNT] ;
153                    useLineCnt = cnt != null && cnt.length() > 0 && ! "null".equalsIgnoreCase( cnt ) ;
154                    if( useLineCnt ) { setValue( LINECNT ,cnt ); }
155    
156                    setValue( BIKO  ,(String)obj[BIKO] );
157    
158                    // 5.7.2.1 (2014/01/17) 
159                    String md5Data = (String)obj[MD5] ;
160                    useMD5 = md5Data != null && md5Data.length() > 0 && ! "null".equalsIgnoreCase( md5Data ) ;
161                    if( useMD5 ) { setValue( MD5 ,md5Data ); }
162    
163                    omitCmnt   = false;                     // 5.7.4.0 (2014/03/07) 既存ã? LineModel から取得できなã�??で、強制設定しますã?
164            }
165    
166            /**
167             * File属æ?値をセãƒ?ƒˆしますã?
168             * LEVEL,FILE,LENGTH,MODIFY,LINECNT,MD5 のå�?±žæ?を設定しますã?
169             *
170             * @og.rev 4.2.2.0 (2008/05/10) 行数カウントã?使用有無
171             * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正しますã?
172             * @og.rev 5.7.2.1 (2014/01/17) MD5計算å?ç�??追åŠ?
173             * @og.rev 5.7.4.0 (2014/03/07) コメント除外ã?可否(true:除外すã‚?対å¿?
174             * @og.rev 5.7.7.1 (2014/06/13) omitCmnt=true(コメント除外すã‚? and useMD5=true(MD5計算すã‚? 場合ã?処ç�?
175             *
176             * @param       level   ファイルのãƒ?‚£レクトリ階層
177             * @param       file    ファイルオブジェクãƒ?
178             */
179            public void setFileVals( final int level, final File file ) {
180                    setValue( LEVEL  ,Integer.valueOf( level ) );
181                    setValue( FILE   ,file );
182                    setValue( MODIFY ,HybsDateUtil.getDate( file.lastModified(),"yyyy/MM/dd HH:mm:ss" ) );          // 5.5.7.2 (2012/10/09) HybsDateUtil を利用する
183    
184                    // 5.7.7.1 (2014/06/13) omitCmnt=true(コメント除外すã‚? and useMD5=true(MD5計算すã‚? 場合ã?処ç�?
185                    // 別にコメント除去されたファイルを作æ?して、それã? MD5 を求めるã?
186                    File ocFile = null;
187                    if( omitCmnt && useMD5 ) {
188                            try {
189                                    ocFile = File.createTempFile( "temp",".tmp" );
190                                    ocFile.deleteOnExit();                                                          // ä¸?¿œã?こã?メソãƒ?ƒ‰å†?�§削除しますが、念のためã€?
191                            }
192                            catch( IOException ex ) {
193                                    String errMsg = "コメント除外ã?MD5計算用 temp ファイルの作æ?に失敗しましたã€? + ex.getMessage() ;
194                                    throw new RuntimeException( errMsg,ex );
195                            }
196                    }
197    
198                    if( useLineCnt || omitCmnt ) {
199    //                      long[] cntVals = getLineCnt( file );
200                            long[] cntVals = getLineCnt( file,ocFile );                     // 5.7.7.1 (2014/06/13) 出力ファイルを渡しますã?
201                            setValue( LINECNT ,String.valueOf( cntVals[0] ) );
202                            setValue( LENGTH  ,Long.valueOf(   cntVals[1] ) );
203                    }
204                    else {
205                            setValue( LENGTH  ,Long.valueOf( file.length() ) );
206                    }
207    
208                    // 5.7.2.1 (2014/01/17) MD5計算がtrue で、かつ、ファイルの場合ã?MD5 計算を行いますã?
209                    if( useMD5 && file.isFile() ) {
210                            // 5.7.7.1 (2014/06/13) omitCmnt をè?慮したMD5計ç®?
211                            if( ocFile == null ) {
212                                    setValue( MD5 ,HybsCryptography.getMD5( file ) );
213                            }
214                            else {
215                                    setValue( MD5 ,HybsCryptography.getMD5( ocFile ) );
216                                    ocFile.delete();
217                            }
218                    }
219            }
220    
221            /**
222             * コメント削除時ã?æ–?­—数計算で利用するファイルのエンコードをセãƒ?ƒˆしますã?
223             * 初期値:JISAutoDetect
224             *
225             * @og.rev 5.7.4.0 (2014/03/07) 新規追åŠ?
226             *
227             * @param       encode  コメント削除時ã?æ–?­—数計算で利用するファイルのエンコーãƒ?
228             */
229            public void setEncode( final String encode ) {
230                    this.encode = encode;
231            }
232    
233            /**
234             * File属æ?値をセãƒ?ƒˆしますã?
235             *
236             * @param       file    ファイルオブジェクãƒ?
237             */
238            public void setFile( final File file ) {
239                    setValue( FILE,file );
240            }
241    
242            /**
243             * 備è?æƒ??属æ?値をセãƒ?ƒˆしますã?
244             *
245             * @og.rev 4.2.2.0 (2008/05/10) 行数カウントã?使用有無
246             *
247             * @param       biko    備è?æƒ??
248             */
249            public void setBiko( final String biko ) {
250                    setValue( BIKO,biko );
251            }
252    
253            /**
254             * レベル File属æ?値を取得しますã?
255             *
256             * @return      ファイルのãƒ?‚£レクトリ階層
257             */
258            public int getLebel() {
259                    return ((Integer)getValue( LEVEL )).intValue();
260            }
261    
262            /**
263             * ファイルを取得しますã?
264             *
265             * @return      ファイル
266             */
267            public File getFile() {
268                    return (File)getValue( FILE );
269            }
270    
271            /**
272             * ファイルサイズ File属æ?値を取得しますã?
273             *
274             * @return      ファイルサイズ
275             */
276            public long getLength() {
277                    return ((Long)getValue( LENGTH )).longValue();
278            }
279    
280            /**
281             * 更新日æ™?File属æ?値を取得しますã?
282             *
283             * @return      更新日æ™?yyyy/MM/dd HH:mm:ss)
284             */
285            public String getModify() {
286                    return (String)getValue( MODIFY );
287            }
288    
289            /**
290             * MD5 File属æ?値を取得しますã?
291             * ただしã?useMD5 ã�?true でなã�?�¨値は返しませんã€?
292             *
293             * @og.rev 5.7.2.1 (2014/01/17) 新規追åŠ?MD5対å¿?
294             *
295             * @return      MD5の値
296             */
297            public String getMD5() {
298                    return (String)getValue( MD5 );
299            }
300    
301            /**
302             * 行数とæ–?­—数を取得しますã?
303             * 行数カウントとファイルのæ–?­—数カウンãƒ?バイト数ではありません)を行いますã?
304             * ※ useLineCnt=false の場合ã?Length(æ–?­—数)は、File#length() メソãƒ?ƒ‰で求めますã?
305             *    ä¸?–¹、useLineCnt=true にすると、行単位に、String#length() を加算するためã?
306             *    先ã?Length(æ–?­—数)値とは異なりますã?でご注意くã�?�•ã�??
307             *
308             * 結果は、long型ã?配å?で返しますã?[0]が行数で、[1]が文字数ですã?
309             * omitCmnt 属æ?を使用した場合ã?、コメント部åˆ?‚’削除した行数とæ–?­—数を求めますã?
310             * これはã€?* から */ の間ã?// から改行までですã?
311             * ただしã?"(二重引用符)で囲まれたæ–?­—å?は、コメントとみなしませんã€?
312             *
313             * @og.rev 5.7.4.0 (2014/03/07) 行数カウントとファイルのæ–?­—数カウントを行うã€?
314             * @og.rev 5.7.7.1 (2014/06/13) omitCmnt=true(コメント除外すã‚? and useMD5=true(MD5計算すã‚? 場合ã?処ç�?
315             *
316             * @param       file    行数を数えるファイルオブジェクãƒ?
317             * @param       ocFile  omitCmnt=trueの場合に、MD5計算する時の、仮出力ファイル(nullの場合ã?、無è¦?
318             *
319             * @return  long型ã?配å?([0]が行数で、[1]が文字数)
320             */
321    //      private long[] getLineCnt( final File file ) {
322            private long[] getLineCnt( final File file,final File ocFile ) {
323                    long lineCnt = 0L;              // 行数
324                    long charCnt = 0L;              // æ–?­—数
325    
326                    BufferedReader reader = FileUtil.getBufferedReader( file,encode );
327    
328                    // 5.7.7.1 (2014/06/13) omitCmnt=true(コメント除外すã‚? and useMD5=true(MD5計算すã‚? 場合ã?処ç�?
329                    PrintWriter writer = null;
330                    if( ocFile != null ) { writer = FileUtil.getPrintWriter( ocFile ,encode ); }
331    
332                    CommentLineParser clp = omitCmnt ? new CommentLineParser() : null;
333                    try {
334                            if( ! file.isDirectory() ) {
335                                    String line ;
336                                    while((line = reader.readLine()) != null) {
337                                            if( omitCmnt ) {
338                                                    line = clp.line( line );
339                                                    if( line == null ) { continue; }        // 戻りå?ã�?null の場合ã?、行として不æ?ç«?
340                                                    if( writer != null ) { writer.println( line ); }        // 5.7.7.1 (2014/06/13)
341                                            }
342    
343                                            lineCnt++;
344                                            charCnt += line.length();
345                                    }
346                            }
347                    }
348                    catch( IOException ex ) {
349                            String errMsg = "ファイルカウント中に例外が発生しましたã€?" + file + "]" ;
350                            throw new RuntimeException( errMsg,ex );
351                    }
352                    finally {
353                            Closer.ioClose( reader ) ;
354                            Closer.ioClose( writer ) ;              // 5.7.7.1 (2014/06/13) ioClose は、引数ã�?null なら無視しますã?
355                    }
356    
357                    return new long[] { lineCnt,charCnt };
358            }
359    }