001package org.opengion.plugin.cloud; 002 003import java.io.ByteArrayInputStream; 004import java.io.File; 005import java.io.FileFilter; 006import java.io.FileNotFoundException; 007import java.io.IOException; 008import java.io.InputStream; 009import java.util.ArrayList; 010import java.util.List; 011 012import org.apache.commons.lang3.StringUtils; 013import org.opengion.fukurou.model.CloudFileOperation; 014import org.opengion.fukurou.model.FileOperation; 015import org.opengion.fukurou.model.FileOperationInfo; 016import org.opengion.fukurou.system.Closer; // 8.0.0.0 (2021/09/30) util.Closer → system.Closer 017import org.opengion.fukurou.util.StringUtil; 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020 021import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // HybsSystem.BUFFER_MIDDLE は fukurou に移動 022 023import com.amazonaws.auth.AWSCredentials; 024import com.amazonaws.auth.AWSStaticCredentialsProvider; 025import com.amazonaws.auth.BasicAWSCredentials; 026import com.amazonaws.auth.InstanceProfileCredentialsProvider; 027import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; 028import com.amazonaws.services.s3.AmazonS3; 029import com.amazonaws.services.s3.AmazonS3ClientBuilder; 030import com.amazonaws.services.s3.model.AmazonS3Exception; 031import com.amazonaws.services.s3.model.ListObjectsV2Request; 032import com.amazonaws.services.s3.model.ListObjectsV2Result; 033import com.amazonaws.services.s3.model.ObjectListing; 034import com.amazonaws.services.s3.model.ObjectMetadata; 035import com.amazonaws.services.s3.model.PutObjectRequest; 036import com.amazonaws.services.s3.model.S3Object; 037import com.amazonaws.services.s3.model.S3ObjectSummary; 038 039/** 040 * FileOperation_AWSは、S3ストレージに対して、 041 * ファイル操作を行うクラスです。 042 * 043 * 認証は下記の2通りが可能です。 044 * ・実行サーバのEC2のインスタンスに、S3ストレージのアクセス許可を付与する 045 * ・システムリソースにアクセスキー・シークレットキー・エンドポイント・レギオンを登録する 046 * (CLOUD_STORAGE_S3_ACCESS_KEY、CLOUD_STORAGE_S3_SECRET_KEY、CLOUD_STORAGE_S3_SERVICE_END_POINT、CLOUD_STORAGE_S3_REGION) 047 * 048 * 注意: 049 * バケット名は全ユーザで共有のため、自身のバケット名か、作成されていないバケット名を指定する必要があります。 050 * 051 * @og.rev 5.10.8.0 (2019/02/01) 新規作成 052 * 053 * @version 5 054 * @author oota 055 * @since JDK7.0 056 */ 057public class FileOperation_AWS extends CloudFileOperation { 058 private static final long serialVersionUID = 5108020190201L ; 059 060 /** クラス変数 */ 061 private final AmazonS3 amazonS3; 062 private final String PLUGIN = "aws"; 063 064 /** 065 * コンストラクター 066 * 067 * 初期化処理です。 068 * AWSの認証処理を行います。 069 * 070 * @param bucket バケット 071 * @param inPath パス 072 */ 073 public FileOperation_AWS(final String bucket, final String inPath) { 074 super(StringUtil.nval(bucket, HybsSystem.sys("CLOUD_BUCKET")), inPath); 075 setPlugin(PLUGIN); 076 077 // アクセスキー 078 final String s3AccessKey = HybsSystem.sys("CLOUD_STORAGE_S3_ACCESS_KEY"); 079 String s3SecretKey = ""; 080 String s3ServiceEndPoint = ""; 081 String s3Region = ""; 082 083 // S3アクセスクライアントの生成 084 if (StringUtils.isEmpty(s3AccessKey)) { 085 // IAMロールによる認証 086 amazonS3 = AmazonS3ClientBuilder.standard() 087 .withCredentials(new InstanceProfileCredentialsProvider(false)) 088 .build(); 089 } else { 090 // リソースのアクセスキーによる認証 091 // シークレットキー 092 s3SecretKey = HybsSystem.sys("CLOUD_STORAGE_S3_SECRET_KEY"); 093 // エンドポイント 094 s3ServiceEndPoint = HybsSystem.sys("CLOUD_STORAGE_S3_SERVICE_END_POINT"); 095 // レギオン 096 s3Region = HybsSystem.sys("CLOUD_STORAGE_S3_REGION"); 097 098 // AWSの認証情報 099 AWSCredentials credentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey); 100 101 // エンドポイント設定 102 EndpointConfiguration endpointConfiguration = new EndpointConfiguration(s3ServiceEndPoint, s3Region); 103 amazonS3 = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) 104 .withEndpointConfiguration(endpointConfiguration) 105 .build(); 106 } 107 108 try { 109 // S3に指定されたバケット(コンテナ)が存在しない場合は、作成する 110 if (!amazonS3.doesBucketExistV2(conBucket)) { // doesBucketExistV2最新JARだと出ている 111 amazonS3.createBucket(conBucket); 112 } 113 } catch (AmazonS3Exception ase) { 114 StringBuilder errMsg = new StringBuilder(BUFFER_MIDDLE); 115 if (StringUtils.isEmpty(s3AccessKey)) { 116 errMsg.append("IAMロールによる認証が失敗しました。"); 117 118 } else { 119 errMsg.append("アクセスキーによる認証が失敗しました。"); 120 errMsg.append(" CLOUD_STORAGE_S3_ACCESS_KEY:").append(s3AccessKey); 121 errMsg.append(" CLOUD_STORAGE_S3_SECRET_KEY:非表示"); 122 errMsg.append(" CLOUD_STORAGE_S3_SERVICE_END_POINT:").append(s3ServiceEndPoint); 123 errMsg.append(" CLOUD_STORAGE_S3_REGION:").append(s3Region); 124 } 125 errMsg.append(" システムエラー情報:").append(ase.getMessage()); 126 throw new HybsSystemException(errMsg.toString()); 127 } 128 } 129 130 /** 131 * 書き込み処理 132 * 133 * InputStreamのデータを書き込みます。 134 * 135 * @param is 書き込みデータのInputStream 136 * @throws IOException ファイル関連エラー情報 137 */ 138 @Override 139 public void write(final InputStream is) throws IOException { 140 ByteArrayInputStream bais = null; 141 try { 142 ObjectMetadata om = new ObjectMetadata(); 143 144 byte[] bytes = toByteArray(is); 145 om.setContentLength(bytes.length); 146 bais = new ByteArrayInputStream(bytes); 147 148 PutObjectRequest request = new PutObjectRequest(conBucket, conPath, bais, om); 149 150 amazonS3.putObject(request); 151 } catch (Exception e) { 152 StringBuilder errMsg = new StringBuilder(BUFFER_MIDDLE); 153 errMsg.append("AWSバケットに書き込みが失敗しました。path:").append(conPath); 154 errMsg.append(" システムエラー情報:").append(e.getMessage()); 155 throw new IOException(errMsg.toString()); 156 } finally { 157 Closer.ioClose(bais); 158 } 159 } 160 161 /** 162 * 読み込み処理 163 * 164 * データを読み込み、InputStreamとして、返します。 165 * 166 * @return 読み込みデータのInputStream 167 * @throws FileNotFoundException ファイル非存在エラー情報 168 */ 169 @Override 170 public InputStream read() throws FileNotFoundException { 171 S3Object object = null; 172 173 try { 174 object = amazonS3.getObject(conBucket, conPath); 175 } catch (Exception e) { 176 StringBuilder errMsg = new StringBuilder(BUFFER_MIDDLE); 177 errMsg.append("AWSバケットから読み込みが失敗しました。path:").append(conPath); 178 errMsg.append(" システムエラー情報:").append(e.getMessage()); 179 throw new FileNotFoundException(errMsg.toString()); 180 } 181 return object.getObjectContent(); 182 } 183 184 /** 185 * 削除処理 186 * 187 * ファイルを削除します。 188 * 189 * @return 成否フラグ 190 */ 191 @Override 192 public boolean delete() { 193 boolean flgRtn = false; 194 195 try { 196 if (isFile()) { 197 // ファイル削除 198 amazonS3.deleteObject(conBucket, conPath); 199 } else if (isDirectory()) { 200 // ディレクトリ削除 201 // 一括削除のapiが無いので、繰り返しで削除を行う 202 ObjectListing objectList = amazonS3.listObjects(conBucket, conPath); 203 List<S3ObjectSummary> list = objectList.getObjectSummaries(); 204 for (S3ObjectSummary obj : list) { 205 amazonS3.deleteObject(conBucket, obj.getKey()); 206 } 207 208 } 209 flgRtn = true; 210 } catch (Exception e) { 211 // エラーはスルーして、falseを返す 212 } 213 214 return flgRtn; 215 } 216 217 /** 218 * コピー処理 219 * 220 * ファイルを指定先に、コピーします。 221 * 222 * @param afPath コピー先 223 * @return 成否フラグ 224 */ 225 @Override 226 public boolean copy(final String afPath) { 227 boolean flgRtn = false; 228 229 try { 230 amazonS3.copyObject(conBucket, conPath, conBucket, afPath); 231 flgRtn = true; 232 } catch (Exception e) { 233 // エラーはスルーして、falseを返す 234 } 235 236 return flgRtn; 237 } 238 239 /** 240 * ファイルサイズ取得 241 * 242 * ファイルサイズを返します。 243 * 244 * @return ファイルサイズ 245 */ 246 @Override 247 public long length() { 248 long rtn = 0; 249 250 try { 251 ObjectMetadata meta = amazonS3.getObjectMetadata(conBucket, conPath); 252 rtn = meta.getContentLength(); 253 } catch (Exception e) { 254 // エラーはスルーして、0を返す。 255 } 256 return rtn; 257 } 258 259 /** 260 * 最終更新時刻取得 261 * 262 * 最終更新時刻を取得します。 263 * 264 * @return 最終更新時刻 265 */ 266 @Override 267 public long lastModified() { 268 long rtn = 0; 269 270 try { 271 ObjectMetadata meta = amazonS3.getObjectMetadata(conBucket, conPath); 272 rtn = meta.getLastModified().getTime(); 273 } catch (Exception e) { 274 // エラーはスルーして、0を返す 275 } 276 return rtn; 277 } 278 279 /** 280 * ファイル判定 281 * 282 * ファイルの場合は、trueを返します。 283 * 284 * @return ファイル判定フラグ 285 */ 286 @Override 287 public boolean isFile() { 288 boolean rtn = false; 289 290 if(!isDirectory()) { 291 rtn = amazonS3.doesObjectExist(conBucket, conPath); 292 } 293 294 return rtn; 295 } 296 297 /** 298 * ディレクトリ判定 299 * 300 * ディレクトリの場合は、trueを返します。 301 * 302 * @return ディレクトリ判定フラグ 303 */ 304 @Override 305 public boolean isDirectory() { 306 boolean flgRtn = false; 307 308 if (StringUtils.isEmpty(conPath)) { 309 return true; 310 } 311 312 // S3にはディレクトリの概念はないので、「/」で続くデータが存在するかで、判定 313 ObjectListing objectList = amazonS3.listObjects(conBucket, setDirTail(conPath)); 314 List<S3ObjectSummary> list = objectList.getObjectSummaries(); 315 flgRtn = list.size() == 0 ? false : true; 316 317 return flgRtn; 318 } 319 320 /** 321 * ファイル一覧取得 322 * 323 * パスのファイルとディレクトリ一覧を取得します。 324 * 325 * @param filter フィルタ情報 326 * @return ファイルとティレクトリ一覧 327 */ 328 @Override 329 public File[] listFiles(final FileFilter filter) { 330 if (!exists()) { 331 return new FileOperationInfo[0]; 332 } 333 334 String search = conPath; 335 if (isDirectory()) { 336 search = setDirTail(conPath); 337 } 338 339 List<File> rtnList = new ArrayList<File>(); 340 341 // 検索処理 342 ListObjectsV2Request request = new ListObjectsV2Request() 343 .withBucketName(conBucket) 344 .withPrefix(search) 345 .withDelimiter("/"); 346 ListObjectsV2Result list = amazonS3.listObjectsV2(request); 347 List<S3ObjectSummary> objects = list.getObjectSummaries(); 348 349 // ファイル情報の取得 350 for (S3ObjectSummary obj : objects) { 351 String key = obj.getKey(); 352 353 FileOperationInfo file = new FileOperationInfo(PLUGIN, conBucket, key); 354 file.setLastModifiedValue(obj.getLastModified().getTime()); 355 file.setFile(true); 356 file.setSize(obj.getSize()); 357 rtnList.add(file); 358 } 359 360 // ディレクトリ情報の取得 361 List<String> folders = list.getCommonPrefixes(); 362 for (String str : folders) { 363 String key = rTrim(str, '/'); 364 365 FileOperationInfo file = new FileOperationInfo(PLUGIN, conBucket, key); 366 file.setDirectory(true); 367 rtnList.add(file); 368 } 369 370 // フィルタ処理 371 File[] filterList = filter(rtnList, filter); 372 373 return filterList; 374 } 375 376 /** 377 * 親ディレクトリ情報の取得 378 * 379 * 親のディレクトリを返します。 380 * 381 * @return 親のディレクトリ情報 382 */ 383 @Override 384 public FileOperation getParentFile() { 385 return new FileOperation_AWS(conBucket, this.getParent()); 386 } 387 388 /** 以下はローカル環境でのテスト用メソッドです。 */ 389// /** 390// * ローカルでのテスト用コンストラクタ 391// * 392// * 要:super.bucketの値は固定値に変更してください。 393// * 394// * @param inPath 395// */ 396// public FileOperation_AWS(String bucket, String inPath, boolean test) { 397// // super( StringUtil.nval( bucket, HybsSystem.sys("CLOUD_BUCKET") ), inPath); 398// super( StringUtil.nval( bucket, "opengiontestbucket" ), inPath); 399// 400// // aws接続情報 401// String s3AccessKey = "[key]"; 402// String s3SecretKey = "[secret]"; 403// String s3ServiceEndPoint = "s3-ap-northeast-1.amazonaws.com"; 404// String s3Region = "ap-northeast-1"; 405// 406// // proxy環境での設定 407// ClientConfiguration conf = new ClientConfiguration(); 408// conf.setProtocol(Protocol.HTTPS); 409// conf.setProxyHost("mtc-px14"); 410// conf.setProxyPort(8081); 411// 412// // AWSの認証情報 413// AWSCredentials credentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey); 414// 415// // エンドポイント設定 416// EndpointConfiguration endpointConfiguration = new EndpointConfiguration(s3ServiceEndPoint, s3Region); 417// amazonS3 = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) 418// .withEndpointConfiguration(endpointConfiguration) 419// .withClientConfiguration(conf) // テスト用にproxy設定 420// .build(); 421// 422// try { 423// // S3に指定されたバケット(コンテナ)が存在しない場合は、作成する 424// if (!amazonS3.doesBucketExistV2(conBucket)) { 425// amazonS3.createBucket(conBucket); 426// } 427// } catch (AmazonS3Exception ase) { 428// StringBuilder errMsg = new StringBuilder(BUFFER_MIDDLE); 429// if (StringUtils.isEmpty(s3AccessKey)) { 430// errMsg.append("IAMロールによる認証か、バケットの作成が失敗しました。"); 431// 432// } else { 433// errMsg.append("アクセスキーによる認証かバケットの作成が失敗しました。"); 434// errMsg.append(" CLOUD_STORAGE_S3_ACCESS_KEY:").append(s3AccessKey); 435// errMsg.append(" CLOUD_STORAGE_S3_SECRET_KEY:非表示"); 436// errMsg.append(" CLOUD_STORAGE_S3_SERVICE_END_POINT:").append(s3ServiceEndPoint); 437// errMsg.append(" CLOUD_STORAGE_S3_REGION:").append(s3Region); 438// } 439// errMsg.append(" バケット名:").append(conBucket); 440// errMsg.append(" システムエラー情報:").append(ase.getMessage()); 441// throw new RuntimeException(errMsg.toString()); 442// } 443// } 444// 445// /** テスト用メソッド */ 446// public static void main(String[] args) { 447//// writeTest(); 448//// listTest(); 449//// methodTest(); 450// copyTest(); 451// } 452// 453// public static void copyTest() { 454// File[] list = new File[] {new File("LIST01.xls"), new File("LIST02.ods")}; 455// 456//// System.out.println(file.exists()); 457// 458// for(File file: list) { 459// FileOperation file2 = new FileOperation_AWS("ootalocaltest", file.getName(), true); 460// FileUtil.copy(file, file2); 461// } 462// } 463// 464// public static void writeTest() { 465// FileOperation file = new FileOperation_AWS("otlocaltest01", "sample/test.txt", true); 466// try(InputStream is = new ByteArrayInputStream("sample".getBytes())){ 467// file.write(is); 468// }catch(Exception e) { 469// System.out.println(e.getMessage()); 470// } 471// 472//// File file 473// } 474// 475// public static void listTest() { 476// File file = new FileOperation_AWS("otlocaltest01", "sample", true); 477// 478// // フィルタ設定 479// HybsFileFilter filter = new HybsFileFilter(); 480// filter.startsWith("te"); 481// 482// File[] list = file.listFiles(filter); 483// 484// System.out.println(list.length); 485// for(File f: list) { 486// FileOperation fo = (FileOperation)f; 487// 488// try(InputStream is = fo.read()){ 489// Files.copy(is, Paths.get("out.txt"), StandardCopyOption.REPLACE_EXISTING); 490// }catch(IOException ioe) { 491// System.out.println(ioe); 492// } 493// } 494// } 495// 496// public static void methodTest() { 497// FileOperation file = new FileOperation_AWS("otlocaltest01", "", true); 498// boolean rtn = false; 499//// rtn = file.isDirectory(); 500// rtn = file.isFile(); 501// 502// System.out.println(rtn); 503// } 504}