All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jp.co.bizreach.s3scala.LocalS3Client.scala Maven / Gradle / Ivy

There is a newer version: 0.0.8
Show newest version
package jp.co.bizreach.s3scala

import java.io.{BufferedInputStream, ByteArrayOutputStream, File, InputStream}
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.{Files, Path, Paths, StandardCopyOption}

import awscala.s3.{Bucket, PutObjectResult, S3 => AWScalaS3}
import com.amazonaws.metrics.RequestMetricCollector
import com.amazonaws.services.s3.model._
import org.apache.commons.codec.binary.Hex
import org.joda.time.DateTime

import scala.annotation.tailrec
import scala.collection.JavaConverters._
import scala.util.{Failure, Success, Try}

/**
 * Mock implementation of S3 client which works on the local file system.
 *
 * @param dir the local root directory
 */
private[s3scala] class LocalS3Client(dir: java.io.File) extends com.amazonaws.services.s3.AmazonS3Client() with AWScalaS3 {

  // Create local root directory if it does not exist
  if(!dir.exists){
    dir.mkdirs()
  }

  override def createBucket(name: String): Bucket = super[S3].createBucket(name)

  override def putObject(putObjectRequest: PutObjectRequest): PutObjectResult = {
    val bucketName = putObjectRequest.getBucketName
    val key  = putObjectRequest.getKey
    val bucketDir = new File(dir, bucketName)
    if(!bucketDir.exists){
      throw new com.amazonaws.services.s3.model.AmazonS3Exception("All access to this object has been disabled")
    }

    val putFile = new File(bucketDir, key)
    val parentDir = putFile.getParentFile
    if(!parentDir.exists){
      parentDir.mkdirs()
    }

    if(putObjectRequest.getFile != null) {
      Files.copy(putObjectRequest.getFile.toPath, putFile.toPath)
    } else {
      IOUtils.write(putFile, IOUtils.toBytes(putObjectRequest.getInputStream))
    }

    // TODO set correct property value
    awscala.s3.PutObjectResult(new Bucket(bucketName), key, null, null, null, DateTime.now(), null, null)
  }

  override def getObject(getObjectRequest: GetObjectRequest): S3Object = {
    val bucketName = getObjectRequest.getBucketName
    val key        = getObjectRequest.getKey

    val bucketDir = new File(dir, bucketName)
    if(!bucketDir.exists){
      throw new com.amazonaws.services.s3.model.AmazonS3Exception("Access Denied")
    }

    val getFile = new File(bucketDir, key)
    if(!getFile.exists){
      null
    } else {
      val s3object = new S3Object()
      s3object.setBucketName(bucketName)
      s3object.setKey(key)
      s3object.setObjectContent(IOUtils.toInputStream(getFile))
      val metadata = new ObjectMetadata()
      metadata.setContentLength(getFile.length)
      s3object.setObjectMetadata(metadata)
      s3object
    }
  }

  override def listObjects(
    listObjectsRequest: ListObjectsRequest
  ): ObjectListing = {
    new ObjectListing(){
      {
        val (baseCommonPrefixes, baseObjectSummaries) =
          createBaseTuple(
            dir,
            listObjectsRequest
          )

        setBucketName(listObjectsRequest.getBucketName)
        setPrefix(listObjectsRequest.getPrefix)
        setMarker(listObjectsRequest.getMarker)
        //引数の型がprimitiveなのでnullチェックを追加している
        setMaxKeys(if(listObjectsRequest.getMaxKeys == null) 0 else listObjectsRequest.getMaxKeys)
        setDelimiter(listObjectsRequest.getDelimiter)
        setEncodingType(listObjectsRequest.getEncodingType)
        getCommonPrefixes
          .addAll(
            createCommonPrefixes(
              listObjectsRequest,
              baseCommonPrefixes
            )
          )
        getObjectSummaries
          .addAll(
            createObjectSummaries(
              listObjectsRequest,
              baseObjectSummaries
            )
          )
        setTruncated(false)
      }
    }
  }

  private[this] def createBaseTuple(
    dir: File,
    listObjectsRequest: ListObjectsRequest
  ): (Iterator[Path], Iterator[Path]) = {
    Try(
      Files.list(
        Paths.get(
          dir.getAbsolutePath,
          listObjectsRequest.getBucketName,
          listObjectsRequest.getPrefix
        )
      )
    ) match {
      case Success(s) =>
        s.iterator
          .asScala
          .partition(_.toFile.isDirectory && listObjectsRequest.getDelimiter != null)
      case Failure(t) =>
        (Iterator.empty, Iterator.empty)
    }
  }

  private[this] def createCommonPrefixes(
    listObjectsRequest: ListObjectsRequest,
    baseCommonPrefixes: Iterator[Path]
  ): java.util.List[String] = {
    baseCommonPrefixes.map(
      cp =>
        s"${listObjectsRequest.getPrefix}${cp.getFileName.toString}${listObjectsRequest.getDelimiter}"
    ).toList
      .distinct
      .sorted
      .asJava
  }

  private[this] def createObjectSummaries(
    listObjectsRequest: ListObjectsRequest,
    baseObjectSummaries: Iterator[Path]
  ): java.util.List[S3ObjectSummary] = {
    baseObjectSummaries.map{
      path =>
        new S3ObjectSummary(){
          {
            val attributes =
              Files.readAttributes(
                path,
                classOf[BasicFileAttributes]
              )

            setBucketName(listObjectsRequest.getBucketName)
            setKey(listObjectsRequest.getPrefix + path.getFileName.toString)
            setETag(
              Hex.encodeHex(
                java.security.MessageDigest.getInstance("MD5")
                .digest(
                  IOUtils.toBytes(
                    Files.newInputStream(path)
                  )
                )
              ).mkString
            )
            setSize(attributes.size)
            setLastModified(
              new java.util.Date(
                attributes.lastModifiedTime
                .toMillis
              )
            )
          }
        }
    }.toList
      .distinct
      .asJava
  }

  override def getS3AccountOwner(): Owner = ???

  override def listBuckets(listBucketsRequest: ListBucketsRequest): java.util.List[com.amazonaws.services.s3.model.Bucket] = {
    dir.listFiles.filter(_.isDirectory).map { child =>
      new com.amazonaws.services.s3.model.Bucket(child.getName)
    }.toList.asJava
  }

  override def getBucketLocation(getBucketLocationRequest: GetBucketLocationRequest): String = ???

  override def createBucket(createBucketRequest: CreateBucketRequest): com.amazonaws.services.s3.model.Bucket = {
    val bucketDir = new File(dir, createBucketRequest.getBucketName)
    if(bucketDir.exists){
      throw new com.amazonaws.services.s3.model.AmazonS3Exception("Your previous request to create the named bucket succeeded and you already own it.")
    }
    bucketDir.mkdir()
    new com.amazonaws.services.s3.model.Bucket(createBucketRequest.getBucketName)
  }

  override def getObjectAcl(bucketName: String, key: String, versionId: String): AccessControlList = ???

  override def setObjectAcl(bucketName: String, key: String, versionId: String, acl: AccessControlList): Unit = ???

  override def setObjectAcl(bucketName: String, key: String, versionId: String, acl: AccessControlList, requestMetricCollector: RequestMetricCollector): Unit = ???

  override def setObjectAcl(bucketName: String, key: String, versionId: String, acl: CannedAccessControlList): Unit = ???

  override def setObjectAcl(bucketName: String, key: String, versionId: String, acl: CannedAccessControlList, requestMetricCollector: RequestMetricCollector): Unit = ???

  override def getBucketAcl(bucketName: String): AccessControlList = ???

  override def getBucketAcl(getBucketAclRequest: GetBucketAclRequest): AccessControlList = ???

  override def setBucketAcl(bucketName: String, acl: AccessControlList): Unit = ???

  override def setBucketAcl(bucketName: String, acl: AccessControlList, requestMetricCollector: RequestMetricCollector): Unit = ???

  override def setBucketAcl(setBucketAclRequest: SetBucketAclRequest): Unit = ???

  override def setBucketAcl(bucketName: String, acl: CannedAccessControlList): Unit = ???

  override def setBucketAcl(bucketName: String, acl: CannedAccessControlList, requestMetricCollector: RequestMetricCollector): Unit = ???

  override def getObjectMetadata(getObjectMetadataRequest: GetObjectMetadataRequest): ObjectMetadata = ???

  override def doesBucketExist(bucketName: String): Boolean = ???

  override def getObject(getObjectRequest: GetObjectRequest, destinationFile: File): ObjectMetadata = ???

  override def deleteBucket(deleteBucketRequest: DeleteBucketRequest): Unit = {
    val bucketDir = new File(dir, deleteBucketRequest.getBucketName)
    if(!bucketDir.exists){
      throw new com.amazonaws.services.s3.model.AmazonS3Exception("Access Denied")
    }
    IOUtils.deleteDirectory(bucketDir)
  }

  override def copyObject(copyObjectRequest: CopyObjectRequest): CopyObjectResult = {
    val srcBucketDir = new File(dir, copyObjectRequest.getSourceBucketName)
    if(!srcBucketDir.exists) throw new com.amazonaws.services.s3.model.AmazonS3Exception("All access to this object has been disabled")
    val src = new File(srcBucketDir, copyObjectRequest.getSourceKey)
    if(!src.exists) throw new com.amazonaws.services.s3.model.AmazonS3Exception("Source object not found")

    val destBucketDir = new File(dir, copyObjectRequest.getDestinationBucketName)
    if(!destBucketDir.exists) throw new com.amazonaws.services.s3.model.AmazonS3Exception("All access to this object has been disabled")
    val dest = new File(destBucketDir, copyObjectRequest.getDestinationKey)

    // Make all directories
    val parentDir = dest.getParentFile
    if(!parentDir.exists){
      parentDir.mkdirs()
    }

    // Copy file
    Files.copy(src.toPath, dest.toPath, StandardCopyOption.REPLACE_EXISTING)
    new CopyObjectResult
  }

  override def copyPart(copyPartRequest: CopyPartRequest): CopyPartResult = ???

  override def deleteObject(deleteObjectRequest: DeleteObjectRequest): Unit = {
    val bucketDir = new File(dir, deleteObjectRequest.getBucketName)
    if(!bucketDir.exists){
      throw new com.amazonaws.services.s3.model.AmazonS3Exception("Access Denied")
    }

    val deleteFile = new File(bucketDir, deleteObjectRequest.getKey)
    if(deleteFile.exists){
      deleteFile.delete()
    }
  }

  override def deleteObjects(deleteObjectsRequest: DeleteObjectsRequest): DeleteObjectsResult = ???

  override def deleteVersion(deleteVersionRequest: DeleteVersionRequest): Unit = ???

  override def setBucketVersioningConfiguration(setBucketVersioningConfigurationRequest: SetBucketVersioningConfigurationRequest): Unit = ???

  override def getBucketVersioningConfiguration(bucketName: String): BucketVersioningConfiguration = ???

  override def getBucketWebsiteConfiguration(getBucketWebsiteConfigurationRequest: GetBucketWebsiteConfigurationRequest): BucketWebsiteConfiguration = ???

  override def getBucketLifecycleConfiguration(bucketName: String): BucketLifecycleConfiguration = ???

  override def setBucketLifecycleConfiguration(setBucketLifecycleConfigurationRequest: SetBucketLifecycleConfigurationRequest): Unit = ???

  override def deleteBucketLifecycleConfiguration(deleteBucketLifecycleConfigurationRequest: DeleteBucketLifecycleConfigurationRequest): Unit = ???

  override def getBucketCrossOriginConfiguration(bucketName: String): BucketCrossOriginConfiguration = ???

  override def setBucketCrossOriginConfiguration(setBucketCrossOriginConfigurationRequest: SetBucketCrossOriginConfigurationRequest): Unit = ???

  override def deleteBucketCrossOriginConfiguration(deleteBucketCrossOriginConfigurationRequest: DeleteBucketCrossOriginConfigurationRequest): Unit = ???

  override def getBucketTaggingConfiguration(bucketName: String): BucketTaggingConfiguration = ???

  override def setBucketTaggingConfiguration(setBucketTaggingConfigurationRequest: SetBucketTaggingConfigurationRequest): Unit = ???

  override def deleteBucketTaggingConfiguration(deleteBucketTaggingConfigurationRequest: DeleteBucketTaggingConfigurationRequest): Unit = ???

  override def setBucketWebsiteConfiguration(setBucketWebsiteConfigurationRequest: SetBucketWebsiteConfigurationRequest): Unit = ???

  override def deleteBucketWebsiteConfiguration(deleteBucketWebsiteConfigurationRequest: DeleteBucketWebsiteConfigurationRequest): Unit = ???

  override def setBucketNotificationConfiguration(setBucketNotificationConfigurationRequest: SetBucketNotificationConfigurationRequest): Unit = ???

  override def getBucketNotificationConfiguration(bucketName: String): BucketNotificationConfiguration = ???

  override def getBucketLoggingConfiguration(bucketName: String): BucketLoggingConfiguration = ???

  override def setBucketLoggingConfiguration(setBucketLoggingConfigurationRequest: SetBucketLoggingConfigurationRequest): Unit = ???

  override def setBucketPolicy(bucketName: String, policyText: String): Unit = ???

  override def getBucketPolicy(getBucketPolicyRequest: GetBucketPolicyRequest): BucketPolicy = ???

  override def setBucketPolicy(setBucketPolicyRequest: SetBucketPolicyRequest): Unit = ???

  override def deleteBucketPolicy(deleteBucketPolicyRequest: DeleteBucketPolicyRequest): Unit = ???

  override def abortMultipartUpload(abortMultipartUploadRequest: AbortMultipartUploadRequest): Unit = ???

  override def completeMultipartUpload(completeMultipartUploadRequest: CompleteMultipartUploadRequest): CompleteMultipartUploadResult = ???

  override def initiateMultipartUpload(initiateMultipartUploadRequest: InitiateMultipartUploadRequest): InitiateMultipartUploadResult = ???

  override def listMultipartUploads(listMultipartUploadsRequest: ListMultipartUploadsRequest): MultipartUploadListing = ???

  override def listParts(listPartsRequest: ListPartsRequest): PartListing = ???

  override def uploadPart(uploadPartRequest: UploadPartRequest): UploadPartResult = ???

  override def restoreObject(restoreObjectRequest: RestoreObjectRequest): Unit = ???

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy