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}