    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.ibm.cloud.objectstorage.SDKGlobalConfiguration;
    022import com.ibm.cloud.objectstorage.auth.AWSCredentials;
    023import com.ibm.cloud.objectstorage.auth.AWSStaticCredentialsProvider;
    024import com.ibm.cloud.objectstorage.client.builder.AwsClientBuilder.EndpointConfiguration;
    025import com.ibm.cloud.objectstorage.oauth.BasicIBMOAuthCredentials;
    026import com.ibm.cloud.objectstorage.services.s3.AmazonS3;
    027import com.ibm.cloud.objectstorage.services.s3.AmazonS3ClientBuilder;
    028import com.ibm.cloud.objectstorage.services.s3.model.AmazonS3Exception;
    029import com.ibm.cloud.objectstorage.services.s3.model.ListObjectsV2Request;
    030import com.ibm.cloud.objectstorage.services.s3.model.ListObjectsV2Result;
    031import com.ibm.cloud.objectstorage.services.s3.model.ObjectListing;
    032import com.ibm.cloud.objectstorage.services.s3.model.ObjectMetadata;
    033import com.ibm.cloud.objectstorage.services.s3.model.PutObjectRequest;
    034import com.ibm.cloud.objectstorage.services.s3.model.S3Object;
    035import com.ibm.cloud.objectstorage.services.s3.model.S3ObjectSummary;
    036
    037/**
    038 * FileOperation_IBM.javaは、Bluemixのストレージ(S3と互換性があります)の、
    039 * ファイル操作を行うクラスです。
    040 *
    041 * IBMCloud(Bluemix)のダッシュボードから、下記の値を取得して、
    042 * システムリソースに登録を行う必要があります。
    043 *
    044 * CLOUD_STORAGE_S3_APIKEY、CLOUD_STORAGE_S3_SERVICEINSTANCEID、CLOUD_STORAGE_S3_SERVICE_END_POINT、CLOUD_STORAGE_S3_REGION
    045 *
    046 * @og.rev 5.10.8.0 (2019/02/01) 新規作成
    047 *
    048 * @version 5.0
    049 * @author  oota
    050 * @since   JDK7.0
    051 *
    052 */
    053public class FileOperation_IBM extends CloudFileOperation {
    054        private static final long serialVersionUID = 5108020190201L;
    055        /** クラス変数 */
    056        private final AmazonS3 amazonS3;
    057        private static final String COS_AUTH_ENDPOINT = "https://iam.ng.bluemix.net/oidc/token";
    058        private final String PLUGIN = "ibm";
    059
    060        /**
    061         * コンストラクター
    062         *
    063         * 初期化処理です。
    064         * IBM(Bluemix)の認証処理を行います。
    065         *
    066         * @param bucket バケット
    067         * @param inPath パス
    068         */
    069        public FileOperation_IBM(final String bucket, final String inPath) {
    070                super(StringUtil.nval( bucket, HybsSystem.sys("CLOUD_BUCKET") ),inPath);
    071                setPlugin(PLUGIN);
    072
    073                // 公式のマニュアルにより、下記のENDPOINTを設定
    074                SDKGlobalConfiguration.IAM_ENDPOINT = COS_AUTH_ENDPOINT;
    075
    076                final String apiKey = HybsSystem.sys("CLOUD_STORAGE_IBMS3_APIKEY");
    077                final String serviceInstanceId = HybsSystem.sys("CLOUD_STORAGE_IBMS3_SERVICEINSTANCEID");
    078                AWSCredentials credentials = new BasicIBMOAuthCredentials(apiKey, serviceInstanceId);
    079
    080                final String serviceEndpoint = HybsSystem.sys("CLOUD_STORAGE_IBMS3_SERVICE_END_POINT");
    081                final String signingRegion = HybsSystem.sys("CLOUD_STORAGE_IBMS3_REGION");
    082                EndpointConfiguration endpointConfiguration = new EndpointConfiguration(serviceEndpoint, signingRegion);
    083
    084                amazonS3 = AmazonS3ClientBuilder.standard()
    085                                .withCredentials(new AWSStaticCredentialsProvider(credentials))
    086                                .withPathStyleAccessEnabled(true)
    087                                .withEndpointConfiguration(endpointConfiguration)
    088                                .build();
    089
    090                try {
    091                        if (!amazonS3.doesBucketExist(conBucket)) {
    092                                amazonS3.createBucket(conBucket);
    093                        }
    094                } catch (AmazonS3Exception ase) {
    095                        StringBuilder errMsg = new StringBuilder(HybsSystem.BUFFER_MIDDLE);
    096                        errMsg.append("アクセスキーによる認証が失敗しました。");
    097                        errMsg.append(" CLOUD_STORAGE_IBMS3_APIKEY：").append(apiKey);
    098                        errMsg.append(" CLOUD_STORAGE_IBMS3_SERVICEINSTANCEID：").append(serviceInstanceId);
    099                        errMsg.append(" CLOUD_STORAGE_IBMS3_SERVICE_END_POINT：").append(serviceEndpoint);
    100                        errMsg.append(" CLOUD_STORAGE_IBMS3_REGION：").append(signingRegion);
    101                        errMsg.append(" システムエラー情報：").append(ase.getMessage());
    102                        throw new HybsSystemException(errMsg.toString());
    103                }
    104        }
    105
    106        /**
    107         * 書き込み処理
    108         *
    109         * InputStreamのデータを書き込みます。
    110         *
    111         * @param is 書き込みデータのInputStream
    112         * @throws IOException ファイル関連エラ情報
    113         */
    114        @Override
    115        public void write(final InputStream is) throws IOException {
    116                ByteArrayInputStream bais = null;
    117                try {
    118                        ObjectMetadata om = new ObjectMetadata();
    119
    120                        byte[] bytes = toByteArray(is);
    121                        om.setContentLength(bytes.length);
    122                        bais = new ByteArrayInputStream(bytes);
    123
    124                        PutObjectRequest request = new PutObjectRequest(conBucket, conPath, bais, om);
    125
    126                        amazonS3.putObject(request);
    127                } catch (Exception e) {
    128                        StringBuilder errMsg = new StringBuilder(HybsSystem.BUFFER_MIDDLE);
    129                        errMsg.append("BLUEMIXバケットに書き込みが失敗しました。path：").append(conPath);
    130                        errMsg.append(" システムエラー情報：").append(e.getMessage());
    131                        throw new IOException(errMsg.toString());
    132                } finally {
    133                        Closer.ioClose(bais);
    134                }
    135        }
    136
    137        /**
    138         * 読み込み処理
    139         *
    140         * データを読み込み、InputStreamとして、返します。
    141         *
    142         * @return 読み込みデータのInputStream
    143         * @throws FileNotFoundException ファイル非存在エラー情報
    144         */
    145        @Override
    146        public InputStream read() throws FileNotFoundException {
    147                S3Object object = null;
    148
    149                try {
    150                        object = amazonS3.getObject(conBucket, conPath);
    151                } catch (Exception e) {
    152                        StringBuilder errMsg = new StringBuilder(HybsSystem.BUFFER_MIDDLE);
    153                        errMsg.append("BLUEMIXバケットから読み込みが失敗しました。path：").append(conPath);
    154                        errMsg.append(" システムエラー情報：").append(e.getMessage());
    155                        throw new FileNotFoundException(errMsg.toString());
    156                }
    157                return object.getObjectContent();
    158        }
    159
    160        /**
    161         * 削除処理
    162         *
    163         * ファイルを削除します。
    164         *
    165         * @return 成否フラグ
    166         */
    167        @Override
    168        public boolean delete() {
    169                boolean flgRtn = false;
    170
    171                try {
    172                        if (isFile()) {
    173                                // ファイル削除
    174                                amazonS3.deleteObject(conBucket, conPath);
    175                        } else if (isDirectory()) {
    176                                // ディレクトリ削除
    177                                // 一括削除のapiが無いので、繰り返しで削除を行う
    178                                ObjectListing objectList = amazonS3.listObjects(conBucket, conPath);
    179                                List<S3ObjectSummary> list = objectList.getObjectSummaries();
    180                                for (S3ObjectSummary obj : list) {
    181                                        amazonS3.deleteObject(conBucket, obj.getKey());
    182                                }
    183
    184                        }
    185                        flgRtn = true;
    186                } catch (Exception e) {
    187                        // エラーはスルーして、falseを返す
    188                }
    189
    190                return flgRtn;
    191        }
    192
    193        /**
    194         * コピー処理
    195         *
    196         * ファイルを指定先に、コピーします。
    197         *
    198         * @param afPath コピー先
    199         * @return 成否フラグ
    200         */
    201        @Override
    202        public boolean copy(final String afPath) {
    203                boolean flgRtn = false;
    204
    205                try {
    206                        amazonS3.copyObject(conBucket, conPath, conBucket, afPath);
    207                        flgRtn = true;
    208                } catch (Exception e) {
    209                        // エラーはスルーして、falseを返す
    210                }
    211
    212                return flgRtn;
    213        }
    214
    215        /**
    216         * ファイルサイズ取得
    217         *
    218         * ファイルサイズを返します。
    219         *
    220         * @return ファイルサイズ
    221         */
    222        @Override
    223        public long length() {
    224                long rtn = 0;
    225
    226                try {
    227                        ObjectMetadata meta = amazonS3.getObjectMetadata(conBucket, conPath);
    228                        rtn = meta.getContentLength();
    229                } catch (Exception e) {
    230                        // エラーはスルーして、0を返す。
    231                }
    232                return rtn;
    233        }
    234
    235        /**
    236         * 最終更新時刻取得
    237         *
    238         * 最終更新時刻を取得します。
    239         *
    240         * @return 最終更新時刻
    241         */
    242        @Override
    243        public long lastModified() {
    244                long rtn = 0;
    245
    246                try {
    247                        ObjectMetadata meta = amazonS3.getObjectMetadata(conBucket, conPath);
    248                        rtn = meta.getLastModified().getTime();
    249                } catch (Exception e) {
    250                        // エラーはスルーして、0を返す
    251                }
    252                return rtn;
    253        }
    254
    255        /**
    256         * ファイル判定
    257         *
    258         * ファイルの場合は、trueを返します。
    259         *
    260         * @return ファイルフラグ
    261         */
    262        @Override
    263        public boolean isFile() {
    264                boolean rtn = false;
    265
    266                if(!isDirectory()) {
    267                        rtn = amazonS3.doesObjectExist(conBucket, conPath);
    268                }
    269
    270                return rtn;
    271        }
    272
    273        /**
    274         * ディレクトリ判定
    275         *
    276         * ディレクトリの場合は、trueを返します。
    277         *
    278         * @return ディレクトリフラグ
    279         */
    280        @Override
    281        public boolean isDirectory() {
    282                boolean flgRtn = false;
    283
    284                if (StringUtils.isEmpty(conPath)) {
    285                        return true;
    286                }
    287
    288                // S3にはディレクトリの概念はないので、「/」で続くデータが存在するかで、判定
    289                ObjectListing objectList = amazonS3.listObjects(conBucket, setDirTail(conPath));
    290                List<S3ObjectSummary> list = objectList.getObjectSummaries();
    291                flgRtn = list.size() == 0 ? false : true;
    292
    293                return flgRtn;
    294        }
    295
    296        /**
    297         * ファイル一覧取得
    298         *
    299         * パスのファイルとディレクトリ一覧を取得します。
    300         *
    301         * @param filter フィルタ情報
    302         * @return ファイルとティレクトリ一覧
    303         */
    304        @Override
    305        public File[] listFiles(final FileFilter filter) {
    306                if (!exists()) {
    307                        return new FileOperationInfo[0];
    308                }
    309
    310                String search = conPath;
    311                if (isDirectory()) {
    312                        search = setDirTail(conPath);
    313                }
    314
    315                List<File> rtnList = new ArrayList<File>();
    316
    317                // 検索処理
    318                ListObjectsV2Request request = new ListObjectsV2Request()
    319                                .withBucketName(conBucket)
    320                                .withPrefix(search)
    321                                .withDelimiter("/");
    322                ListObjectsV2Result list = amazonS3.listObjectsV2(request);
    323                List<S3ObjectSummary> objects = list.getObjectSummaries();
    324
    325                // ファイル情報の取得
    326                for (S3ObjectSummary obj : objects) {
    327                        String key = obj.getKey();
    328
    329                        FileOperationInfo file = new FileOperationInfo(PLUGIN, conBucket, key);
    330                        file.setLastModified(obj.getLastModified().getTime());
    331                        file.setFile(true);
    332                        file.setSize(obj.getSize());
    333                        rtnList.add(file);
    334                }
    335
    336                // サブディレクトリ情報の取得
    337                List<String> folders = list.getCommonPrefixes();
    338                for (String str : folders) {
    339                        String key = rTrim(str, '/');
    340
    341                        FileOperationInfo file = new FileOperationInfo(PLUGIN, conBucket, key);
    342                        file.setDirectory(true);
    343                        rtnList.add(file);
    344                }
    345
    346                // フィルタ処理
    347                File[] filterList = filter(rtnList, filter);
    348
    349                return filterList;
    350        }
    351
    352        /**
    353         * 親ディレクトリ取得
    354         *
    355         * 親のディレクトリを返します。
    356         *
    357         * @return 親のディレクトリ
    358         */
    359        @Override
    360        public FileOperation getParentFile() {
    361                return new FileOperation_IBM(conBucket,getParent());
    362        }
    363
    364        /** Bluemixの場合はローカル環境でのテストは出来ないようです。(proxyを設定しても接続できません) */
    365}