    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.servlet;
    017
    018// import jakarta.servlet.http.HttpSession;                                     // 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
    019
    020import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
    021import static org.opengion.fukurou.system.HybsConst.CR ;        // 6.1.0.0 (2014/12/26)
    022import org.opengion.fukurou.util.FileUtil;
    023import org.opengion.fukurou.util.FileInfo;                                      // 6.2.0.0 (2015/02/27)
    024import org.opengion.fukurou.util.StringUtil;                            // 6.0.2.4 (2014/10/17)
    025
    026// import org.opengion.hayabusa.common.HybsSystem;                      // 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
    027// import org.opengion.hayabusa.io.StorageAPI;                          // 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
    028// import org.opengion.hayabusa.io.StorageAPIFactory;           // 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
    029import org.opengion.hayabusa.io.HybsFileOperationFactory;       // 8.0.0.0 (2021/09/30)
    030
    031import java.io.File;
    032
    033/**
    034 * ﾌｧｲﾙをｻｰﾊﾞｰにｱｯﾌﾟﾛｰﾄﾞする場合に使用されるﾌｧｲﾙ管理ｸﾗｽです｡
    035 * HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応 に伴い､一つのｸﾗｽとして public化します｡
    036 *
    037 * @og.group その他機能
    038 * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
    039 * @og.rev 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
    040 *
    041 * @version  4.0
    042 * @author       Kazuhiko Hasegawa
    043 * @since    JDK5.0,
    044 */
    045public final class UploadedFile implements Comparable<UploadedFile> {
    046
    047        /** ﾊﾞｯﾌｧの初期容量を通常より多い目に設定します｡  {@value}  */
    048        public static final int BUFFER_MIDDLE = 200;
    049
    050        // 5.9.25.0 (2017/10/06) MODIFY File型をString型に変更
    051        private String filename ;                               // 現時点での置き換え後ﾌｧｲﾙ名
    052
    053        private final String uniqKey    ;               // ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ名(ﾕﾆｰｸにしておきます)
    054        private final String dir                ;
    055        private final String name               ;
    056        private final String original   ;
    057        private final String type               ;
    058
    059        /**
    060         * ｱｯﾌﾟﾛｰﾄﾞﾌｧｲﾙの管理ｵﾌﾞｼﾞｪｸﾄを作成します｡
    061         *
    062         * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
    063         *
    064         * @param       uniqKey         ﾕﾆｰｸｷｰ(初期ｱｯﾌﾟﾛｰﾄﾞﾌｧｲﾙ名)
    065         * @param       dir                     ﾌｧｲﾙを保管するﾌｫﾙﾀﾞ
    066         * @param       name            ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性
    067         * @param       original        ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)
    068         * @param       type            ｺﾝﾃﾝﾄﾀｲﾌﾟ
    069         */
    070        UploadedFile( final String uniqKey, final String dir, final String name, final String original, final String type ) {
    071                this.uniqKey    = uniqKey;              // 5.7.1.1 (2013/12/13) uniqKey を確定させる｡
    072                this.dir                = dir;
    073                this.name               = name;
    074                this.original   = original;
    075                this.type               = type;
    076        }
    077
    078        /**
    079         * ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性を取得します｡
    080         *
    081         * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
    082         *
    083         * @return      ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性
    084         */
    085        public String getName() {
    086                return name;
    087        }
    088
    089        /**
    090         * ｺﾝﾃﾝﾄﾀｲﾌﾟを取得します｡
    091         *
    092         * @return      ｺﾝﾃﾝﾄﾀｲﾌﾟ
    093         */
    094        public String getContentType() {
    095                return type;
    096        }
    097
    098        /**
    099         * ﾌｧｲﾙ名(置き換え後)を取得します｡
    100         *
    101         * @og.rev 5.7.1.2 (2013/12/20) zip 対応で､Fileｵﾌﾞｼﾞｪｸﾄを返すようにします｡
    102         * @og.rev 5.9.25.0 (2017/10/06) FILE型をString型に変更
    103         *
    104         * @return      ﾌｧｲﾙ名(置き換え後)
    105         */
    106        public String getUploadFile(){
    107                return filename;
    108        }
    109
    110        /**
    111         * Fileｵﾌﾞｼﾞｪｸﾄ(置き換え後)を取得します｡
    112         *
    113         * @og.rev 8.1.2.0 (2022/03/10) Fileｵﾌﾞｼﾞｪｸﾄを返すようにします｡
    114         *
    115         * @param       useLocal        強制的にﾛｰｶﾙﾌｧｲﾙを使用する場合､true にｾｯﾄします｡
    116         *
    117         * @return      Fileｵﾌﾞｼﾞｪｸﾄ(置き換え後)
    118         */
    119        public File getFile( final boolean useLocal ) {
    120                return HybsFileOperationFactory.create( useLocal, dir, filename );
    121        }
    122
    123        /**
    124         * ﾌｧｲﾙ名(置き換え後)の置き換えを実行します｡
    125         * useBackup = true にすると､dir の直下に､"_backup" ﾌｫﾙﾀﾞを作成します｡
    126         * ﾊﾞｯｸｱｯﾌﾟﾌｧｲﾙ名は､元のﾌｧｲﾙ名(拡張子含む) ＋ "_" + 現在時刻のlong値 + "." + 元のﾌｧｲﾙの拡張子
    127         *
    128         * newName が null の場合は､original のﾌｧｲﾙ名に､変換します｡
    129         *
    130         * 6.0.2.4 (2014/10/17)
    131         * useBackup="rename" で､すでに同名のﾌｧｲﾙが存在した場合に､"_001" のような文字列を追加したﾌｧｲﾙにﾘﾈｰﾑします｡
    132         * Windowsの " - ｺﾋﾟｰ (2)" に近いですが､桁数を抑えるのと､useBackup="true" と異なり､過去の同一ﾌｧｲﾙ名は
    133         * そのまま､有効になります｡同一ﾌｧｲﾙが同一ﾌｫﾙﾀﾞに存在する場合のみ連番が付与されます｡
    134         *
    135         * newName の指定に､ﾌｫﾙﾀﾞ名を含めることを可能にしました｡
    136         *
    137         * @og.rev 5.7.1.1 (2013/12/13) 新規追加
    138         * @og.rev 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
    139         * @og.rev 6.0.2.4 (2014/10/17) useBackup 修正､newName に､ﾌｫﾙﾀﾞ名を含めることが可能
    140         * @og.rev 6.2.0.0 (2015/02/27) FileInfoｸﾗｽを使用｡ (FileUtil#getExtension(String) の廃止)
    141         * @og.rev 5.9.25.0 (2017/10/06) returnをString型に変更｡引数にfileURLとsessionを追加
    142         * @og.rev 5.10.9.0 (2019/03/01) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ対応の追加｡
    143         * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加｡storageType , bucketName 削除
    144         *
    145         * @param       newName         ﾌｧｲﾙ名(nullの場合は､ｵﾘｼﾞﾅﾙ)
    146         * @param       prefix          接頭辞(nullの場合は､何もつけない)
    147         * @param       sufix           接尾辞(nullの場合は､何もつけない)
    148         * @param       useBackup       置き換え後ﾌｧｲﾙの処理方法(true:backupﾌｫﾙﾀﾞ/false:しない/rename:重複しない連番)
    149         * @param       fileURL         ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ用のURL
    150//       * @param       hsession        ｾｯｼｮﾝ
    151//       * @param       storage         ｸﾗｳﾄﾞﾌﾟﾗｸﾞｲﾝ名(ﾛｰｶﾙﾌｧｲﾙを強制する場合は､LOCAL を指定する)
    152//       * @param       bucket          ﾊﾞｹｯﾄ名(ﾛｰｶﾙﾌｧｲﾙを強制する場合は､LOCAL を指定する)
    153         * @param       useLocal        強制的にﾛｰｶﾙﾌｧｲﾙを使用する場合､true にｾｯﾄします｡
    154         * @return      最終的に作成されたﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
    155         */
    156//      public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL, final HttpSession hsession ) {
    157        public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL,
    158//                              final String storage, final String bucket ) {
    159                                final boolean useLocal ) {
    160
    161                // 6.0.2.4 (2014/10/17) prfix が null でなければ､連結｡newName が null なら､original を使う｡
    162                String newNm = StringUtil.nvalAdd( prefix, StringUtil.coalesce( newName,original ) );
    163
    164                if( newNm == null || newNm.isEmpty() ) {
    165                        final String errMsg = "新ﾌｧｲﾙ名が存在しません｡[" + newNm + "]" ;
    166                        throw new OgRuntimeException( errMsg );
    167                }
    168
    169                // 新ﾌｧｲﾙ名から拡張子取得
    170                final String newExt = FileInfo.getSUFIX( newNm );                       // 6.2.3.0 (2015/05/01)
    171                if( newExt == null || newExt.isEmpty() ) {                                                              // 拡張子なし
    172                        final String oldExt = FileInfo.getSUFIX( original );
    173                        newNm = StringUtil.nvalAdd( newNm , sufix , "." , oldExt ) ;            // sufix を入れ込む｡
    174                }
    175                else if( sufix != null ) {                                                                                              // 拡張子あり､sufixあり
    176                        final StringBuilder buf = new StringBuilder( newNm );
    177                        buf.insert( newNm.length()-newExt.length()-1 , sufix );
    178                        newNm = buf.toString() ;
    179                }
    180
    181                // 8.0.1.0 (2021/10/29) storageType , bucketName 削除
    182        //      File newFile = new File( dir,newNm );
    183//              final File newFile = HybsFileOperationFactory.create(storage, bucket, dir, newNm );     // 8.0.0.0
    184                final File newFile = HybsFileOperationFactory.create(useLocal, dir, newNm );    // 8.0.0.0
    185
    186                // 5.10.9.0 (2019/03/01) MODIFY
    187                // File uniqFile = new File( dir , uniqKey );           // 5.7.1.1 (2013/12/13) ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ
    188//              final File uniqFile = HybsFileOperationFactory.create(storage, bucket, dir, uniqKey);
    189                final File uniqFile = HybsFileOperationFactory.create(useLocal, dir, uniqKey);
    190
    191                // 5.10.9.0 (2019/03/01) MODIFY HybsFileUtilｸﾗｽの利用に変更｡
    192                FileUtil.renameTo( uniqFile , newFile, useBackup );             // from ⇒ to の順番に指定｡
    193
    194                // (2017/09/22) ADD FILE型をString型に変更したので､getName()をfilenameに設定｡
    195                filename = newFile.getName();
    196
    197        //      if( newNm != null && newNm.length() > 0 ) {
    198                        // 5.9.25.0 (2017/10/06) ADD bluemixｸﾗｳﾄﾞｽﾄﾚｰｼﾞを利用する処理を追加
    199//                      final String storage = HybsSystem.sys( "CLOUD_TARGET");
    200//                      if(storage != null && storage.length() > 0){
    201//                              // ｽﾄﾚｰｼﾞに保存
    202//                              final StorageAPI storageApi = StorageAPIFactory.newStorageAPI(storage, HybsSystem.sys("CLOUD_BUCKET"), hsession);
    203//                              storageApi.rename(fileURL, uniqKey, newNm, Boolean.valueOf( useBackup ), hsession);
    204//                              // ﾌｧｲﾙ名をfilenameに設定する
    205//                              filename = newNm;
    206//                      } else {
    207//                              // 標準のﾌｧｲﾙ作成
    208//      //                      newFile = new File( dir,newNm );
    209//
    210//                              final File uniqFile = new File( dir , uniqKey );                // 5.7.1.1 (2013/12/13) ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ
    211//
    212//                              // 6.0.2.4 (2014/10/17) 戻り値は､変更後の新しい File ｵﾌﾞｼﾞｪｸﾄ
    213//                              newFile = FileUtil.renameTo( uniqFile, newFile, useBackup );            // from ⇒ to の順番に指定｡
    214//
    215//                              // 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
    216//      //                      FileUtil.renameTo( newFile, uniqFile , useBackup );
    217//      //                      FileUtil.renameTo( uniqFile , newFile, useBackup );             // from ⇒ to の順番に指定｡
    218//                              // (2017/09/22) ADD FILE型をString型に変更したので､getName()をfilenameに設定｡
    219//                              filename = newFile.getName();
    220//                      }
    221        //      }
    222        //      // 5.7.1.1 (2013/12/13) ここの処理が走ることは無いはず｡
    223        //      else {
    224        //              String errMsg = "新ﾌｧｲﾙ名が存在しません｡[" + newNm + "]" ;
    225        //              throw new RuntimeException( errMsg );
    226        //      }
    227
    228                        // 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
    229                        // 6.0.2.4 (2014/10/17) 戻り値は､変更後の新しい File ｵﾌﾞｼﾞｪｸﾄ
    230                // 新ﾌｧｲﾙ名のｾｯﾄは､すべての処理が完了してから､設定する｡
    231                // 5.9.25.0 (2017/10/06) DELETE FILE型をString型に変更により､前の処理でfinenameは設定済み
    232                return filename;
    233        }
    234
    235        /**
    236         * ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)を取得します｡
    237         *
    238         * @return      ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)
    239         */
    240        public String getOriginalFileName() {
    241                return original;
    242        }
    243
    244        /**
    245         * 自然比較ﾒｿｯﾄﾞ
    246         * ｲﾝﾀﾌｪｰｽ Comparable の 実装に関連して､再定義しています｡
    247         * 登録されたｼｰｹﾝｽ(画面の表示順)で比較します｡
    248         * equals ﾒｿｯﾄﾞでは､ｷｰの同一性のみに着目して判定しています｡
    249         * この比較では､(運用上同一ｷｰは発生しませんが)たとえ同一ｷｰが存在した
    250         * としても､その比較値が同じになることを保証していません｡
    251         *
    252         * @param   other 比較対象のObject
    253         *
    254         * @return  このｵﾌﾞｼﾞｪｸﾄが指定されたｵﾌﾞｼﾞｪｸﾄより小さい場合は負の整数､等しい場合はｾﾞﾛ､大きい場合は正の整数
    255         * @throws  ClassCastException 引数が UploadedFile ではない場合
    256         * @throws  IllegalArgumentException 引数が null の場合
    257         */
    258        @Override
    259        public int compareTo( final UploadedFile other ) {
    260                if( other == null ) {
    261                        final String errMsg = "引数が､null です｡" ;
    262                        throw new IllegalArgumentException( errMsg );
    263                }
    264
    265                return uniqKey.compareTo( other.uniqKey );
    266        }
    267
    268        /**
    269         * このｵﾌﾞｼﾞｪｸﾄと他のｵﾌﾞｼﾞｪｸﾄが等しいかどうかを示します｡
    270         * 画面は､画面IDが等しければ､言語や表示順に関係なく同一とみなされます｡
    271         * GUIInfo は､ﾕｰｻﾞｰ個別に扱われ､そのｸﾞﾙｰﾌﾟには､key は唯一で､かつ
    272         * 同一言語内で扱われるｵﾌﾞｼﾞｪｸﾄの為､同一とみなします｡
    273         *
    274         * @param   object 比較対象の参照ｵﾌﾞｼﾞｪｸﾄ
    275         *
    276         * @return      引数に指定されたｵﾌﾞｼﾞｪｸﾄとこのｵﾌﾞｼﾞｪｸﾄが等しい場合は true､そうでない場合は false
    277         */
    278        @Override
    279        public boolean equals( final Object object ) {
    280                // 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
    281                return object instanceof UploadedFile && uniqKey.equals( ((UploadedFile)object).uniqKey ) ;
    282        }
    283
    284        /**
    285         * ｵﾌﾞｼﾞｪｸﾄのﾊｯｼｭｺｰﾄﾞ値を返します｡
    286         * このﾒｿｯﾄﾞは､java.util.Hashtable によって提供されるような
    287         * ﾊｯｼｭﾃｰﾌﾞﾙで使用するために用意されています｡
    288         * equals( Object ) ﾒｿｯﾄﾞをｵｰﾊﾞｰﾗｲﾄした場合は､hashCode() ﾒｿｯﾄﾞも
    289         * 必ず 記述する必要があります｡
    290         * この実装では､getKey().hashCode() と同値を返します｡
    291         *
    292         * @return  このｵﾌﾞｼﾞｪｸﾄのﾊｯｼｭｺｰﾄﾞ値
    293         */
    294        @Override
    295        public int hashCode() {
    296                return uniqKey.hashCode() ;
    297        }
    298
    299        /**
    300         * ｵﾌﾞｼﾞｪｸﾄの識別子として，詳細な画面情報を返します｡
    301         *
    302         * @return  詳細な画面情報
    303         * @og.rtnNotNull
    304         */
    305        @Override
    306        public String toString() {
    307                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
    308                        .append( this.getClass().getName()                      ).append( CR )
    309                        .append( "  uniqKey  :").append( uniqKey        ).append( CR )
    310                        .append( "  filename :").append( filename       ).append( CR )
    311                        .append( "  name     :").append( name           ).append( CR )
    312                        .append( "  dir      :").append( dir            ).append( CR )
    313                        .append( "  original :").append( original       ).append( CR )
    314                        .append( "  type     :").append( type           ).append( CR );
    315                return rtn.toString();
    316        }
    317}