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}