    001package org.opengion.plugin.cloud;
    002
    003        // import java.io.IOException;
    004        // import java.text.SimpleDateFormat;
    005        // import java.util.Iterator;
    006import java.io.InputStream;
    007import java.util.ArrayList;
    008import java.util.HashMap;
    009import java.util.List;
    010import java.util.Map;
    011
    012import javax.servlet.http.HttpSession;
    013
    014import org.opengion.hayabusa.io.StorageAPI;
    015        // import org.opengion.fukurou.system.Closer;
    016        // import org.opengion.fukurou.util.FileUtil;
    017        // import org.opengion.hayabusa.common.HybsSystemException;
    018        // 5.9.25.0 (2017/10/06) とりあえず、拡張jar は入れていません。
    019        // import org.openstack4j.api.OSClient.OSClientV3;
    020        // import org.openstack4j.api.storage.ObjectStorageService;
    021        // import org.openstack4j.model.common.DLPayload;
    022        // import org.openstack4j.model.common.Identifier;
    023        // import org.openstack4j.model.common.Payload;
    024        // import org.openstack4j.model.storage.object.SwiftObject;
    025        // import org.openstack4j.model.storage.object.options.ObjectListOptions;
    026        // import org.openstack4j.model.storage.object.options.ObjectLocation;
    027        // import org.openstack4j.openstack.OSFactory;
    028        // import org.openstack4j.openstack.internal.OSClientSession;
    029
    030        // import com.fasterxml.jackson.databind.JsonNode;
    031        // import com.fasterxml.jackson.databind.ObjectMapper;
    032
    033/**
    034 * bluemix用のクラウドストレージ操作実装
    035 *
    036 * bluemix上での利用を想定しているため、ユーザ情報は環境変数VCAP_SERVICESから取得可能という前提です。
    037 * この環境変数はbluemix上でオブジェクトストレージを接続設定する事で自動設定されます。
    038 *
    039 * このクラスのコンパイルには
    040 * openstack4j-core及び openstack4j-okhttpが必要です。
    041 * 実行にはそれ以外に以下のモジュールが必要です。（バージョンは作成時のもの）
    042 * btf-1.2.jar ,guava-20.0.jar, jackson-coreutils-1.6.jar, jackson-dataformat-yaml-2.8.8.jar, json-patch-1.9.jar, jsr305-2.0.0.jar
    043 *      ,msg-simple-1.1.jar, okhttp-3.2.0.jar, okio-1.6.0.jar, slf4j-api-1.7.21.jar, slf4j-simple-1.7.21.jar, snakeyaml-1.15.jar
    044 *
    045 *
    046 * @og.group クラウド
    047 * @og.rev 5.9.25.0 (2017/10/06) 新規作成
    048 *
    049 * @version 5.0
    050 * @author T.OTA
    051 * @sinse JDK7.0
    052 */
    053public class StorageAPI_bluemix implements StorageAPI {
    054
    055        //      // クラス変数
    056        //      /** ｺﾝﾃﾅ名 */
    057        //      private final String container ;
    058        //      /* ﾕｰｻﾞ名 */
    059        //      private final String username ;
    060        //      /** ﾊﾟｽﾜｰﾄﾞ */
    061        //      private final String password ;
    062        //      /** ﾄﾞﾒｲﾝID */
    063        //      private final String domainId ;
    064        //      /** ﾌﾟﾛｼﾞｪｸﾄID */
    065        //      private final String projectId ;
    066        //      /** 認証URL */
    067        //      private final String auth_url ;
    068
    069        /**
    070         * ｺﾝｽﾄﾗｸﾀ。
    071         *
    072         * bluemixに設定されているﾕｰｻﾞ情報の取得。
    073         * ｼｽﾃﾑIDを名称としたｺﾝﾃﾅを作成する。
    074         *
    075         * @param container ｺﾝﾃﾅ
    076         * @param hsession ｾｯｼｮﾝ
    077         */
    078        public StorageAPI_bluemix( final String container, final HttpSession hsession) {
    079/***********
    080                // ｸﾗｽ変数に設定
    081                this.container = container;
    082                // CloudFoundryの環境変数から、接続情報を取得します。
    083                String env = System.getenv("VCAP_SERVICES");
    084                ObjectMapper mapper = new ObjectMapper();
    085                try {
    086                        JsonNode node = mapper.readTree(env);
    087                        Iterator<JsonNode> userNode = node.get("Object-Storage").elements();
    088                        JsonNode cred = (JsonNode) userNode.next().get("credentials");
    089
    090                        // ﾕｰｻﾞ名
    091                        username = cred.get("username").textValue();
    092                        // ﾊﾟｽﾜｰﾄﾞ
    093                        password = cred.get("password").textValue();
    094                        // ﾄﾞﾒｲﾝID
    095                        domainId = cred.get("domainId").textValue();
    096                        // ﾌﾟﾛｼﾞｪｸﾄID
    097                        projectId = cred.get("projectId").textValue();
    098                        // 認証url
    099                        auth_url = cred.get("auth_url").textValue() + "/v3";
    100                } catch (Exception e) {
    101                        String errMsg = "VCAP_SERVICESの取得に失敗しました。ストレージと接続されているか確認して下さい。" + e;
    102                        throw new HybsSystemException(errMsg);
    103                }
    104
    105                // コンテナの作成(既に存在する場合は、そのまま通過する)
    106                try{
    107                        ObjectStorageService objectStorage = auth(hsession);
    108                        objectStorage.containers().create(container);
    109                }catch(Exception e){
    110                        StringBuilder sbErrMsg = new StringBuilder();
    111                        sbErrMsg.append("コンテナの作成に失敗しました。container:");
    112                        sbErrMsg.append(container);
    113                        sbErrMsg.append(" errInfo:");
    114                        sbErrMsg.append(e);
    115                        throw new HybsSystemException(sbErrMsg.toString());
    116                }
    117*************/
    118        }
    119
    120        /**
    121         * 認証処理
    122         * @param hsession      ｾｯｼｮﾝ
    123         * @return ObjectStorageService
    124         */
    125/***********
    126        private ObjectStorageService auth(HttpSession hsession) {
    127                OSClientSession<?, ?> session = OSClientSession.getCurrent();
    128                if (session != null) {
    129                        // 既に認証されている場合は、認証情報を返却
    130                        return session.objectStorage();
    131                } else {
    132                        // ｾｯｼｮﾝから認証ﾄｰｸﾝを取得
    133                        String token = (String) hsession.getAttribute(SESSION_CLOUD_TOKEN);
    134                        // 認証ﾄｰｸﾝがある場合は、ﾄｰｸﾝによる認証を行う
    135                        if (token != null && !"".equals(token)) {
    136                                // ﾄｰｸﾝによる認証
    137                                OSClientV3 os = OSFactory.builderV3().endpoint(auth_url).token(token)
    138                                                .scopeToProject(Identifier.byId(projectId))
    139                                                .authenticate();
    140                                return os.objectStorage();
    141                        }
    142                }
    143
    144                // ﾕｰｻﾞによる認証(ｽﾚｯﾄﾞ間はOSClientSessionに保持される)
    145                Identifier domainIdentifier = Identifier.byId(domainId);
    146                OSClientV3 os = OSFactory.builderV3().endpoint(auth_url).credentials(username, password, domainIdentifier)
    147                                .scopeToProject(Identifier.byId(projectId))
    148                                .authenticate();
    149
    150                // 認証ﾄｰｸﾝの保持
    151                hsession.setAttribute(SESSION_CLOUD_TOKEN, os.getToken().getId());
    152
    153                ObjectStorageService objectStorage = os.objectStorage();
    154
    155                return objectStorage;
    156        }
    157*************/
    158
    159        /**
    160         * ｱｯﾌﾟﾛｰﾄﾞ。
    161         *
    162         * @param partInputStream       ｱｯﾌﾟﾛｰﾄﾞ対象のｽﾄﾘｰﾑ
    163         * @param updFolder             ｱｯﾌﾟﾛｰﾄﾞﾌｫﾙﾀ名
    164         * @param updFileName           ｱｯﾌﾟﾛｰﾄﾞﾌｧｲﾙ名
    165         * @param hsession                      ｾｯｼｮﾝ
    166         */
    167        @Override
    168        public void add( final InputStream partInputStream, final String updFolder, final String updFileName, final HttpSession hsession) {
    169/***********
    170                // 認証
    171                ObjectStorageService objectStorage = auth(hsession);
    172                // ｱｯﾌﾟﾛｰﾄﾞｽﾄﾚｰﾑ
    173                Payload<InputStream> payload = new InputPayload<InputStream>(partInputStream);
    174                try {
    175                        // ｱｯﾌﾟﾛｰﾄﾞ処理
    176                        objectStorage.objects().put(this.container, updFolder + updFileName, payload);
    177                } catch (Exception e) {
    178                        StringBuilder sbErrMsg = new StringBuilder();
    179                        sbErrMsg.append("ストレージへのファイルアップロードに失敗しました。updFolder:");
    180                        sbErrMsg.append(updFolder);
    181                        sbErrMsg.append(" updFileName:");
    182                        sbErrMsg.append(updFileName);
    183                        sbErrMsg.append(" errInfo:");
    184                        sbErrMsg.append(e);
    185                        throw new HybsSystemException(sbErrMsg.toString());
    186                } finally {
    187                        // ｸﾛｰｽﾞ処理
    188                        Closer.ioClose(partInputStream);
    189                        Closer.ioClose(payload);
    190                }
    191*************/
    192        }
    193
    194        /**
    195         * ﾀﾞｳﾝﾛｰﾄﾞ。
    196         *
    197         * @param filePath      ﾀﾞｳﾝﾛｰﾄﾞ対象のﾌｧｲﾙﾊﾟｽ
    198         * @param hsession      ｾｯｼｮﾝ
    199         * @return ストリーム
    200         */
    201        @Override
    202        public InputStream get( final String filePath, final HttpSession hsession) {
    203/***********
    204                // 認証
    205                ObjectStorageService objectStorage = auth(hsession);
    206                DLPayload payload = null;
    207                // ﾀﾞｳﾝﾛｰﾄﾞ
    208                try {
    209                        SwiftObject swiftObject = objectStorage.objects().get(ObjectLocation.create(this.container, filePath));
    210                        payload = swiftObject.download();
    211                } catch (Exception e) {
    212                        StringBuilder sbErrMsg = new StringBuilder();
    213                        sbErrMsg.append("ストレージからのファイルダウンロードに失敗しました。filePath:");
    214                        sbErrMsg.append(filePath);
    215                        sbErrMsg.append(" errInfo:");
    216                        sbErrMsg.append(e);
    217                        throw new HybsSystemException(sbErrMsg.toString());
    218                }
    219
    220                return payload.getInputStream();
    221*************/
    222                return null;
    223        }
    224
    225        /**
    226         * ｺﾋﾟｰ。
    227         *
    228         * @param oldFilePath   ｺﾋﾟｰ元ﾌｧｲﾙﾊﾟｽ
    229         * @param newFilePath   ｺﾋﾟｰ先ﾌｧｲﾙﾊﾟｽ
    230         * @param hsession              ｾｯｼｮﾝ
    231         */
    232        @Override
    233        public void copy( final String oldFilePath, final String newFilePath, final HttpSession hsession) {
    234/***********
    235                // ｺﾋﾟｰ処理
    236                Payload<InputStream> payload = null;
    237                InputStream is = null;
    238                try {
    239                        // openstack4jにcopyﾒｿｯﾄﾞは実装されているが、全角文字が利用できないため、
    240                        // ﾀﾞｳﾝﾛｰﾄﾞ・ｱｯﾌﾟﾛｰﾄﾞで対応
    241                        // ｺﾋﾟｰ元情報の取得
    242                        is = get(oldFilePath, hsession);
    243                        // ｺﾋﾟｰ先に登録
    244                        payload = new InputPayload<InputStream>(is);
    245
    246                        // 認証
    247                        ObjectStorageService objectStorage = auth(hsession);
    248                        objectStorage.objects().put(this.container, newFilePath, payload);
    249                } catch (Exception e) {
    250                        StringBuilder sbErrMsg = new StringBuilder();
    251                        sbErrMsg.append("ストレージのファイルコピー処理に失敗しました。oldFilePath:");
    252                        sbErrMsg.append(oldFilePath);
    253                        sbErrMsg.append(" newFilePath:");
    254                        sbErrMsg.append(newFilePath);
    255                        sbErrMsg.append(" errInfo:");
    256                        sbErrMsg.append(e);
    257                        throw new HybsSystemException(sbErrMsg.toString());
    258                }finally{
    259                        // ｸﾛｰｽﾞ処理
    260                        Closer.ioClose(payload);
    261                        Closer.ioClose(is);
    262                }
    263*************/
    264        }
    265
    266        /**
    267         * 削除。
    268         *
    269         * @param filePath      削除ﾌｧｲﾙのﾊﾟｽ
    270         * @param hsession      ｾｯｼｮﾝ
    271         */
    272        @Override
    273        public void delete( final String filePath, final HttpSession hsession) {
    274/***********
    275                // 認証
    276                ObjectStorageService objectStorage = auth(hsession);
    277                // 削除
    278                try {
    279                        objectStorage.objects().delete(ObjectLocation.create(this.container, filePath));
    280                } catch (Exception e) {
    281                        StringBuilder sbErrMsg = new StringBuilder();
    282                        sbErrMsg.append("ストレージのファイル削除に失敗しました。filePath:");
    283                        sbErrMsg.append(filePath);
    284                        sbErrMsg.append(" errInfo:");
    285                        sbErrMsg.append(e);
    286                        throw new HybsSystemException(sbErrMsg.toString());
    287                }
    288*************/
    289        }
    290
    291        /**
    292         * ﾌｧｲﾙ名変更。
    293         *
    294         * @param filePath              ﾌｧｲﾙﾊﾟｽ
    295         * @param oldFileName   変更前ﾌｧｲﾙ名
    296         * @param newFileName   変更後ﾌｧｲﾙ名
    297         * @param useBackup     変更後ﾌｧｲﾙ名が既に存在する場合のﾊﾞｯｸｱｯﾌﾟ作成ﾌﾗｸﾞ
    298         * @param hsession              ｾｯｼｮﾝ
    299         */
    300        public void rename( final String filePath, final String oldFileName, final String newFileName, final boolean useBackup,final HttpSession hsession) {
    301/***********
    302                String newFilePath = filePath + newFileName;
    303                String oldFilePath = filePath + oldFileName;
    304
    305                // 変更先のファイルが存在した場合の処理
    306                if (exists(newFilePath, hsession)) {
    307                        // バックアップ作成する場合
    308                        if (useBackup) {
    309                                // バックアップファイル名は、元のファイル名(拡張子含む) ＋ "_" + 現在時刻のlong値 + "." +
    310                                // 元のファイルの拡張子
    311                                String bkupPath = filePath + "_backup/" + newFileName + "_" + System.currentTimeMillis()
    312                                                + FileUtil.EXTENSION_SEPARATOR + FileUtil.getExtension(newFileName);
    313                                // バックアップフォルダに移動
    314                                copy(newFilePath, bkupPath, hsession);
    315                        }
    316                }
    317
    318                // コピー
    319                copy(oldFilePath, newFilePath, hsession);
    320                // 削除
    321                delete(oldFilePath, hsession);
    322*************/
    323        }
    324
    325        /**
    326         * ﾌｧｲﾙ存在ﾁｪｯｸ。
    327         *
    328         * @param filePath                      ﾌｧｲﾙﾊﾟｽ
    329         * @param hsession              ｾｯｼｮﾝ
    330         * @return                              true:存在 false:存在しない
    331         */
    332        @Override
    333        public boolean exists( final String filePath, final HttpSession hsession) {
    334                boolean blnRtn = true;
    335/***********
    336
    337                // 認証
    338                ObjectStorageService objectStorage = auth(hsession);
    339
    340                try {
    341                        SwiftObject so = objectStorage.objects().get(ObjectLocation.create(this.container, filePath));
    342
    343                        if (so == null) {
    344                                // ﾌｧｲﾙが取得できなかった場合は、falseを設定
    345                                blnRtn = false;
    346                        }
    347                } catch (Exception e) {
    348                        StringBuilder sbErrMsg = new StringBuilder();
    349                        sbErrMsg.append("ストレージのファイル取得に失敗しました。filePath:");
    350                        sbErrMsg.append(filePath);
    351                        sbErrMsg.append(" errInfo:");
    352                        sbErrMsg.append(e);
    353                        throw new HybsSystemException(sbErrMsg.toString());
    354                }
    355
    356*************/
    357                return blnRtn;
    358        }
    359
    360        /**
    361         * ﾌｧｲﾙ一覧取得。
    362         *
    363         * @param startsWith    ﾊﾟｽの前方一致
    364         * @param hsession              ｾｯｼｮﾝ
    365         * @return                              ﾌｧｲﾙﾊﾟｽ一覧
    366         */
    367        @Override
    368        public String[] list( final String startsWith, final HttpSession hsession) {
    369                final List<String> rtnList = new ArrayList<String>();
    370/***********
    371                // 認証
    372                ObjectStorageService objectStorage = auth(hsession);
    373                List<? extends SwiftObject> list = null;
    374                try{
    375                        // ｵﾌﾟｼｮﾝの指定
    376                        ObjectListOptions olo = ObjectListOptions.create().startsWith(startsWith);
    377                        // 一覧の取得
    378                        list = objectStorage.objects().list(this.container, olo);
    379                        for(SwiftObject so: list){
    380                                rtnList.add(so.getName());
    381                        }
    382                } catch (Exception e){
    383                        StringBuilder sbErrMsg = new StringBuilder();
    384                        sbErrMsg.append("ファイル一覧の取得に失敗しました。startsWith:");
    385                        sbErrMsg.append(startsWith);
    386                        sbErrMsg.append(" errInfo:");
    387                        sbErrMsg.append("e");
    388                        throw new HybsSystemException(sbErrMsg.toString());
    389                }
    390*************/
    391                return rtnList.toArray(new String[rtnList.size()]);
    392        }
    393
    394        /**
    395         * ﾌｧｲﾙ情報取得。
    396         *
    397         * @param path                  ﾌｧｲﾙﾊﾟｽ
    398         * @param hsession              ｾｯｼｮﾝ
    399         * @return                              ﾌｧｲﾙ情報格納Map
    400         */
    401        @Override
    402        public Map<String, String> getInfo( final String path, final HttpSession hsession) {
    403                final Map<String, String> rtnMap = new HashMap<String,String>();
    404/***********
    405
    406                // 認証
    407                ObjectStorageService objectStorage = auth(hsession);
    408
    409                SwiftObject so = null;
    410                try{
    411                        // ﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄの取得
    412                         so = objectStorage.objects().get(ObjectLocation.create(this.container, path));
    413                }catch(Exception e){
    414                        StringBuilder sbErrMsg = new StringBuilder();
    415                        sbErrMsg.append("ファイルの取得に失敗しました。path:");
    416                        sbErrMsg.append(path);
    417                        sbErrMsg.append(" errInfo:");
    418                        sbErrMsg.append(e);
    419                        throw new HybsSystemException(sbErrMsg.toString());
    420                }
    421                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
    422
    423                // ﾌｧｲﾙｻｲｽﾞ
    424                rtnMap.put(FILEINFO_SIZE, String.valueOf(so.getSizeInBytes()));
    425                // 最終更新時刻
    426                rtnMap.put(FILEINFO_LASTMODIFIED, sdf.format(so.getLastModified()));
    427
    428*************/
    429                return rtnMap;
    430        }
    431
    432
    433        /**
    434         * payloadを利用するための内部クラス。
    435         * (AWSやAzureで利用するか不明なので、とりあえず内部クラスとしておきます）
    436         *
    437         * @param <T>
    438         */
    439        //      public class InputPayload<T extends InputStream> implements Payload<T>{
    440        //              private T stream = null;
    441        //
    442        //              /**
    443        //               * @param stream
    444        //               */
    445        //              public InputPayload(T stream) {
    446        //                      this.stream = stream;
    447        //              }
    448        //
    449        //              @Override
    450        //              public void close() throws IOException {
    451        //                      stream.close();
    452        //              }
    453        //
    454        //              @Override
    455        //              public T open() {
    456        //                      return stream;
    457        //              }
    458        //
    459        //              @Override
    460        //              public void closeQuietly() {
    461        //                      Closer.ioClose(stream);
    462        //              }
    463        //
    464        //              @Override
    465        //              public T getRaw() {
    466        //                      return stream;
    467        //              }
    468        //      }
    469}