    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
    018import 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
    026import 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         * ファイル名(置き換え後)の置き換えを実行します。
    112         * useBackup = true にすると、dir の直下に、"_backup" フォルダを作成します。
    113         * バックアップファイル名は、元のファイル名(拡張子含む) ＋ "_" + 現在時刻のlong値 + "." + 元のファイルの拡張子
    114         *
    115         * newName が null の場合は、original のファイル名に、変換します。
    116         *
    117         * 6.0.2.4 (2014/10/17)
    118         * useBackup="rename" で、すでに同名のファイルが存在した場合に、"_001" のような文字列を追加したファイルにリネームします。
    119         * Windowsの " - コピー (2)" に近いですが、桁数を抑えるのと、useBackup="true" と異なり、過去の同一ファイル名は
    120         * そのまま、有効になります。同一ファイルが同一フォルダに存在する場合のみ連番が付与されます。
    121         *
    122         * newName の指定に、フォルダ名を含めることを可能にしました。
    123         *
    124         * @og.rev 5.7.1.1 (2013/12/13) 新規追加
    125         * @og.rev 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた。
    126         * @og.rev 6.0.2.4 (2014/10/17) useBackup 修正、newName に、フォルダ名を含めることが可能
    127         * @og.rev 6.2.0.0 (2015/02/27) FileInfoクラスを使用。 (FileUtil#getExtension(String) の廃止)
    128         * @og.rev 5.9.25.0 (2017/10/06) returnをString型に変更。引数にfileURLとsessionを追加
    129         * @og.rev 5.10.9.0 (2019/03/01) クラウドストレージ対応の追加。
    130         *
    131         * @param       newName         ファイル名(nullの場合は、オリジナル)
    132         * @param       prefix          接頭辞(nullの場合は、何もつけない)
    133         * @param       sufix           接尾辞(nullの場合は、何もつけない)
    134         * @param       useBackup       置き換え後ファイルの処理方法(true:backupフォルダ/false:しない/rename:重複しない連番)
    135         * @param       fileURL         クラウドストレージ用のURL
    136//       * @param       hsession        セッション
    137         * @param  storageType  クラウドプラグイン名
    138         * @param  bucketName   バケット名
    139         * @return      最終的に作成されたファイルオブジェクト
    140         */
    141//      public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL, final HttpSession hsession ) {
    142        public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL,
    143                                final String storageType, final String bucketName ) {
    144
    145                // 6.0.2.4 (2014/10/17) prfix が null でなければ、連結。newName が null なら、original を使う。
    146                String newNm = StringUtil.nvalAdd( prefix, StringUtil.coalesce( newName,original ) );
    147
    148                if( newNm == null || newNm.isEmpty() ) {
    149                        final String errMsg = "新ファイル名が存在しません。[" + newNm + "]" ;
    150                        throw new OgRuntimeException( errMsg );
    151                }
    152
    153                // 新ファイル名から拡張子取得
    154                final String newExt = FileInfo.getSUFIX( newNm );                       // 6.2.3.0 (2015/05/01)
    155                if( newExt == null || newExt.isEmpty() ) {                                                              // 拡張子なし
    156                        final String oldExt = FileInfo.getSUFIX( original );
    157                        newNm = StringUtil.nvalAdd( newNm , sufix , "." , oldExt ) ;            // sufix を入れ込む。
    158                }
    159                else if( sufix != null ) {                                                                                              // 拡張子あり、sufixあり
    160                        final StringBuilder buf = new StringBuilder( newNm );
    161                        buf.insert( newNm.length()-newExt.length()-1 , sufix );
    162                        newNm = buf.toString() ;
    163                }
    164
    165        //      File newFile = new File( dir,newNm );
    166                final File newFile = HybsFileOperationFactory.create(storageType, bucketName, dir, newNm );     // 8.0.0.0
    167
    168                // 5.10.9.0 (2019/03/01) MODIFY
    169                // File uniqFile = new File( dir , uniqKey );           // 5.7.1.1 (2013/12/13) アップロードされたファイル
    170                final File uniqFile = HybsFileOperationFactory.create(storageType, bucketName, dir, uniqKey);
    171
    172                // 5.10.9.0 (2019/03/01) MODIFY HybsFileUtilクラスの利用に変更。
    173                FileUtil.renameTo( uniqFile , newFile, useBackup );             // from ⇒ to の順番に指定。
    174
    175                // (2017/09/22) ADD FILE型をString型に変更したので、getName()をfilenameに設定。
    176                filename = newFile.getName();
    177
    178        //      if( newNm != null && newNm.length() > 0 ) {
    179                        // 5.9.25.0 (2017/10/06) ADD bluemixｸﾗｳﾄﾞｽﾄﾚｰｼﾞを利用する処理を追加
    180//                      final String storage = HybsSystem.sys( "CLOUD_TARGET");
    181//                      if(storage != null && storage.length() > 0){
    182//                              // ｽﾄﾚｰｼﾞに保存
    183//                              final StorageAPI storageApi = StorageAPIFactory.newStorageAPI(storage, HybsSystem.sys("CLOUD_BUCKET"), hsession);
    184//                              storageApi.rename(fileURL, uniqKey, newNm, Boolean.valueOf( useBackup ), hsession);
    185//                              // ﾌｧｲﾙ名をfilenameに設定する
    186//                              filename = newNm;
    187//                      } else {
    188//                              // 標準のﾌｧｲﾙ作成
    189//      //                      newFile = new File( dir,newNm );
    190//
    191//                              final File uniqFile = new File( dir , uniqKey );                // 5.7.1.1 (2013/12/13) アップロードされたファイル
    192//
    193//                              // 6.0.2.4 (2014/10/17) 戻り値は、変更後の新しい File オブジェクト
    194//                              newFile = FileUtil.renameTo( uniqFile, newFile, useBackup );            // from ⇒ to の順番に指定。
    195//
    196//                              // 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた。
    197//      //                      FileUtil.renameTo( newFile, uniqFile , useBackup );
    198//      //                      FileUtil.renameTo( uniqFile , newFile, useBackup );             // from ⇒ to の順番に指定。
    199//                              // (2017/09/22) ADD FILE型をString型に変更したので、getName()をfilenameに設定。
    200//                              filename = newFile.getName();
    201//                      }
    202        //      }
    203        //      // 5.7.1.1 (2013/12/13) ここの処理が走ることは無いはず。
    204        //      else {
    205        //              String errMsg = "新ファイル名が存在しません。[" + newNm + "]" ;
    206        //              throw new RuntimeException( errMsg );
    207        //      }
    208
    209                        // 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた。
    210                        // 6.0.2.4 (2014/10/17) 戻り値は、変更後の新しい File オブジェクト
    211                // 新ファイル名のセットは、すべての処理が完了してから、設定する。
    212                // 5.9.25.0 (2017/10/06) DELETE FILE型をString型に変更により、前の処理でfinenameは設定済み
    213                return filename;
    214        }
    215
    216        /**
    217         * ファイル名(オリジナル)を取得します。
    218         *
    219         * @return      ファイル名(オリジナル)
    220         */
    221        public String getOriginalFileName() {
    222                return original;
    223        }
    224
    225        /**
    226         * 自然比較メソッド
    227         * インタフェース Comparable の 実装に関連して、再定義しています。
    228         * 登録されたシーケンス(画面の表示順)で比較します。
    229         * equals メソッドでは、キーの同一性のみに着目して判定しています。
    230         * この比較では、(運用上同一キーは発生しませんが)たとえ同一キーが存在した
    231         * としても、その比較値が同じになることを保証していません。
    232         *
    233         * @param   other 比較対象のObject
    234         *
    235         * @return  このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数
    236         * @throws  ClassCastException 引数が UploadedFile ではない場合
    237         * @throws  IllegalArgumentException 引数が null の場合
    238         */
    239        @Override
    240        public int compareTo( final UploadedFile other ) {
    241                if( other == null ) {
    242                        final String errMsg = "引数が、null です。" ;
    243                        throw new IllegalArgumentException( errMsg );
    244                }
    245
    246                return uniqKey.compareTo( other.uniqKey );
    247        }
    248
    249        /**
    250         * このオブジェクトと他のオブジェクトが等しいかどうかを示します。
    251         * 画面は、画面IDが等しければ、言語や表示順に関係なく同一とみなされます。
    252         * GUIInfo は、ユーザー個別に扱われ、そのグループには、key は唯一で、かつ
    253         * 同一言語内で扱われるオブジェクトの為、同一とみなします。
    254         *
    255         * @param   object 比較対象の参照オブジェクト
    256         *
    257         * @return      引数に指定されたオブジェクトとこのオブジェクトが等しい場合は true、そうでない場合は false
    258         */
    259        @Override
    260        public boolean equals( final Object object ) {
    261                // 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
    262                return object instanceof UploadedFile && uniqKey.equals( ((UploadedFile)object).uniqKey ) ;
    263        }
    264
    265        /**
    266         * オブジェクトのハッシュコード値を返します。
    267         * このメソッドは、java.util.Hashtable によって提供されるような
    268         * ハッシュテーブルで使用するために用意されています。
    269         * equals( Object ) メソッドをオーバーライトした場合は、hashCode() メソッドも
    270         * 必ず 記述する必要があります。
    271         * この実装では、getKey().hashCode() と同値を返します。
    272         *
    273         * @return  このオブジェクトのハッシュコード値
    274         */
    275        @Override
    276        public int hashCode() {
    277                return uniqKey.hashCode() ;
    278        }
    279
    280        /**
    281         * オブジェクトの識別子として，詳細な画面情報を返します。
    282         *
    283         * @return  詳細な画面情報
    284         * @og.rtnNotNull
    285         */
    286        @Override
    287        public String toString() {
    288                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
    289                        .append( this.getClass().getName()                      ).append( CR )
    290                        .append( "  uniqKey  :").append( uniqKey        ).append( CR )
    291                        .append( "  filename :").append( filename       ).append( CR )
    292                        .append( "  name     :").append( name           ).append( CR )
    293                        .append( "  dir      :").append( dir            ).append( CR )
    294                        .append( "  original :").append( original       ).append( CR )
    295                        .append( "  type     :").append( type           ).append( CR );
    296                return rtn.toString();
    297        }
    298}