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 java.io.File;
019
020import javax.servlet.http.HttpSession;
021
022import org.opengion.fukurou.util.FileUtil;
023import org.opengion.hayabusa.common.HybsSystem;
024import org.opengion.hayabusa.io.StorageAPI;
025import org.opengion.hayabusa.io.StorageAPIFactory;
026
027/**
028 * ファイルをサーバーにアップロードする場合に使用されるファイル管理クラスです。
029 * HTML5 ファイルアップロードの複数選択(multiple)対応 に伴い、一つのクラスとして public化します。
030 *
031 * @og.group その他機能
032 * @og.rev 5.7.1.1 (2013/12/13) HTML5 ファイルアップロードの複数選択(multiple)対応
033 * @og.rev 5.9.25.0 (2017/10/06) クラウドストレージ追加対応
034 *
035 * @version  4.0
036 * @author       Kazuhiko Hasegawa
037 * @since    JDK5.0,
038 */
039public final class UploadedFile implements Comparable<UploadedFile> {
040
041        /** バッファの初期容量を通常より多い目に設定します。  {@value}  */
042        public static final int BUFFER_MIDDLE = 200;
043
044        /** システム依存の改行記号をセットします。 */
045        public static final String CR = System.getProperty("line.separator");
046
047        // 5.9.25.0 (2017/10/06) MODIFY File型をString型に変更
048        //private File filename = null;         // 現時点での置き換え後ファイル名
049        private String filename = null; // 現時点での置き換え後ファイル名
050
051        private final String uniqKey ;          // アップロードされたファイル名(ユニークにしておきます)
052        private final String dir;
053        private final String name;
054        private final String original;
055        private final String type;
056
057        /**
058         * アップロードファイルの管理オブジェクトを作成します。
059         *
060         * @og.rev 5.7.1.1 (2013/12/13) HTML5 ファイルアップロードの複数選択(multiple)対応
061         *
062         * @param       uniqKey         ユニークキー(初期アップロードファイル名)
063         * @param       dir                     ファイルを保管するフォルダ
064         * @param       name            ファイルアップロードされた時のname属性
065         * @param       original        ファイル名(オリジナル)
066         * @param       type    コンテントタイプ
067         */
068//      UploadedFile( final String dir, final String name, final String filename, final String original, final String type) {
069        UploadedFile( final String uniqKey, final String dir, final String name, final String original, final String type ) {
070                this.uniqKey    = uniqKey;              // 5.7.1.1 (2013/12/13) uniqKey を確定させる。
071                this.dir                = dir;
072                this.name               = name;
073//              this.filename   = filename;
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 getFilesystemName() {
107//      public File getUploadFile() {
108        public String getUploadFile(){
109                return filename;
110        }
111
112        /**
113         * ファイル名(置き換え後)の置き換えを実行します。
114         * useBackup = true にすると、dir の直下に、"_backup" フォルダを作成します。
115         * バックアップファイル名は、元のファイル名(拡張子含む) + "_" + 現在時刻のlong値 + "." + 元のファイルの拡張子
116         *
117         * newName が null の場合は、original のファイル名に、変換します。
118         *
119         * @og.rev 5.7.1.1 (2013/12/13) 新規追加
120         * @og.rev 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた。
121         * @og.rev 5.9.25.0 (2017/10/06) returnをString型に変更。引数にfileURLとsessionを追加
122         *
123         * @param       newName         ファイル名(置き換え後)
124         * @param       useBackup       置き換え後ファイルをバックアップするかどうか(true:バックアップする/false:しない)
125         * @param  fileURL              クラウドストレージ用のURL
126         * @param  hsession             セッション
127         * @return      最終的に作成されたファイルオブジェクト
128         */
129        //public File renameTo( final String newName , final boolean useBackup) {
130        public String renameTo( final String newName , final boolean useBackup, final String fileURL, HttpSession hsession) {
131
132                String newNm = newName ;
133                // 新規ファイル名を作成します。(拡張子等)
134                if( newNm != null && newNm.length() > 0 ) {
135                        // 新ファイル名から拡張子取得
136                        String newExt = FileUtil.getExtension( newNm );
137                        if( newExt == null || newExt.length() == 0 ) {
138                                String oldExt = FileUtil.getExtension( original );
139                                newNm = newNm + "." + oldExt ;
140                        }
141                }
142                else {
143                        newNm = original;
144                }
145
146                File newFile = null ;
147                if( newNm != null && newNm.length() > 0 ) {
148                        // 5.9.25.0 (2017/10/06) ADD bluemixクラウドストレージを利用する処理を追加
149                        String storage = HybsSystem.sys( "CLOUD_STORAGE");
150                        if(storage != null && storage.length() > 0){
151                                // ストレージに保存
152                                StorageAPI storageApi = StorageAPIFactory.newStorageAPI(storage, HybsSystem.sys("CLOUD_STORAGE_CONTAINER"), hsession);
153                                storageApi.rename(fileURL, uniqKey, newNm, useBackup, hsession);
154                                // ファイル名をfilenameに設定する
155                                filename = newNm;
156                        }else{
157                                // 標準のファイル作成
158                                newFile = new File( dir,newNm );
159
160                                File uniqFile = new File( dir , uniqKey );              // 5.7.1.1 (2013/12/13) アップロードされたファイル
161
162                                // 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた。
163        //                      FileUtil.renameTo( newFile, uniqFile , useBackup );
164                                FileUtil.renameTo( uniqFile , newFile, useBackup );             // from ⇒ to の順番に指定。
165                                // (2017/09/22) ADD FILE型をString型に変更したので、getName()をfilenameに設定。
166                                filename = newFile.getName();
167                        }
168
169//                      // 置き換えファイルの存在チェック。
170//                      if( newFile.exists() ) {
171//                              if( useBackup ) {
172//                                      // newNm にフォルダ階層を含む場合に、そなえて。
173//                                      File parent = newFile.getParentFile();                  // バックアップすべきファイルのフォルダ
174//                                      File backup = new File( parent , "_backup" );   // その直下に、"_backup" フォルダを作成
175//                                      if( !backup.exists() && !backup.mkdirs() ) {
176//                                              String errMsg = "バックアップ処理でbackupフォルダの作成に失敗しました。[" + backup + "]";
177//                                              throw new RuntimeException( errMsg );
178//                                      }
179//                                      // バックアップファイル名は、元のファイル名(拡張子含む) + "_" + 現在時刻のlong値 + "." + 元のファイルの拡張子
180//                                      String bkupName = newFile.getName() + "_" + System.currentTimeMillis() + "."  + FileUtil.getExtension( newNm ) ;
181//                                      File fromFile = new File( dir,newNm );          // オリジナルの newFile をrename するとまずいので、同名のFileオブジェクトを作成
182//                                      File bkupFile = new File( backup,bkupName );
183//
184//                                      if( !fromFile.renameTo( bkupFile ) ) {
185//                                              String errMsg = "バックアップ処理でバックアップファイルをリネームできませんでした。" +CR
186//                                                                                       + "  [" + fromFile + "] ⇒ [" + bkupFile + "]" ;
187//                                              throw new RuntimeException( errMsg );
188//                                      }
189//                              }
190//                              else if( !newFile.delete() ) {
191//                                      String errMsg = "既存のファイル[" + newNm + "]が削除できませんでした。";
192//                                      throw new RuntimeException( errMsg );
193//                              }
194//                      }
195//
196//                      File uniqFile = new File( dir , uniqKey );              // 5.7.1.1 (2013/12/13) アップロードされたファイル
197//                      if( !uniqFile.renameTo( newFile ) ) {
198//                              String errMsg = "所定のファイルをリネームできませんでした。" + CR
199//                                                                      + "  [" + uniqFile + "] ⇒ [" + newFile + "]" ;
200//                              throw new RuntimeException( errMsg );
201//                      }
202
203                }
204                // 5.7.1.1 (2013/12/13) ここの処理が走ることは無いはず。
205                else {
206                        String errMsg = "新ファイル名が存在しません。[" + newNm + "]" ;
207                        throw new RuntimeException( errMsg );
208                }
209                // 新ファイル名のセットは、すべての処理が完了してから、設定する。
210                // 5.9.25.0 (2017/10/06) DELETE FILE型をString型に変更により、前の処理でfinenameは設定済み
211                //filename = newFile ;
212                return filename;
213        }
214
215        /**
216         * ファイル名(置き換え後)をセットします。
217         *
218         * @og.rev 5.7.1.1 (2013/12/13) 廃止
219         *
220         * @param       name    ファイル名(置き換え後)
221         */
222//      public void setFilesystemName( final String name ) {
223//              filename = name;
224//      }
225
226        /**
227         * ファイル名(オリジナル)を取得します。
228         *
229         * @return      ファイル名(オリジナル)
230         */
231        public String getOriginalFileName() {
232                return original;
233        }
234
235        /**
236         * ファイル名(置き換え後)の File オブジェクトを取得します。
237         *
238         * @og.rev 5.7.1.1 (2013/12/13) 廃止。
239         *
240         * @return Fileオブジェクト
241         */
242//      public File getFile() {
243//              if(dir == null || filename == null) {
244//                      return null;
245//              }
246//              else {
247//                      return new File(dir + File.separator + filename);
248//              }
249//      }
250
251        /**
252         * ファイル名から 拡張子を取得します。
253         *
254         * @og.rev 5.7.1.1 (2013/12/13) ローカルに移動。若干のロジック変更
255         *
256         * @param       fileName        ファイル名
257         * @return      拡張子
258         */
259//      private String getExtension( final String fileName ) {
260//              int index = fileName.lastIndexOf('.');
261////            if(index!=-1) {
262////                    return fileName.substring(index + 1, fileName.length());
263////            }
264//              if( index >= 0 ) {
265//                      return fileName.substring( index + 1 );
266//              }
267//              return "";
268//      }
269
270        /**
271         * 自然比較メソッド
272         * インタフェース Comparable の 実装に関連して、再定義しています。
273         * 登録されたシーケンス(画面の表示順)で比較します。
274         * equals メソッドでは、キーの同一性のみに着目して判定しています。
275         * この比較では、(運用上同一キーは発生しませんが)たとえ同一キーが存在した
276         * としても、その比較値が同じになることを保証していません。
277         *
278         * @param   other 比較対象のObject
279         *
280         * @return  このオブジェクトが指定されたオブジェクトより小さい場合は負の整数、等しい場合はゼロ、大きい場合は正の整数
281         * @throws  ClassCastException 引数が UploadedFile ではない場合
282         * @throws  IllegalArgumentException 引数が null の場合
283         */
284        @Override
285        public int compareTo( final UploadedFile other ) {
286                if( other == null ) {
287                        String errMsg = "引数が、null です。" ;
288                        throw new IllegalArgumentException( errMsg );
289                }
290
291                return ( uniqKey ).compareTo( other.uniqKey );
292        }
293
294        /**
295         * このオブジェクトと他のオブジェクトが等しいかどうかを示します。
296         * 画面は、画面IDが等しければ、言語や表示順に関係なく同一とみなされます。
297         * GUIInfo は、ユーザー個別に扱われ、そのグループには、key は唯一で、かつ
298         * 同一言語内で扱われるオブジェクトの為、同一とみなします。
299         *
300         * @param   object 比較対象の参照オブジェクト
301         *
302         * @return      引数に指定されたオブジェクトとこのオブジェクトが等しい場合は true、そうでない場合は false
303         */
304        @Override
305        public boolean equals( final Object object ) {
306                if( object instanceof UploadedFile ) {
307                        return uniqKey.equals( ((UploadedFile)object).uniqKey );
308                }
309
310                return false ;
311        }
312
313        /**
314         * オブジェクトのハッシュコード値を返します。
315         * このメソッドは、java.util.Hashtable によって提供されるような
316         * ハッシュテーブルで使用するために用意されています。
317         * equals( Object ) メソッドをオーバーライトした場合は、hashCode() メソッドも
318         * 必ず 記述する必要があります。
319         * この実装では、getKey().hashCode() と同値を返します。
320         *
321         * @return  このオブジェクトのハッシュコード値
322         */
323        @Override
324        public int hashCode() {
325                return uniqKey.hashCode() ;
326        }
327
328        /**
329         * オブジェクトの識別子として,詳細な画面情報を返します。
330         *
331         * @return  詳細な画面情報
332         */
333        @Override
334        public String toString() {
335                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
336                rtn.append( this.getClass().getName()                   ).append( CR );
337                rtn.append( "  uniqKey  :").append( uniqKey             ).append( CR );
338                rtn.append( "  filename :").append( filename    ).append( CR );
339                rtn.append( "  name     :").append( name                ).append( CR );
340                rtn.append( "  dir      :").append( dir                 ).append( CR );
341                rtn.append( "  original :").append( original    ).append( CR );
342                rtn.append( "  type     :").append( type                ).append( CR );
343                return rtn.toString();
344        }
345}