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