    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.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    019import org.opengion.hayabusa.common.HybsSystem;
    020import org.opengion.hayabusa.common.HybsSystemException;
    021import org.opengion.fukurou.util.FileUtil;
    022import org.opengion.fukurou.util.StringUtil ;
    023import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
    024import org.opengion.fukurou.util.ZipArchive;                                    // 5.9.2.2 (2015/11/12)
    025import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
    026import org.opengion.fukurou.model.POIUtil;                                              // 6.2.3.0 (2015/05/01)
    027
    028import static org.opengion.fukurou.util.StringUtil.nval ;
    029
    030import java.io.File;
    031import java.io.IOException;
    032import java.util.List;                                                                                  // 6.2.3.0 (2015/05/01)
    033import java.util.Set;                                                                                   // 6.4.3.4 (2016/03/11)
    034import java.util.ArrayList;                                                                             // 6.2.3.0 (2015/05/01)
    035import java.util.Locale ;
    036
    037import javax.servlet.ServletContext;                                                    // 6.3.6.1 (2015/08/28)
    038
    039/**
    040 * 各種アクションを指定して、ファイル関連の操作をおこなうタグです。
    041 *
    042 * 各種アクション に応じた振る舞いを行います。
    043 * 結果については、false の場合は、body 要素を表示して、終了します。
    044 * これは、BODYにエラーメッセージを書いておくことを想定した作りになっています。
    045
    046 * 判定結果を反転したい場合は、notEquals 属性を使用してください。また、
    047 * 結果に応じて、処理を止めたくない場合は、useStop 属性を false に指定することで、
    048 * 後続処理を実行できます。
    049 *
    050 * [各種アクション]
    051 *       canRead          読み込めるかどうかを判定。
    052 *       canWrite         変更できるかどうか判定。
    053 *       createNewFile    空の新しいファイルを不可分 (atomic) に生成。(そのファイルがまだ存在しない場合だけ)
    054 *       delete           ファイルまたはディレクトリを削除(ディレクトリ階層をすべて削除)。
    055 *       renameTo         ファイルまたはディレクトリ名を変更。
    056 *       exists           ファイルが存在するかどうか判定。
    057 *       isDirectory      ファイルがディレクトリであるかどうか判定。
    058 *       isFile           ファイルが普通のファイルかどうか判定。
    059 *       isHidden         ファイルが隠しファイルかどうか判定。
    060 *       mkdir            ディレクトリを生成。
    061 *       mkdirs           ディレクトリを複数生成。
    062 *       read             ファイルを読み込んで、パラメータにセットします(6.2.3.0 (2015/05/01))。
    063 *       existsLength     ファイルサイズが０Byte以上のファイルが存在するかどうか判定。
    064 *       copy             ファイルまたはディレクトリをコピー(file1 ⇒ file2 にコピー)。
    065 *       copyST           ストリームファイルをコピー(file1(アドレス) ⇒ file2 にコピー)。
    066 *       list             ファイルリストをListオブジェクトにコピーして、パラメータにセットします(6.2.3.0 (2015/05/01))。
    067 *       zip              ファイルまたはディレクトリをZIPファイルに圧縮します。(file1⇒file2)
    068 *       timeStamp        ファイルのタイムスタンプを現在時刻に変更します。(file1のみ)
    069 *
    070 * @og.formSample
    071 * ●形式：&lt;og:file action="…" fileURL="…" &gt;･･･&lt;/og:file&gt;
    072 * ●body：あり(EVAL_BODY_INCLUDE:BODYをインクルードし、{&#064;XXXX} は解析しません)
    073 *
    074 * ●Tag定義：
    075 *   &lt;og:file
    076 *       action           ○【TAG】アクション(canRead,canWrite,createNewFile,delete,renameTo,exists,isDirectory,isFile,isHidden,mkdir,mkdirs,read,existsLength,copy,copyST,list,zip,timeStamp)を指定します(必須)。
    077 *       fileURL            【TAG】操作するファイルのディレクトリを指定します (初期値:FILE_URL[=filetemp/])
    078 *       file1              【TAG】基準となるファイル名を指定します(コマンドの左辺のファイル名です)
    079 *       file2              【TAG】処理結果となるファイル名を指定します(コマンドの右辺のファイル名です)
    080 *       notEquals          【TAG】判定結果を反転させるかどうか[true/false]を指定します(初期値:false)
    081 *       useStop            【TAG】エラー時BODYを処理後に停止するかどうか[true/false]を指定します(初期値:true)
    082 *       encode             【TAG】ファイルを読み込む(action="read")際のエンコードを指定します(初期値:OS依存文字コード)
    083 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 5.7.7.2 (2014/06/20)
    084 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 5.7.7.2 (2014/06/20)
    085 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
    086 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 5.7.7.2 (2014/06/20)
    087 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
    088 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    089 *   &gt;   ... Body ...
    090 *   &lt;/og:file&gt;
    091 *
    092 * ●使用例
    093 *    ・ファイルの存在チェック→存在しなければエラーメッセージを表示。
    094 *        &lt;og:file action="exists" fileURL="N:/CIR/" file1="{&#064;USER.LKISB}/{&#064;USER.LDNO1KAI}.cir/001.sht"&gt;
    095 *            &lt;og:message lbl="RKE_0157" comment="回路図が存在しません。" /&gt;
    096 *        &lt;/og:file&gt;
    097 *
    098 *    ・N:/Filetemp/にユーザーディレクトリが存在しなければ作成。→失敗した場合エラーメッセージを表示。
    099 *        &lt;og:file action="mkdir" fileURL="N:/Filetemp/{&#064;USER.ID}" &gt;
    100 *            &lt;og:message comment="エラーが発生しました。システム管理者に連絡してください。" /&gt;
    101 *        &lt;/og:file&gt;
    102 *
    103 *    ・N:/Filetemp/test.txt ファイルの削除。ファイルが存在しなくても処理を続ける。
    104 *        &lt;og:file action="delete" fileURL="N:/Filetemp/" file1="test.txt" useStop="false" &gt;
    105 *            &lt;og:message comment="ファイルは存在しませんでした。" /&gt;
    106 *        &lt;/og:file&gt;
    107 *
    108 * @og.group その他部品
    109 *
    110 * @version  4.0
    111 * @author       Kazuhiko Hasegawa
    112 * @since    JDK5.0,
    113 */
    114public class FileTag extends CommonTagSupport {
    115        /** このプログラムのVERSION文字列を設定します。   {@value} */
    116        private static final String VERSION = "7.2.6.3 (2020/08/07)" ;
    117        private static final long serialVersionUID = 726320200807L ;
    118
    119        /** action 引数に渡す事の出来る アクションコマンド  読み込めるかどうか {@value} */
    120        public static final String ACT_CANREAD  = "canRead" ;
    121        /** action 引数に渡す事の出来る アクションコマンド  変更できるかどうか {@value} */
    122        public static final String ACT_CANWRITE    = "canWrite" ;
    123        /** action 引数に渡す事の出来る アクションコマンド  空の新しいファイルを不可分 (atomic) に生成します (そのファイルがまだ存在しない場合だけ {@value} */
    124        public static final String ACT_CREATENEWFILE    = "createNewFile" ;
    125        /** action 引数に渡す事の出来る アクションコマンド  ファイルまたはディレクトリを削除{@value}       */
    126        public static final String ACT_DELETE    = "delete" ;
    127        /** action 引数に渡す事の出来る アクションコマンド  ファイルが存在するかどうか {@value} */
    128        public static final String ACT_EXISTS    = "exists" ;
    129        /** action 引数に渡す事の出来る アクションコマンド  ファイルがディレクトリであるかどうか{@value}     */
    130        public static final String ACT_ISDIRECTORY        = "isDirectory" ;
    131        /** action 引数に渡す事の出来る アクションコマンド  ファイルが普通のファイルかどうか{@value}       */
    132        public static final String ACT_ISFILE    = "isFile" ;
    133        /** action 引数に渡す事の出来る アクションコマンド  ファイルが隠しファイルかどうか {@value} */
    134        public static final String ACT_ISHIDDEN    = "isHidden" ;
    135        /** action 引数に渡す事の出来る アクションコマンド  ディレクトリを生成します。 {@value} */
    136        public static final String ACT_MKDIR    = "mkdir" ;
    137        /** action 引数に渡す事の出来る アクションコマンド  ディレクトリを生成します。 {@value} */
    138        public static final String ACT_MKDIRS   = "mkdirs" ;
    139        /** action 引数に渡す事の出来る アクションコマンド  ファイル名を変更します。 {@value} */
    140        public static final String ACT_RENAMETO = "renameTo" ;          // 3.5.6.5 (2004/08/09)
    141        /** action 引数に渡す事の出来る アクションコマンド  ファイルを読み込んで表示します。 {@value} */
    142        public static final String ACT_READ     = "read" ;              // 3.6.0.0 (2004/09/25)
    143        /** action 引数に渡す事の出来る アクションコマンド  ファイルサイズが０Byte以上のファイルが存在するかどうか判定。 {@value} */
    144        public static final String ACT_EXISTSLENGTH      = "existsLength" ;             // 3.8.5.2 (2006/05/31)
    145        /** action 引数に渡す事の出来る アクションコマンド  ファイルまたはディレクトリをコピーします。 {@value} */
    146        public static final String ACT_COPY      = "copy" ;             // 5.3.6.0 (2011/06/01)
    147        /** action 引数に渡す事の出来る アクションコマンド  ストリームファイルをコピーします。 {@value} */
    148        public static final String ACT_COPYST = "copyST" ;      // 6.3.6.1 (2015/08/28)
    149        /** action 引数に渡す事の出来る アクションコマンド  ディレクトリのファイルリストをListオブジェクトにコピーします。 {@value} */
    150        public static final String ACT_LIST      = "list" ;             // 6.2.3.0 (2015/05/01)
    151        /** action 引数に渡す事の出来る アクションコマンド  ZIP圧縮します。 {@value} */
    152        public static final String ACT_ZIP       = "zip" ;              // 5.9.2.2 (2015/11/20)
    153        /** action 引数に渡す事の出来る アクションコマンド  タイムスタンプを現在時刻に変更します。 {@value} */
    154        public static final String ACT_TIMESTAMP         = "timeStamp" ;                // 6.7.0.0 (2016/12/28)
    155
    156        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    157        private static final Set<String> ACTION_SET = new ArraySet<>(
    158                                                                                                        ACT_CANREAD , ACT_CANWRITE , ACT_CREATENEWFILE , ACT_DELETE , ACT_EXISTS , ACT_ISDIRECTORY ,
    159                                                                                                        ACT_ISFILE , ACT_ISHIDDEN , ACT_MKDIR , ACT_MKDIRS , ACT_RENAMETO , ACT_READ ,
    160                                                                                                        ACT_EXISTSLENGTH , ACT_COPY , ACT_COPYST , ACT_LIST , ACT_ZIP , ACT_TIMESTAMP );
    161
    162        private String  fileURL         = HybsSystem.sys( "FILE_URL" );
    163        private String  file1           = "";
    164        private String  file2           ;
    165        private String  action          ;
    166        private boolean rtnCode         ;
    167
    168        private boolean notEquals       ;                       // 3.8.5.2 (2006/05/31) 判定結果を反転させて処理します。
    169        private boolean useStop         = true;         // 3.8.5.2 (2006/05/31) エラー時BODYを処理後に停止(true)するかどうか
    170
    171        private String encode           ;                       // 5.1.9.0 (2010/08/01) READ時のエンコード指定
    172
    173        /**
    174         * デフォルトコンストラクター
    175         *
    176         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    177         */
    178        public FileTag() { super(); }           // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    179
    180        /**
    181         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    182         *
    183         * @og.rev 3.6.0.0 (2004/09/25) file オブジェクトの作成を actionExec 移動
    184         * @og.rev 3.8.5.2 (2006/05/31) notEquals追加。 判定結果を反転させて処理します。
    185         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    186         *
    187         * @return      後続処理の指示
    188         */
    189        @Override
    190        public int doStartTag() {
    191                // 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    192                if( useTag() ) {
    193                        try {
    194                                rtnCode = notEquals ^ actionExec( action );             // 3.8.5.2 (2006/05/31) 排他的論理和(XOR)
    195                        }
    196                        catch( final IOException ex ) {
    197                                final String errMsg = "指定のアクションは実行できません。アクションエラー" + CR
    198                                                                + "\t  action=["        + action        + "]"   + CR
    199                                                                + "\t  fileURL=["       + fileURL       + "]"   + CR
    200                                                                + "\t  file1=["         + file1         + "]"   + CR
    201                                                                + "\t  file2=["         + file2         + "]"   + CR ;
    202                                throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び順変更
    203                        }
    204
    205                        if( rtnCode ) { return SKIP_BODY ; }                    // Body を評価しない
    206                        else {                  return EVAL_BODY_INCLUDE ; }    // Body インクルード( extends TagSupport 時)
    207                }
    208
    209                return SKIP_BODY ;
    210        }
    211
    212        /**
    213         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    214         *
    215         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    216         * @og.rev 3.8.5.2 (2006/05/31) useStop 追加。 エラー時BODYを処理後に停止(true)するかどうか
    217         * @og.rev 5.7.7.2 (2014/06/20) caseKey,caseVal,caseNN,caseNull 属性を追加
    218         *
    219         * @return      後続処理の指示
    220         */
    221        @Override
    222        public int doEndTag() {
    223                debugPrint();           // 4.0.0 (2005/02/28)
    224
    225                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    226                return useTag() && useStop && !rtnCode  ? SKIP_PAGE : EVAL_PAGE ;
    227        }
    228
    229        /**
    230         * タグリブオブジェクトをリリースします。
    231         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    232         *
    233         * @og.rev 2.0.0.4 (2002/09/27) カスタムタグの release() メソッドを、追加
    234         * @og.rev 3.1.1.2 (2003/04/04) Tomcat4.1 対応。release2() を doEndTag()で呼ぶ。
    235         * @og.rev 3.6.0.0 (2004/09/24) columns 、tableId 、file 削除
    236         * @og.rev 3.8.5.2 (2006/05/31) notEquals 、useStop 追加
    237         * @og.rev 5.1.9.0 (2010/08/01) READ時のエンコード指定
    238         *
    239         */
    240        @Override
    241        protected void release2() {
    242                super.release2();
    243                fileURL         = HybsSystem.sys( "FILE_URL" );
    244                file1           = "";
    245                file2           = null;
    246                action          = null;
    247                rtnCode         = false;
    248                notEquals       = false;        // 3.8.5.2 (2006/05/31) 判定結果を反転させて処理します。
    249                useStop         = true;         // 3.8.5.2 (2006/05/31) エラー時BODYを処理後に停止(true)するかどうか
    250                encode          = null;         // 5.1.9.0 (2010/08/01) READ時のエンコード指定
    251        }
    252
    253        /**
    254         * アクションを実行します。
    255         * アクションは,指定のアクションコマンドに対応する処理を入力データに
    256         * 対して行います。
    257         *
    258         * @og.rev 3.0.0.0 (2002/12/25) ACTION_LIST のチェックを削除
    259         * @og.rev 3.6.0.0 (2004/09/25) ACT_read を追加 , file オブジェクトを移動
    260         * @og.rev 3.8.5.2 (2006/05/31) existsLength 追加
    261         * @og.rev 4.0.0.0 (2007/11/28) メソッドの戻り値をチェックします。
    262         * @og.rev 5.1.9.0 (2010/08/01) READ時のエンコード指定
    263         * @og.rev 5.3.6.0 (2011/06/01) ACT_COPY 対応
    264         * @og.rev 5.7.1.1 (2013/12/13) copy元(file1)のファイルが存在しなければ、エラーにします。
    265         * @og.rev 6.2.3.0 (2015/05/01) list アクション追加、delete 処理は、フォルダ階層を丸ごと削除します。
    266         * @og.rev 6.3.6.1 (2015/08/28) ACT_COPYST 対応( copyST アクション時に、copy元に、ｱﾄﾞﾚｽ指定できるようにする)。
    267         * @og.rev 5.9.2.2 (2015/11/12) ACT_ZIP追加
    268         * @og.rev 6.7.0.0 (2016/12/28) ACT_TIMESTAMP追加
    269         * @og.rev 6.8.0.0 (2017/06/02) zipFile の親ディレクトリを作成します。
    270         * @og.rev 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド(mkdirs)
    271         * @og.rev 7.2.6.3 (2020/08/07) mkdirs は、先に存在チェックを入れて、存在していればtrueにする。
    272         *
    273         * @param       action アクション (public static final 宣言されている文字列)
    274         *
    275         * @return      実行後のデータ
    276         */
    277        private boolean actionExec( final String action ) throws IOException {
    278                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    279                if( action == null ) {
    280                        final String errMsg = "アクションが指定されていません。アクション NULL エラー" + CR
    281                                                        + "\t  file=["          + file1         + "]"   + CR
    282                                                        + "\t  matches=["       + file2         + "]"   + CR ;
    283                        throw new HybsSystemException( errMsg );
    284                }
    285
    286                final String directory = HybsSystem.url2dir( fileURL );
    287                final File file = new File( StringUtil.urlAppend( directory,file1 ) );
    288
    289                boolean rtnVal = false;
    290                        if(      ACT_CANREAD.equalsIgnoreCase(           action ) ) { rtnVal = file.canRead(); }
    291                        else if( ACT_CANWRITE.equalsIgnoreCase(          action ) ) { rtnVal = file.canWrite(); }
    292                        else if( ACT_CREATENEWFILE.equalsIgnoreCase( action ) ) { rtnVal = file.createNewFile(); }
    293                        else if( ACT_DELETE.equalsIgnoreCase(            action ) ) { rtnVal = FileUtil.deleteFiles( file ); }
    294                        else if( ACT_EXISTS.equalsIgnoreCase(            action ) ) { rtnVal = file.exists(); }
    295                        else if( ACT_ISDIRECTORY.equalsIgnoreCase(       action ) ) { rtnVal = file.isDirectory(); }
    296                        else if( ACT_ISFILE.equalsIgnoreCase(            action ) ) { rtnVal = file.isFile(); }
    297                        else if( ACT_ISHIDDEN.equalsIgnoreCase(          action ) ) { rtnVal = file.isHidden(); }
    298                        else if( ACT_MKDIR.equalsIgnoreCase(             action ) ) {
    299                                if( file.isDirectory() ) { rtnVal = true; }
    300                                else { rtnVal = file.mkdir(); }
    301                        }
    302                        // 7.2.6.3 (2020/08/07) mkdirs は、先に存在チェックを入れて、存在していればtrueにする。
    303//                      else if( ACT_MKDIRS.equalsIgnoreCase(            action ) ) { rtnVal = file.mkdirs(); }
    304                        else if( ACT_MKDIRS.equalsIgnoreCase(            action ) ) {           // 7.2.6.3 (2020/08/07)
    305                                if( file.isDirectory() ) { rtnVal = true; }
    306                                else { rtnVal = file.mkdirs(); }
    307                        }
    308                        else if( ACT_RENAMETO.equalsIgnoreCase(          action ) ) {
    309                                if( file2 != null ) {
    310                                        final File newFile = new File( StringUtil.urlAppend( directory,file2 ) );
    311                                        if( newFile.exists() && !newFile.delete() ) {
    312                                                final String errMsg = "所定のファイルを削除できませんでした。[" + newFile + "]" ;
    313                                                throw new OgRuntimeException( errMsg );
    314                                        }
    315                                        rtnVal = file.renameTo( newFile );
    316                                }
    317                        }
    318                        // 3.6.0.0 (2004/09/25) ACT_read を追加
    319                        else if( ACT_READ.equalsIgnoreCase(                      action ) ) {
    320                                if( file.isFile() ) {
    321                                        // 6.2.3.0 (2015/05/01)
    322                                        String text ;
    323                                        if( POIUtil.isPOI( file ) ) {
    324                                                text = POIUtil.extractor( file );
    325                                        }
    326                                        else {
    327                                                final String enc = encode == null ? "UTF-8" : encode ;
    328                                                text = POIUtil.extractor( file,enc );
    329                                        }
    330
    331                                        rtnVal = true;
    332                                        setRequestAttribute( "read",text );
    333                                }
    334                                else {
    335                                        final String errMsg = "ファイルが存在しないか、ファイルではありません。" + CR
    336                                                        + "\t  action=["        + action        + "]"   + CR
    337                                                        + "\t  fileURL=["       + fileURL       + "]"   + CR
    338                                                        + "\t  directory=[" + directory + "]"   + CR
    339                                                        + "\t  file1=["         + file1         + "]"   + CR ;
    340                                        throw new HybsSystemException( errMsg );
    341                                }
    342                        }
    343                        // 3.8.5.2 (2006/05/31) ファイルサイズが０Byte以上のファイルが存在するかどうか判定。
    344                        else if( ACT_EXISTSLENGTH.equalsIgnoreCase( action ) ) {
    345                                rtnVal = file.exists() && file.length() > 0L ;
    346                        }
    347                        // 5.3.6.0 (2011/06/01) ファイルコピー対応
    348                        // 6.0.0.1 (2014/04/25) These nested if statements could be combined
    349                        // 6.3.6.1 (2015/08/28) フォルダとファイルの自動判定(FileUtil.copy側で判断する)
    350                        else if( ACT_COPY.equalsIgnoreCase( action ) && file2 != null ) {
    351                                final File newFile = new File( StringUtil.urlAppend( directory,file2 ) );
    352
    353                                if( file.exists() ) {
    354                                        // FileUtil.copy 側で、toFile のフォルダを作成します。
    355                                        // 6.3.6.1 (2015/08/28) で、fromFile がディレクトリでも処理できるように変更。
    356                                        rtnVal = FileUtil.copy( file, newFile );
    357                                }
    358                                else {
    359                                        final String errMsg = "copy元(file1)のファイルが存在しません。" + CR
    360                                                        + "\t  action=["        + action        + "]"   + CR
    361                                                        + "\t  fileURL=["       + fileURL       + "]"   + CR
    362                                                        + "\t  directory=[" + directory + "]"   + CR
    363                                                        + "\t  file1=["         + file1         + "]"   + CR
    364                                                        + "\t  file2=["         + file2         + "]"   + CR ;
    365                                        throw new HybsSystemException( errMsg );
    366                                }
    367                        }
    368                        // 6.3.6.1 (2015/08/28) copyST アクション時に、copy元に、ｱﾄﾞﾚｽ指定できるようにする。
    369                        else if( ACT_COPYST.equalsIgnoreCase( action ) && file2 != null ) {
    370                                final File newFile = new File( StringUtil.urlAppend( directory,file2 ) );
    371
    372                                // ※ getResourceAsStream は、/gf/jsp/･･･ ではなく、/jsp/･･･ でのアドレス指定で取得します。
    373                                final ServletContext application = pageContext.getServletContext();
    374                                rtnVal = FileUtil.copy( application.getResourceAsStream( file1 ), newFile );
    375
    376                                if( !rtnVal ) {
    377                                        final String errMsg = action + " アクションが実行できませんでした。" + CR
    378                                                        + "\t  action=["        + action        + "]"   + CR
    379                                                        + "\t  fileURL=["       + fileURL       + "]"   + CR
    380                                                        + "\t  directory=[" + directory + "]"   + CR
    381                                                        + "\t  file1=["         + file1         + "]"   + CR
    382                                                        + "\t  file2=["         + file2         + "]"   + CR ;
    383                                        throw new HybsSystemException( errMsg );
    384                                }
    385                        }
    386                        // 6.2.3.0 (2015/05/01)
    387                        else if( ACT_LIST.equalsIgnoreCase( action ) ) {
    388                                final String[] files = file.isDirectory() ? file.list() : new String[] { file.getName() };
    389                                final List<String> list = new ArrayList<>();
    390
    391                                // 6.3.9.0 (2015/11/06) null になっている可能性がある(findbugs)
    392                                if( files != null ) {
    393                                        final boolean use = file2 == null || file2.isEmpty();
    394                                        for( final String nm : files ) {
    395                                                if( use || nm.matches( file2 ) ) {
    396                                                        list.add( nm );
    397                                                }
    398                                        }
    399                                }
    400
    401                                setRequestAttribute( "list",list );
    402                                rtnVal = true;
    403                        }
    404                        // 5.9.2.2 (2015/11/20) zip追加
    405                        else if( ACT_ZIP.equalsIgnoreCase( action ) && file2 != null ) {
    406                                //あるかないかだけ見る
    407                                if( file2.toLowerCase(Locale.JAPAN).indexOf( ".zip" ) < 0 ){                    // 6.4.1.1 (2016/01/16) PMD refactoring. When doing a String.toLowerCase()/toUpperCase() call, use a Locale
    408                                        file2 = file2 + ".zip";
    409                                }
    410                                final File zipFile = new File( StringUtil.urlAppend( directory,file2 ) );
    411                                // 6.9.8.0 (2018/05/28) FindBugs:例外的戻り値を無視しているメソッド
    412//                              zipFile.getParentFile().mkdirs();                                                                               // 6.8.0.0 (2017/06/02) zipFile の親ディレクトリを作成します。
    413                                final File parent = zipFile.getParentFile();            // 親フォルダを取得。nullもありえる
    414                                if( parent == null || !parent.exists() && !parent.mkdirs() ) {
    415                                        final String errMsg = "zipFileファイルの親フォルダを作成できませんでした。"   + CR
    416                                                                                + " zipFile=[" + zipFile + "]"  + CR ;
    417                                        throw new HybsSystemException( errMsg );
    418                                }
    419
    420                                final List<File> ziplist = ZipArchive.compress( file , zipFile );               // 6.7.0.0 (2016/12/28) 返り値で、正誤判定します。
    421                                rtnVal = !ziplist.isEmpty();                    // 6.7.0.0 (2016/12/28) true/false の判定を入れます。
    422                        }
    423                        // 6.7.0.0 (2016/12/28) timeStamp追加。タイムスタンプを現在時刻に変更します。
    424                        else if( ACT_TIMESTAMP.equalsIgnoreCase( action ) ) {
    425                                rtnVal = file.setLastModified( System.currentTimeMillis() );
    426                        }
    427
    428                return rtnVal;
    429        }
    430
    431        /**
    432         * 【TAG】アクション(canRead,canWrite,createNewFile,delete,renameTo,exists,isDirectory,isFile,isHidden,mkdir,mkdirs,read,existsLength,copy,copyST,list,zip,timeStamp)を指定します。
    433         *
    434         * @og.tag
    435         * アクションは,HTMLから(get/post)指定されますので,ACT_xxx で設定される
    436         * フィールド定数値のいづれかを、指定できます。
    437         * 処理の結果が、false の場合は、body 要素を表示して終了します。
    438         * useStop 属性と、notEquals 属性によって、上記の振る舞いをけることが可能です。
    439         *
    440         *       canRead          読み込めるかどうかを判定。
    441         *       canWrite         変更できるかどうか判定。
    442         *       createNewFile    空の新しいファイルを不可分 (atomic) に生成。(そのファイルがまだ存在しない場合だけ)
    443         *       delete           ファイルまたはディレクトリを削除(ディレクトリ階層をすべて削除)。
    444         *       renameTo         ファイルまたはディレクトリ名を変更。
    445         *       exists           ファイルが存在するかどうか判定。
    446         *       isDirectory      ファイルがディレクトリであるかどうか判定。
    447         *       isFile           ファイルが普通のファイルかどうか判定。
    448         *       isHidden         ファイルが隠しファイルかどうか判定。
    449         *       mkdir            ディレクトリを生成。
    450         *       mkdirs           ディレクトリを複数生成。
    451         *       read             ファイルを読み込んで、パラメータにセットします(6.2.3.0 (2015/05/01))。
    452         *       existsLength     ファイルサイズが０Byte以上のファイルが存在するかどうか判定。
    453         *       copy             ファイルまたはディレクトリをコピー(file1 ⇒ file2 にコピー)。
    454         *       copyST           ストリームファイルをコピー(file1(アドレス) ⇒ file2 にコピー)。
    455         *       list             ファイルリストをListオブジェクトにコピーして、パラメータにセットします(6.2.3.0 (2015/05/01))。
    456         *       zip              ファイルまたはディレクトリをZIPファイルに圧縮します。(file1⇒file2)
    457         *       timeStamp        ファイルのタイムスタンプを現在時刻に変更します。(file1のみ)
    458         *
    459         * ※1 copyST の file1 は、getResourceAsStream を使用の為、/gf/jsp/･･･ ではなく、/jsp/･･･ でのアドレス指定で取得します。
    460         *
    461         * @og.rev 3.0.0.0 (2002/12/25) ACTION_LIST のチェックを導入
    462         * @og.rev 3.5.6.2 (2004/07/05) 文字列の連結にStringBuilderを使用します。
    463         * @og.rev 6.3.4.0 (2015/08/01) エラーメッセージを、変更。
    464         * @og.rev 6.3.6.1 (2015/08/28) copyST アクション追加
    465         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    466         *
    467         * @param       cmd アクション文字列
    468         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.FileTag.ACT_canRead">アクション定数</a>
    469         */
    470        public void setAction( final String cmd ) {
    471                action = getRequestParameter( cmd );
    472
    473                if( ! check( action, ACTION_SET ) ) {
    474                        final String errMsg = "指定のアクションは実行できません。アクションエラー"       + CR
    475                                                        + "\t  action=["        + action        + "]"   + CR
    476                                                        + "\t  actionList=" + String.join( ", " , ACTION_SET ) ;
    477                        throw new HybsSystemException( errMsg );
    478                }
    479        }
    480
    481        /**
    482         * 【TAG】操作するファイルのディレクトリを指定します
    483         *              (初期値:FILE_URL[={@og.value SystemData#FILE_URL}])。
    484         *
    485         * @og.tag
    486         * この属性で指定されるディレクトリのファイルを操作します。
    487         * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、２文字目が、
    488         * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、
    489         * (初期値:システム定数のFILE_URL[={@og.value SystemData#FILE_URL}])。
    490         *
    491         * @og.rev 4.0.0.0 (2005/01/31) urlAppend メソッドの利用
    492         * @og.rev 4.0.0.0 (2007/11/20) 指定されたディレクトリ名の最後が"\"or"/"で終わっていない場合に、"/"を付加する。
    493         * @og.rev 6.4.2.1 (2016/02/05) URLの最後に、"/" を追加する処理を廃止。
    494         *
    495         * @param       url ファイルURL
    496         * @see         org.opengion.hayabusa.common.SystemData#FILE_URL
    497         */
    498        public void setFileURL( final String url ) {
    499                final String furl = nval( getRequestParameter( url ),null );
    500                if( furl != null ) {
    501                        fileURL = StringUtil.urlAppend( fileURL,furl );
    502                }
    503        }
    504
    505        /**
    506         * 【TAG】基準となるファイル名を指定します(コマンドの左辺のファイル名です)。
    507         *
    508         * @og.tag
    509         * コマンドの左辺のファイル名です。
    510         *
    511         * ※ 6.3.6.1 (2015/08/28)
    512         *    copyST アクション時に、copy元に、ｱﾄﾞﾚｽ指定できるようにする。
    513         *
    514         * @param       fname ファイル名１
    515         */
    516        public void setFile1( final String fname ) {
    517                file1 = nval( getRequestParameter( fname ),file1 );
    518        }
    519
    520        /**
    521         * 【TAG】処理結果となるファイル名を指定します(コマンドの右辺のファイル名です)。
    522         *
    523         * @og.tag
    524         * コマンドの右辺のファイル名です。
    525         * ただし、action="list" の時は、file2 を、フィルターとして使用します。
    526         *
    527         * @param       fname ファイル名２
    528         */
    529        public void setFile2( final String fname ) {
    530                file2 = nval( getRequestParameter( fname ),file2 );
    531        }
    532
    533        /**
    534         * 【TAG】判定結果を反転させるかどうか[true/false]を指定します(初期値:false)。
    535         *
    536         * @og.tag
    537         * 通常の判定結果において、不成立(false)の場合に、BODY を実行します。
    538         * 通常の処理結果の正反対の処理を行います。
    539         * 初期値は、通常 (true 以外)です。
    540         *
    541         * @og.rev 3.8.5.2 (2006/05/31) 新規追加
    542         *
    543         * @param   flag 判定結果反転 [true:反転する/それ以外:通常]
    544         */
    545        public void setNotEquals( final String flag ) {
    546                notEquals = nval( getRequestParameter( flag ),notEquals );
    547        }
    548
    549        /**
    550         * 【TAG】エラー時BODYを処理後に停止するかどうか[true/false]を指定します(初期値:true)。
    551         *
    552         * @og.tag
    553         * 処理結果などに応じて、以下の処理を停止したい場合に、使用します。
    554         * 通常は、条件を判定後、false の場合に、BODY部を出力(処理)した後に、
    555         * 処理を停止します。(useStop="true")
    556         * false を指定すると、判定結果に無関係に、以下の処理を実行します。
    557         * 処理は継続したいが、警告表示する場合に、useStop="false" を指定します。
    558         * 初期値は、停止する ("true")です。
    559         *
    560         * @og.rev 3.8.5.2 (2006/05/31) 新規追加
    561         *
    562         * @param   flag 処理後停止 [true:する/それ以外:しない]
    563         */
    564        public void setUseStop( final String flag ) {
    565                useStop = nval( getRequestParameter( flag ),useStop );
    566        }
    567
    568        /**
    569         * 【TAG】ファイルを読み込む(action="read")際のエンコードを指定します(初期値:OS依存文字コード)。
    570         *
    571         * @og.tag
    572         * ファイルを読み込む(action="read")際のエンコードを指定します。
    573         * action="read"以外場合には、この属性値は利用されません。
    574         * 指定しない場合は、OS依存文字コードで読み込まれます。
    575         *
    576         * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    577         *
    578         * @param   enc ファイル読み込みのエンコード
    579         */
    580        public void setEncode( final String enc ) {
    581                encode = nval( getRequestParameter( enc ),encode );
    582        }
    583
    584        /**
    585         * このオブジェクトの文字列表現を返します。
    586         * 基本的にデバッグ目的に使用します。
    587         *
    588         * @return このクラスの文字列表現
    589         * @og.rtnNotNull
    590         */
    591        @Override
    592        public String toString() {
    593                return ToString.title( this.getClass().getName() )
    594                                .println( "VERSION"             ,VERSION        )
    595                                .println( "fileURL"             ,fileURL        )
    596                                .println( "file1"               ,file1          )
    597                                .println( "file2"               ,file2          )
    598                                .println( "action"              ,action         )
    599                                .println( "rtnCode"             ,rtnCode        )
    600                                .println( "notEquals"   ,notEquals      )
    601                                .println( "useStop"             ,useStop        )
    602                                .println( "Other..."    ,getAttributes().getAttribute() )
    603                                .fixForm().toString() ;
    604        }
    605}