    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)
    025
    026import static org.opengion.fukurou.util.StringUtil.nval ;
    027import static org.opengion.fukurou.system.HybsConst.BR;                 // 6.1.0.0 (2014/12/26) refactoring
    028
    029import java.util.Locale ;
    030import java.util.Set ;
    031import java.util.TreeSet ;
    032import java.util.Comparator ;
    033import java.io.File ;
    034import java.io.Serializable;
    035import java.io.IOException ;                                                                    // 7.0.5.0 (2019/09/13)
    036
    037/**
    038 * ファイル検索リストを元に、action に基づいた処理を行うタグです。
    039 * command="ENTRY" 時のみ処理を行います。
    040 *
    041 * fileQuery などで検索したファイル一覧のDBTableModel を元に、ファイルの
    042 * コピー(COPY)、移動(MOVE,MODIFY)、削除(DELETE)などの処理を行います。
    043 * 処理を行うオリジナルファイルは、PARENT,NAME というカラムでなければなりません。
    044 * このカラム名は、fileQuery の検索時には、必ず作成されるカラムです。
    045 * また、各アクションに対応するターゲットファイルは、TO_PARENT,TO_NAME という
    046 * カラムで指定するか、targetDir 属性を利用してフォルダを指定します。
    047 * TO_PARENT(先フォルダ)と、TO_NAME(先ファイル名)は、処理に応じて、必要なカラムが
    048 * あれば、自動的に処理します。
    049 * つまり、TO_PARENT のみの場合は、ファイル名はオリジナルのまま、フォルダのみ変更します。
    050 * 逆に、TO_NAME の場合は、フォルダはそのままで、ファイル名のみ指定します。
    051 * 両方同時に指定することも可能です。
    052 * targetDir 属性で指定する場合は、TO_PARENT のみに同じ値を設定した場合と同じになります。
    053 * この属性を指定すると、TO_PARENT は無視されます。(TO_NAME は有効です。)
    054 * COPY、MOVE(,MODIFY) の場合は、指定のフォルダに一括処理可能です。
    055 * COPY、MOVE(,MODIFY) などの処理で、ターゲットフォルダが存在しないときに、作成するか、エラーにするかは
    056 * createDir属性 で指定できます。初期値は、(true:作成する) です。
    057 * これは、COPY先やMOVE(,MODIFY)先が存在している前提のシステムで、不要な箇所に間違ってフォルダを
    058 * 自動作成されると困る場合に、(false:作成しない) とすれば、間違いに気づく確率が上がります。
    059 *
    060 * ※ このタグは、Transaction タグの対象ではありません。
    061 *
    062 * @og.formSample
    063 * ●body：なし
    064 * ●形式：
    065 *      ・&lt;og:fileUpdate
    066 *          action        = "COPY|MOVE|MODIFY|DELETE" アクション属性(必須)
    067 *          command       = "[ENTRY]"                 ENTRY 時のみ実行します(初期値:ENTRY)
    068 *          targetDir     = "[指定フォルダ]"          ターゲットとなるフォルダ
    069 *          createDir     = "[true/false]"            ターゲットとなるフォルダがなければ作成する(true)かどうか(初期値:true)
    070 *          tableId       = [HybsSystem.TBL_MDL_KEY]  DBTableModel を取り出すキー
    071 *          outMessage    = "[true/false]"            検索結果のメッセージを表示する(true)かどうかを指定(初期値:true)
    072 *          displayMsg    = "MSG0040";                処理結果を表示します(初期値:｢　件登録しました。｣)
    073 *          selectedAll   = "[false/true]"            データを全件選択済みとして処理する(true)かどうか指定(初期値:false)
    074 *          keepTimeStamp = "[false/true]"            COPY,親違いMOVE(,MODIFY)の時にオリジナルのタイムスタンプを使用するかどうか(初期値:false)
    075 *      /&gt;
    076 *
    077 *    [action属性(必須)]
    078 *      COPY   オリジナルファイルを、ターゲット(TO_PARENT,TO_NAMEで指定)にコピーします。
    079 *      MOVE   オリジナルファイルを、ターゲットに移動(COPY+DELETE)/名称変更(RENAME)します。
    080 *      MODIFY (MOVE と同じ。エンジンの command を利用するための簡易action)
    081 *      DELETE オリジナルファイルを削除します(ターゲット(TO_PARENT,TO_NAME)は、関係しません)。
    082 *
    083 * ●Tag定義：
    084 *   &lt;og:fileUpdate
    085 *       action           ○【TAG】アクション[COPY|MOVE|MODIFY|DELETE]をセットします(必須)。
    086 *       command            【TAG】コマンド[ENTRY]をセットします(初期値:ENTRY)
    087 *       targetDir          【TAG】ターゲットとなるフォルダを指定します
    088 *       createDir          【TAG】ターゲットとなるフォルダがなければ、作成するかどうかを指定します(初期値:true)
    089 *       tableId            【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    090 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/application]を指定します(初期値:session)
    091 *       outMessage         【TAG】検索結果のメッセージを表示する/しない[true/false]を指定します(初期値:true)
    092 *       displayMsg         【TAG】処理結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0040[　件登録しました])
    093 *       selectedAll        【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)
    094 *       keepTimeStamp      【TAG】オリジナルのタイムスタンプを利用するかどうかを指定します(初期値:false)
    095 *       inPath             【TAG】入力共通パスを指定します(PARENTフォルダの共通部分、COPY/MOVE時にtargetDirと置換されます) 6.8.0.0 (2017/06/02)。
    096 *       useTimeView        【TAG】処理時間を表示する TimeView を表示するかどうかを指定します
    097 *                                                                              (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
    098 *       useSLabel          【TAG】7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    099 *       caseKey            【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null)
    100 *       caseVal            【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null)
    101 *       caseNN             【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない)
    102 *       caseNull           【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない)
    103 *       caseIf             【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない)
    104 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    105 *   /&gt;
    106 *
    107 * ●使用例
    108 *       ・&lt;og:fileUpdate command="{&#064;command}" action="COPY" /&gt;
    109 *             TO_PARENT または、 TO_NAME(両方指定も可)による行単位 COPY 処理
    110 *             fileQuery の useUpdateClm="true" を設定し、検索結果に、TO_PARENT、 TO_NAMEカラムを追加します。
    111 *             TO_PARENT または、 TO_NAME は、columnSet などで値をセットしておきます。
    112 *
    113 *       ・&lt;og:fileUpdate command="{&#064;command}" action="MODIFY" targetDir="AAA_DIR"  /&gt;
    114 *             fileQuery の検索結果を、AAA_DIR フォルダに移動します。
    115 *             ファイル名は、そのままオリジナルの値が使用されます。
    116 *
    117 * @og.rev 5.3.4.0 (2011/04/01) 新規追加
    118 * @og.group ファイル出力
    119 *
    120 * @version  4.0
    121 * @author       Kazuhiko Hasegawa
    122 * @since    JDK5.0,
    123 */
    124public class FileUpdateTag extends CommonTagSupport {
    125        /** このプログラムのVERSION文字列を設定します。   {@value} */
    126        private static final String VERSION = "7.0.7.0 (2019/12/13)" ;
    127        private static final long serialVersionUID = 707020191213L ;
    128
    129        /** command 引数に渡す事の出来る コマンド  登録{@value} */
    130        public static final String CMD_ENTRY  = "ENTRY" ;
    131        /** command 引数に渡す事の出来る コマンド リスト  */
    132        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    133        private static final Set<String> COMMAND_SET = new ArraySet<>( CMD_ENTRY );
    134
    135        /** エラーメッセージID {@value} */
    136        private static final String ERR_MSG_ID  = HybsSystem.ERR_MSG_KEY;               // 6.4.1.1 (2016/01/16) errMsgId → ERR_MSG_ID  refactoring
    137
    138        /** action 引数に渡す事の出来る アクションコマンド  COPY {@value} */
    139        public static final String ACT_COPY             = "COPY" ;
    140        /** action 引数に渡す事の出来る アクションコマンド  MOVE {@value} */
    141        public static final String ACT_MOVE             = "MOVE" ;
    142        /** action 引数に渡す事の出来る アクションコマンド  MODIFY {@value} */
    143        public static final String ACT_MODIFY           = "MODIFY" ;
    144        /** action 引数に渡す事の出来る アクションコマンド  DELETE {@value} */
    145        public static final String ACT_DELETE   = "DELETE" ;
    146        // 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    147        private static final Set<String> ACTION_SET = new ArraySet<>( ACT_COPY , ACT_MOVE , ACT_MODIFY , ACT_DELETE );
    148
    149        private String  action          ;
    150        private String  targetDir       ;                       // ターゲットとなるフォルダ
    151        private boolean createDir       = true;         // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
    152
    153        private String  inPath          ;                       // 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
    154
    155        private String  tableId         = HybsSystem.TBL_MDL_KEY;
    156        private String  command         = CMD_ENTRY;
    157        private boolean outMessage      = true;
    158        private String  displayMsg      = "MSG0040";            // 　件登録しました。
    159        private boolean selectedAll ;
    160        private boolean keepTimeStamp;                                  // オリジナルのタイムスタンプを利用する場合、true
    161
    162        private transient DBTableModel  table           ;
    163        private transient ErrorMessage  errMessage      ;
    164        private int             executeCount    = -1;                   // 処理件数
    165        private int             errCode                 = ErrorMessage.OK;
    166        private boolean useTimeView             = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );             // 6.3.6.0 (2015/08/16)
    167        private boolean useSLabel               ;                               // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    168
    169        /**
    170         * デフォルトコンストラクター
    171         *
    172         * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
    173         */
    174        public FileUpdateTag() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
    175
    176        /**
    177         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    178         *
    179         * @og.rev 6.4.4.1 (2016/03/18) 意味のない、StringBuilderだったので、廃止します。
    180         * @og.rev 6.9.9.0 (2018/08/20) ｢ERR0041:検索処理中に割り込みの検索要求がありました｣エラーを、標準のErrorMessageに追加するようにします。
    181         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    182         *
    183         * @return      後続処理の指示
    184         */
    185        @Override
    186        public int doEndTag() {
    187                debugPrint();
    188                // 5.2.2.0 (2010/11/01) caseKey 、caseVal 属性対応
    189                if( !useTag() ) { return EVAL_PAGE ; }
    190
    191                final long dyStart = System.currentTimeMillis();
    192
    193                table = (DBTableModel)getObject( tableId );
    194
    195                String label  = "";                             // 4.0.0 (2005/11/30) 検索しなかった場合。
    196                if( table != null && table.getRowCount() > 0 && check( command, COMMAND_SET ) ) {
    197                        startQueryTransaction( tableId );
    198
    199                        execute();      // 実際の処理を実行します。
    200
    201                        setRequestAttribute( "DB.COUNT"   , String.valueOf( executeCount ) );
    202                        setRequestAttribute( "DB.ERR_CODE", String.valueOf( errCode ) );
    203
    204                        // 6.9.9.0 (2018/08/20) ｢ERR0041:検索処理中に割り込みの検索要求がありました｣エラーを、標準のErrorMessageに追加するようにします。
    205                        if( ! commitTableObject( tableId, table ) ) {
    206                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Query Error!" ); }
    207                                // ERR0041:検索処理中に割り込みの検索要求がありました。処理されません。
    208                                errMessage.addMessage( 0,ErrorMessage.NG,"ERR0041" );
    209                                errCode = ErrorMessage.NG;
    210                        }
    211
    212//                      final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource() );
    213                        final String err = TaglibUtil.makeHTMLErrorTable( errMessage,getResource(),useSLabel );         // 7.0.7.0 (2019/12/13)
    214                        if( err != null && err.length() > 0 ) {
    215                                label = err ;           // 6.4.4.1 (2016/03/18)
    216                                setSessionAttribute( ERR_MSG_ID,errMessage );
    217                        }
    218
    219//                      // 6.9.9.0 (2018/08/20) ｢ERR0041:検索処理中に割り込みの検索要求がありました｣エラーを、標準のErrorMessageに追加するようにします。
    220//                      if( table != null && ! commitTableObject( tableId, table ) ) {
    221//                              jspPrint( "FileUpdateTag Query処理が割り込まれました。DBTableModel は登録しません。" );
    222//                              return SKIP_PAGE ;
    223//                      }
    224                }
    225
    226                jspPrint( label );
    227
    228                // 実行件数の表示
    229                // 4.0.0 (2005/11/30) 出力順の変更。一番最初に出力します。
    230                if( displayMsg != null && displayMsg.length() > 0 ) {
    231                        final String status = executeCount + getResource().getLabel( displayMsg ) ;
    232                        jspPrint( status + BR );
    233                }
    234
    235                if( useTimeView ) {             // 6.3.6.0 (2015/08/16)
    236                        // 3.5.4.7 (2004/02/06)
    237                        final long dyTime = System.currentTimeMillis()-dyStart;
    238                        jspPrint( "<div id=\"queryTime\" value=\"" + (dyTime) + "\"></div>" );  // 3.5.6.3 (2004/07/12)
    239                }
    240                return EVAL_PAGE ;
    241        }
    242
    243        /**
    244         * タグリブオブジェクトをリリースします。
    245         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    246         *
    247         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
    248         * @og.rev 7.0.7.0 (2019/12/13) useSLabel 属性を追加。
    249         */
    250        @Override
    251        protected void release2() {
    252                super.release2();
    253                tableId         = HybsSystem.TBL_MDL_KEY;
    254                command         = CMD_ENTRY;
    255                action          = null;
    256                targetDir       = null;         // ターゲットとなるフォルダ
    257                createDir       = true;         // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
    258                outMessage      = true;
    259                displayMsg      = "MSG0040";    // 　件登録しました。
    260                selectedAll = false;
    261                keepTimeStamp = false;          // オリジナルのタイムスタンプを利用する場合、true
    262                table           = null;
    263                errMessage      = null;
    264                executeCount= -1;               // 処理件数
    265                errCode         = ErrorMessage.OK;
    266                useTimeView     = HybsSystem.sysBool( "VIEW_USE_TIMEBAR" );     // 6.3.6.0 (2015/08/16)
    267                inPath          = null;         // 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
    268                useSLabel       = false;        // 7.0.7.0 (2019/12/13) ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)
    269        }
    270
    271        /**
    272         * 処理を実行します。
    273         *
    274         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
    275         */
    276        private void execute() {
    277                final int[] rowNo = getParameterRows();
    278                if( rowNo.length > 0 ) {
    279
    280                        final FromToFiles fromToFiles = new FromToFiles( table , targetDir , createDir , inPath );      // 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定
    281
    282                        if( ACT_COPY.equalsIgnoreCase( action ) ) {
    283                                actionCOPY( rowNo,fromToFiles );
    284                        }
    285                        // ACT_MODIFY は、エンジンの command で使うため、便利
    286                        else if( ACT_MOVE.equalsIgnoreCase( action ) || ACT_MODIFY.equalsIgnoreCase( action ) ) {
    287                                actionMOVE( rowNo,fromToFiles );
    288                        }
    289                        else if( ACT_DELETE.equalsIgnoreCase( action ) ) {
    290                                actionDELETE( rowNo,fromToFiles );
    291                        }
    292                }
    293        }
    294
    295        /**
    296         * COPY アクションを実行します。
    297         *
    298         * @og.rev 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
    299         *
    300         * @param       rowNo           処理を実施する行番号
    301         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
    302         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
    303         */
    304        private void actionCOPY( final int[] rowNo , final FromToFiles fromToFiles ) {
    305                File fromFile = null ;
    306                File toFile   = null ;
    307
    308                executeCount = 0 ;      // 開始前に初期化しておく。
    309                final int rowCount = rowNo.length ;
    310                for( int i=0; i<rowCount; i++ ) {
    311                        final File[] files = fromToFiles.makeFromToFile( rowNo[i] );    // FromFile,ToFile
    312                        fromFile = files[0];
    313                        toFile   = files[1];
    314
    315                        // 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
    316                        if( fromFile.isFile() && !FileUtil.copy( fromFile,toFile,keepTimeStamp ) ) {
    317                                final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    318                                                                        + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
    319                                // 6.0.2.5 (2014/10/31) refactoring
    320                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    321                                errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionCOPY",errMsg );
    322                        }
    323                        executeCount++ ;
    324                }
    325        }
    326
    327        /**
    328         * MOVE アクションを実行します。
    329         *
    330         * @og.rev 5.5.2.4 (2012/05/16) メソッドの戻り値の設定
    331         * @og.rev 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
    332         *
    333         * @param       rowNo           処理を実施する行番号
    334         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
    335         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
    336         */
    337        private void actionMOVE( final int[] rowNo , final FromToFiles fromToFiles ) {
    338                File fromFile = null ;
    339                File toFile   = null ;
    340
    341                executeCount = 0 ;      // 開始前に初期化しておく。
    342                final int rowCount = rowNo.length ;
    343                for( int i=0; i<rowCount; i++ ) {
    344                        final File[] files = fromToFiles.makeFromToFile( rowNo[i] );    // FromFile,ToFile
    345                        fromFile = files[0];
    346                        toFile   = files[1];
    347
    348                        if( fromToFiles.lastParentEquals() ) {  // FromDirとToDirが同じなので、RENAMEできる。
    349                                if( !fromFile.renameTo( toFile ) ) {
    350                                        final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    351                                                                                + "同一親フォルダのため、RENAME処理を行っています。" + CR
    352                                                                                + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
    353                                        // 6.0.2.5 (2014/10/31) refactoring
    354                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    355                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
    356                                }
    357                        }
    358                        // 5.6.5.2 (2013/06/21) From側がファイルの場合のみ処理します。
    359                        else if( fromFile.isFile() ) {                  // FromDirとToDirが異なるので、COPY ＋ DELETE する。
    360                                if( !FileUtil.copy( fromFile,toFile,keepTimeStamp ) ) {
    361                                        final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    362                                                                                + "移動前のCOPY処理を行っていました。" + CR
    363                                                                                + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
    364                                        // 6.0.2.5 (2014/10/31) refactoring
    365                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    366                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
    367                                }
    368
    369                                if( !fromFile.delete() ) {
    370                                        String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    371                                                                                + "移動後のオリジナルファイルの削除処理を行っていました。" + CR
    372                                                                                + "From=[" + fromFile + "],To=[" + toFile + "]" + CR;
    373                                        // 5.5.2.4 (2012/05/16) メソッドの戻り値の設定
    374                                        if( !toFile.delete() ) {
    375                                                errMsg = errMsg + "toFile も削除に失敗しました。" + CR;
    376                                        }
    377
    378                                        // 6.0.2.5 (2014/10/31) refactoring
    379                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    380                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionMOVE",errMsg );
    381                                }
    382                        }
    383                        executeCount++ ;
    384                }
    385        }
    386
    387        /**
    388         * DELETE アクションを実行します。
    389         *
    390         * この処理では、リストにフォルダが含まれている場合も削除します。
    391         * 通常、フォルダの削除は、その要素（内部）にファイル等が存在しない場合のみ
    392         * 行いますが、検索リストから削除する順番によっては、フォルダもファイルも
    393         * 削除対象になる場合があります。そこで、まず。ファイルだけ削除し、フォルダは、
    394         * あとで削除するように処理を行います。
    395         *
    396         * @og.rev 5.6.5.2 (2013/06/21) フォルダも削除対象にします。
    397         *
    398         * @param       rowNo           処理を実施する行番号
    399         * @param       fromToFiles     FromFile,ToFileをまとめた補助クラス
    400         * @throws      HybsSystemException     処理中に何らかのエラーが発生した場合
    401         */
    402        private void actionDELETE( final int[] rowNo , final FromToFiles fromToFiles ) {
    403                File fromFile = null;
    404
    405                // 5.6.5.2 (2013/06/21) フォルダを削除する為の、退避
    406                final Set<File> dirSet = new TreeSet<>( new FileNameLengthComparator() );               // ファイルの文字数順に並べたSet
    407
    408                executeCount = 0 ;      // 開始前に初期化しておく。
    409                final int rowCount = rowNo.length ;
    410                for( int i=0; i<rowCount; i++ ) {
    411                        fromFile = fromToFiles.makeFromOnly( rowNo[i] );        // FromFile
    412
    413                        // 5.6.5.2 (2013/06/21) まず、ファイルを削除します。
    414                        if( fromFile.isFile() ) {
    415                                if( !fromFile.delete() ) {
    416                                        final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    417                                                                                + "From=[" + fromFile + "]" + CR;
    418                                        // 6.0.2.5 (2014/10/31) refactoring
    419                                        if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    420                                        errMessage.addMessage( rowNo[i]+1,ErrorMessage.NG,"actionDELETE",errMsg );
    421                                }
    422                        }
    423                        else {
    424                                // 5.6.5.2 (2013/06/21) フォルダの場合は、アドレスの桁数をキーにソートしておきます。
    425                                dirSet.add( fromFile );
    426                        }
    427                        executeCount++ ;
    428                }
    429
    430                // 5.6.5.2 (2013/06/21) フォルダの削除は、アドレスの桁数の大きい順（階層の深い順）に削除します。
    431                for( final File file : dirSet ) {
    432                        if( !file.delete() ) {
    433                                final String errMsg = "アクション=[" + action + "]中にエラーが発生しました。" + CR
    434                                                                        + "From(Dir)=[" + file + "]" + CR;
    435                                // 6.0.2.5 (2014/10/31) refactoring
    436                                if( errMessage == null ) { errMessage = new ErrorMessage( "FileUpdateTag Error" ); }
    437                                errMessage.addMessage(-1,ErrorMessage.NG,"actionDELETE",errMsg );
    438                        }
    439                }
    440        }
    441
    442        /**
    443         * ファイルの名称の長さ順（長い順）に比較する、Comparator インターフェースの実装クラス
    444         *
    445         * ここでの大小比較は、ファイル名の文字数が、大きい方が、小さいとみなされます。
    446         * つまり階層が深いので、先に処理する必要があるという事を意味します。
    447         * 処理としては、f1 != null &amp;&amp; f2 != null で、len1 = f1.getAbsolutePath().length() と len2 = f2.getAbsolutePath().length() を比較し
    448         * len1 &gt; len2 ⇒ 負 , len1 &lt; len2 ⇒ 正 , len1 == len2 ⇒ 0 を返します。
    449         * 具体的には、return ( len2 - len1 ); です。
    450         *
    451         * 注: このコンパレータは equals と一貫性のない順序付けを課します。
    452         *
    453         * @og.rev 5.6.5.2 (2013/06/21) 新規追加
    454         *
    455         */
    456        private static final class FileNameLengthComparator implements Comparator<File> , Serializable {
    457                private static final long serialVersionUID = 565220130621L ;            // 5.6.5.2 (2013/06/21)
    458                /**
    459                 * 順序付けのために ２つの引数を比較します。
    460                 *
    461                 * ここでの大小比較は、ファイル名の文字数が、大きい方が、小さいとみなされます。
    462                 * 具体的には、return ( len2 - len1 ); です。
    463                 *
    464                 * @param       f1 比較対象の１番目のオブジェクト
    465                 * @param       f2 比較対象の２番目のオブジェクト
    466                 * @return      最初の引数が２番目の引数より小さい場合は負の整数、両方が等しい場合は 0、最初の引数が ２番目の引数より大きい場合は正の整数
    467                 */
    468                public int compare( final File f1 , final File f2 ) {
    469                        if( f1 == null || f2 == null ) {
    470                                final String errMsg = "引数のFileにnullが含まれています。file1=[" + f1 + "] , file2=[" + f2 + "]" ;
    471                                throw new IllegalArgumentException( errMsg );
    472                        }
    473
    474                        final int len1 = f1.getAbsolutePath().length();
    475                        final int len2 = f2.getAbsolutePath().length();
    476
    477                        return len2 - len1 ;
    478                }
    479        }
    480
    481        /**
    482         * 表示データの HybsSystem.ROW_SEL_KEY を元に、選ばれた 行を処理の対象とします。
    483         *
    484         * @return      選択行の配列
    485         * @og.rtnNotNull
    486         */
    487        @Override
    488        protected int[] getParameterRows() {
    489                final int[] rowNo ;
    490                if( selectedAll ) {
    491                        final int rowCnt = table.getRowCount();
    492                        rowNo = new int[ rowCnt ];
    493                        for( int i=0; i<rowCnt; i++ ) {
    494                                rowNo[i] = i;
    495                        }
    496                } else {
    497                        rowNo = super.getParameterRows();
    498                }
    499                return rowNo ;
    500        }
    501
    502        /**
    503         * 【TAG】アクション[COPY|MOVE|MODIFY|DELETE]をセットします。
    504         *
    505         * @og.tag
    506         * アクションは、ファイルをコピー(COPY)したり、移動(MOVE,MODIFY)したり、削除(DELETE)する
    507         * などの操作を指定する必須属性です。
    508         *
    509         * <table class="plain">
    510         *   <caption>action属性(必須)のキーワード</caption>
    511         *   <tr><th>action</th><th>名称</th><th>機能</th></tr>
    512         *   <tr><td>COPY  </td><td>コピー</td><td>オリジナルファイルを、ターゲット(TO_PARENT,TO_NAMEで指定)にコピーします。</td></tr>
    513         *   <tr><td>MOVE  </td><td>移動  </td><td>オリジナルファイルを、ターゲットに移動(COPY+DELETE)/名称変更(RENAME)します。</td></tr>
    514         *   <tr><td>MODIFY</td><td>移動  </td><td>(MOVE と同じ。エンジンの command を利用するための簡易action)</td></tr>
    515         *   <tr><td>DELETE</td><td>削除  </td><td>オリジナルファイルを、削除します。(フォルダ、ファイルに関わらず)</td></tr>
    516         * </table>
    517         *
    518         * @og.rev 6.3.4.0 (2015/08/01) Arrays.toString から String.join に置き換え。
    519         * @og.rev 6.4.3.4 (2016/03/11) String配列 から、Setに置き換えます。
    520         *
    521         * @param       act アクション (public static final 宣言されている文字列)
    522         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.FileUpdateTag.ACT_COPY">アクション定数</a>
    523         */
    524        public void setAction( final String act ) {
    525                action = nval( getRequestParameter( act ),action );
    526
    527                if( action != null && !check( action, ACTION_SET ) ) {
    528                        final String errMsg = "指定のアクションは実行できません。アクションエラー"       + CR
    529                                                        + "action=[" + action + "] "                                                            + CR
    530                                                        + "actionList=" + String.join( ", " , ACTION_SET ) ;
    531                        throw new HybsSystemException( errMsg );
    532                }
    533        }
    534
    535        /**
    536         * 【TAG】ターゲットとなるフォルダを指定します(初期値:null)。
    537         *
    538         * @og.tag
    539         * targetDir 属性を利用する場合は、引数のファイル、またはフォルダが指定されたことに
    540         * なります。COPY、MOVE(,MODIFY) の場合は、targetDir 属性にフォルダを指定することで一括処理可能です。
    541         * 指定先のフォルダが存在しない場合は、createDir属性の値により処理が異なります。
    542         * createDir="true"(初期値)で、ターゲットフォルダが存在しない場合は、自動作成します。
    543         *
    544         * @param  dir ターゲットとなるフォルダ
    545         * @see         #setCreateDir( String )
    546         */
    547        public void setTargetDir( final String dir ) {
    548                targetDir = nval( getRequestParameter( dir ),targetDir );
    549        }
    550
    551        /**
    552         * 【TAG】ターゲットとなるフォルダがなければ、作成するかどうかを指定します(初期値:true)。
    553         *
    554         * @og.tag
    555         * COPY,MOVE(,MODIFY) などの処理で、ターゲットフォルダが存在しないときに、作成するか、エラーにするかを
    556         * createDir属性 で指定できます。
    557         * これは、COPY先やMOVE(,MODIFY)先が存在している前提のシステムで、不要な箇所に間違ってフォルダを
    558         * 自動作成されると困る場合に、false:作成しない とすれば、間違いに気づく確率が上がります。
    559         * 初期値は true:作成する です。
    560         *
    561         * @param       flag    フォルダ作成可否 [true:作成する/false:作成しない]
    562         */
    563        public void setCreateDir( final String flag ) {
    564                createDir = nval( getRequestParameter( flag ),createDir );
    565        }
    566
    567        /**
    568         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    569         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    570         *
    571         * @og.tag
    572         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    573         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    574         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    575         * この tableId 属性を利用して、メモリ空間を分けます。
    576         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value HybsSystem#TBL_MDL_KEY}])。
    577         *
    578         * @param       id テーブルID (sessionに登録する時のID)
    579         */
    580        public void setTableId( final String id ) {
    581                tableId = nval( getRequestParameter( id ),tableId );
    582        }
    583
    584        /**
    585         * 【TAG】コマンド (ENTRY)をセットします(初期値:ENTRY)。
    586         *
    587         * @og.tag
    588         * このタグは、command="ENTRY" でのみ実行されます。
    589         * コマンドは,HTMLから(get/post)指定されますので,CMD_xxx で設定される
    590         * フィールド定数値のいづれかを、指定できます。
    591         * 初期値は、ENTRY なので、何も指定しなければ、実行されます。
    592         *
    593         * @param       cmd コマンド (public static final 宣言されている文字列)
    594         * @see         <a href="../../../../constant-values.html#org.opengion.hayabusa.taglib.FileUpdateTag.CMD_ENTRY">コマンド定数</a>
    595         */
    596        public void setCommand( final String cmd ) {
    597                final String cmd2 = getRequestParameter( cmd );
    598                if( cmd2 != null && cmd2.length() >= 0 ) { command = cmd2.toUpperCase(Locale.JAPAN); }
    599        }
    600
    601        /**
    602         * 【TAG】検索結果のメッセージを表示する/しない[true/false]を指定します(初期値:true)。
    603         *
    604         * @og.tag
    605         * 初期値は、表示する：true です。
    606         *
    607         * @param       flag  メッセージ表示可否 [true:表示する/それ以外:含めない]
    608         */
    609        public void setOutMessage( final String flag ) {
    610                outMessage = nval( getRequestParameter( flag ),outMessage );
    611        }
    612
    613        /**
    614         * 【TAG】処理結果を画面上に表示するメッセージリソースIDを指定します(初期値:MSG0040[　件登録しました])。
    615         *
    616         * @og.tag
    617         * ここでは、検索結果の件数や登録された件数をまず出力し、
    618         * その次に、ここで指定したメッセージをリソースから取得して表示します。
    619         * 表示させたくない場合は, displayMsg = "" をセットしてください。
    620         * displayMsg の初期値は、MSG0040[　件登録しました]です。
    621         *
    622         * @param       id 処理結果表示メッセージID
    623         */
    624        public void setDisplayMsg( final String id ) {
    625                final String ids = getRequestParameter( id );
    626                if( ids != null ) { displayMsg = ids; }
    627        }
    628
    629        /**
    630         * 【TAG】データを全件選択済みとして処理するかどうか[true/false]を指定します(初期値:false)。
    631         *
    632         * @og.tag
    633         * 全てのデータを選択済みデータとして扱って処理します。
    634         * 全件処理する場合に、(true/false)を指定します。
    635         * 初期値は false です。
    636         *
    637         * @param  all 全件選択済み指定 [true:全件選択済み/false:通常]
    638         */
    639        public void setSelectedAll( final String all ) {
    640                selectedAll = nval( getRequestParameter( all ),selectedAll );
    641        }
    642
    643        /**
    644         * 【TAG】オリジナルのタイムスタンプを利用するかどうかを指定します(初期値:false)。
    645         *
    646         * @og.tag
    647         * COPYや親違いMOVE(,MODIFY)の時に、オリジナルのタイムスタンプをそのままコピー先のファイルにも
    648         * 適用するかどうかを指定します。
    649         * タイムスタンプを初期化されたくない場合に、true に設定します。
    650         * 初期値は 利用しない:false です。
    651         *
    652         * @param  flag タイムスタンプ利用 [true:する/false:しない]
    653         */
    654        public void setKeepTimeStamp( final String flag ) {
    655                keepTimeStamp = nval( getRequestParameter( flag ),keepTimeStamp );
    656        }
    657
    658        /**
    659         * 【TAG】処理時間を表示する TimeView を表示するかどうか[true:する/false:しない]を指定します
    660         *              (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
    661         *
    662         * @og.tag
    663         * true に設定すると、処理時間を表示するバーイメージが表示されます。
    664         * これは、DB検索、APサーバー処理、画面表示の各処理時間をバーイメージで
    665         * 表示させる機能です。処理時間の目安になります。
    666         * (初期値:VIEW_USE_TIMEBAR[={@og.value SystemData#VIEW_USE_TIMEBAR}])。
    667         *
    668         * @og.rev 6.3.6.0 (2015/08/16) useTimeView の初期値を、VIEW_USE_TIMEBAR にする。
    669         *
    670         * @param       flag    処理時間を表示 [true:する/false:しない]
    671         */
    672        public void setUseTimeView( final String flag ) {
    673                useTimeView = nval( getRequestParameter( flag ),useTimeView );
    674        }
    675
    676        /**
    677         * 【TAG】入力共通パスを指定します。
    678         *
    679         * @og.tag
    680         * 通常、fileQueryタグ等で、検索した結果は、PARENT,NAME というカラムにセットされます。
    681         * この、fileQueryのfrom属性に、検索を開始するディレクトリを指定し、multi="true"で、
    682         * 多段階展開 した場合、この、from属性に指定したパスを、inPath にセットすることで、
    683         * 以下の階層フォルダそのままに、targetDir にCOPY または、MOVE することが出来ます。
    684         * 逆に、指定しない場合は、フォルダ階層無しで、COPY,MOVE されます。
    685         *
    686         * @og.rev 6.8.0.0 (2017/06/02) 入力共通パスを指定します。
    687         * @og.rev 7.0.5.0 (2019/09/13) inPath のﾊﾟｽは、正規パス名から作成。
    688         *
    689         * @param       path    入力共通パス
    690         */
    691        public void setInPath( final String path ) {
    692                inPath = nval( getRequestParameter( path ),inPath );
    693
    694                // 7.0.5.0 (2019/09/13) inPath のﾊﾟｽは、正規パス名から作成。
    695                if( inPath != null ) {
    696                        try {
    697                                inPath = new File(inPath).getCanonicalPath();
    698                        }
    699                        catch( final IOException ex ) {
    700                                final String errMsg = "inPathの正式なファイル名の取得に失敗しました。[" + inPath + "]"
    701                                                        + CR + ex.getMessage();
    702                                throw new HybsSystemException( errMsg,ex );
    703                        }
    704                }
    705        }
    706
    707        /**
    708         * 【TAG】ｴﾗｰﾒｯｾｰｼﾞにSLABELを利用するかどうか[true/false]を指定します(初期値:false)。
    709         *
    710         * @og.tag
    711         * 通常のｴﾗｰﾒｯｾｰｼﾞは、ﾗﾍﾞﾙ（長）が使われますが、これをﾗﾍﾞﾙ（短）を使いたい場合に、true にセットします。
    712         * ここでのラベル（短）は、ﾀｸﾞ修飾なしの、ﾗﾍﾞﾙ（短）です。
    713         * 標準はfalse:利用しない=ﾗﾍﾞﾙ（長）です。
    714         * true/false以外を指定した場合はfalse扱いとします。
    715         *
    716         * ﾗﾍﾞﾙﾘｿｰｽの概要説明があれば表示しますが、useSLabel="true" 時は、概要説明を表示しません。
    717         *
    718         * @og.rev 7.0.7.0 (2019/12/13) 新規追加
    719         *
    720         * @param prm SLABEL利用 [true:利用する/false:利用しない]
    721         */
    722        public void setUseSLabel( final String prm ) {
    723                useSLabel = nval( getRequestParameter( prm ),useSLabel );
    724        }
    725
    726        /**
    727         * DBTableModel から、FromFile,ToFile を作成するための処理をまとめた補助クラスです。
    728         *
    729         * ここでは、オリジナルファイルやターゲットファイルを作成するための処理のみを集めています。
    730         * メソッドにすると、ローカル変数を多く管理するか、多数の引数渡しを繰り返すことになるため、
    731         * このローカルクラスに処理と、値を格納します。
    732         *
    733         */
    734        private static final class FromToFiles {
    735                private final DBTableModel      table ;
    736
    737                private final int PARENT        ;
    738                private final int NAME          ;
    739                private final int TO_PARENT     ;
    740                private final int TO_NAME       ;
    741
    742                private final File              toDir   ;
    743                private final boolean   createDir;      // ターゲットとなるフォルダがなければ、作成するかどうか(true:作成する)
    744                private final int       inPathCnt       ;       // 6.8.0.0 (2017/06/02) 入力共通パスの文字数
    745
    746                private boolean equalParent     ;               // 最後に実行された処理で、親フォルダが同一の場合は、true
    747
    748                /**
    749                 *  引数指定のコンストラクター
    750                 *
    751                 * 必要なパラメータを渡して、オブジェクトを構築します。
    752                 * 入力共通パス(inPath)は、COPY/MOVE時にtargetDirと置換されます。
    753                 *
    754                 * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
    755                 *
    756                 * @param       table     一覧が格納されているDBTableModel
    757                 * @param       targetDir       ターゲットとなるフォルダ
    758                 * @param       createDir       フォルダ作成可否 [true:作成する/false:作成しない]
    759                 * @param       inPath          入力共通パス
    760                 */
    761                public FromToFiles( final DBTableModel table , final String targetDir , final boolean createDir , final String inPath ) {
    762                        this.table              = table;
    763                        this.createDir  = createDir ;
    764                        toDir                   = mkDirs( targetDir,createDir );                        // targetDir が指定されていない場合は、null
    765                        // 7.0.5.0 (2019/09/13) inPath のﾊﾟｽの文字数も、正規パス名から作成。
    766                        inPathCnt               = inPath == null ? 0 : inPath.length() ;        // 6.8.0.0 (2017/06/02) 入力共通パスの文字数
    767
    768                        // "PARENT","NAME","TO_PARENT","TO_NAME" のカラム名のDBTableModelのカラム番号。存在しない場合は、-1
    769                        PARENT          = table.getColumnNo( "PARENT"   , false );
    770                        NAME            = table.getColumnNo( "NAME"             , false );
    771                        TO_PARENT       = table.getColumnNo( "TO_PARENT", false );
    772                        TO_NAME         = table.getColumnNo( "TO_NAME"  , false );
    773                }
    774
    775                /**
    776                 * 行番号より、対応するオリジナルファイル(FromFile)を返します。
    777                 *
    778                 * ここでは、TO_PARENT や TO_NAME は、判定する必要がないため、makeFromToFile( int ) の
    779                 * 一部のみで処理が終了できます。
    780                 * １．FromDir は、PARENT 列の値から作成する。
    781                 * ２．FromFileは、FromDir ＋ NAME列の値から作成する。
    782                 *
    783                 * 配列返しの関係で、メソッド(および内部処理)を分けています。
    784                 *
    785                 * @param       rowNo   カラムNo
    786                 * @return      オリジナルファイル(FromFile)
    787                 * @og.rtnNotNull
    788                 * @see         #makeFromToFile( int )
    789                 */
    790                public File makeFromOnly( final int rowNo ) {
    791                        final String[] value = table.getValues( rowNo );
    792                        final File fromDir  = mkDirs( value[PARENT],createDir );
    793
    794                        return new File( fromDir, value[NAME] ) ;
    795                }
    796
    797                /**
    798                 * 行番号より、対応するオリジナルファイル(FromFile)とターゲットファイル(ToFile)を配列に格納して返します。
    799                 *
    800                 * ここでは、TO_PARENT や TO_NAME は、存在するかどうか不明なので、以下の手順で作成します。
    801                 * １．FromDir は、PARENT 列の値から作成する。
    802                 * ２．FromFileは、FromDir ＋ NAME列の値から作成する。
    803                 * ３．toDir は、
    804                 *       Ａ．targetDir が有れば、それを使う。
    805                 *       Ｂ．なければ、TO_PARENT 列の値から作成する。
    806                 *       Ｃ．TO_PARENT 列がないか、値が未設定の場合は、FromDir をそのまま使う。
    807                 * ４．toFile は、
    808                 *       Ａ．toDir ＋ TO_NAME 列の値から作成する。
    809                 *       Ｂ．TO_NAME 列がないか、値が未設定の場合は、toDir ＋ NAME列の値から作成する。
    810                 * 返り値は、new File[] { formFile , toFile }; とする。
    811                 *
    812                 * @og.rev 6.8.0.0 (2017/06/02) 入力共通パス(inPath)を指定します。
    813                 *
    814                 * @param       rowNo   カラムNo
    815                 * @return      ファイル配列(0:オリジナルファイル 1:ターゲットファイル)
    816                 * @og.rtnNotNull
    817                 */
    818                public File[] makeFromToFile( final int rowNo ) {
    819                        final String[] value = table.getValues( rowNo );
    820                        final File fromDir  = mkDirs( value[PARENT],createDir );
    821                        final File formFile = new File( fromDir, value[NAME] );
    822                        File tempToDir = toDir;
    823
    824                        equalParent = false;    // 最後に実行された処理で、親フォルダが同一かどうかのフラグをリセットする。
    825                        if( tempToDir == null ) {
    826                                if( TO_PARENT >= 0 && nval( value[TO_PARENT],null ) != null ) {
    827                                        tempToDir = mkDirs( value[TO_PARENT],createDir );
    828                                }
    829                                else {
    830                                        tempToDir = fromDir;
    831                                        equalParent = true;             // 最後に実行された処理で、親フォルダが同一の場合は、true
    832                                }
    833                        }
    834                        // 6.8.0.0 (2017/06/02) toDirが指定され、かつ、入力共通パスの文字数(inPathCnt)が指定された場合。
    835                        else if( inPathCnt > 0 ) {
    836                                if( TO_PARENT >= 0 && nval( value[TO_PARENT],null ) != null ) {
    837                                        final String prntVal = toDir.getAbsolutePath() + value[TO_PARENT].substring( inPathCnt );
    838                                        tempToDir = mkDirs( prntVal,createDir );
    839                                }
    840                                else {
    841                                        final String prntVal = toDir.getAbsolutePath() + value[PARENT].substring( inPathCnt );
    842                                        tempToDir = mkDirs( prntVal,createDir );
    843                                }
    844                        }
    845
    846                        File toFile = null;
    847                        if( TO_NAME >= 0 && nval(value[TO_NAME],null) != null  ) {
    848                                toFile = new File( tempToDir, value[TO_NAME] );
    849                        }
    850                        else {
    851                                toFile = new File( tempToDir, value[NAME] );
    852                        }
    853
    854                        return new File[] { formFile , toFile };
    855                }
    856
    857                /**
    858                 * 最後に実行された処理で、親フォルダが同一かどうかを返します(同一の場合は、true)。
    859                 *
    860                 * makeFromToFile( int ) が処理されたときの、FromDir と toDir が同一であれば、true を、
    861                 * 異なる場合は、false を返します。
    862                 * ここでの結果は、厳密な同一判定ではなく、処理的に、同一かどうかを判定しています。
    863                 * つまり、toDir に FromDir をセットする(３．Ｃのケース)場合に、true を内部変数にセットします。
    864                 * この判定値は、ファイルの移動処理で、異なる親フォルダの場合は、COPY ＆ DELETE しなければ
    865                 * なりませんが、同一親フォルダの場合は、RENAME で済む という処理負荷の軽減が目的です。
    866                 * よって、結果的に、PARENT と TO_PARENT が同じとか、PARENT と targetDir が同じでも
    867                 * ここでのフラグは、false が返されます。
    868                 *
    869                 * @return      最後に実行された処理で、親フォルダが同一の場合は、true
    870                 * @see         #makeFromToFile( int )
    871                 */
    872                public boolean lastParentEquals() {
    873                        return equalParent ;
    874                }
    875
    876        //      /**
    877        //       *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
    878        //       *
    879        //       * ここでは、TO_PARENT や TO_NAME は、存在するかどうか不明なので、
    880        //       * EXCEPTION にせず、配列番号に、-1 を返すようにしています。
    881        //       *
    882        //       * @param       table     一覧が格納されているDBTableModel
    883        //       * @param       nameArray       カラム名配列
    884        //       * @return      カラムNo配列(カラム名が存在しない場合は、-1)
    885        //       */
    886        //      private int[] getTableColumnNo( final DBTableModel table ,final String[] nameArray ) {
    887        //              int[] clmNo = new int[ nameArray.length ];
    888        //              for( int i=0; i<clmNo.length; i++ ) {
    889        //                      clmNo[i] = table.getColumnNo( nameArray[i] , false );   // カラム名が存在しない場合は、-1 を返す。
    890        //              }
    891        //              return clmNo;
    892        //      }
    893
    894                /**
    895                 * フォルダを作成します。
    896                 *
    897                 * フォルダが存在しない場合は、途中階層をすべて作成します。
    898                 *
    899                 * @og.rev 7.0.5.0 (2019/09/13) target のﾊﾟｽも、正規パス名から作成。
    900                 *
    901                 * @param       fname   フォルダ名
    902                 * @param       createDir       フォルダ作成可否 [true:作成する/false:作成しない]
    903                 * @return      フォルダを表すファイルオブジェクト。引数が null の場合は、null を返します。
    904                 * @throws      HybsSystemException             ファイルか、存在しない場合に、createDir=false か、mkdirs() が false の場合
    905                 */
    906                private File mkDirs( final String fname , final boolean createDir ) {
    907                        File target = null;
    908                        if( fname != null ) {
    909                                // 7.0.5.0 (2019/09/13) target のﾊﾟｽも、正規パス名から作成。
    910//                              target = new File( fname );
    911                                try {
    912                                        target = new File( fname ).getCanonicalFile();
    913                                        if( target.exists() ) {                 // 存在する
    914                                                if( target.isFile() ) {
    915                                                        final String errMsg = "ターゲットに、ファイル名は指定できません。" + CR
    916                                                                                                + "ターゲット=[" + fname + "]"  + CR;
    917                                                        throw new HybsSystemException( errMsg );
    918                                                }
    919                                        }
    920                                        else {                                                  // 存在しない
    921                                                // 存在しないのに、作成しない
    922                                                if( !createDir ) {
    923                                                        final String errMsg = "ターゲットが存在しません。 " + CR
    924                                                                                                + "ターゲット=[" + fname + "]"  + CR;
    925                                                        throw new HybsSystemException( errMsg );
    926                                                }
    927                                                // 作成できない
    928                                                if( !target.mkdirs() ) {
    929                                                        final String errMsg = "ターゲットを自動作成使用としましたが、作成できませんでした。" + CR
    930                                                                                                + "ターゲット=[" + fname + "]"  + CR;
    931                                                        throw new HybsSystemException( errMsg );
    932                                                }
    933                                        }
    934                                }
    935                                catch( final IOException ex ) {
    936                                        final String errMsg = "File#getCanonicalFile() で、正式パス名を求めることができませんでした。" + CR
    937                                                                                + ex.getMessage()
    938                                                                                + "ターゲット=[" + fname + "]"  + CR;
    939                                        throw new HybsSystemException( errMsg,ex );
    940                                }
    941                        }
    942                        return target;
    943                }
    944        }
    945
    946        /**
    947         * このオブジェクトの文字列表現を返します。
    948         * 基本的にデバッグ目的に使用します。
    949         *
    950         * @return このクラスの文字列表現
    951         * @og.rtnNotNull
    952         */
    953        @Override
    954        public String toString() {
    955                return ToString.title( this.getClass().getName() )
    956                                .println( "VERSION"                     ,VERSION                )
    957                                .println( "action"                      ,action                 )
    958                                .println( "command"                     ,command                )
    959                                .println( "targetDir"           ,targetDir              )
    960                                .println( "createDir"           ,createDir              )
    961                                .println( "tableId"                     ,tableId                )
    962                                .println( "outMessage"          ,outMessage     )
    963                                .println( "displayMsg"          ,displayMsg     )
    964                                .println( "selectedAll"         ,selectedAll    )
    965                                .println( "keepTimeStamp"       ,keepTimeStamp  )
    966                                .fixForm().toString() ;
    967        }
    968}