001package org.opengion.plugin.cloud; 002 003import java.io.InputStream; 004import java.text.SimpleDateFormat; 005import java.util.ArrayList; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009 010import javax.servlet.http.HttpSession; 011 012import org.apache.commons.lang3.StringUtils; 013import org.opengion.fukurou.util.Closer; 014import org.opengion.fukurou.util.FileUtil; 015import org.opengion.hayabusa.common.HybsSystem; 016import org.opengion.hayabusa.common.HybsSystemException; 017import org.opengion.hayabusa.io.StorageAPI; 018 019import com.amazonaws.auth.AWSCredentials; 020import com.amazonaws.auth.AWSStaticCredentialsProvider; 021import com.amazonaws.auth.BasicAWSCredentials; 022import com.amazonaws.auth.InstanceProfileCredentialsProvider; 023import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; 024import com.amazonaws.services.s3.AmazonS3; 025import com.amazonaws.services.s3.AmazonS3ClientBuilder; 026import com.amazonaws.services.s3.model.CopyObjectRequest; 027import com.amazonaws.services.s3.model.DeleteObjectRequest; 028import com.amazonaws.services.s3.model.ListObjectsV2Request; 029import com.amazonaws.services.s3.model.ListObjectsV2Result; 030import com.amazonaws.services.s3.model.ObjectMetadata; 031import com.amazonaws.services.s3.model.PutObjectRequest; 032import com.amazonaws.services.s3.model.S3Object; 033import com.amazonaws.services.s3.model.S3ObjectSummary; 034import com.microsoft.azure.storage.blob.BlobOutputStream; 035 036/** 037 * aws用のクラウドストレージ操作実装 038 * 039 * システムリソースのS3_ACCESS_KEY,S3_SECRET_KEY,S3_SERVICE_END_POINT,S3_REGIONに、AWSのキー情報を登録する必要があります。 040 * (IAMを利用する場合には認証情報を登録する必要はありません) 041 * 042 * また、Edit機能のファイル出力を利用する場合はS3上(例えばvar/lib/tomcat8/webapps/ge/jsp/common)に 043 * fileDownloadListDef.txtをアップロードしておく必要があります。 044 * 045 * @og.group クラウド 046 * @og.rev (2018/02/15) 新規作成 047 * @og.rev 5.9.32.1 (2018/05/11) パスの先頭が「/」の場合は「/」の除去と、「//」を「/」に置換処理の追加。 048 * 049 * @version 5.0 050 * @author T.OTA 051 * @sinse JDK7.0 052 */ 053public class StorageAPI_aws implements StorageAPI { 054 // 認証文字列 055 // アクセスキー 056 private String s3AccessKey = ""; 057 // シークレットキー 058 private String s3SecretKey = ""; 059 // エンドポイント 060 private String s3ServiceEndPoint = ""; 061 // レギオン 062 private String s3Region = ""; 063 // バケット名(コンテナ名) 064 String s3bucket = ""; 065 066 AmazonS3 client = null; 067 068 /** 069 * コンストラクタ 070 * 071 * @param container 072 * @param hsession 073 */ 074 public StorageAPI_aws(String container, HttpSession hsession){ 075 // リソースパラメータ設定 076 // アクセスキー 077 s3AccessKey = HybsSystem.sys("CLOUD_STORAGE_S3_ACCESS_KEY"); 078 // コンテナ名をs3bucketとして保持しておく 079 s3bucket = container; 080 081 // S3アクセスクライアントの生成 082 if(StringUtils.isEmpty(s3AccessKey)){ 083 // IAMロールによる認証 084 client = AmazonS3ClientBuilder.standard() 085 .withCredentials(new InstanceProfileCredentialsProvider(false)) 086 .build(); 087 }else { 088 // リソースのアクセスキーによる認証 089 // シークレットキー 090 s3SecretKey = HybsSystem.sys("CLOUD_STORAGE_S3_SECRET_KEY"); 091 // エンドポイント 092 s3ServiceEndPoint = HybsSystem.sys("CLOUD_STORAGE_S3_SERVICE_END_POINT"); 093 // レギオン 094 s3Region = HybsSystem.sys("CLOUD_STORAGE_S3_REGION"); 095 096 // 初期チェック 097 initCheck(); 098 099 // AWSの認証情報 100 AWSCredentials credentials = new BasicAWSCredentials(s3AccessKey, s3SecretKey); 101 102 // エンドポイント設定 103 EndpointConfiguration endpointConfiguration = new EndpointConfiguration(s3ServiceEndPoint, s3Region); 104 client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials)) 105 .withEndpointConfiguration(endpointConfiguration).build(); 106 } 107 108 // S3に指定されたバケット(コンテナ)が存在しない場合は、作成する 109 if(!client.doesBucketExist(container)){ 110 client.createBucket(container); 111 } 112 } 113 114 /** 115 * 初期チェック 116 */ 117 private void initCheck(){ 118 // システムリソースに認証情報が登録されていない場合は、エラー 119 StringBuilder errString = new StringBuilder(); 120 if(StringUtils.isEmpty(s3AccessKey)){ 121 errString.append("CLOUD_STORAGE_S3_ACCESS_KEY"); 122 } 123 if(StringUtils.isEmpty(s3SecretKey)){ 124 errString.append(",CLOUD_STORAGE_S3_SECRET_KEY"); 125 } 126 if(StringUtils.isEmpty(s3ServiceEndPoint)){ 127 errString.append(",CLOUD_STORAGE_S3_SERVICE_END_POINT"); 128 } 129 if(StringUtils.isEmpty(s3Region)){ 130 errString.append(",CLOUD_STORAGE_S3_REGION"); 131 } 132 133 if(errString.length() > 0){ 134 throw new HybsSystemException("AWSのキー情報("+errString.toString()+")がシステムリソースに登録されていません。"); 135 } 136 137 } 138 139 /** 140 * ファイルパスの編集 2018/05/07 ADD 141 * パスの先頭が「/」の場合は「/」の除去と、「//」を「/」に置換処理の追加。 142 * 143 * @og.rev 5.9.32.1 (2018/05/11) 144 * @param path 145 * @return 変更後パス 146 */ 147 private String editPath(String path) { 148 // 先頭が「/」の場合は除去 149 if("/".equals(path.substring(0, 1))) { 150 path = path.substring(1); 151 } 152 // 「//」は「/」に置換 153 path = path.replaceAll("//", "/"); 154 155 return path; 156 } 157 158 /** 159 * アップロード 160 * 161 * @og.rev 5.9.32.1 (2018/05/11) 162 * @param partInputStream アップロード対象のストリーム 163 * @param updFolder アップロードフォルタ名 164 * @param updFileName アップロードファイル名 165 * @param hsession セッション 166 */ 167 @Override 168 public void add(InputStream partInputStream, String updFolder, String updFileName, HttpSession hsession) { 169 BlobOutputStream blobOutputStream = null; 170 try { 171 // 2018/05/07 ADD 172 updFolder = editPath(updFolder); 173 174 // アップロード処理 175 ObjectMetadata om = new ObjectMetadata(); 176 177 final PutObjectRequest putRequest = new PutObjectRequest(s3bucket, updFolder + updFileName, partInputStream,om); 178 // アップロード実行 179 client.putObject(putRequest); 180 181 } catch (Exception e) { 182 StringBuilder sbErrMsg = new StringBuilder(); 183 sbErrMsg.append("ストレージへのファイルアップロードに失敗しました。updFolder:"); 184 sbErrMsg.append(updFolder); 185 sbErrMsg.append(" updFileName:"); 186 sbErrMsg.append(updFileName); 187 sbErrMsg.append(" errInfo:"); 188 sbErrMsg.append(e); 189 throw new HybsSystemException(sbErrMsg.toString()); 190 } finally { 191 // クローズ処理 192 Closer.ioClose(blobOutputStream); 193 Closer.ioClose(partInputStream); 194 } 195 } 196 197 /** 198 * ダウンロード 199 * 200 * @og.rev 5.9.32.1 (2018/05/11) 201 * @param filePath ダウンロード対象のファイルパス 202 * @param hsession セッション 203 * @return ストリーム 204 */ 205 @Override 206 public InputStream get(String filePath, HttpSession hsession) { 207 InputStream is = null; 208 // ダウンロード 209 try { 210 // 2018/05/07 ADD 211 filePath = editPath(filePath); 212 213 S3Object object = client.getObject(s3bucket, filePath); 214 215 is = object.getObjectContent(); 216 } catch (Exception e) { 217 StringBuilder sbErrMsg = new StringBuilder(); 218 sbErrMsg.append("ストレージからのファイルダウンロードに失敗しました。filePath:"); 219 sbErrMsg.append(filePath); 220 sbErrMsg.append(" errInfo:"); 221 sbErrMsg.append(e); 222 throw new HybsSystemException(sbErrMsg.toString()); 223 } 224 225 return is; 226 } 227 228 /** 229 * コピー 230 * 231 * @og.rev 5.9.32.1 (2018/05/11) 232 * @param oldFilePath コピー元ファイルパス 233 * @param newFilePath コピー先ファイルパス 234 * @param hsession セッション 235 */ 236 @Override 237 public void copy(String oldFilePath, String newFilePath, HttpSession hsession) { 238 try { 239 // 2018/05/07 ADD 240 oldFilePath = editPath(oldFilePath); 241 newFilePath = editPath(newFilePath); 242 243 final CopyObjectRequest copyRequest = new CopyObjectRequest(s3bucket, oldFilePath, s3bucket, newFilePath); 244 client.copyObject(copyRequest); 245 } catch (Exception e) { 246 StringBuilder sbErrMsg = new StringBuilder(); 247 sbErrMsg.append("ストレージのファイルコピー処理に失敗しました。oldFilePath:"); 248 sbErrMsg.append(oldFilePath); 249 sbErrMsg.append(" newFilePath:"); 250 sbErrMsg.append(newFilePath); 251 sbErrMsg.append(" errInfo:"); 252 sbErrMsg.append(e); 253 throw new HybsSystemException(sbErrMsg.toString()); 254 } 255 } 256 257 /** 258 * 削除 259 * 260 * @og.rev 5.9.32.1 (2018/05/11) 261 * @param filePath 削除ファイルのパス 262 * @param hsession セッション 263 */ 264 @Override 265 public void delete(String filePath, HttpSession hsession) { 266 // 削除 267 try { 268 // 2018/05/07 ADD 269 filePath = editPath(filePath); 270 271 final DeleteObjectRequest deleteRequest = new DeleteObjectRequest(s3bucket, filePath); 272 client.deleteObject(deleteRequest); 273 client.deleteObject(s3bucket, filePath); 274 } catch (Exception e) { 275 StringBuilder sbErrMsg = new StringBuilder(); 276 sbErrMsg.append("ストレージのファイル削除に失敗しました。filePath:"); 277 sbErrMsg.append(filePath); 278 sbErrMsg.append(" errInfo:"); 279 sbErrMsg.append(e); 280 throw new HybsSystemException(sbErrMsg.toString()); 281 } 282 } 283 284 /** 285 * ファイル名変更 286 * 287 * @param filePath ファイルパス 288 * @param oldFileName 変更前ファイル名 289 * @param newFileName 変更後ファイル名 290 * @param useBackup 変更後ファイル名が既に存在する場合のバックアップ作成フラグ 291 * @param hsession セッション 292 */ 293 public void rename(String filePath, String oldFileName, String newFileName, final boolean useBackup, 294 HttpSession hsession) { 295 String newFilePath = filePath + newFileName; 296 String oldFilePath = filePath + oldFileName; 297 298 // 変更先のファイルが存在した場合の処理 299 if (exists(newFilePath, hsession)) { 300 // バックアップ作成する場合 301 if (useBackup) { 302 // バックアップファイル名は、元のファイル名(拡張子含む) + "_" + 現在時刻のlong値 + "." + 303 // 元のファイルの拡張子 304 String bkupPath = filePath + "_backup/" + newFileName + "_" + System.currentTimeMillis() 305 + FileUtil.EXTENSION_SEPARATOR + FileUtil.getExtension(newFileName); 306 // バックアップフォルダに移動 307 copy(newFilePath, bkupPath, hsession); 308 } 309 } 310 311 // コピー 312 copy(oldFilePath, newFilePath, hsession); 313 // 削除 314 delete(oldFilePath, hsession); 315 } 316 317 /** 318 * ファイル存在チェック 319 * 320 * @og.rev 5.9.32.1 (2018/05/11) 321 * @param filePath ファイルパス 322 * @param hsession セッション 323 * @return true:存在 false:存在しない 324 */ 325// @Override 326 public boolean exists(String filePath, HttpSession hsession) { 327 boolean blnRtn = true; 328 try { 329 // 2018/05/07 ADD 330 filePath = editPath(filePath); 331 332 if (!client.doesObjectExist(s3bucket, filePath)) { 333 // ファイルが取得できなかった場合は、falseを設定 334 blnRtn = false; 335 } 336 } catch (Exception e) { 337 StringBuilder sbErrMsg = new StringBuilder(); 338 sbErrMsg.append("ストレージのファイル取得に失敗しました。filePath:"); 339 sbErrMsg.append(filePath); 340 sbErrMsg.append(" errInfo:"); 341 sbErrMsg.append(e); 342 throw new HybsSystemException(sbErrMsg.toString()); 343 } 344 345 return blnRtn; 346 } 347 348 /** 349 * ファイル一覧取得 350 * 351 * @param startsWith パスの前方一致 352 * @param hsession セッション 353 * @return ファイルパス一覧 354 */ 355 @Override 356 public String[] list(String startsWith, HttpSession hsession) { 357 // 認証 358 List<String> rtnList = new ArrayList<String>(); 359 try{ 360 // 2018/05/07 ADD 361 startsWith = editPath(startsWith); 362 363 ListObjectsV2Request request = new ListObjectsV2Request() 364 .withBucketName(s3bucket) 365 .withPrefix(startsWith); 366 ListObjectsV2Result list = client.listObjectsV2(request); 367 List<S3ObjectSummary> objects = list.getObjectSummaries(); 368 // 一覧の取得 369 for(S3ObjectSummary obj: objects){ 370 // 名称を格納 371 rtnList.add(obj.getKey()); 372 } 373 } catch (Exception e){ 374 StringBuilder sbErrMsg = new StringBuilder(); 375 sbErrMsg.append("ファイル一覧の取得に失敗しました。startsWith:"); 376 sbErrMsg.append(startsWith); 377 sbErrMsg.append(" errInfo:"); 378 sbErrMsg.append("e"); 379 throw new HybsSystemException(sbErrMsg.toString()); 380 } 381 return rtnList.toArray(new String[rtnList.size()]); 382 } 383 384 /** 385 * ファイル情報取得 386 * 387 * @og.rev 5.9.32.1 (2018/05/11) 388 * @param path ファイルパス 389 * @param hsession セッション 390 * @return ファイル情報格納Map 391 */ 392// @Override 393 public Map<String, String> getInfo(String path, HttpSession hsession) { 394 Map<String, String> rtnMap = new HashMap<String,String>(); 395 396 ObjectMetadata meta = null; 397 try{ 398 // 2018/05/07 ADD 399 path = editPath(path); 400 401 // ファイルオブジェクトの取得 402 meta = client.getObjectMetadata(s3bucket, path); 403 }catch(Exception e){ 404 StringBuilder sbErrMsg = new StringBuilder(); 405 sbErrMsg.append("ファイルの取得に失敗しました。path:"); 406 sbErrMsg.append(path); 407 sbErrMsg.append(" errInfo:"); 408 sbErrMsg.append(e); 409 throw new HybsSystemException(sbErrMsg.toString()); 410 } 411 SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss"); 412 413 // ファイルサイズ 414 rtnMap.put(FILEINFO_SIZE, String.valueOf(meta.getContentLength())); 415 // 最終更新時刻 416 rtnMap.put(FILEINFO_LASTMODIFIED, sdf.format(meta.getLastModified())); 417 418 return rtnMap; 419 } 420}