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.fukurou.util.XHTMLTag;
021import org.opengion.fukurou.util.Attributes;
022import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
023import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
024import org.opengion.hayabusa.io.HybsFileOperationFactory;               // 8.0.0.2 (2021/10/08)
025
026import static org.opengion.fukurou.util.StringUtil.nval ;
027
028import java.io.File;
029import java.io.FileFilter;
030import java.io.Serializable;
031import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
032import java.util.Arrays;
033import java.util.Comparator;
034
035/**
036 * ファイルのプルダウンリストの作成するタグです。
037 *
038 * SelectタグのBODY部に指定します。
039 * 並び替えについては、このタグで指定しますが、ファイルの選別は、
040 * BODY 部に記述する fileWhere タグで指定します。
041 *
042 * @og.formSample
043 * ●形式:<og:fileOption from="…" value="[…]" ・・・ >・・・</og:fileOption>
044 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します)
045 *
046 * ●Tag定義:
047 *   <og:fileOption
048 *       from               【TAG】ファイルの検索元となるディレクトリを指定します (初期値:FILE_URL[=filetemp/])
049 *       value              【TAG】Optionの初期値で選ばれる値を指定します
050 *       nameOnly           【TAG】ファイルの拡張子を除いた名前部分のみの値で行います。7.2.4.0 (2020/05/11)
051 *       groupDir           【TAG】optgroupを、ディレクトリの値で作成します(1レベルのみ)。
052 *       orderBy            【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序)
053 *       desc               【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)
054 *       useLocal           【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false) 8.0.1.0 (2021/10/29)
055 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 6.8.0.0 (2017/06/02)
056 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 6.8.0.0 (2017/06/02)
057 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
058 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
059 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 6.8.0.0 (2017/06/02)
060 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
061 * X     useDir             【廃止】(廃止:7.2.6.0 (2020/06/30))optionリストの作成を、ディレクトリの値で行います。
062 *   >   ... Body ...
063 *   </og:fileOption>
064 *
065 * ●使用例
066 *      ・<og:fileOption val1="ABCD" val2="{@value}" >
067 *            <og:fileWhere startsWith="ABCD" ・・・ />
068 *        </og:fileOption>
069 *
070 * @og.rev 2.1.1.0 (2002/11/11) 新規作成
071 * @og.rev 4.0.0.0 (2005/01/31) 内部ロジック改定
072 * @og.group その他入力
073 *
074 * @version  4.0
075 * @author   Kazuhiko Hasegawa
076 * @since    JDK5.0,
077 */
078public class FileOptionTag extends CommonTagSupport {
079        /** このプログラムのVERSION文字列を設定します。 {@value} */
080        private static final String VERSION = "8.0.1.0 (2021/10/29)" ;
081        private static final long serialVersionUID = 801020211029L ;
082
083        private transient       FileFilter      filter  ;       // FileWhere で指定したフィルター
084
085        private String          from            = HybsSystem.sys( "FILE_URL" ); // 検索起点ファイル
086        private String          selValue        ;                       // 選択済み初期値にする場合
087//      private boolean         useDir          ;                       // 6.3.4.0 (2015/08/01) 7.2.6.0 (2020/06/30) useDIR 属性 廃止
088        private boolean         nameOnly        ;                       // 7.2.4.0 (2020/05/11)
089        private boolean         groupDir        ;                       // 6.3.4.0 (2015/08/01)
090        private String          orderBy         ;                       // ソート項目
091        private boolean         desc            ;                       // 降順フラグ
092        private boolean         useLocal        ;                       // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
093
094        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
095        private static final Set<String> ORDER_BY_SET = new ArraySet<>( "NAME","LASTMODIFIED","FILE_LENGTH","LENGTH" );
096
097        /**
098         * デフォルトコンストラクター
099         *
100         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
101         */
102        public FileOptionTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
103
104        /**
105         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
106         *
107         * @og.rev 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
108         *
109         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
110         */
111        @Override
112        public int doStartTag() {
113                // 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
114                return useTag() ? EVAL_BODY_BUFFERED : SKIP_BODY ;
115        }
116
117        /**
118         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
119         *
120         * @return      後続処理の指示(SKIP_BODY)
121         */
122        @Override
123        public int doAfterBody() {
124                return SKIP_BODY ;
125        }
126
127        /**
128         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
129         *
130         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
131         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
132         * @og.rev 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
133         * @og.rev 8.0.0.1 (2021/10/08) cloud対応
134         *
135         * @return      後続処理の指示
136         */
137        @Override
138        public int doEndTag() {
139                debugPrint();           // 4.0.0 (2005/02/28)
140                // 6.8.0.0 (2017/06/02) caseKey,caseVal,caseNN,caseNull 属性を追加
141                if( useTag() ) {
142                        final OptionAncestorIF select = (OptionAncestorIF)findAncestorWithClass( this, OptionAncestorIF.class );
143                        if( select == null ) {
144                                final String errMsg = "<b>" + getTagName() + "タグは、SelectTag または、DatalistTag のBODY に記述する必要があります。</b>";
145                                throw new HybsSystemException( errMsg );
146                        }
147                        final Comparator<File> comp = makeComparator( orderBy,desc );
148        //              makeLabel( select,comp );
149//                      makeLabel( new File( from ) , select , comp , groupDir );
150                        final File path = HybsFileOperationFactory.create( useLocal,from );             // 8.0.0.1 (2021/10/08)
151                        makeLabel( path , select , comp , groupDir );
152                }
153
154                return EVAL_PAGE ;
155        }
156
157        /**
158         * タグリブオブジェクトをリリースします。
159         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
160         *
161         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
162         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
163         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
164         * @og.rev 7.2.6.0 (2020/06/30) ディレクトリ処理を統一します。
165         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
166         */
167        @Override
168        protected void release2() {
169                super.release2();
170                filter          = null;
171                from            = HybsSystem.sys( "FILE_URL" );
172                selValue        = null;
173                nameOnly        = false;        // 7.2.4.0 (2020/05/11)
174                groupDir        = false;        // 6.3.4.0 (2015/08/01)
175                orderBy         = null;         // ソート項目
176                desc            = false;        // 降順フラグ
177                useLocal        = false;        // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
178//              useDir          = false;        // 6.3.4.0 (2015/08/01) 7.2.6.0 (2020/06/30)
179        }
180
181        /**
182         * オプションを作成します。
183         *
184         * ファイル名を "value" に、
185         * BODY属性 に登録するOptionを作成します。
186         *
187         * @og.rev 5.3.4.0 (2011/04/01) FILE_LENGTH 追加
188         *
189         * @param       orderBy ソートする属性 [NAME/LASTMODIFIED/FILE_LENGTH/LENGTH]
190         * @param       desc    並び順 [true:昇順/false:降順]
191         *
192         * @return      ファイル比較用のComparatorオブジェクト
193         */
194        private Comparator<File> makeComparator( final String orderBy,final boolean desc ) {
195                if( orderBy == null ) { return null; }
196
197                Comparator<File> comp = null ;
198
199                if( "NAME".equalsIgnoreCase( orderBy ) ) {
200                        comp = new NameComparator( desc );
201                }
202                else if( "LASTMODIFIED".equalsIgnoreCase( orderBy ) ) {
203                        comp = new ModifiedComparator( desc );
204                }
205                // "LENGTH" を残すのは、互換性のため
206                else if( "FILE_LENGTH".equalsIgnoreCase( orderBy ) || "LENGTH".equalsIgnoreCase( orderBy ) ) {
207                        comp = new LengthComparator( desc );
208                }
209
210                return comp ;
211        }
212
213        /**
214         * オプションを作成します。
215         *
216         * ファイル名を "value" と、BODY属性 に登録するOptionを作成します。
217         *
218         * @og.rev 3.8.0.9 (2005/10/17) 複数選択可能時に全選択を設定する。
219         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加します。
220         * @og.rev 6.8.0.0 (2017/06/02) フォルダ内のファイルが無い場合は、階層に加えない。
221         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
222         *
223         * @param       path    処理の開始パス名(ディレクトリ)
224         * @param       select  SelectTagオブジェクト
225         * @param       comp    並び順を指定するためのComparatorオブジェクト
226         * @param       grpDir  フォルダ階層を、optgroup タグで表すかどうか [true:階層/false:1層]
227         * @return      フォルダ内のファイルが無い場合は階層に加えないためのフラグ [true:階層/false:ファイルなし]
228         */
229        private boolean makeLabel( final File path , final OptionAncestorIF select , final Comparator<File> comp , final boolean grpDir ) {
230
231                final File[] list = path.listFiles( filter );
232
233                final boolean multipleAll = select.isMultipleAll();             // 3.8.0.9 (2005/10/17)
234                if( list != null )  {
235                        Arrays.sort( list, comp );
236                        boolean isSet = false;                                                          // 6.8.0.0 (2017/06/02)
237                        for( int i=0; i<list.length; i++ ) {
238//                              final String value = list[i].getName();
239                                String value = list[i].getName();                               // 7.2.4.0 (2020/05/11) 書き換える
240                                // 6.3.4.0 (2015/08/01) useDir 属性と、groupDir 属性 を追加
241                                if( grpDir && list[i].isDirectory() ) {
242                                        select.addOption( "<optgroup label=\"" + value + "\">" );
243                                        if( makeLabel( list[i] , select , comp , false ) ) {    // リストに追加されたかどうかを判定します。
244                                                select.addOption( "</optgroup>" );
245                                                isSet = true;                                                           // 6.8.0.0 (2017/06/02)
246                                        }
247                                        else {
248                                                select.removeLast();                                            // 6.8.0.0 (2017/06/02) リストに追加されなかった場合は、最後に追加した optgroup を削除します。
249                                        }
250
251                                        continue;
252                                }
253//                              // 7.2.6.0 (2020/06/30) useDIR 属性 廃止
254//                              else {
255//                                      // ディレクトリ時のuseDir=true と、ファイル時useDir=false でない場合( XOR )時は、処理しない。
256//                                      if( list[i].isDirectory() ^ useDir ) { continue; }
257//                              }
258
259                                // 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
260                                if( nameOnly ) {
261                                        final int ad = value.lastIndexOf( '.' );
262                                        if( ad >= 0 ) { value = value.substring( 0,ad ); }
263                                }
264
265                                // 6.1.1.0 (2015/01/17) Attributesの連結記述
266                                final String selected = ( selValue != null && selValue.equalsIgnoreCase( value ) ) || multipleAll
267                                                                                        ? "selected" : null ;
268
269                                select.addOption(
270                                        XHTMLTag.option(
271                                                new Attributes()
272                                                        .set( "value"   , value )
273                                                        .set( "selected", selected )
274                                                        .set( "body"    , value )
275                                        )
276                                );
277                        }
278                        return isSet;   // 6.8.0.0 (2017/06/02)
279                }
280                return false;           // 6.8.0.0 (2017/06/02) フォルダ内のファイルが無い場合は、階層に加えない。
281        }
282
283        /**
284         * 【TAG】Optionの初期値で選ばれる値を指定します。
285         *
286         * @og.tag
287         * キーになるのは、ファイル属性の NAME です。(ディレクトリなしのファイル名)
288         * ここで value属性に指定した場合、このファイル名と(大文字小文字を無視して)
289         * 一致する場合に、プルダウンの初期値に表示されます。(selected 属性が設定される。)
290         *
291         * @param   val  初期値で選ばれる値
292         */
293        public void setValue( final String val ) {
294                selValue = nval( getRequestParameter( val ),selValue );
295        }
296
297        /**
298         * 【廃止】optionリストの作成を、ディレクトリの値で行います(初期値:false)。
299         *
300         * @og.tag
301         * ファイル検索で、ディレクトリ名のリストで、オプションを作成します。
302         * 初期値は、false (ファイル名でリスト) です。
303         *
304         * @og.rev 6.3.4.0 (2015/08/01) useDir 属性の追加
305         * @og.rev 7.2.6.0 (2020/06/30) ディレクトリ処理を統一します。
306         *
307         * @param       flag ディレクトリ名のリストで、オプションを作成するかどうか [true:ディレクトリ/false:ファイル]
308         */
309        public void setUseDir( final String flag ) {
310//              useDir = nval( getRequestParameter( flag ),useDir );
311        }
312
313        /**
314         * 【TAG】ファイルの拡張子を除いた名前部分のみの値で行います(初期値:false)。
315         *
316         * @og.tag
317         * ファイル検索の値を、ファイルの拡張子を取り除いた値のみで、オプションを作成します。
318         * 初期値は、false (拡張子付きファイル名でリスト) です。
319         *
320         * @og.rev 7.2.4.0 (2020/05/11) nameOnly 属性 を追加します。
321         *
322         * @param       flag ファイルの拡張子を除いた名前部分のみで、オプションを作成するかどうか [true:名前部分のみ/false:ファイル名]
323         */
324        public void setNameOnly( final String flag ) {
325                nameOnly = nval( getRequestParameter( flag ),nameOnly );
326        }
327
328        /**
329         * 【TAG】optgroupを、ディレクトリの値で作成します(1レベルのみ)(初期値:false)。
330         *
331         * @og.tag
332         * optgroupをディレクトリで作成することで、階層のメニューを作成します。
333         * 初期値は、false(通常) です。
334         *
335         * @og.rev 6.3.4.0 (2015/08/01) groupDir 属性の追加
336         *
337         * @param       flag ディレクトリで階層メニューを作成するかどうか [true:階層/false:通常]
338         */
339        public void setGroupDir( final String flag ) {
340                groupDir = nval( getRequestParameter( flag ),groupDir );
341        }
342
343        /**
344         * 【TAG】ファイルの検索元となるディレクトリを指定します
345         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
346         *
347         * @og.tag ファイルの検索元となるディレクトリを指定します。
348         * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。
349         *
350         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
351         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
352         * @og.rev 6.4.2.1 (2016/02/05) HybsSystem.url2dir に引数追加。
353         *
354         * @param       url ファイルの検索元となるディレクトリ
355         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
356         */
357        public void setFrom( final String url ) {
358                final String furl = nval( getRequestParameter( url ),null );
359                from = HybsSystem.url2dir( from,furl,"." );                     // 6.4.2.1 (2016/02/05)
360        }
361
362        /**
363         * 【TAG】検索した結果を表示する表示順をファイル属性名[null/NAME/LASTMODIFIED/FILE_LENGTH]で指定します(初期値:自然順序)。
364         *
365         * @og.tag
366         * ファイルをソートする順(Comparator)を指定します。ソートに指定できる
367         * ファイル属性名は、"NAME","LASTMODIFIED","FILE_LENGTH" の内のどれかひとつです。
368         * 何も指定しない場合は、Fileオブジェクトの自然順序でのソートになります。
369         * (※ 下位互換性のため、LENGTH も残しますが、廃止予定です。)
370         *
371         * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
372         * @og.rev 4.0.0.0 (2005/01/31) 新規ロジックで改定
373         * @og.rev 5.3.4.0 (2011/04/01) ORDER_BYリストの出力方法 見直し
374         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
375         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
376         *
377         * @param       ordr  ソートキー [null/NAME/LASTMODIFIED/FILE_LENGTH]
378         */
379        public void setOrderBy( final String ordr ) {
380                orderBy = nval( getRequestParameter( ordr ),orderBy );
381
382                if( orderBy != null && ! check( orderBy, ORDER_BY_SET ) ) {
383                        final String errMsg = "orderBy 属性に、下記の属性名以外の値が設定されました。" + CR
384                                                        + "orderBy=[" + orderBy + "] "                                                          + CR
385                                                        + "orderBy List=" + String.join( ", " , ORDER_BY_SET ) ;
386                        throw new HybsSystemException( errMsg );
387                }
388        }
389
390        /**
391         * 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。
392         *
393         * @og.tag
394         * orderBy 属性で指定した表示順を、逆順にするかどうかを指定できます。
395         * 初期値は、false (昇順) です。
396         *
397         * @param       flag 表示順を逆転するかどうか [true:逆順/false:昇順]
398         */
399        public void setDesc( final String flag ) {
400                desc = nval( getRequestParameter( flag ),desc );
401        }
402
403        /**
404         * 【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false)。
405         *
406         * @og.tag
407         * クラウド設定は、システム定数の『CLOUD_TARGET』と『CLOUD_BUCKET』の設定で自動的に使用しますが、
408         * どうしてもローカルでのみ使いたい場合は、この属性を true に設定します。
409         * 標準はfalse:設定どおりとなります。
410         *
411         * true/false以外を指定した場合はfalse扱いとします。
412         *
413         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
414         *
415         * @param flag ローカル環境のみ [true:ローカルのみ/false:設定どおり]
416         */
417        public void setUseLocal( final String flag ) {
418                useLocal = nval( getRequestParameter( flag ),useLocal );
419        }
420
421        /**
422         * FileFilterオブジェクトをセットします。
423         * これは、BODY 部に登録した、FileWhereタグによって設定された
424         * ファイルフィルターです。
425         *
426         * @param       filter  オブジェクト
427         */
428        protected void setFileFilter( final FileFilter filter ) {
429                this.filter = filter;
430        }
431
432        /**
433         * 名前順でのソート順を指定する Comparator の実体内部クラス
434         *
435         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
436         *
437         * @version  4.0
438         * @author   Kazuhiko Hasegawa
439         * @since    JDK5.0,
440         */
441        private static final class NameComparator implements Comparator<File>,Serializable {
442                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
443
444                private final boolean desc ;
445
446                /**
447                 * 名前順での比較を行うオブジェクトを作成します。
448                 *
449                 * @param desc 表示順逆転 [true:昇順/false:降順]
450                 */
451                public NameComparator( final boolean desc ) { this.desc = desc; }
452
453                /**
454                 * Comparator インターフェースの compare( File,File ) メソッド。
455                 *
456                 * @param o1 比較元1のファイルオブジェクト
457                 * @param o2 比較元2のファイルオブジェクト
458                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
459                 */
460                @Override       // Comparator
461                public int compare( final File o1, final File o2 ) {
462                        final File f1 = desc ? o2 : o1 ;
463                        final File f2 = desc ? o1 : o2 ;
464                        return f1.getName().compareTo( f2.getName() ) ;
465                }
466        }
467
468        /**
469         * 更新日順でのソート順を指定する Comparator の実体内部クラス
470         *
471         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
472         *
473         * @version  4.0
474         * @author   Kazuhiko Hasegawa
475         * @since    JDK5.0,
476         */
477        private static final class ModifiedComparator implements Comparator<File>,Serializable {
478                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
479
480                private final boolean desc ;
481
482                /**
483                 * 更新日順での比較を行うオブジェクトを作成します。
484                 *
485                 * @param desc 表示順逆順 [true:昇順/false:降順]
486                 */
487                public ModifiedComparator( final boolean desc ) { this.desc = desc; }
488
489                /**
490                 * Comparator インターフェースの compare( File,File ) メソッド。
491                 *
492                 * @param o1 比較元1のファイルオブジェクト
493                 * @param o2 比較元2のファイルオブジェクト
494                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
495                 */
496                @Override       // Comparator
497                public int compare( final File o1, final File o2 ) {
498                        final File f1 = desc ? o2 : o1 ;
499                        final File f2 = desc ? o1 : o2 ;
500                        return (int)( f1.lastModified() - f2.lastModified() ) ;
501                }
502        }
503
504        /**
505         * ファイルサイズ順でのソート順を指定する Comparator の実体内部クラス
506         *
507         * @og.rev 6.3.9.1 (2015/11/27) 修飾子を、なし → private static final class に変更。
508         *
509         * @version  4.0
510         * @author   Kazuhiko Hasegawa
511         * @since    JDK5.0,
512         */
513        private static final class LengthComparator implements Comparator<File>,Serializable {
514                private static final long serialVersionUID = 400020050131L ;    // 4.0.0.0 (2005/01/31)
515
516                private final boolean desc ;
517
518                /**
519                 * ファイルサイズでの比較を行うオブジェクトを作成します。
520                 *
521                 * @param desc 表示順逆順 [true:昇順/false:降順]
522                 */
523                public LengthComparator( final boolean desc ) { this.desc = desc; }
524
525                /**
526                 * Comparator インターフェースの compare( File,File ) メソッド。
527                 *
528                 * @param o1 比較元1のファイルオブジェクト
529                 * @param o2 比較元2のファイルオブジェクト
530                 * @return      最初の引数が 2 番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が 2 番目の引数より大きい場合は正の整数
531                 */
532                @Override       // Comparator
533                public int compare( final File o1, final File o2 ) {
534                        final File f1 = desc ? o2 : o1 ;
535                        final File f2 = desc ? o1 : o2 ;
536                        return (int)( f1.length() - f2.length() ) ;
537                }
538        }
539
540        /**
541         * このオブジェクトの文字列表現を返します。
542         * 基本的にデバッグ目的に使用します。
543         *
544         * @return このクラスの文字列表現
545         * @og.rtnNotNull
546         */
547        @Override
548        public String toString() {
549                return ToString.title( this.getClass().getName() )
550                                .println( "VERSION"             ,VERSION        )
551                                .println( "orderBy"             ,orderBy        )
552                                .println( "desc"                ,desc           )
553                                .println( "from"                ,from           )
554                                .println( "selValue"    ,selValue       )
555                                .println( "Other..."    ,getAttributes().getAttribute() )
556                                .fixForm().toString() ;
557        }
558}