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