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