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.hayabusa.db.DBTableModel;
021import org.opengion.fukurou.util.ErrorMessage;
022import org.opengion.fukurou.util.FileUtil;
023import org.opengion.fukurou.util.ToString;                                              // 6.1.1.0 (2015/01/17)
024import org.opengion.fukurou.util.ArraySet;                                              // 6.4.3.4 (2016/03/11)
025import org.opengion.fukurou.util.StringUtil;                                    // 7.2.7.0 (2020/08/07)
026import org.opengion.hayabusa.io.HybsFileOperationFactory;               // 8.0.0.1 (2021/10/08)
027
028import static org.opengion.fukurou.util.StringUtil.nval ;
029import static org.opengion.fukurou.system.HybsConst.BR;                 // 6.1.0.0 (2014/12/26) refactoring
030
031import java.util.Locale ;
032import java.util.Set ;
033// import java.util.TreeSet ;
034// import java.util.Comparator ;
035import java.io.File ;
036// import java.io.Serializable;
037import java.io.IOException ;                                                                    // 7.0.5.0 (2019/09/13)
038
039/**
040 * ファイル検索リストを元に、action に基づいた処理を行うタグです。
041 * command="ENTRY" 時のみ処理を行います。
042 *
043 * fileQuery などで検索したファイル一覧のDBTableModel を元に、ファイルの
044 * コピー(COPY)、移動(MOVE,MODIFY)、削除(DELETE)などの処理を行います。
045 * 処理を行うオリジナルファイルは、PARENT,NAME というカラムでなければなりません。
046 *   ※ 7.2.7.0 (2020/08/07) parentClm,nameClm で指定可能になりました。
047 * このカラム名は、fileQuery の検索時には、必ず作成されるカラムです。
048 * また、各アクションに対応するターゲットファイルは、TO_PARENT,TO_NAME という
049 * カラムで指定するか、targetDir 属性を利用してフォルダを指定します。
050 * TO_PARENT(先フォルダ)と、TO_NAME(先ファイル名)は、処理に応じて、必要なカラムが
051 * あれば、自動的に処理します。
052 * つまり、TO_PARENT のみの場合は、ファイル名はオリジナルのまま、フォルダのみ変更します。
053 * 逆に、TO_NAME の場合は、フォルダはそのままで、ファイル名のみ指定します。
054 * 両方同時に指定することも可能です。
055 * targetDir 属性で指定する場合は、TO_PARENT のみに同じ値を設定した場合と同じになります。
056 * この属性を指定すると、TO_PARENT は無視されます。(TO_NAME は有効です。)
057 * COPY、MOVE(,MODIFY) の場合は、指定のフォルダに一括処理可能です。
058 * COPY、MOVE(,MODIFY) などの処理で、ターゲットフォルダが存在しないときに、作成するか、エラーにするかは
059 * createDir属性 で指定できます。初期値は、(true:作成する) です。
060 * これは、COPY先やMOVE(,MODIFY)先が存在している前提のシステムで、不要な箇所に間違ってフォルダを
061 * 自動作成されると困る場合に、(false:作成しない) とすれば、間違いに気づく確率が上がります。
062 *
063 *   ※ 7.2.7.0 (2020/08/07) PARENT,NAME,TO_PARENT,TO_NAME のカラム名を指定できるようにしました。
064 *      action にMKDIRS を追加しました。これは、TO_PARENT フォルダが作成できるかどうかを判定します。
065 *
066 * ※ このタグは、Transaction タグの対象ではありません。
067 *
068 * @og.formSample
069 * ●body:なし
070 * ●形式:
071 *      ・<og:fileUpdate
072 *          action        = "COPY|MOVE|MODIFY|DELETE|MKDIRS" アクション属性(必須)
073 *          command       = "[ENTRY]"                 ENTRY 時のみ実行します(初期値:ENTRY)
074 *          targetDir     = "[指定フォルダ]"          ターゲットとなるフォルダ
075 *          createDir     = "[true/false]"            ターゲットとなるフォルダがなければ作成する(true)かどうか(初期値:true)
076 *          tableId       = [HybsSystem.TBL_MDL_KEY]  DBTableModel を取り出すキー
077 *          displayMsg    = "MSG0040";                処理結果を表示します(初期値:「 件登録しました。」)
078 *          selectedAll   = "[false/true]"            データを全件選択済みとして処理する(true)かどうか指定(初期値:false)
079 *          keepTimeStamp = "[false/true]"            COPY,親違いMOVE(,MODIFY)の時にオリジナルのタイムスタンプを使用するかどうか(初期値:false)
080 *      />
081 *
082 *    [action属性(必須)]
083 *      COPY   オリジナルファイルを、ターゲット(TO_PARENT,TO_NAMEで指定)にコピーします。
084 *      MOVE   オリジナルファイルを、ターゲットに移動(COPY+DELETE)/名称変更(RENAME)します。
085 *      MODIFY (MOVE と同じ。エンジンの command を利用するための簡易action)
086 *      DELETE オリジナルファイルを削除します(ターゲット(TO_PARENT,TO_NAME)は、関係しません)。
087 *      MKDIRS ターゲット(TO_PARENTで指定)フォルダを作成します。(PARENT,NAME,TO_NAMEは、関係しません)。 7.2.7.0 (2020/08/07) 新規追加
088 *
089 * ●Tag定義:
090 *   <og:fileUpdate
091 *       action           ○【TAG】アクション[COPY|MOVE|MODIFY|DELETE|MKDIRS]をセットします(必須)。
092 *       command            【TAG】コマンド[ENTRY]をセットします(初期値:ENTRY)
093 *       targetDir          【TAG】ターゲットとなるフォルダを指定します
094 *       createDir          【TAG】ターゲットとなるフォルダがなければ、作成するかどうかを指定します(初期値:true)
095 *       parentClm          【TAG】7.2.7.0 (2020/08/07) fileQuery以外の場合の元親フォルダを示すカラム名を指定します(初期値:"PARENT")
096 *       nameClm            【TAG】7.2.7.0 (2020/08/07) fileQuery以外の場合の元ファイル名を示すカラム名を指定します(初期値:"NAME")
097 *       toParentClm        【TAG】7.2.7.0 (2020/08/07) fileQuery以外の場合の先親フォルダを示すカラム名を指定します(初期値:"TO_PARENT")
098 *       toNameClm          【TAG】7.2.7.0 (2020/08/07) fileQuery以外の場合の先ファイル名を示すカラム名を指定します(初期値:"TO_NAME")
099 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
100 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
101 *       displayMsg         【TAG】処理結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0040[ 件登録しました])
102 *       actErrMsg          【TAG】7.2.7.0 (2020/08/07) action実行時のエラーメッセージのメッセージリソースIDを指定します(初期値:ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2})
103 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
104 *       keepTimeStamp      【TAG】オリジナルのタイムスタンプを利用するかどうかを指定します(初期値:false)
105 *       inPath             【TAG】6.8.0.0 (2017/06/02) 入力共通パスを指定します(PARENTフォルダの共通部分、COPY/MOVE時にtargetDirと置換されます) 。
106 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
107 *                                      (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
108 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
109 *       useStop            【TAG】7.2.7.0 (2020/08/07) エラー時に処理後に停止するかどうか[true/false]を指定します(初期値:true)
110 *       useLocal           【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false) 8.0.1.0 (2021/10/29)
111 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
112 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
113 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
114 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
115 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
116 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
117 *   />
118 *
119 * ●使用例
120 *       ・<og:fileUpdate command="{@command}" action="COPY" />
121 *             TO_PARENT または、 TO_NAME(両方指定も可)による行単位 COPY 処理
122 *             fileQuery の useUpdateClm="true" を設定し、検索結果に、TO_PARENT、 TO_NAMEカラムを追加します。
123 *             TO_PARENT または、 TO_NAME は、columnSet などで値をセットしておきます。
124 *
125 *       ・<og:fileUpdate command="{@command}" action="MODIFY" targetDir="AAA_DIR"  />
126 *             fileQuery の検索結果を、AAA_DIR フォルダに移動します。
127 *             ファイル名は、そのままオリジナルの値が使用されます。
128 *
129 * @og.rev 5.3.4.0 (2011/04/01) 新規追加
130 * @og.group ファイル出力
131 *
132 * @version  4.0
133 * @author       Kazuhiko Hasegawa
134 * @since    JDK5.0,
135 */
136public class FileUpdateTag extends CommonTagSupport {
137        /** このプログラムのVERSION文字列を設定します。 {@value} */
138        private static final String VERSION = "8.4.2.2 (2023/03/17)" ;
139        private static final long serialVersionUID = 842220230317L ;
140
141        /** command 引数に渡す事の出来る コマンド  登録{@value} */
142        public static final String CMD_ENTRY  = "ENTRY" ;
143        /** command 引数に渡す事の出来る コマンド リスト  */
144        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
145        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_ENTRY );
146
147        /** エラーメッセージID {@value} */
148        private static final String ERR_MSG_ID  = HybsSystem.ERR_MSG_KEY;               // 6.4.1.1 (2016/01/16) errMsgId → ERR_MSG_ID  refactoring
149
150        /** action 引数に渡す事の出来る アクションコマンド  COPY {@value} */
151        public static final String ACT_COPY             = "COPY" ;
152        /** action 引数に渡す事の出来る アクションコマンド  MOVE {@value} */
153        public static final String ACT_MOVE             = "MOVE" ;
154        /** action 引数に渡す事の出来る アクションコマンド  MODIFY {@value} */
155        public static final String ACT_MODIFY   = "MODIFY" ;
156        /** action 引数に渡す事の出来る アクションコマンド  DELETE {@value} */
157        public static final String ACT_DELETE   = "DELETE" ;
158        /** action 引数に渡す事の出来る アクションコマンド  MKDIRS {@value} */
159        public static final String ACT_MKDIRS   = "MKDIRS" ;                                            // 7.2.7.0 (2020/08/07)
160        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
161//      private static final Set<String> ACTION_SET = new ArraySet<>( ACT_COPY , ACT_MOVE , ACT_MODIFY , ACT_DELETE );
162        private static final Set<String> ACTION_SET = new ArraySet<>( ACT_COPY , ACT_MOVE , ACT_MODIFY , ACT_DELETE ,ACT_MKDIRS );      // 7.2.7.0 (2020/08/07)
163
164        private String  action          ;
165        private String  targetDir       ;                       // ターゲットとなるフォルダ
166        private boolean createDir       = true;         // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
167
168        private String  inPath          ;                       // 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
169
170        private String  parentClm       = "PARENT";             // 7.2.7.0 (2020/08/07) fileQuery以外の場合の元親フォルダを示すカラム名を指定します(初期値:"PARENT")
171        private String  nameClm         = "NAME";               // 7.2.7.0 (2020/08/07) fileQuery以外の場合の元ファイル名を示すカラム名を指定します(初期値:"NAME")
172        private String  toParentClm     = "TO_PARENT";  // 7.2.7.0 (2020/08/07) fileQuery以外の場合の先親フォルダを示すカラム名を指定します(初期値:"TO_PARENT")
173        private String  toNameClm       = "TO_NAME";    // 7.2.7.0 (2020/08/07) fileQuery以外の場合の先ファイル名を示すカラム名を指定します(初期値:"TO_NAME")
174
175        private String  tableId         = HybsSystem.TBL_MDL_KEY;
176        private String  command         = CMD_ENTRY;
177//      private boolean outMessage      = true;                         // 7.2.7.0 (2020/08/07) 削除
178        private String  displayMsg      = "MSG0040";            //  件登録しました。
179        private String  actErrMsg       = "ERR0050";            // 7.2.7.0 (2020/08/07) アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
180
181        private boolean selectedAll ;
182        private boolean keepTimeStamp;                                  // オリジナルのタイムスタンプを利用する場合、true
183
184        private transient DBTableModel  table           ;
185        private transient ErrorMessage  errMessage      ;
186        private int             executeCount    = -1;                   // 処理件数
187        private int             errCode                 = ErrorMessage.OK;
188        private boolean useTimeView             = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );             // 6.3.6.0 (2015/08/16)
189        private boolean useSLabel               ;                               // 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
190        private boolean useStop                 = true;                 // 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか(useStop対応)
191        private boolean useLocal                ;                               // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
192
193        /**
194         * デフォルトコンストラクター
195         *
196         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
197         */
198        public FileUpdateTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
199
200        /**
201         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
202         *
203         * @og.rev 6.4.4.1 (2016/03/18) 意味のない、StringBuilderだったので、廃止します。
204         * @og.rev 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
205         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
206         * @og.rev 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか(useStop対応)
207         *
208         * @return      後続処理の指示
209         */
210        @Override
211        public int doEndTag() {
212                debugPrint();
213                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
214                if( !useTag() ) { return EVAL_PAGE ; }
215
216                final long dyStart = System.currentTimeMillis();
217
218                table = (DBTableModel)getObject( tableId );
219
220                // 7.2.7.0 (2020/08/07) 出力のタイミングを、useStop の判定前に持ってきます。
221//              String label  = "";                             // 4.0.0 (2005/11/30) 検索しなかった場合。
222                if( table != null && table.getRowCount() > 0 && check( command, COMMAND_SET ) ) {
223                        startQueryTransaction( tableId );
224
225                        execute();      // 実際の処理を実行します。
226
227                        setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
228                        setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
229
230                        // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
231                        if( ! commitTableObject( tableId, table ) ) {
232                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Query Error!" ); }
233                                // ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
234                                errMessage.addMessage( 0,ErrorMessage.NG,"ERR0041" );
235                                errCode = ErrorMessage.NG;
236                        }
237
238//                      final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
239                        final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource(),useSLabel );         // 7.0.7.0 (2019/12/13)
240                        if( err != null && err.length() > 0 ) {
241                                // 7.2.7.0 (2020/08/07) 出力のタイミングを、useStop の判定前に持ってきます。
242//                              label = err ;           // 6.4.4.1 (2016/03/18)
243                                jspPrint( err );        // 7.2.7.0 (2020/08/07)
244                                setSessionAttribute( ERR_MSG_ID,errMessage );
245                        }
246
247                        // 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか
248                        if( useStop && errCode >= ErrorMessage.NG ) {
249                                return SKIP_PAGE ;
250                        }
251
252//                      // 6.9.9.0 (2018/08/20) 「ERR0041:検索処理中に割り込みの検索要求がありました」エラーを、標準のErrorMessageに追加するようにします。
253//                      if( table != null && ! commitTableObject( tableId, table ) ) {
254//                              jspPrint( "FileUpdateTag Query処理が割り込まれました。DBTableModel は登録しません。" );
255//                              return SKIP_PAGE ;
256//                      }
257                }
258
259//              jspPrint( label );                                              // 7.2.7.0 (2020/08/07)
260
261                // 実行件数の表示
262                // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。
263                if( displayMsg != null && displayMsg.length() > 0 ) {
264                        final String status = executeCount + getResource().getLabel( displayMsg ) ;
265                        jspPrint( status + BR );
266                }
267
268                if( useTimeView ) {             // 6.3.6.0 (2015/08/16)
269                        // 3.5.4.7 (2004/02/06)
270                        final long dyTime = System.currentTimeMillis()-dyStart;
271                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );  // 3.5.6.3 (2004/07/12)
272                }
273                return EVAL_PAGE ;
274        }
275
276        /**
277         * タグリブオブジェクトをリリースします。
278         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
279         *
280         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
281         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
282         * @og.rev 7.2.7.0 (2020/08/07) outMessage 削除
283         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
284         * @og.rev 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか(useStop対応)
285         * @og.rev 7.2.7.0 (2020/08/07) ERR0050:アクション実行中にエラーが発生しました。
286         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
287         */
288        @Override
289        protected void release2() {
290                super.release2();
291                tableId         = HybsSystem.TBL_MDL_KEY;
292                command         = CMD_ENTRY;
293                action          = null;
294                targetDir       = null;                 // ターゲットとなるフォルダ
295                createDir       = true;                 // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
296//              outMessage      = true;
297                parentClm       = "PARENT";             // 7.2.7.0 (2020/08/07) fileQuery以外の場合の元親フォルダを示すカラム名を指定します(初期値:"PARENT")
298                nameClm         = "NAME";               // 7.2.7.0 (2020/08/07) fileQuery以外の場合の元ファイル名を示すカラム名を指定します(初期値:"NAME")
299                toParentClm     = "TO_PARENT";  // 7.2.7.0 (2020/08/07) fileQuery以外の場合の先親フォルダを示すカラム名を指定します(初期値:"TO_PARENT")
300                toNameClm       = "TO_NAME";    // 7.2.7.0 (2020/08/07) fileQuery以外の場合の先ファイル名を示すカラム名を指定します(初期値:"TO_NAME")
301                displayMsg      = "MSG0040";    //  件登録しました。
302                actErrMsg       = "ERR0050";    // 7.2.7.0 (2020/08/07) アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
303                selectedAll = false;
304                keepTimeStamp = false;          // オリジナルのタイムスタンプを利用する場合、true
305                table           = null;
306                errMessage      = null;
307                executeCount= -1;                       // 処理件数
308                errCode         = ErrorMessage.OK;
309                useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );     // 6.3.6.0 (2015/08/16)
310                inPath          = null;                 // 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
311                useSLabel       = false;                // 7.0.7.0 (2019/12/13) エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
312                useStop         = true;                 // 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか
313                useLocal        = false;                // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
314        }
315
316        /**
317         * 処理を実行します。
318         *
319         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
320         * @og.rev 7.2.7.0 (2020/08/07) MKDIRSアクション 追加
321         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
322         */
323        private void execute() {
324                final int[] rowNo = getParameterRows();
325                if( rowNo.length > 0 ) {
326                        // 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
327                        final String[] clms = new String[] { parentClm,nameClm,toParentClm,toNameClm } ;
328
329//                      final FromToFiles fromToFiles = new FromToFiles( table , targetDir , createDir , inPath );                      // 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定
330                        final FromToFiles fromToFiles = new FromToFiles( useLocal,table,targetDir,createDir,inPath,clms );      // 7.2.7.0 (2020/08/07)
331
332                        if( ACT_COPY.equalsIgnoreCase( action ) ) {
333                                actionCOPY( rowNo,fromToFiles );
334                        }
335                        // ACT_MODIFY は、エンジンの command で使うため、便利
336                        else if( ACT_MOVE.equalsIgnoreCase( action ) || ACT_MODIFY.equalsIgnoreCase( action ) ) {
337                                actionMOVE( rowNo,fromToFiles );
338                        }
339                        else if( ACT_DELETE.equalsIgnoreCase( action ) ) {
340                                actionDELETE( rowNo,fromToFiles );
341                        }
342                        else if( ACT_MKDIRS.equalsIgnoreCase( action ) ) {              // 7.2.7.0 (2020/08/07)
343                                actionMKDIRS( rowNo,fromToFiles );
344                        }
345                }
346        }
347
348        /**
349         * COPY アクションを実行します。
350         *
351         * エラー発生時の引数は、アクション:{0} From:{1} To:{2} です。
352         *
353         * @og.rev 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
354         * @og.rev 7.2.7.0 (2020/08/07) ERR0050:アクション実行中にエラーが発生しました。
355         *
356         * @param       rowNo           処理を実施する行番号
357         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
358         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
359         */
360        private void actionCOPY( final int[] rowNo , final FromToFiles fromToFiles ) {
361                File fromFile = null ;
362                File toFile   = null ;
363
364                executeCount = 0 ;      // 開始前に初期化しておく。
365                final int rowCount = rowNo.length ;
366                for( int i=0; i<rowCount; i++ ) {
367                        final File[] files = fromToFiles.makeFromToFile( rowNo[i] );    // FromFile,ToFile
368                        fromFile = files[0];
369                        toFile   = files[1];
370
371                        if( fromFile.isFile() && !FileUtil.copy( fromFile,toFile,keepTimeStamp ) ) {
372                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
373                                // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
374                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,fromFile.toString(),toFile.toString() );
375                                errCode = ErrorMessage.NG;
376                        }
377
378//                      // 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
379//                      if( fromFile.isFile() && !FileUtil.copy( fromFile,toFile,keepTimeStamp ) ) {
380//                              final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
381//                                                                      + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
382//                              // 6.0.2.5 (2014/10/31) refactoring
383//                              if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
384//                              errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionCOPY",errMsg );
385//                      }
386                        executeCount++ ;
387                }
388        }
389
390        /**
391         * MOVE アクションを実行します。
392         *
393         * エラー発生時の引数は、アクション:{0} From:{1} To:{2} です。
394         *
395         * @og.rev 5.5.2.4 (2012/05/16) メソッドの戻り値の設定
396         * @og.rev 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
397         * @og.rev 7.2.7.0 (2020/08/07) ERR0050:アクション実行中にエラーが発生しました。
398         *
399         * @param       rowNo           処理を実施する行番号
400         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
401         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
402         */
403        private void actionMOVE( final int[] rowNo , final FromToFiles fromToFiles ) {
404                File fromFile = null ;
405                File toFile   = null ;
406
407                executeCount = 0 ;      // 開始前に初期化しておく。
408                final int rowCount = rowNo.length ;
409                for( int i=0; i<rowCount; i++ ) {
410                        final File[] files = fromToFiles.makeFromToFile( rowNo[i] );    // FromFile,ToFile
411                        fromFile = files[0];
412                        toFile   = files[1];
413
414                        if( fromToFiles.lastParentEquals() ) {  // FromDirとToDirが同じなので、RENAMEできる。
415                                if( !fromFile.renameTo( toFile ) ) {
416                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
417                                        // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
418                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,fromFile.toString(),toFile.toString() );
419                                        final String errMsg1 = "同一親フォルダのため、RENAME処理を行っています。";
420                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,errMsg1 );
421                                        errCode = ErrorMessage.NG;
422
423//                                      final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
424//                                                                              + "同一親フォルダのため、RENAME処理を行っています。" + CR
425//                                                                              + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
426//                                      // 6.0.2.5 (2014/10/31) refactoring
427//                                      if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
428//                                      errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
429                                }
430                        }
431                        // 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
432                        else if( fromFile.isFile() ) {                  // FromDirとToDirが異なるので、COPY + DELETE する。
433                                if( !FileUtil.copy( fromFile,toFile,keepTimeStamp ) ) {
434                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
435                                        // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
436                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,fromFile.toString(),toFile.toString() );
437                                        final String errMsg1 = "移動前のCOPY処理を行っていました。";
438                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,errMsg1 );
439                                        errCode = ErrorMessage.NG;
440
441//                                      final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
442//                                                                              + "移動前のCOPY処理を行っていました。" + CR
443//                                                                              + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
444//                                      // 6.0.2.5 (2014/10/31) refactoring
445//                                      if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
446//                                      errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
447                                }
448
449                                if( !fromFile.delete() ) {
450                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
451                                        // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
452                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,fromFile.toString(),toFile.toString() );
453                                        final String errMsg1 = "移動後のオリジナルファイルの削除処理を行っていました。";
454                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,errMsg1 );
455                                        errCode = ErrorMessage.NG;
456
457//                                      String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
458//                                                                              + "移動後のオリジナルファイルの削除処理を行っていました。" + CR
459//                                                                              + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
460//                                      // 5.5.2.4 (2012/05/16) メソッドの戻り値の設定
461                                        if( !toFile.delete() ) {
462//                                              errMsg = errMsg + "toFile も削除に失敗しました。" + CR;
463                                                final String errMsg3 = "toFile も削除に失敗しました。";
464                                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,errMsg3 );
465                                        }
466
467//                                      // 6.0.2.5 (2014/10/31) refactoring
468//                                      if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
469//                                      errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
470                                }
471                        }
472                        executeCount++ ;
473                }
474        }
475
476        /**
477         * DELETE アクションを実行します。
478         *
479         * この処理では、リストにフォルダが含まれている場合も削除します。
480         * 通常、フォルダの削除は、その要素(内部)にファイル等が存在しない場合のみ
481         * 行いますが、検索リストから削除する順番によっては、フォルダもファイルも
482         * 削除対象になる場合があります。そこで、まず。ファイルだけ削除し、フォルダは、
483         * あとで削除するように処理を行います。
484         *
485         * エラー発生時の引数は、アクション:{0} From:{1} To:"" です。
486         *
487         * @og.rev 5.6.5.2 (2013/06/21) フォルダも削除対象にします。
488         * @og.rev 7.2.6.0 (2020/06/30) 削除方法を変更します。
489         * @og.rev 7.2.7.0 (2020/08/07) ERR0050:アクション実行中にエラーが発生しました。
490         *
491         * @param       rowNo           処理を実施する行番号
492         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
493         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
494         */
495        private void actionDELETE( final int[] rowNo , final FromToFiles fromToFiles ) {
496                final int rowCount = rowNo.length ;
497                for( int i=0; i<rowCount; i++ ) {
498                        final File fmFile = fromToFiles.makeFromOnly( rowNo[i] );       // FromFile
499                        try {
500                                delete( fmFile );
501                                executeCount++ ;
502                        }
503                        catch( final Throwable th ) {
504                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
505                                // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
506                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,fmFile.toString(),"" );
507                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,th.getMessage() );
508                                errCode = ErrorMessage.NG;
509
510//                              final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
511//                                                                      + "From=[" + fmFile + "]" + CR;
512//                              // 6.0.2.5 (2014/10/31) refactoring
513//                              if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
514//                              errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionDELETE",errMsg );
515                        }
516                }
517        }
518
519        /**
520         * フォルダやファイルがあっても、すべて再帰的に削除します。
521         *
522         * @og.rev 7.2.6.0 (2020/06/30) 削除方法を変更します。
523         * @og.rev 7.2.9.4 (2020/11/20) spotbugs:null になっている可能性があるメソッドの戻り値を利用している
524         *
525         * @param       inFile  起点となるフォルダ
526         */
527        private static void delete( final File inFile ) {
528                final File[] flist = inFile.listFiles();
529                if( flist != null ) {                                           // 7.2.9.4 (2020/11/20)
530                        for( final File file : flist) {
531                                if( file.isDirectory() ) {
532                                        delete( file );
533                                } else {
534//                                      file.delete();
535                                        if( !file.delete() ) {                  // 7.3.0.0 (2021/01/06) SpotBugs 例外的戻り値を無視しているメソッド
536                                                System.err.println( "file Delete Error! " + file );
537                                        }
538                                }
539                        }
540                }
541//              inFile.delete();
542                if( !inFile.delete() ) {                                        // 7.3.0.0 (2021/01/06) SpotBugs 例外的戻り値を無視しているメソッド
543                        System.err.println( "inFile Delete Error! " + inFile );
544                }
545        }
546
547        /**
548         * MKDIRS アクションを実行します。
549         *
550         * この処理では、TO_PARENT カラムに指定されたターゲットフォルダを 多階層mkdirします。
551         * 実際は、ファイル作成やコピー時には、mkdirs するので、ここでの使い方の想定は、
552         * ターゲットフォルダへのアクセスが可能かどうかの確認です。
553         * 存在チェック(EXISTS)では、本当に存在しない場合も、アクセス出来ない場合も
554         * false となるためです。
555         * なお、通常の mkdirs では、フォルダが新規に作成されなかった場合(すでに存在)
556         * false となりますが、ここのアクションでは、アクセスチェックも兼ねているため、
557         * mkdirs が成功するか、すでに存在している場合は、正常と判断します。
558         *
559         * エラー発生時の引数は、アクション:{0} From:"" To:{2} です。
560         *
561         * @og.rev 7.2.7.0 (2020/08/07) MKDIRSアクション 追加
562         *
563         * @param       rowNo           処理を実施する行番号
564         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
565         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
566         */
567        private void actionMKDIRS( final int[] rowNo , final FromToFiles fromToFiles ) {
568                final int rowCount = rowNo.length ;
569                for( int i=0; i<rowCount; i++ ) {
570                        try {
571                                fromToFiles.makeToParent( rowNo[i] );           // 戻り値は確認しない。
572                        }
573                        catch( final Throwable th ) {
574                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
575                                // ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
576                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,actErrMsg,action,"",fromToFiles.getLastDir() );
577                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,action,th.getMessage() );
578                                errCode = ErrorMessage.NG;
579                        }
580                }
581        }
582
583        /**
584         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
585         *
586         * @return      選択行の配列
587         * @og.rtnNotNull
588         */
589        @Override
590        protected int[] getParameterRows() {
591                final int[] rowNo ;
592                if( selectedAll ) {
593                        final int rowCnt = table.getRowCount();
594                        rowNo = new int[ rowCnt ];
595                        for( int i=0; i<rowCnt; i++ ) {
596                                rowNo[i] = i;
597                        }
598                } else {
599                        rowNo = super.getParameterRows();
600                }
601                return rowNo ;
602        }
603
604        /**
605         * 【TAG】アクション[COPY|MOVE|MODIFY|DELETE|MKDIRS]をセットします。
606         *
607         * @og.tag
608         * アクションは、ファイルをコピー(COPY)したり、移動(MOVE,MODIFY)したり、削除(DELETE)、
609         * フォルダ作成(MKDIRS)するなどの操作を指定する必須属性です。
610         *
611         * <table class="plain">
612         *   <caption>action属性(必須)のキーワード</caption>
613         *   <tr><th>action</th><th>名称</th><th>機能</th></tr>
614         *   <tr><td>COPY  </td><td>コピー</td><td>オリジナルファイルを、ターゲット(TO_PARENT,TO_NAMEで指定)にコピーします。</td></tr>
615         *   <tr><td>MOVE  </td><td>移動  </td><td>オリジナルファイルを、ターゲットに移動(COPY+DELETE)/名称変更(RENAME)します。</td></tr>
616         *   <tr><td>MODIFY</td><td>移動  </td><td>(MOVE と同じ。エンジンの command を利用するための簡易action)</td></tr>
617         *   <tr><td>DELETE</td><td>削除  </td><td>オリジナルファイルを、削除します。(フォルダ、ファイルに関わらず)</td></tr>
618         *   <tr><td>MKDIRS</td><td>削除  </td><td>ターゲット(TO_PARENTで指定)フォルダを作成します。 7.2.7.0 (2020/08/07)</td></tr>
619         * </table>
620         *
621         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
622         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
623         *
624         * @param       act アクション (public static final 宣言されている文字列)
625         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.FileUpdateTag.ACT_COPY">アクション定数</a>
626         */
627        public void setAction( final String act ) {
628                action = nval( getRequestParameter( act ),action );
629
630                if( action != null && !check( action, ACTION_SET ) ) {
631                        final String errMsg = "指定のアクションは実行できません。アクションエラー"       + CR
632                                                        + "action=[" + action + "] "                                                            + CR
633                                                        + "actionList=" + String.join( ", " , ACTION_SET ) ;
634                        throw new HybsSystemException( errMsg );
635                }
636        }
637
638        /**
639         * 【TAG】ターゲットとなるフォルダを指定します(初期値:null)。
640         *
641         * @og.tag
642         * targetDir 属性を利用する場合は、引数のファイル、またはフォルダが指定されたことに
643         * なります。COPY、MOVE(,MODIFY) の場合は、targetDir 属性にフォルダを指定することで一括処理可能です。
644         * 指定先のフォルダが存在しない場合は、createDir属性の値により処理が異なります。
645         * createDir="true"(初期値)で、ターゲットフォルダが存在しない場合は、自動作成します。
646         *
647         * @param  dir ターゲットとなるフォルダ
648         * @see         #setCreateDir( String )
649         */
650        public void setTargetDir( final String dir ) {
651                targetDir = nval( getRequestParameter( dir ),targetDir );
652        }
653
654        /**
655         * 【TAG】ターゲットとなるフォルダがなければ、作成するかどうかを指定します(初期値:true)。
656         *
657         * @og.tag
658         * COPY,MOVE(,MODIFY) などの処理で、ターゲットフォルダが存在しないときに、作成するか、エラーにするかを
659         * createDir属性 で指定できます。
660         * これは、COPY先やMOVE(,MODIFY)先が存在している前提のシステムで、不要な箇所に間違ってフォルダを
661         * 自動作成されると困る場合に、false:作成しない とすれば、間違いに気づく確率が上がります。
662         * 初期値は true:作成する です。
663         *
664         * @param       flag    フォルダ作成可否 [true:作成する/false:作成しない]
665         */
666        public void setCreateDir( final String flag ) {
667                createDir = nval( getRequestParameter( flag ),createDir );
668        }
669
670        /**
671         * 【TAG】fileQuery以外の場合の元親フォルダを示すカラム名を指定します(初期値:"PARENT")。
672         *
673         * @og.tag
674         * 通常、fileQueryで取得したフォルダとファイル名は、PARENT,NAME というカラムに作成されます。
675         * ここでは、データベース等で管理しているフォルダやファイル名を検索した場合に処理できるように
676         * それぞれのカラム名を指定できるようにします。
677         * (初期値:"PARENT")
678         *
679         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
680         *
681         * @param       clm 元親フォルダを示すカラム名
682         */
683        public void setParentClm( final String clm ) {
684                parentClm = nval( getRequestParameter( clm ),parentClm );
685        }
686
687        /**
688         * 【TAG】fileQuery以外の場合の元ファイル名を示すカラム名を指定します(初期値:"NAME")。
689         *
690         * @og.tag
691         * 通常、fileQueryで取得したフォルダとファイル名は、PARENT,NAME というカラムに作成されます。
692         * ここでは、データベース等で管理しているフォルダやファイル名を検索した場合に処理できるように
693         * それぞれのカラム名を指定できるようにします。
694         * (初期値:"NAME")
695         *
696         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
697         *
698         * @param       clm 元ファイル名を示すカラム名
699         */
700        public void setNameClm( final String clm ) {
701                nameClm = nval( getRequestParameter( clm ),nameClm );
702        }
703
704        /**
705         * 【TAG】fileQuery以外の場合の先親フォルダを示すカラム名を指定します(初期値:"TO_PARENT")。
706         *
707         * @og.tag
708         * 通常、fileQueryで取得したフォルダとファイル名は、PARENT,NAME というカラムに作成されます。
709         * ここでは、データベース等で管理しているフォルダやファイル名を検索した場合に処理できるように
710         * それぞれのカラム名を指定できるようにします。
711         * (初期値:"TO_PARENT")
712         *
713         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
714         *
715         * @param       clm 先親フォルダを示すカラム名
716         */
717        public void setToParentClm( final String clm ) {
718                toParentClm = nval( getRequestParameter( clm ),toParentClm );
719        }
720
721        /**
722         * 【TAG】fileQuery以外の場合の先ファイル名を示すカラム名を指定します(初期値:"TO_NAME")。
723         *
724         * @og.tag
725         * 通常、fileQueryで取得したフォルダとファイル名は、PARENT,NAME というカラムに作成されます。
726         * ここでは、データベース等で管理しているフォルダやファイル名を検索した場合に処理できるように
727         * それぞれのカラム名を指定できるようにします。
728         * (初期値:"TO_NAME")
729         *
730         * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
731         *
732         * @param       clm 先ファイル名を示すカラム名
733         */
734        public void setToNameClm( final String clm ) {
735                toNameClm = nval( getRequestParameter( clm ),toNameClm );
736        }
737
738        /**
739         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
740         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
741         *
742         * @og.tag
743         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
744         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
745         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
746         * この tableId 属性を利用して、メモリ空間を分けます。
747         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
748         *
749         * @param       id テーブルID (sessionに登録する時のID)
750         */
751        public void setTableId( final String id ) {
752                tableId = nval( getRequestParameter( id ),tableId );
753        }
754
755        /**
756         * 【TAG】コマンド (ENTRY)をセットします(初期値:ENTRY)。
757         *
758         * @og.tag
759         * このタグは、command="ENTRY" でのみ実行されます。
760         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
761         * フィールド定数値のいづれかを、指定できます。
762         * 初期値は、ENTRY なので、何も指定しなければ、実行されます。
763         *
764         * @param       cmd コマンド (public static final 宣言されている文字列)
765         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.FileUpdateTag.CMD_ENTRY">コマンド定数</a>
766         */
767        public void setCommand( final String cmd ) {
768                final String cmd2 = getRequestParameter( cmd );
769                if( cmd2 != null && cmd2.length() >= 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
770        }
771
772//      /**
773//       * 【TAG】検索結果のメッセージを表示する/しない[true/false]を指定します(初期値:true)。
774//       *
775//       * @og.tag
776//       * 初期値は、表示する:true です。
777//       *
778//       * @og.rev 7.2.7.0 (2020/08/07) outMessage 削除
779//       *
780//       * @param       flag  メッセージ表示可否 [true:表示する/それ以外:含めない]
781//       */
782//      public void setOutMessage( final String flag ) {
783//              outMessage = nval( getRequestParameter( flag ),outMessage );
784//      }
785
786        /**
787         * 【TAG】処理結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0040[ 件登録しました])。
788         *
789         * @og.tag
790         * ここでは、検索結果の件数や登録された件数をまず出力し、
791         * その次に、ここで指定したメッセージをリソースから取得して表示します。
792         * 表示させたくない場合は, displayMsg = "" をセットしてください。
793         * displayMsg の初期値は、MSG0040[ 件登録しました]です。
794         *
795         * @param       id 処理結果表示メッセージID
796         */
797        public void setDisplayMsg( final String id ) {
798                final String ids = getRequestParameter( id );
799                if( ids != null ) { displayMsg = ids; }
800        }
801
802        /**
803         * 【TAG】action実行時のエラーメッセージのメッセージリソースIDを指定します(初期値:ERR0050:アクション実行中にエラーが発生しました。
804         *
805         * @og.tag
806         * action実行時のエラーメッセージは、COPY|MOVE|MODIFY|DELETE|MKDIRS などのアクション実行時に
807         * エラーが発生した際に、表示するメッセージリソースのID をセットします。
808         * エラーメッセージのため、未指定にすることはできません。
809         * actErrMsg の初期値は、ERR0050:アクション実行中にエラーが発生しました。アクション:{0} From:{1} To:{2}
810         *
811         * @og.rev 7.2.7.0 (2020/08/07) MKDIRSアクション 追加
812         *
813         * @param       id action実行時のエラーメッセージのメッセージリソースID
814         */
815        public void setActErrMsg( final String id ) {
816                actErrMsg = nval( getRequestParameter( id ),actErrMsg );
817        }
818
819        /**
820         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
821         *
822         * @og.tag
823         * 全てのデータを選択済みデータとして扱って処理します。
824         * 全件処理する場合に、(true/false)を指定します。
825         * 初期値は false です。
826         *
827         * @param  all 全件選択済み指定 [true:全件選択済み/false:通常]
828         */
829        public void setSelectedAll( final String all ) {
830                selectedAll = nval( getRequestParameter( all ),selectedAll );
831        }
832
833        /**
834         * 【TAG】オリジナルのタイムスタンプを利用するかどうかを指定します(初期値:false)。
835         *
836         * @og.tag
837         * COPYや親違いMOVE(,MODIFY)の時に、オリジナルのタイムスタンプをそのままコピー先のファイルにも
838         * 適用するかどうかを指定します。
839         * タイムスタンプを初期化されたくない場合に、true に設定します。
840         * 初期値は 利用しない:false です。
841         *
842         * @param  flag タイムスタンプ利用 [true:する/false:しない]
843         */
844        public void setKeepTimeStamp( final String flag ) {
845                keepTimeStamp = nval( getRequestParameter( flag ),keepTimeStamp );
846        }
847
848        /**
849         * 【TAG】処理時間を表示する TimeView を表示するかどうか[true:する/false:しない]を指定します
850         *              (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
851         *
852         * @og.tag
853         * true に設定すると、処理時間を表示するバーイメージが表示されます。
854         * これは、DB検索、APサーバー処理、画面表示の各処理時間をバーイメージで
855         * 表示させる機能です。処理時間の目安になります。
856         * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
857         *
858         * @og.rev 6.3.6.0 (2015/08/16) useTimeView の初期値を、VIEW_USE_TIMEBAR にする。
859         *
860         * @param       flag    処理時間を表示 [true:する/false:しない]
861         */
862        public void setUseTimeView( final String flag ) {
863                useTimeView = nval( getRequestParameter( flag ),useTimeView );
864        }
865
866        /**
867         * 【TAG】入力共通パスを指定します。
868         *
869         * @og.tag
870         * 通常、fileQueryタグ等で、検索した結果は、PARENT,NAME というカラムにセットされます。
871         * この、fileQueryのfrom属性に、検索を開始するディレクトリを指定し、multi="true"で、
872         * 多段階展開 した場合、この、from属性に指定したパスを、inPath にセットすることで、
873         * 以下の階層フォルダそのままに、targetDir にCOPY または、MOVE することが出来ます。
874         * 逆に、指定しない場合は、フォルダ階層無しで、COPY,MOVE されます。
875         *
876         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
877         * @og.rev 7.0.5.0 (2019/09/13) inPath のパスは、正規パス名から作成。
878         *
879         * @param       path    入力共通パス
880         */
881        public void setInPath( final String path ) {
882                inPath = nval( getRequestParameter( path ),inPath );
883
884                // 7.0.5.0 (2019/09/13) inPath のパスは、正規パス名から作成。
885                if( inPath != null ) {
886                        try {
887                                inPath = new File(inPath).getCanonicalPath();
888                        }
889                        catch( final IOException ex ) {
890                                final String errMsg = "inPathの正式なファイル名の取得に失敗しました。[" + inPath + "]"
891                                                        + CR + ex.getMessage();
892                                throw new HybsSystemException( errMsg,ex );
893                        }
894                }
895        }
896
897        /**
898         * 【TAG】エラーメッセージにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
899         *
900         * @og.tag
901         * 通常のエラーメッセージは、ラベル(長)が使われますが、これをラベル(短)を使いたい場合に、true にセットします。
902         * ここでのラベル(短)は、タグ修飾なしの、ラベル(短)です。
903         * 標準はfalse:利用しない=ラベル(長)です。
904         * true/false以外を指定した場合はfalse扱いとします。
905         *
906         * ラベルリソースの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
907         *
908         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
909         *
910         * @param prm SLABEL利用 [true:利用する/false:利用しない]
911         */
912        public void setUseSLabel( final String prm ) {
913                useSLabel = nval( getRequestParameter( prm ),useSLabel );
914        }
915
916        /**
917         * 【TAG】エラー時に処理後に停止するかどうか[true/false]を指定します(初期値:true)。
918         *
919         * @og.tag
920         * 処理結果などに応じて、以下の処理を停止したい場合に、使用します。
921         * false を指定すると、判定結果に無関係に、以下の処理を実行します。
922         * 処理は継続したいが、警告表示する場合に、useStop="false" を指定します。
923         * 初期値は、停止する ("true")です。
924         *
925         * @og.rev 7.2.7.0 (2020/08/07) エラー時に処理後に停止(true)するかどうか(useStop対応)
926         *
927         * @param   flag 処理後停止 [true:する/それ以外:しない]
928         */
929        public void setUseStop( final String flag ) {
930                useStop = nval( getRequestParameter( flag ),useStop );
931        }
932
933        /**
934         * 【TAG】システム定数でクラウド設定されていても、クラウド環境を使用しない場合、trueを指定します(初期値:false)。
935         *
936         * @og.tag
937         * クラウド設定は、システム定数の『CLOUD_TARGET』と『CLOUD_BUCKET』の設定で自動的に使用しますが、
938         * どうしてもローカルでのみ使いたい場合は、この属性を true に設定します。
939         * 標準はfalse:設定どおりとなります。
940         *
941         * true/false以外を指定した場合はfalse扱いとします。
942         *
943         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
944         *
945         * @param flag ローカル環境のみ [true:ローカルのみ/false:設定どおり]
946         */
947        public void setUseLocal( final String flag ) {
948                useLocal = nval( getRequestParameter( flag ),useLocal );
949        }
950
951        /**
952         * DBTableModel から、FromFile,ToFile を作成するための処理をまとめた補助クラスです。
953         *
954         * ここでは、オリジナルファイルやターゲットファイルを作成するための処理のみを集めています。
955         * メソッドにすると、ローカル変数を多く管理するか、多数の引数渡しを繰り返すことになるため、
956         * このローカルクラスに処理と、値を格納します。
957         *
958         * @og.rev 7.2.7.0 (2020/08/07) 相対パスの場合の基準フォルダ(FILE_URL) 考慮
959         */
960        private static final class FromToFiles {
961                private final String fileURL = HybsSystem.sys( "FILE_URL" );            // 7.2.7.0 (2020/08/07) 相対パスの場合の基準フォルダ
962
963                private final DBTableModel      table ;
964
965                private final int PARENT        ;
966                private final int NAME          ;
967                private final int TO_PARENT     ;
968                private final int TO_NAME       ;
969
970                private final File              toDir           ;
971                private final boolean   createDir       ;       // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
972                private final int               inPathCnt       ;       // 6.8.0.0 (2017/06/02) 入力共通パスの文字数
973                private final boolean   useLocal        ;       // 8.0.1.0 (2021/10/29) クラウド設定を使用しない場合は、true
974
975                private boolean equalParent     ;                       // 最後に実行された処理で、親フォルダが同一の場合は、true
976                private String  lastDir ;                               // 7.2.7.0 (2020/08/07) 一番最後にmkdirsしたフォルダ名(Exceptionの直前の設定値)
977
978                /**
979                 *  引数指定のコンストラクター
980                 *
981                 * 必要なパラメータを渡して、オブジェクトを構築します。
982                 * 入力共通パス(inPath)は、COPY/MOVE時にtargetDirと置換されます。
983                 *
984                 * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
985                 * @og.rev 7.2.7.0 (2020/08/07) parentClm,nameClm,toParentClm,toNameClm 追加
986                 * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加。
987                 *
988                 * @param       useLocal        強制的にローカルファイルを使用する場合、true にセットします。
989                 * @param       table           一覧が格納されているDBTableModel
990                 * @param       targetDir       ターゲットとなるフォルダ
991                 * @param       createDir       フォルダ作成可否 [true:作成する/false:作成しない]
992                 * @param       inPath          入力共通パス
993                 * @param       clms            parentClm,nameClm,toParentClm,toNameClm の配列
994                 */
995//              public FromToFiles( final DBTableModel table , final String targetDir , final boolean createDir , final String inPath ) {
996                public FromToFiles( final boolean       useLocal, final DBTableModel table , final String targetDir , final boolean createDir , final String inPath , final String[] clms ) {
997                        this.useLocal   = useLocal;
998                        this.table              = table;
999                        this.createDir  = createDir ;
1000                        toDir                   = mkDirs( targetDir,createDir );                        // targetDir が指定されていない場合は、null
1001                        // 7.0.5.0 (2019/09/13) inPath のパスの文字数も、正規パス名から作成。
1002                        inPathCnt               = inPath == null ? 0 : inPath.length() ;        // 6.8.0.0 (2017/06/02) 入力共通パスの文字数
1003
1004                        // "PARENT","NAME","TO_PARENT","TO_NAME" のカラム名のDBTableModelのカラム番号。存在しない場合は、-1
1005//                      PARENT          = table.getColumnNo( "PARENT"   , false );
1006//                      NAME            = table.getColumnNo( "NAME"             , false );
1007//                      TO_PARENT       = table.getColumnNo( "TO_PARENT", false );
1008//                      TO_NAME         = table.getColumnNo( "TO_NAME"  , false );
1009
1010                        PARENT          = table.getColumnNo( clms[0]    , false );              // 7.2.7.0 (2020/08/07) parentClm
1011                        NAME            = table.getColumnNo( clms[1]    , false );              // 7.2.7.0 (2020/08/07) nameClm
1012                        TO_PARENT       = table.getColumnNo( clms[2]    , false );              // 7.2.7.0 (2020/08/07) toParentClm
1013                        TO_NAME         = table.getColumnNo( clms[3]    , false );              // 7.2.7.0 (2020/08/07) toNameClm
1014                }
1015
1016                /**
1017                 * 行番号より、対応するオリジナルファイル(FromFile)を返します。
1018                 *
1019                 * ここでは、TO_PARENT や TO_NAME は、判定する必要がないため、makeFromToFile( int ) の
1020                 * 一部のみで処理が終了できます。
1021                 * 1.FromDir は、PARENT 列の値から作成する。
1022                 * 2.FromFileは、FromDir + NAME列の値から作成する。
1023                 *
1024                 * 配列返しの関係で、メソッド(および内部処理)を分けています。
1025                 *
1026                 * @og.rev 8.0.0.1 (2021/10/08) cloud対応
1027                 * @og.rev 8.4.2.2 (2023/03/17) targetDir が存在する場合(toDir)は、これを使用する。
1028                 *
1029                 * @param       rowNo   カラムNo
1030                 * @return      オリジナルファイル(FromFile)
1031                 * @og.rtnNotNull
1032                 * @see         #makeFromToFile( int )
1033                 */
1034                public File makeFromOnly( final int rowNo ) {
1035                        final String[] value = table.getValues( rowNo );
1036        //              final File fromDir  = mkDirs( value[PARENT],createDir );
1037                        // 8.4.2.2 (2023/03/17) 削除しか呼ばれないので、mkdirs する必要はない。toDir のみ考慮する。
1038                        final File fromDir  = toDir == null
1039                                                                        ? mkDirs( value[PARENT],createDir )             // 従来通り
1040                                                                        : new File( toDir , value[PARENT] );    // 相対パスチェックなしの単純な連結
1041
1042//                      return new File( fromDir, value[NAME] ) ;
1043                        return HybsFileOperationFactory.create( useLocal,fromDir, value[NAME] );                // 8.0.0.1 (2021/10/08)
1044                }
1045
1046                /**
1047                 * 行番号より、対応するTO_PARENT フォルダのFileオブジェクトを返します。
1048                 *
1049                 * ここでは、TO_PARENT のみで処理します。
1050                 *
1051                 * 実質的には、MKDIRSアクション でしか使用しないので、Fileオブジェクトを作成する必要すら
1052                 * ありませんが、メソッド共通化の関係で、オリジナルをそのまま使用します。
1053                 *
1054                 * @og.rev 7.2.7.0 (2020/08/07) MKDIRSアクション 追加
1055                 *
1056                 * @param       rowNo   カラムNo
1057                 * @return      TO_PARENT フォルダのFileオブジェクト(カラムが存在しない場合は、null)
1058                 */
1059                public File makeToParent( final int rowNo ) {
1060                        final File rtnFile ;
1061                        if( TO_PARENT >= 0 ) {
1062                                final String[] value = table.getValues( rowNo );
1063                                rtnFile = mkDirs( value[TO_PARENT],true );
1064                        }
1065                        else {
1066                                rtnFile = null;
1067                        }
1068                        return rtnFile;
1069                }
1070
1071                /**
1072                 * 行番号より、対応するオリジナルファイル(FromFile)とターゲットファイル(ToFile)を配列に格納して返します。
1073                 *
1074                 * ここでは、TO_PARENT や TO_NAME は、存在するかどうか不明なので、以下の手順で作成します。
1075                 * 1.FromDir は、PARENT 列の値から作成する。
1076                 * 2.FromFileは、FromDir + NAME列の値から作成する。
1077                 * 3.toDir は、
1078                 *       A.targetDir が有れば、それを使う。
1079                 *       B.なければ、TO_PARENT 列の値から作成する。
1080                 *       C.TO_PARENT 列がないか、値が未設定の場合は、FromDir をそのまま使う。
1081                 * 4.toFile は、
1082                 *       A.toDir + TO_NAME 列の値から作成する。
1083                 *       B.TO_NAME 列がないか、値が未設定の場合は、toDir + NAME列の値から作成する。
1084                 * 返り値は、new File[] { formFile , toFile }; とする。
1085                 *
1086                 * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
1087                 * @og.rev 7.2.7.0 (2020/08/07) 入力共通パス(inPath)指定時は、TO_PARENTかPARENTの桁数より小さい場合のみ処理する。
1088                 * @og.rev 8.0.0.1 (2021/10/08) cloud対応
1089                 *
1090                 * @param       rowNo   カラムNo
1091                 * @return      ファイル配列(0:オリジナルファイル 1:ターゲットファイル)
1092                 * @og.rtnNotNull
1093                 */
1094                public File[] makeFromToFile( final int rowNo ) {
1095                        final String[] value = table.getValues( rowNo );
1096                        final File fromDir  = mkDirs( value[PARENT],createDir );
1097//                      final File fromFile = new File( fromDir, value[NAME] );
1098                        final File fromFile = HybsFileOperationFactory.create( useLocal,fromDir, value[NAME] ); // 8.0.0.1 (2021/10/08)
1099                        File tempToDir = toDir;
1100
1101                        equalParent = false;    // 最後に実行された処理で、親フォルダが同一かどうかのフラグをリセットする。
1102                        if( tempToDir == null ) {
1103                                if( TO_PARENT >= 0 && nval( value[TO_PARENT],null ) != null ) {
1104                                        tempToDir = mkDirs( value[TO_PARENT],createDir );
1105                                }
1106                                else {
1107                                        tempToDir = fromDir;
1108                                        equalParent = true;             // 最後に実行された処理で、親フォルダが同一の場合は、true
1109                                }
1110                        }
1111                        // 6.8.0.0 (2017/06/02) toDirが指定され、かつ、入力共通パスの文字数(inPathCnt)が指定された場合。
1112                        else if( inPathCnt > 0 ) {
1113                                if( TO_PARENT >= 0 && nval( value[TO_PARENT],null ) != null ) {
1114                                        // 7.2.7.0 (2020/08/07) 入力共通パス(inPath)指定時は、TO_PARENTかPARENTの桁数より小さい場合のみ処理する。
1115                                        if( value[TO_PARENT].length() > inPathCnt ) {
1116                                                final String prntVal = toDir.getAbsolutePath() + value[TO_PARENT].substring( inPathCnt );
1117                                                tempToDir = mkDirs( prntVal,createDir );
1118                                        }
1119                                }
1120                                else {
1121                                        // 7.2.7.0 (2020/08/07) 入力共通パス(inPath)指定時は、TO_PARENTかPARENTの桁数より小さい場合のみ処理する。
1122                                        if( value[PARENT].length() > inPathCnt ) {
1123                                                final String prntVal = toDir.getAbsolutePath() + value[PARENT].substring( inPathCnt );
1124                                                tempToDir = mkDirs( prntVal,createDir );
1125                                        }
1126                                }
1127                        }
1128
1129                        File toFile = null;
1130                        if( TO_NAME >= 0 && nval(value[TO_NAME],null) != null  ) {
1131//                              toFile = new File( tempToDir, value[TO_NAME] );
1132                                toFile = HybsFileOperationFactory.create( useLocal,tempToDir, value[TO_NAME] ); // 8.0.0.1 (2021/10/08)
1133                        }
1134                        else {
1135//                              toFile = new File( tempToDir, value[NAME] );
1136                                toFile = HybsFileOperationFactory.create( useLocal,tempToDir, value[NAME] );            // 8.0.0.1 (2021/10/08)
1137                        }
1138
1139                        return new File[] { fromFile , toFile };
1140                }
1141
1142                /**
1143                 * 最後に実行された処理で、親フォルダが同一かどうかを返します(同一の場合は、true)。
1144                 *
1145                 * makeFromToFile( int ) が処理されたときの、FromDir と toDir が同一であれば、true を、
1146                 * 異なる場合は、false を返します。
1147                 * ここでの結果は、厳密な同一判定ではなく、処理的に、同一かどうかを判定しています。
1148                 * つまり、toDir に FromDir をセットする(3.Cのケース)場合に、true を内部変数にセットします。
1149                 * この判定値は、ファイルの移動処理で、異なる親フォルダの場合は、COPY & DELETE しなければ
1150                 * なりませんが、同一親フォルダの場合は、RENAME で済む という処理負荷の軽減が目的です。
1151                 * よって、結果的に、PARENT と TO_PARENT が同じとか、PARENT と targetDir が同じでも
1152                 * ここでのフラグは、false が返されます。
1153                 *
1154                 * @return      最後に実行された処理で、親フォルダが同一の場合は、true
1155                 * @see         #makeFromToFile( int )
1156                 */
1157                public boolean lastParentEquals() {
1158                        return equalParent ;
1159                }
1160
1161                /**
1162                 * 一番最後にmkdirsしたフォルダ名(Exceptionの直前の設定値)を返します。
1163                 *
1164                 * mkdirs でException が発生した場合、発生元のフォルダ名を表示するためのデバッグ用です。
1165                 *
1166                 * @og.rev 7.2.7.0 (2020/08/07) MKDIRSアクション 追加
1167                 *
1168                 * @return      一番最後にmkdirsしたフォルダ名(Exceptionの直前の設定値)
1169                 */
1170                public String getLastDir() {
1171                        return lastDir ;
1172                }
1173
1174        //      /**
1175        //       *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
1176        //       *
1177        //       * ここでは、TO_PARENT や TO_NAME は、存在するかどうか不明なので、
1178        //       * EXCEPTION にせず、配列番号に、-1 を返すようにしています。
1179        //       *
1180        //       * @param       table     一覧が格納されているDBTableModel
1181        //       * @param       nameArray       カラム名配列
1182        //       * @return      カラムNo配列(カラム名が存在しない場合は、-1)
1183        //       */
1184        //      private int[] getTableColumnNo( final DBTableModel table ,final String[] nameArray ) {
1185        //              int[] clmNo = new int[ nameArray.length ];
1186        //              for( int i=0; i<clmNo.length; i++ ) {
1187        //                      clmNo[i] = table.getColumnNo( nameArray[i] , false );   // カラム名が存在しない場合は、-1 を返す。
1188        //              }
1189        //              return clmNo;
1190        //      }
1191
1192                /**
1193                 * フォルダを作成します。
1194                 *
1195                 * フォルダが存在しない場合は、途中階層をすべて作成します。
1196                 *
1197                 * @og.rev 7.0.5.0 (2019/09/13) target のパスも、正規パス名から作成。
1198                 * @og.rev 7.2.7.0 (2020/08/07) 相対パスの場合の基準フォルダ(FILE_URL) 考慮
1199                 * @og.rev 8.0.0.1 (2021/10/08) cloud対応
1200                 *
1201                 * @param       fname   フォルダ名
1202                 * @param       createDir       フォルダ作成可否 [true:作成する/false:作成しない]
1203                 * @return      フォルダを表すファイルオブジェクト。引数が null の場合は、null を返します。
1204                 * @throws      HybsSystemException             ファイルか、存在しない場合に、createDir=false か、mkdirs() が false の場合
1205                 */
1206                private File mkDirs( final String fname , final boolean createDir ) {
1207                        lastDir = fname;                                                // 7.2.7.0 (2020/08/07)
1208                        File target = null;
1209                        if( fname != null ) {
1210                                // 7.0.5.0 (2019/09/13) target のパスも、正規パス名から作成。
1211//                              target = new File( fname );
1212                                try {
1213//                                      target = new File( fname ).getCanonicalFile();
1214                                        final String fname2 = StringUtil.urlAppend( fileURL,fname );                    // 7.2.7.0 (2020/08/07)
1215                                        target = new File( HybsSystem.url2dir( fname2 ) ).getCanonicalFile();   // 7.2.7.0 (2020/08/07)
1216                                        target = HybsFileOperationFactory.create( useLocal,target.getPath() );  // 8.0.0.1 (2021/10/08)
1217                                        if( target.exists() ) {                 // 存在する
1218                                                if( target.isFile() ) {
1219                                                        final String errMsg = "ターゲットに、ファイル名は指定できません。" + CR
1220                                                                                                + "ターゲット=[" + fname2 + "]"  + CR;
1221                                                        throw new HybsSystemException( errMsg );
1222                                                }
1223                                        }
1224                                        else {                                                  // 存在しない
1225                                                // 存在しないのに、作成しない
1226                                                if( !createDir ) {
1227                                                        final String errMsg = "ターゲットが存在しません。 " + CR
1228                                                                                                + "ターゲット=[" + fname2 + "]"  + CR;
1229                                                        throw new HybsSystemException( errMsg );
1230                                                }
1231                                                // 作成できない
1232                                                if( !target.mkdirs() ) {
1233                                                        final String errMsg = "ターゲットを自動作成使用としましたが、作成できませんでした。" + CR
1234                                                                                                + "ターゲット=[" + fname2 + "]"  + CR;
1235                                                        throw new HybsSystemException( errMsg );
1236                                                }
1237                                        }
1238                                }
1239                                catch( final IOException ex ) {
1240                                        final String errMsg = "File#getCanonicalFile() で、正式パス名を求めることができませんでした。" + CR
1241                                                                                + ex.getMessage()
1242                                                                                + "ターゲット=[" + fname + "]"  + CR;
1243                                        throw new HybsSystemException( errMsg,ex );
1244                                }
1245                        }
1246                        return target;
1247                }
1248        }
1249
1250        /**
1251         * このオブジェクトの文字列表現を返します。
1252         * 基本的にデバッグ目的に使用します。
1253         *
1254         * @return このクラスの文字列表現
1255         * @og.rtnNotNull
1256         */
1257        @Override
1258        public String toString() {
1259                return ToString.title( this.getClass().getName() )
1260                                .println( "VERSION"                     ,VERSION                )
1261                                .println( "action"                      ,action                 )
1262                                .println( "command"                     ,command                )
1263                                .println( "targetDir"           ,targetDir              )
1264                                .println( "createDir"           ,createDir              )
1265                                .println( "tableId"                     ,tableId                )
1266//                              .println( "outMessage"          ,outMessage     )
1267                                .println( "displayMsg"          ,displayMsg     )
1268                                .println( "selectedAll"         ,selectedAll    )
1269                                .println( "keepTimeStamp"       ,keepTimeStamp  )
1270                                .fixForm().toString() ;
1271        }
1272}