    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.StringUtil;
    023
    024import static org.opengion.fukurou.util.StringUtil.nval ;
    025
    026import java.io.File;
    027import java.io.FileFilter;
    028import java.io.Serializable;
    029import java.io.ObjectOutputStream;
    030import java.io.ObjectInputStream;
    031import java.io.IOException;
    032import java.util.Arrays;
    033import java.util.Comparator;
    034
    035/**
    036 * ファイルのプルダウンリストの作成するタグです。
    037 *
    038 * SelectタグのBODY部に指定します。
    039 * 並び替えについては、このタグで指定しますが、ファイルの選別は、
    040 * BODY 部に記述する fileWhere タグで指定します。
    041 *
    042 * @og.formSample
    043 * ●形式：&lt;og:fileOption from="…" value="[…]" ･･･ &gt;･･･&lt;/og:fileOption&gt;
    044 * ●body：あり(EVAL_BODY_BUFFERED:BODYを評価し、{&#064;XXXX} を解析します)
    045 *
    046 * ●Tag定義：
    047 *   &lt;og:fileOption
    048 *       from               【TAG】ファイルの検索元となるディレクトリを指定します (初期値:FILE_URL[=filetemp/])
    049 *       value              【TAG】Optionの初期値で選ばれる値を指定します
    050 *       orderBy            【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序)
    051 *       desc               【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)
    052 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    053 *   &gt;   ... Body ...
    054 *   &lt;/og:fileOption&gt;
    055 *
    056 * ●使用例
    057 *      ・&lt;og:fileOption val1="ABCD" val2="{&#064;value}" &gt;
    058 *            &lt;og:fileWhere startsWith="ABCD" ･･･ /&gt;
    059 *        &lt;/og:fileOption&gt;
    060 *
    061 * @og.rev 2.1.1.0 (2002/11/11) 新規作成
    062 * @og.rev 4.0.0.0 (2005/01/31) 内部ロジック改定
    063 * @og.group その他入力
    064 *
    065 * @version  4.0
    066 * @author   Kazuhiko Hasegawa
    067 * @since    JDK5.0,
    068 */
    069public class FileOptionTag extends CommonTagSupport {
    070        //* このプログラムのVERSION文字列を設定します。   {@value} */
    071        private static final String VERSION = "5.3.4.0 (2011/04/01)" ;
    072
    073        private static final long serialVersionUID = 534020110401L ;
    074
    075        private String          orderBy         = null;         // ｿｰﾄ項目
    076        private boolean         desc            = false;        // 降順ﾌﾗｸﾞ
    077        private String      from                = HybsSystem.sys( "FILE_URL" ); // 検索起点ﾌｧｲﾙ
    078        private String          selValue        = null;         // 選択済み初期値にする場合
    079        private transient FileFilter    filter          = null;                                                 // FileWhere で指定したフィルター
    080
    081        private static final String[] ORDER_BY = new String[] {
    082                                                                        "NAME","LASTMODIFIED","FILE_LENGTH","LENGTH" }; // 5.3.4.0 (2011/04/01) FILE_LENGTH 追加
    083
    084        /**
    085         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    086         *
    087         * @return      後続処理の指示( EVAL_BODY_BUFFERED )
    088         */
    089        @Override
    090        public int doStartTag() {
    091                return( EVAL_BODY_BUFFERED );   // Body を評価する。( extends BodyTagSupport 時)
    092        }
    093
    094        /**
    095         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    096         *
    097         * @return      後続処理の指示(SKIP_BODY)
    098         */
    099        @Override
    100        public int doAfterBody() {
    101                return(SKIP_BODY);
    102        }
    103
    104        /**
    105         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    106         *
    107         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    108         *
    109         * @return      後続処理の指示
    110         */
    111        @Override
    112        public int doEndTag() {
    113                debugPrint();           // 4.0.0 (2005/02/28)
    114//              SelectTag select = (SelectTag)findAncestorWithClass( this, SelectTag.class );
    115                OptionAncestorIF select = (OptionAncestorIF)findAncestorWithClass( this, OptionAncestorIF.class );
    116                if( select == null ) {
    117//                      String errMsg = "このタグは、SelectTag のBODY に記述する必要があります。";
    118                        String errMsg = "<b>" + getTagName() + "タグは、SelectTag または、DatalistTag のBODY に記述する必要があります。</b>";
    119                        throw new HybsSystemException( errMsg );
    120                }
    121                Comparator<File> comp = makeComparator( orderBy,desc );
    122                makeLabel( select,comp );
    123
    124                return(EVAL_PAGE);
    125        }
    126
    127        /**
    128         * タグリブオブジェクトをリリースします。
    129         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    130         *
    131         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    132         *
    133         */
    134        @Override
    135        protected void release2() {
    136                super.release2();
    137                orderBy         = null;         // ｿｰﾄ項目
    138                desc            = false;        // 降順ﾌﾗｸﾞ
    139                from            = HybsSystem.sys( "FILE_URL" );
    140                filter          = null;
    141                selValue        = null;
    142        }
    143
    144        /**
    145         * オプションを作成します。
    146         *
    147         * ファイル名を "value" に、
    148         * BODY属性 に登録するOptionを作成します。
    149         *
    150         * @og.rev 5.3.4.0 (2011/04/01) FILE_LENGTH 追加
    151         *
    152         * @param       orderBy ソートする属性[NAME/LASTMODIFIED/FILE_LENGTH/LENGTH]
    153         * @param       desc    並び順[true:昇順/false:降順]
    154         *
    155         * @return      ファイル比較用のComparatorオブジェクト
    156         */
    157        private Comparator<File> makeComparator( final String orderBy,final boolean desc ) {
    158                if( orderBy == null ) { return null; }
    159
    160                Comparator<File> comp = null ;
    161
    162                if( "NAME".equalsIgnoreCase( orderBy ) ) {
    163                        comp = new NameComparator( desc );
    164                }
    165                else if( "LASTMODIFIED".equalsIgnoreCase( orderBy ) ) {
    166                        comp = new ModifiedComparator( desc );
    167                }
    168                // "LENGTH" を残すのは、互換性のため
    169                else if( "FILE_LENGTH".equalsIgnoreCase( orderBy ) || "LENGTH".equalsIgnoreCase( orderBy ) ) {
    170                        comp = new LengthComparator( desc );
    171                }
    172
    173                return comp ;
    174        }
    175
    176        /**
    177         * オプションを作成します。
    178         *
    179         * ﾌｧｲﾙ名を "value" に、
    180         * BODY属性 に登録するOptionを作成します。
    181         *
    182         * @og.rev 3.8.0.9 (2005/10/17) 複数選択可能時に全選択を設定する。
    183         *
    184         * @param       select  SelectTagオブジェクト
    185         * @param       comp    並び順を指定するためのComparatorオブジェクト
    186         */
    187//      private void makeLabel( final SelectTag select,final Comparator<File> comp ) {
    188        private void makeLabel( final OptionAncestorIF select,final Comparator<File> comp ) {
    189                File path = new File( from );
    190
    191                File[] list = path.listFiles( filter );
    192
    193                boolean multipleAll = select.isMultipleAll();           // 3.8.0.9 (2005/10/17)
    194                if( list != null )  {
    195                        Arrays.sort( list, comp );
    196                        for( int i = 0; i < list.length; i++ ) {
    197                                if( list[i].isDirectory() ) { continue; }       // ディレクトリは除外
    198                                Attributes attri = new Attributes();
    199                                String value = list[i].getName();
    200                                attri.set( "value", value );
    201                                if( ( selValue != null && selValue.equalsIgnoreCase( value ) ) || multipleAll ) {
    202                                        attri.set( "selected", "selected" );
    203                                }
    204                                attri.set( "body", value );
    205                                select.addOption( XHTMLTag.option( attri ) );
    206                        }
    207                }
    208        }
    209
    210        /**
    211         * 【TAG】Optionの初期値で選ばれる値を指定します。
    212         *
    213         * @og.tag
    214         * キーになるのは、ファイル属性の NAME です。(ディレクトリなしのファイル名)
    215         * ここで value属性に指定した場合、このファイル名と(大文字小文字を無視して)
    216         * 一致する場合に、プルダウンの初期値に表示されます。(selected 属性が設定される。)
    217         *
    218         * @param   val  初期値で選ばれる値
    219         */
    220        public void setValue( final String val ) {
    221                selValue = nval( getRequestParameter( val ),selValue );
    222        }
    223
    224        /**
    225         * 【TAG】ファイルの検索元となるディレクトリを指定します
    226         *              (初期値:FILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
    227         *
    228         * @og.tag ファイルの検索元となるディレクトリを指定します。
    229         * (初期値:システム定数のFILE_URL[={@og.value org.opengion.hayabusa.common.SystemData#FILE_URL}])。
    230         *
    231         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
    232         *
    233         * @param       url ファイルの検索元となるディレクトリ
    234         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
    235         */
    236        public void setFrom( final String url ) {
    237                String furl = nval( getRequestParameter( url ),null );
    238                if( furl != null ) {
    239                        char ch = furl.charAt( furl.length()-1 );
    240                        if( ch != '/' && ch != '\\' ) { furl = furl + "/"; }
    241                }
    242                furl = StringUtil.urlAppend( from,furl );
    243                furl = StringUtil.urlAppend( furl,"." );
    244                from = HybsSystem.url2dir( furl );
    245        }
    246
    247        /**
    248         * 【TAG】検索した結果を表示する表示順をファイル属性名で指定します(初期値:自然順序)。
    249         *
    250         * @og.tag
    251         * ファイルをソートする順(Comparator)を指定します。ソートに指定できる
    252         * ファイル属性名は、"NAME","LASTMODIFIED","FILE_LENGTH" の内のどれかひとつです。
    253         * 何も指定しない場合は、Fileオブジェクトの自然順序でのソートになります。
    254         * (※ 下位互換性のため、LENGTH も残しますが、廃止予定です。)
    255         *
    256         * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
    257         * @og.rev 4.0.0.0 (2005/01/31) 新規ロジックで改定
    258         * @og.rev 5.3.4.0 (2011/04/01) ORDER_BYリストの出力方法 見直し
    259         *
    260         * @param       ordr  ソートキー("NAME","LASTMODIFIED","FILE_LENGTH")
    261         */
    262        public void setOrderBy( final String ordr ) {
    263                orderBy = nval( getRequestParameter( ordr ),orderBy );
    264
    265                if( orderBy != null && ! check( orderBy, ORDER_BY ) ) {
    266                        StringBuilder errMsg = new StringBuilder();
    267                        errMsg.append( "orderBy 属性に、下記の属性名以外の値が設定されました。" );
    268                        errMsg.append( HybsSystem.CR );
    269                        errMsg.append( " orderBy=[" ).append( orderBy ).append( "]" );
    270                        errMsg.append( HybsSystem.CR );
    271                        errMsg.append( " orderBy List=[" );
    272                        errMsg.append( StringUtil.array2csv( ORDER_BY ) );
    273                        errMsg.append( "]" );
    274//                      for( int i=0; i<ORDER_BY.length; i++ ) {
    275//                              errMsg.append( ORDER_BY[i] );
    276//                              if( i == ORDER_BY.length-1 ) { errMsg.append( "]" ); }
    277//                              else {                                             errMsg.append( "," ); }
    278//                      }
    279                        throw new HybsSystemException( errMsg.toString() );
    280                }
    281        }
    282
    283        /**
    284         * 【TAG】表示順を逆転するかどうか[true/false]を指定します(初期値:false)。
    285         *
    286         * @og.tag
    287         * orderBy 属性で指定した表示順を、逆順にするかどうかを指定できます。
    288         * 初期値は、false (昇順) です。
    289         *
    290         * @param       flag 表示順を逆転するかどうか [true:逆順/false:昇順]
    291         */
    292        public void setDesc( final String flag ) {
    293                desc = nval( getRequestParameter( flag ),desc );
    294        }
    295
    296        /**
    297         * FileFilterオブジェクトをセットします。
    298         * これは、BODY 部に登録した、FileWhereタグによって設定された
    299         * ファイルフィルターです。
    300         *
    301         * @param       filter  オブジェクト
    302         */
    303        protected void setFileFilter( final FileFilter filter ) {
    304                this.filter = filter;
    305        }
    306
    307        /**
    308         * 名前順でのソート順を指定する Comparator の実体内部クラス
    309         *
    310         * @og.group その他入力
    311         *
    312         * @version  4.0
    313         * @author   Kazuhiko Hasegawa
    314         * @since    JDK5.0,
    315         */
    316        static class NameComparator implements Comparator<File>,Serializable {
    317                private static final long serialVersionUID = 4000 ;
    318
    319                private final boolean desc ;
    320
    321                /**
    322                 * 名前順での比較を行うオブジェクトを作成します。
    323                 *
    324                 * @param desc [true:昇順/false:降順]
    325                 */
    326                public NameComparator( final boolean desc ) { this.desc = desc; }
    327
    328                /**
    329                 * Comparator インターフェースの compare( File,File ) メソッド
    330                 *
    331                 * @param o1 File 比較元１のファイルオブジェクト
    332                 * @param o2 File 比較元２のファイルオブジェクト
    333                 */
    334                public int compare( final File o1, final File o2 ) {
    335                        File f1 = (desc) ? o2 : o1 ;
    336                        File f2 = (desc) ? o1 : o2 ;
    337                        return (f1.getName()).compareTo( f2.getName() ) ;
    338                }
    339        }
    340
    341        /**
    342         * 更新日順でのソート順を指定する Comparator の実体内部クラス
    343         *
    344         * @og.group その他入力
    345         *
    346         * @version  4.0
    347         * @author   Kazuhiko Hasegawa
    348         * @since    JDK5.0,
    349         */
    350        static class ModifiedComparator implements Comparator<File>,Serializable {
    351                private static final long serialVersionUID = 4000 ;
    352
    353                private final boolean desc ;
    354
    355                /**
    356                 * 更新日順での比較を行うオブジェクトを作成します。
    357                 *
    358                 * @param desc [true:昇順/false:降順]
    359                 */
    360                public ModifiedComparator( final boolean desc ) { this.desc = desc; }
    361
    362                /**
    363                 * Comparator インターフェースの compare( File,File ) メソッド
    364                 *
    365                 * @param o1 File 比較元１のファイルオブジェクト
    366                 * @param o2 File 比較元２のファイルオブジェクト
    367                 */
    368                public int compare( final File o1, final File o2 ) {
    369                        File f1 = (desc) ? o2 : o1 ;
    370                        File f2 = (desc) ? o1 : o2 ;
    371                        return (int)( f1.lastModified() - f2.lastModified() ) ;
    372                }
    373        }
    374
    375        /**
    376         * ファイルサイズ順でのソート順を指定する Comparator の実体内部クラス
    377         *
    378         * @og.group その他入力
    379         *
    380         * @version  4.0
    381         * @author   Kazuhiko Hasegawa
    382         * @since    JDK5.0,
    383         */
    384        static class LengthComparator implements Comparator<File>,Serializable {
    385                private static final long serialVersionUID = 4000 ;
    386
    387                private final boolean desc ;
    388
    389                /**
    390                 * ファイルサイズでの比較を行うオブジェクトを作成します。
    391                 *
    392                 * @param desc [true:昇順/false:降順]
    393                 */
    394                public LengthComparator( final boolean desc ) { this.desc = desc; }
    395
    396                /**
    397                 * Comparator インターフェースの compare( File,File ) メソッド
    398                 *
    399                 * @param o1 File 比較元１のファイルオブジェクト
    400                 * @param o2 File 比較元２のファイルオブジェクト
    401                 */
    402                public int compare( final File o1, final File o2 ) {
    403                        File f1 = (desc) ? o2 : o1 ;
    404                        File f2 = (desc) ? o1 : o2 ;
    405                        return (int)( f1.length() - f2.length() ) ;
    406                }
    407        }
    408
    409        /**
    410         * シリアライズ用のカスタムシリアライズ書き込みメソッド
    411         *
    412         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
    413         * @serialData 一部のオブジェクトは、シリアライズされません。
    414         *
    415         * @param       strm    ObjectOutputStreamオブジェクト
    416         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
    417         */
    418        private void writeObject( final ObjectOutputStream strm ) throws IOException {
    419                strm.defaultWriteObject();
    420        }
    421
    422        /**
    423         * シリアライズ用のカスタムシリアライズ読み込みメソッド
    424         *
    425         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
    426         *
    427         * @og.rev 4.0.0.0 (2006/09/31) 新規追加
    428         * @serialData 一部のオブジェクトは、シリアライズされません。
    429         *
    430         * @param       strm    ObjectInputStreamオブジェクト
    431         * @see #release2()
    432         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
    433         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
    434         */
    435        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
    436                strm.defaultReadObject();
    437        }
    438
    439        /**
    440         * このオブジェクトの文字列表現を返します。
    441         * 基本的にデバッグ目的に使用します。
    442         *
    443         * @return このクラスの文字列表現
    444         */
    445        @Override
    446        public String toString() {
    447                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
    448                                .println( "VERSION"             ,VERSION        )
    449                                .println( "orderBy"             ,orderBy        )
    450                                .println( "desc"                ,desc           )
    451                                .println( "from"                ,from           )
    452                                .println( "selValue"    ,selValue       )
    453                                .println( "Other..."    ,getAttributes().getAttribute() )
    454                                .fixForm().toString() ;
    455        }
    456}