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}