Coverage Report - com.jcabi.s3.AwsOcket
 
Classes in this File Line Coverage Branch Coverage Complexity
AwsOcket
54%
31/57
0%
0/22
2.778
AwsOcket$AjcClosure1
0%
0/1
N/A
2.778
AwsOcket$AjcClosure11
100%
1/1
N/A
2.778
AwsOcket$AjcClosure13
0%
0/1
N/A
2.778
AwsOcket$AjcClosure3
0%
0/1
N/A
2.778
AwsOcket$AjcClosure5
100%
1/1
N/A
2.778
AwsOcket$AjcClosure7
0%
0/1
N/A
2.778
AwsOcket$AjcClosure9
100%
1/1
N/A
2.778
 
 1  0
 /**
 2  
  * Copyright (c) 2012-2015, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.s3;
 31  
 
 32  
 import com.amazonaws.AmazonServiceException;
 33  
 import com.amazonaws.services.s3.AmazonS3;
 34  
 import com.amazonaws.services.s3.model.AmazonS3Exception;
 35  
 import com.amazonaws.services.s3.model.GetObjectMetadataRequest;
 36  
 import com.amazonaws.services.s3.model.GetObjectRequest;
 37  
 import com.amazonaws.services.s3.model.ListObjectsRequest;
 38  
 import com.amazonaws.services.s3.model.ObjectListing;
 39  
 import com.amazonaws.services.s3.model.ObjectMetadata;
 40  
 import com.amazonaws.services.s3.model.S3Object;
 41  
 import com.amazonaws.services.s3.transfer.TransferManager;
 42  
 import com.amazonaws.services.s3.transfer.Upload;
 43  
 import com.amazonaws.services.s3.transfer.model.UploadResult;
 44  
 import com.jcabi.aspects.Immutable;
 45  
 import com.jcabi.aspects.Loggable;
 46  
 import com.jcabi.log.Logger;
 47  
 import java.io.IOException;
 48  
 import java.io.InputStream;
 49  
 import java.io.OutputStream;
 50  
 import lombok.EqualsAndHashCode;
 51  
 import org.apache.commons.io.IOUtils;
 52  
 import org.apache.commons.io.input.CountingInputStream;
 53  
 
 54  
 /**
 55  
  * Amazon S3 bucket.
 56  
  *
 57  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 58  
  * @version $Id: 7b0311f602dfce82d09f32f355afb1fb59810b69 $
 59  
  * @since 0.1
 60  
  */
 61  0
 @Immutable
 62  0
 @EqualsAndHashCode(of = { "bkt", "name" })
 63  
 @Loggable(Loggable.DEBUG)
 64  
 final class AwsOcket implements Ocket {
 65  
 
 66  
     /**
 67  
      * Bucket we're in.
 68  
      */
 69  
     private final transient Bucket bkt;
 70  
 
 71  
     /**
 72  
      * Object name.
 73  
      */
 74  
     private final transient String name;
 75  
 
 76  
     /**
 77  
      * Public ctor.
 78  
      * @param bucket Bucket name
 79  
      * @param obj Object name
 80  
      */
 81  4
     AwsOcket(final Bucket bucket, final String obj) {
 82  4
         this.bkt = bucket;
 83  4
         this.name = obj;
 84  4
     }
 85  
 
 86  
     @Override
 87  
     public String toString() {
 88  1
         return this.name;
 89  
     }
 90  
 
 91  
     @Override
 92  
     public Bucket bucket() {
 93  0
         return this.bkt;
 94  
     }
 95  
 
 96  
     @Override
 97  
     public String key() {
 98  0
         return this.name;
 99  
     }
 100  
 
 101  
     @Override
 102  
     public ObjectMetadata meta() throws IOException {
 103  
         try {
 104  2
             final AmazonS3 aws = this.bkt.region().aws();
 105  1
             final long start = System.currentTimeMillis();
 106  1
             final ObjectMetadata meta = aws.getObjectMetadata(
 107  
                 new GetObjectMetadataRequest(this.bkt.name(), this.name)
 108  
             );
 109  0
             Logger.info(
 110  
                 this,
 111  
                 // @checkstyle LineLength (1 line)
 112  
                 "metadata loaded for ocket '%s' in bucket '%s' in %[ms]s (etag=%s)",
 113  
                 this.name, this.bkt.name(),
 114  
                 System.currentTimeMillis() - start,
 115  
                 meta.getETag()
 116  
             );
 117  0
             return meta;
 118  1
         } catch (final AmazonS3Exception ex) {
 119  1
             throw new OcketNotFoundException(
 120  
                 String.format(
 121  
                     "ocket '%s' not found in '%s', can't fetch meta()",
 122  
                     this.name, this.bkt.name()
 123  
                 ),
 124  
                 ex
 125  
             );
 126  0
         } catch (final AmazonServiceException ex) {
 127  0
             throw new IOException(
 128  
                 String.format(
 129  
                     "failed to fetch meta of '%s' in '%s'",
 130  
                     this.name, this.bkt
 131  
                     ),
 132  
                 ex
 133  
             );
 134  
         }
 135  
     }
 136  
 
 137  
     @Override
 138  
     public boolean exists() throws IOException {
 139  
         try {
 140  0
             final AmazonS3 aws = this.bkt.region().aws();
 141  0
             final long start = System.currentTimeMillis();
 142  0
             final ObjectListing listing = aws.listObjects(
 143  
                 new ListObjectsRequest()
 144  
                     .withBucketName(this.bkt.name())
 145  
                     .withPrefix(this.name)
 146  
                     .withMaxKeys(1)
 147  
             );
 148  0
             final boolean exists = !listing.getObjectSummaries().isEmpty();
 149  0
             Logger.info(
 150  
                 this,
 151  
                 "ocket '%s' existence checked in bucket '%s' in %[ms]s (%b)",
 152  
                 this.name, this.bkt.name(),
 153  
                 System.currentTimeMillis() - start,
 154  
                 exists
 155  
             );
 156  0
             return exists;
 157  0
         } catch (final AmazonServiceException ex) {
 158  0
             throw new IOException(
 159  
                 String.format(
 160  
                     "failed to check existence of '%s' in '%s'",
 161  
                     this.name, this.bkt
 162  
                 ),
 163  
                 ex
 164  
             );
 165  
         }
 166  
     }
 167  
 
 168  
     @Override
 169  
     public void read(final OutputStream output) throws IOException {
 170  2
         final AmazonS3 aws = this.bkt.region().aws();
 171  
         try {
 172  1
             final long start = System.currentTimeMillis();
 173  1
             final S3Object obj = aws.getObject(
 174  
                 new GetObjectRequest(this.bkt.name(), this.name)
 175  
             );
 176  1
             final InputStream input = obj.getObjectContent();
 177  1
             final int bytes = IOUtils.copy(input, output);
 178  1
             input.close();
 179  1
             Logger.info(
 180  
                 this,
 181  
                 // @checkstyle LineLength (1 line)
 182  
                 "loaded %d byte(s) from ocket '%s' in bucket '%s' in %[ms]s (etag=%s)",
 183  
                 bytes, this.name, this.bkt.name(),
 184  
                 System.currentTimeMillis() - start,
 185  
                 obj.getObjectMetadata().getETag()
 186  
             );
 187  0
         } catch (final AmazonS3Exception ex) {
 188  0
             throw new OcketNotFoundException(
 189  
                 String.format(
 190  
                     "ocket '%s' not found in '%s'",
 191  
                     this.name, this.bkt.name()
 192  
                 ),
 193  
                 ex
 194  
             );
 195  0
         } catch (final AmazonServiceException ex) {
 196  0
             throw new IOException(
 197  
                 String.format(
 198  
                     "failed to read the content of '%s' in '%s'",
 199  
                     this.name, this.bkt
 200  
                 ),
 201  
                 ex
 202  
             );
 203  1
         }
 204  1
     }
 205  
 
 206  
     @Override
 207  
     public void write(final InputStream input, final ObjectMetadata meta)
 208  
         throws IOException {
 209  2
         final CountingInputStream cnt = new CountingInputStream(input);
 210  
         try {
 211  1
             final AmazonS3 aws = this.bkt.region().aws();
 212  1
             final long start = System.currentTimeMillis();
 213  1
             final TransferManager tmgr = new TransferManager(aws);
 214  1
             final Upload upload = tmgr.upload(
 215  
                 this.bkt.name(), this.name, cnt, meta
 216  
             );
 217  1
             final UploadResult result = upload.waitForUploadResult();
 218  1
             Logger.info(
 219  
                 this,
 220  
                 // @checkstyle LineLength (1 line)
 221  
                 "saved %d byte(s) to ocket '%s' in bucket '%s' in %[ms]s (etag=%s)",
 222  
                 cnt.getByteCount(), this.name, this.bkt.name(),
 223  
                 System.currentTimeMillis() - start,
 224  
                 result.getETag()
 225  
             );
 226  1
             tmgr.shutdownNow(false);
 227  0
         } catch (final AmazonServiceException ex) {
 228  0
             throw new IOException(
 229  
                 String.format(
 230  
                     "failed to write content to '%s' in '%s'",
 231  
                     this.name, this.bkt
 232  
                 ),
 233  
                 ex
 234  
             );
 235  0
         } catch (final InterruptedException ex) {
 236  0
             Thread.currentThread().interrupt();
 237  0
             throw new IOException(
 238  
                 String.format(
 239  
                     "writing to '%s' in '%s' interrupted",
 240  
                     this.name, this.bkt
 241  
                 ),
 242  
                 ex
 243  
             );
 244  
         } finally {
 245  1
             cnt.close();
 246  1
         }
 247  1
     }
 248  
 
 249  
     @Override
 250  
     public int compareTo(final Ocket ocket) {
 251  0
         return this.key().compareTo(ocket.key());
 252  
     }
 253  
 }