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