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