Coverage Report - com.jcabi.dynamo.AwsTable
 
Classes in this File Line Coverage Branch Coverage Complexity
AwsTable
84%
43/51
10%
3/30
2.286
AwsTable$AjcClosure1
100%
1/1
N/A
2.286
AwsTable$AjcClosure11
100%
1/1
N/A
2.286
AwsTable$AjcClosure13
100%
1/1
N/A
2.286
AwsTable$AjcClosure3
0%
0/1
N/A
2.286
AwsTable$AjcClosure5
100%
1/1
N/A
2.286
AwsTable$AjcClosure7
100%
1/1
N/A
2.286
AwsTable$AjcClosure9
100%
1/1
N/A
2.286
 
 1  2
 /**
 2  
  * Copyright (c) 2012-2016, 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.dynamo;
 31  
 
 32  
 import com.amazonaws.AmazonClientException;
 33  
 import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
 34  
 import com.amazonaws.services.dynamodbv2.model.AttributeValue;
 35  
 import com.amazonaws.services.dynamodbv2.model.DeleteItemRequest;
 36  
 import com.amazonaws.services.dynamodbv2.model.DeleteItemResult;
 37  
 import com.amazonaws.services.dynamodbv2.model.DescribeTableRequest;
 38  
 import com.amazonaws.services.dynamodbv2.model.DescribeTableResult;
 39  
 import com.amazonaws.services.dynamodbv2.model.KeySchemaElement;
 40  
 import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
 41  
 import com.amazonaws.services.dynamodbv2.model.PutItemResult;
 42  
 import com.amazonaws.services.dynamodbv2.model.ReturnConsumedCapacity;
 43  
 import com.amazonaws.services.dynamodbv2.model.ReturnValue;
 44  
 import com.jcabi.aspects.Cacheable;
 45  
 import com.jcabi.aspects.Immutable;
 46  
 import com.jcabi.aspects.Loggable;
 47  
 import com.jcabi.immutable.Array;
 48  
 import com.jcabi.log.Logger;
 49  
 import java.io.IOException;
 50  
 import java.util.Collection;
 51  
 import java.util.LinkedList;
 52  
 import java.util.Map;
 53  
 import lombok.EqualsAndHashCode;
 54  
 import lombok.ToString;
 55  
 
 56  
 /**
 57  
  * Single table in Dynamo, through AWS SDK.
 58  
  *
 59  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 60  
  * @version $Id: 4f10ccb08264f0799da94a738a1ed35b9be9653f $
 61  
  * @checkstyle ClassDataAbstractionCoupling (150 lines)
 62  
  * @since 0.1
 63  
  */
 64  0
 @Immutable
 65  
 @Loggable(Loggable.DEBUG)
 66  4
 @ToString
 67  1
 @EqualsAndHashCode(of = { "credentials", "reg", "self" })
 68  
 final class AwsTable implements Table {
 69  
 
 70  
     /**
 71  
      * AWS credentials.
 72  
      */
 73  
     private final transient Credentials credentials;
 74  
 
 75  
     /**
 76  
      * Region.
 77  
      */
 78  
     private final transient Region reg;
 79  
 
 80  
     /**
 81  
      * Table name.
 82  
      */
 83  
     private final transient String self;
 84  
 
 85  
     /**
 86  
      * Public ctor.
 87  
      * @param creds Credentials
 88  
      * @param region Region
 89  
      * @param table Table name
 90  
      */
 91  
     AwsTable(final Credentials creds, final Region region,
 92  5
         final String table) {
 93  5
         this.credentials = creds;
 94  5
         this.reg = region;
 95  5
         this.self = table;
 96  5
     }
 97  
 
 98  
     @Override
 99  
     public Item put(final Map<String, AttributeValue> attributes)
 100  
         throws IOException {
 101  2
         final AmazonDynamoDB aws = this.credentials.aws();
 102  
         try {
 103  1
             final PutItemRequest request = new PutItemRequest();
 104  1
             request.setTableName(this.self);
 105  1
             request.setItem(attributes);
 106  1
             request.setReturnValues(ReturnValue.NONE);
 107  1
             request.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
 108  1
             final PutItemResult result = aws.putItem(request);
 109  1
             final long start = System.currentTimeMillis();
 110  1
             Logger.info(
 111  
                 this, "#put('%[text]s'): created item in '%s', %s, in %[ms]s",
 112  
                 attributes, this.self,
 113  
                 new PrintableConsumedCapacity(
 114  
                     result.getConsumedCapacity()
 115  
                 ).print(),
 116  
                 System.currentTimeMillis() - start
 117  
             );
 118  1
             return new AwsItem(
 119  
                 this.credentials,
 120  
                 this.frame(),
 121  
                 this.self,
 122  
                 new Attributes(attributes).only(this.keys()),
 123  
                 new Array<String>(this.keys())
 124  
             );
 125  0
         } catch (final AmazonClientException ex) {
 126  0
             throw new IOException(
 127  
                 String.format(
 128  
                     "failed to put into \"%s\" with %s",
 129  
                     this.self, attributes
 130  
                 ),
 131  
                 ex
 132  
             );
 133  
         } finally {
 134  1
             aws.shutdown();
 135  
         }
 136  
     }
 137  
 
 138  
     @Override
 139  
     public Region region() {
 140  0
         return this.reg;
 141  
     }
 142  
 
 143  
     @Override
 144  
     public AwsFrame frame() {
 145  2
         return new AwsFrame(this.credentials, this, this.self);
 146  
     }
 147  
 
 148  
     @Override
 149  
     public String name() {
 150  6
         return this.self;
 151  
     }
 152  
 
 153  
     /**
 154  
      * Get names of keys.
 155  
      * @return Names of attributes, which are primary keys
 156  
      * @throws IOException If DynamoDB fails
 157  
      */
 158  
     @Cacheable(forever = true)
 159  
     public Collection<String> keys() throws IOException {
 160  4
         final AmazonDynamoDB aws = this.credentials.aws();
 161  
         try {
 162  1
             final long start = System.currentTimeMillis();
 163  1
             final DescribeTableResult result = aws.describeTable(
 164  
                 new DescribeTableRequest().withTableName(this.self)
 165  
             );
 166  1
             final Collection<String> keys = new LinkedList<String>();
 167  
             for (final KeySchemaElement key
 168  1
                 : result.getTable().getKeySchema()) {
 169  1
                 keys.add(key.getAttributeName());
 170  1
             }
 171  1
             Logger.info(
 172  
                 this, "#keys(): table %s described, in %[ms]s",
 173  
                 this.self, System.currentTimeMillis() - start
 174  
             );
 175  1
             return keys;
 176  0
         } catch (final AmazonClientException ex) {
 177  0
             throw new IOException(
 178  
                 String.format(
 179  
                     "failed to describe \"%s\"",
 180  
                     this.self
 181  
                 ),
 182  
                 ex
 183  
             );
 184  
         } finally {
 185  1
             aws.shutdown();
 186  
         }
 187  
     }
 188  
 
 189  
     @Override
 190  
     public void delete(final Map<String, AttributeValue> attributes)
 191  
         throws IOException {
 192  2
         final AmazonDynamoDB aws = this.credentials.aws();
 193  
         try {
 194  1
             final DeleteItemRequest request = new DeleteItemRequest();
 195  1
             request.setTableName(this.self);
 196  1
             request.setKey(attributes);
 197  1
             request.setReturnValues(ReturnValue.NONE);
 198  1
             request.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
 199  1
             final DeleteItemResult result = aws.deleteItem(request);
 200  1
             final long start = System.currentTimeMillis();
 201  1
             Logger.info(
 202  
                 this,
 203  
                 "#delete('%[text]s'): deleted item in '%s', %s, in %[ms]s",
 204  
                 attributes, this.self,
 205  
                 new PrintableConsumedCapacity(
 206  
                     result.getConsumedCapacity()
 207  
                 ).print(),
 208  
                 System.currentTimeMillis() - start
 209  
             );
 210  0
         } catch (final AmazonClientException ex) {
 211  0
             throw new IOException(
 212  
                 String.format(
 213  
                     "failed to delete at \"%s\" by keys %s",
 214  
                     this.self, attributes
 215  
                 ),
 216  
                 ex
 217  
             );
 218  
         } finally {
 219  1
             aws.shutdown();
 220  1
         }
 221  1
     }
 222  
 }