001package org.opengion.plugin.cloud;
002
003import java.io.InputStream;
004import java.text.SimpleDateFormat;
005import java.util.ArrayList;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009
010import javax.servlet.http.HttpSession;
011
012import org.apache.commons.lang3.StringUtils;
013import org.opengion.fukurou.util.Closer;
014import org.opengion.fukurou.util.FileUtil;
015import org.opengion.hayabusa.common.HybsSystem;
016import org.opengion.hayabusa.common.HybsSystemException;
017import org.opengion.hayabusa.io.StorageAPI;
018
019import com.amazonaws.auth.AWSCredentials;
020import com.amazonaws.auth.AWSStaticCredentialsProvider;
021import com.amazonaws.auth.BasicAWSCredentials;
022import com.amazonaws.auth.InstanceProfileCredentialsProvider;
023import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
024import com.amazonaws.services.s3.AmazonS3;
025import com.amazonaws.services.s3.AmazonS3ClientBuilder;
026import com.amazonaws.services.s3.model.CopyObjectRequest;
027import com.amazonaws.services.s3.model.DeleteObjectRequest;
028import com.amazonaws.services.s3.model.ListObjectsV2Request;
029import com.amazonaws.services.s3.model.ListObjectsV2Result;
030import com.amazonaws.services.s3.model.ObjectMetadata;
031import com.amazonaws.services.s3.model.PutObjectRequest;
032import com.amazonaws.services.s3.model.S3Object;
033import com.amazonaws.services.s3.model.S3ObjectSummary;
034import com.microsoft.azure.storage.blob.BlobOutputStream;
035
036/**
037 * azure用のクラウドストレージ操作実装
038 *
039 * システムリソースのS3_ACCESS_KEY,S3_SECRET_KEY,S3_SERVICE_END_POINT,S3_REGIONに、AWSのキー情報を登録する必要があります。
040 *
041 * @og.group クラウド
042 * @og.rev  (2018/02/15) 新規作成
043 * @og.rev 5.9.32.0 (2018/05/02) IAM対応
044 *
045 * @version 5.0
046 * @author T.OTA
047 * @sinse JDK7.0
048 */
049public class StorageAPI_aws implements StorageAPI {
050        // 認証文字列
051        // アクセスキー
052        private String s3AccessKey = "";
053        // シークレットキー
054        private String s3SecretKey = "";
055        // エンドポイント
056        private String s3ServiceEndPoint = "";
057        // レギオン
058        private String s3Region = "";
059        // バケット名(コンテナ名)
060        String s3bucket = "";
061
062        AmazonS3 client = null;
063
064        /**
065         * コンストラクタ
066         * 
067         * @og.rev 5.9.32.0 (2018/05/02) IAM対応
068         * @param container
069         * @param hsession
070         */
071        public StorageAPI_aws(String container, HttpSession hsession){
072                // リソースパラメータ設定
073                // アクセスキー
074                s3AccessKey = HybsSystem.sys("CLOUD_STORAGE_S3_ACCESS_KEY");
075        // コンテナ名をs3bucketとして保持しておく
076        s3bucket = container;
077
078        // S3アクセスクライアントの生成
079        if(StringUtils.isEmpty(s3AccessKey)){
080                // 5.9.32.0 (2018/05/02) IAMロールによる認証
081                client = AmazonS3ClientBuilder.standard()
082                                .withCredentials(new InstanceProfileCredentialsProvider(false))
083                                .build();
084        }else {
085                // リソースのアクセスキーによる認証
086                // シークレットキー
087                s3SecretKey = HybsSystem.sys("CLOUD_STORAGE_S3_SECRET_KEY");
088                // エンドポイント
089                s3ServiceEndPoint = HybsSystem.sys("CLOUD_STORAGE_S3_SERVICE_END_POINT");
090                // レギオン
091                s3Region = HybsSystem.sys("CLOUD_STORAGE_S3_REGION");
092
093                        // 初期チェック
094                        initCheck();
095
096                // AWSの認証情報
097                AWSCredentials credentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey);
098
099                // エンドポイント設定
100                EndpointConfiguration endpointConfiguration = new EndpointConfiguration(s3ServiceEndPoint,  s3Region);
101                client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials))
102                                .withEndpointConfiguration(endpointConfiguration).build();
103        }
104
105        // S3に指定されたバケット(コンテナ)が存在しない場合は、作成する
106        if(!client.doesBucketExist(container)){
107                client.createBucket(container);
108        }
109        }
110
111        /**
112         * 初期チェック
113         */
114        private void initCheck(){
115                // システムリソースに認証情報が登録されていない場合は、エラー
116                StringBuilder errString = new StringBuilder();
117                if(StringUtils.isEmpty(s3AccessKey)){
118                        errString.append("CLOUD_STORAGE_S3_ACCESS_KEY");
119                }
120                if(StringUtils.isEmpty(s3SecretKey)){
121                        errString.append(",CLOUD_STORAGE_S3_SECRET_KEY");
122                }
123                if(StringUtils.isEmpty(s3ServiceEndPoint)){
124                        errString.append(",CLOUD_STORAGE_S3_SERVICE_END_POINT");
125                }
126                if(StringUtils.isEmpty(s3Region)){
127                        errString.append(",CLOUD_STORAGE_S3_REGION");
128                }
129
130                if(errString.length() > 0){
131                        throw new HybsSystemException("AWSのキー情報("+errString.toString()+")がシステムリソースに登録されていません。");
132                }
133
134        }
135
136        /**
137         * アップロード
138         *
139         * @param partInputStream       アップロード対象のストリーム
140         * @param updFolder             アップロードフォルタ名
141         * @param updFileName           アップロードファイル名
142         * @param hsession                      セッション
143         */
144        @Override
145        public void add(InputStream partInputStream, String updFolder, String updFileName, HttpSession hsession) {
146                BlobOutputStream blobOutputStream = null;
147                try {
148                        // アップロード処理
149                        ObjectMetadata om = new ObjectMetadata();
150                        final PutObjectRequest putRequest = new PutObjectRequest(s3bucket, updFolder + updFileName, partInputStream,om);
151                        // アップロード実行
152                        client.putObject(putRequest);
153
154                } catch (Exception e) {
155                        StringBuilder sbErrMsg = new StringBuilder();
156                        sbErrMsg.append("ストレージへのファイルアップロードに失敗しました。updFolder:");
157                        sbErrMsg.append(updFolder);
158                        sbErrMsg.append(" updFileName:");
159                        sbErrMsg.append(updFileName);
160                        sbErrMsg.append(" errInfo:");
161                        sbErrMsg.append(e);
162                        throw new HybsSystemException(sbErrMsg.toString());
163                } finally {
164                        // クローズ処理
165                        Closer.ioClose(blobOutputStream);
166                        Closer.ioClose(partInputStream);
167                }
168        }
169
170        /**
171         * ダウンロード
172         *
173         * @param filePath      ダウンロード対象のファイルパス
174         * @param hsession      セッション
175         * @return ストリーム
176         */
177        @Override
178        public InputStream get(String filePath, HttpSession hsession) {
179                InputStream is = null;
180                // ダウンロード
181                try {
182                        S3Object object = client.getObject(s3bucket, filePath);
183
184                        is = object.getObjectContent();
185                } catch (Exception e) {
186                        StringBuilder sbErrMsg = new StringBuilder();
187                        sbErrMsg.append("ストレージからのファイルダウンロードに失敗しました。filePath:");
188                        sbErrMsg.append(filePath);
189                        sbErrMsg.append(" errInfo:");
190                        sbErrMsg.append(e);
191                        throw new HybsSystemException(sbErrMsg.toString());
192                }
193
194                return is;
195        }
196
197        /**
198         * コピー
199         *
200         * @param oldFilePath   コピー元ファイルパス
201         * @param newFilePath   コピー先ファイルパス
202         * @param hsession              セッション
203         */
204        @Override
205        public void copy(String oldFilePath, String newFilePath, HttpSession hsession) {
206                try {
207                        final CopyObjectRequest copyRequest = new CopyObjectRequest(s3bucket, oldFilePath, s3bucket, newFilePath);
208                        client.copyObject(copyRequest);
209                } catch (Exception e) {
210                        StringBuilder sbErrMsg = new StringBuilder();
211                        sbErrMsg.append("ストレージのファイルコピー処理に失敗しました。oldFilePath:");
212                        sbErrMsg.append(oldFilePath);
213                        sbErrMsg.append(" newFilePath:");
214                        sbErrMsg.append(newFilePath);
215                        sbErrMsg.append(" errInfo:");
216                        sbErrMsg.append(e);
217                        throw new HybsSystemException(sbErrMsg.toString());
218                }
219        }
220
221        /**
222         * 削除
223         *
224         * @param filePath      削除ファイルのパス
225         * @param hsession      セッション
226         */
227        @Override
228        public void delete(String filePath, HttpSession hsession) {
229                // 削除
230                try {
231                        final DeleteObjectRequest deleteRequest = new DeleteObjectRequest(s3bucket, filePath);
232                        client.deleteObject(deleteRequest);
233                        client.deleteObject(s3bucket, filePath);
234                } catch (Exception e) {
235                        StringBuilder sbErrMsg = new StringBuilder();
236                        sbErrMsg.append("ストレージのファイル削除に失敗しました。filePath:");
237                        sbErrMsg.append(filePath);
238                        sbErrMsg.append(" errInfo:");
239                        sbErrMsg.append(e);
240                        throw new HybsSystemException(sbErrMsg.toString());
241                }
242        }
243
244        /**
245         * ファイル名変更
246         *
247         * @param filePath              ファイルパス
248         * @param oldFileName   変更前ファイル名
249         * @param newFileName   変更後ファイル名
250         * @param useBackup     変更後ファイル名が既に存在する場合のバックアップ作成フラグ
251         * @param hsession              セッション
252         */
253        public void rename(String filePath, String oldFileName, String newFileName, final boolean useBackup,
254                        HttpSession hsession) {
255                String newFilePath = filePath + newFileName;
256                String oldFilePath = filePath + oldFileName;
257
258                // 変更先のファイルが存在した場合の処理
259                if (exists(newFilePath, hsession)) {
260                        // バックアップ作成する場合
261                        if (useBackup) {
262                                // バックアップファイル名は、元のファイル名(拡張子含む) + "_" + 現在時刻のlong値 + "." +
263                                // 元のファイルの拡張子
264                                String bkupPath = filePath + "_backup/" + newFileName + "_" + System.currentTimeMillis()
265                                                + FileUtil.EXTENSION_SEPARATOR + FileUtil.getExtension(newFileName);
266                                // バックアップフォルダに移動
267                                copy(newFilePath, bkupPath, hsession);
268                        }
269                }
270
271                // コピー
272                copy(oldFilePath, newFilePath, hsession);
273                // 削除
274                delete(oldFilePath, hsession);
275        }
276
277        /**
278         * ファイル存在チェック
279         *
280         * @param filePath                      ファイルパス
281         * @param hsession              セッション
282         * @return                              true:存在 false:存在しない
283         */
284//      @Override
285        public boolean exists(String filePath, HttpSession hsession) {
286                boolean blnRtn = true;
287                try {
288                        if (!client.doesObjectExist(s3bucket, filePath)) {
289                                // ファイルが取得できなかった場合は、falseを設定
290                                blnRtn = false;
291                        }
292                } catch (Exception e) {
293                        StringBuilder sbErrMsg = new StringBuilder();
294                        sbErrMsg.append("ストレージのファイル取得に失敗しました。filePath:");
295                        sbErrMsg.append(filePath);
296                        sbErrMsg.append(" errInfo:");
297                        sbErrMsg.append(e);
298                        throw new HybsSystemException(sbErrMsg.toString());
299                }
300
301                return blnRtn;
302        }
303
304        /**
305         * ファイル一覧取得
306         *
307         * @param startsWith    パスの前方一致
308         * @param hsession              セッション
309         * @return                              ファイルパス一覧
310         */
311        @Override
312        public String[] list(String startsWith, HttpSession hsession) {
313                // 認証
314                List<String> rtnList = new ArrayList<String>();
315                try{
316                        ListObjectsV2Request request = new ListObjectsV2Request()
317                                        .withBucketName(s3bucket)
318                                        .withPrefix(startsWith);
319                        ListObjectsV2Result list = client.listObjectsV2(request);
320                        List<S3ObjectSummary> objects =  list.getObjectSummaries();
321                        // 一覧の取得
322                        for(S3ObjectSummary obj: objects){
323                                // 名称を格納
324                                rtnList.add(obj.getKey());
325                        }
326                } catch (Exception e){
327                        StringBuilder sbErrMsg = new StringBuilder();
328                        sbErrMsg.append("ファイル一覧の取得に失敗しました。startsWith:");
329                        sbErrMsg.append(startsWith);
330                        sbErrMsg.append(" errInfo:");
331                        sbErrMsg.append("e");
332                        throw new HybsSystemException(sbErrMsg.toString());
333                }
334                return rtnList.toArray(new String[rtnList.size()]);
335        }
336
337        /**
338         * ファイル情報取得
339         *
340         * @param path                  ファイルパス
341         * @param hsession              セッション
342         * @return                              ファイル情報格納Map
343         */
344//      @Override
345        public Map<String, String> getInfo(String path, HttpSession hsession) {
346                Map<String, String> rtnMap = new HashMap<String,String>();
347
348                ObjectMetadata meta = null;
349                try{
350                        // ファイルオブジェクトの取得
351                        meta = client.getObjectMetadata(s3bucket, path);
352                }catch(Exception e){
353                        StringBuilder sbErrMsg = new StringBuilder();
354                        sbErrMsg.append("ファイルの取得に失敗しました。path:");
355                        sbErrMsg.append(path);
356                        sbErrMsg.append(" errInfo:");
357                        sbErrMsg.append(e);
358                        throw new HybsSystemException(sbErrMsg.toString());
359                }
360                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
361
362                // ファイルサイズ
363                rtnMap.put(FILEINFO_SIZE, String.valueOf(meta.getContentLength()));
364                // 最終更新時刻
365                rtnMap.put(FILEINFO_LASTMODIFIED, sdf.format(meta.getLastModified()));
366
367                return rtnMap;
368        }
369}