Coverage Report - com.jcabi.dynamo.AwsItem
 
Classes in this File Line Coverage Branch Coverage Complexity
AwsItem
24%
15/62
27%
12/44
2.833
AwsItem$AjcClosure1
0%
0/1
N/A
2.833
AwsItem$AjcClosure3
100%
1/1
N/A
2.833
AwsItem$AjcClosure5
0%
0/1
N/A
2.833
AwsItem$AjcClosure7
0%
0/1
N/A
2.833
AwsItem$AjcClosure9
0%
0/1
N/A
2.833
 
 1  4
 /**
 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.AttributeValueUpdate;
 36  
 import com.amazonaws.services.dynamodbv2.model.GetItemRequest;
 37  
 import com.amazonaws.services.dynamodbv2.model.GetItemResult;
 38  
 import com.amazonaws.services.dynamodbv2.model.ReturnConsumedCapacity;
 39  
 import com.amazonaws.services.dynamodbv2.model.ReturnValue;
 40  
 import com.amazonaws.services.dynamodbv2.model.UpdateItemRequest;
 41  
 import com.amazonaws.services.dynamodbv2.model.UpdateItemResult;
 42  
 import com.jcabi.aspects.Immutable;
 43  
 import com.jcabi.aspects.Loggable;
 44  
 import com.jcabi.immutable.Array;
 45  
 import com.jcabi.log.Logger;
 46  
 import java.io.IOException;
 47  
 import java.util.Collections;
 48  
 import java.util.Locale;
 49  
 import java.util.Map;
 50  
 import java.util.NoSuchElementException;
 51  
 import lombok.EqualsAndHashCode;
 52  
 import lombok.ToString;
 53  
 
 54  
 /**
 55  
  * Single item/row in a DynamoDB table.
 56  
  *
 57  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 58  
  * @version $Id: 1d2b6329f00902e790b31754d8332d955e3d2641 $
 59  
  * @since 0.1
 60  
  */
 61  
 @Immutable
 62  
 @Loggable(Loggable.DEBUG)
 63  3
 @ToString
 64  1
 @EqualsAndHashCode(of = { "credentials", "frm", "name", "attributes" })
 65  
 final class AwsItem implements Item {
 66  
 
 67  
     /**
 68  
      * AWS credentials.
 69  
      */
 70  
     private final transient Credentials credentials;
 71  
 
 72  
     /**
 73  
      * Frame.
 74  
      */
 75  
     private final transient AwsFrame frm;
 76  
 
 77  
     /**
 78  
      * Table name.
 79  
      */
 80  
     private final transient String name;
 81  
 
 82  
     /**
 83  
      * Pre-loaded attributes and their values.
 84  
      */
 85  
     private final transient Attributes attributes;
 86  
 
 87  
     /**
 88  
      * Table keys.
 89  
      */
 90  
     private final transient Array<String> keys;
 91  
 
 92  
     /**
 93  
      * Public ctor.
 94  
      * @param creds Credentials
 95  
      * @param frame Frame
 96  
      * @param table Table name
 97  
      * @param attrs Loaded already attributes with values
 98  
      * @param pks Keys of the table
 99  
      * @checkstyle ParameterNumber (5 lines)
 100  
      */
 101  
     AwsItem(final Credentials creds, final AwsFrame frame,
 102  
         final String table, final Attributes attrs,
 103  5
         final Array<String> pks) {
 104  5
         this.credentials = creds;
 105  5
         this.frm = frame;
 106  5
         this.name = table;
 107  5
         this.attributes = attrs;
 108  5
         this.keys = pks;
 109  5
     }
 110  
 
 111  
     @Override
 112  
     public boolean has(final String attr) throws IOException {
 113  0
         final String attrib = String.format(Locale.ENGLISH, attr);
 114  0
         boolean has = this.attributes.containsKey(attrib);
 115  0
         if (!has) {
 116  0
             final AmazonDynamoDB aws = this.credentials.aws();
 117  
             try {
 118  0
                 final GetItemRequest request = new GetItemRequest();
 119  0
                 request.setTableName(this.name);
 120  0
                 request.setAttributesToGet(Collections.singletonList(attr));
 121  0
                 request.setKey(this.attributes.only(this.keys));
 122  0
                 request.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
 123  0
                 request.setConsistentRead(true);
 124  0
                 final long start = System.currentTimeMillis();
 125  0
                 final GetItemResult result = aws.getItem(request);
 126  0
                 has = result.getItem().get(attrib) != null;
 127  0
                 Logger.info(
 128  
                     this, "#has('%s'): %B from DynamoDB, %s, in %[ms]s",
 129  
                     attr, has,
 130  
                     new PrintableConsumedCapacity(
 131  
                         result.getConsumedCapacity()
 132  
                     ).print(),
 133  
                     System.currentTimeMillis() - start
 134  
                 );
 135  0
             } catch (final AmazonClientException ex) {
 136  0
                 throw new IOException(
 137  
                     String.format(
 138  
                         "failed to check existence of \"%s\" at \"%s\" by %s",
 139  
                         attr, this.name, this.keys
 140  
                     ),
 141  
                     ex
 142  
                 );
 143  
             } finally {
 144  0
                 aws.shutdown();
 145  0
             }
 146  
         }
 147  0
         return has;
 148  
     }
 149  
 
 150  
     @Override
 151  
     public AttributeValue get(final String attr) throws IOException {
 152  4
         final String attrib = String.format(Locale.ENGLISH, attr);
 153  2
         AttributeValue value = this.attributes.get(attrib);
 154  2
         if (value == null) {
 155  0
             final AmazonDynamoDB aws = this.credentials.aws();
 156  
             try {
 157  0
                 final GetItemRequest request = new GetItemRequest();
 158  0
                 request.setTableName(this.name);
 159  0
                 request.setAttributesToGet(Collections.singletonList(attrib));
 160  0
                 request.setKey(this.attributes.only(this.keys));
 161  0
                 request.setReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL);
 162  0
                 request.setConsistentRead(true);
 163  0
                 final long start = System.currentTimeMillis();
 164  0
                 final GetItemResult result = aws.getItem(request);
 165  0
                 value = result.getItem().get(attrib);
 166  0
                 Logger.info(
 167  
                     this,
 168  
                     // @checkstyle LineLength (1 line)
 169  
                     "#get('%s'): loaded '%[text]s' from DynamoDB, %s, in %[ms]s",
 170  
                     attrib, value,
 171  
                     new PrintableConsumedCapacity(
 172  
                         result.getConsumedCapacity()
 173  
                     ).print(),
 174  
                     System.currentTimeMillis() - start
 175  
                 );
 176  0
             } catch (final AmazonClientException ex) {
 177  0
                 throw new IOException(
 178  
                     String.format(
 179  
                         "failed to get \"%s\" from \"%s\" by %s",
 180  
                         attr, this.name, this.keys
 181  
                     ),
 182  
                     ex
 183  
                 );
 184  
             } finally {
 185  0
                 aws.shutdown();
 186  0
             }
 187  
         }
 188  2
         if (value == null) {
 189  0
             throw new NoSuchElementException(
 190  
                 String.format("attribute \"%s\" not found", attr)
 191  
             );
 192  
         }
 193  2
         return value;
 194  
     }
 195  
 
 196  
     @Override
 197  
     public Map<String, AttributeValue> put(final String attr,
 198  
         final AttributeValueUpdate value) throws IOException {
 199  0
         return this.put(new AttributeUpdates().with(attr, value));
 200  
     }
 201  
 
 202  
     @Override
 203  
     public Map<String, AttributeValue> put(
 204  
         final Map<String, AttributeValueUpdate> attrs) throws IOException {
 205  0
         final AmazonDynamoDB aws = this.credentials.aws();
 206  0
         final Attributes expected = this.attributes.only(this.keys);
 207  
         try {
 208  0
             final UpdateItemRequest request = new UpdateItemRequest()
 209  
                 .withTableName(this.name)
 210  
                 .withExpected(expected.asKeys())
 211  
                 .withKey(expected)
 212  
                 .withAttributeUpdates(attrs)
 213  
                 .withReturnConsumedCapacity(ReturnConsumedCapacity.TOTAL)
 214  
                 .withReturnValues(ReturnValue.UPDATED_NEW);
 215  0
             final long start = System.currentTimeMillis();
 216  0
             final UpdateItemResult result = aws.updateItem(request);
 217  0
             Logger.info(
 218  
                 this, "#put('%s'): updated item to DynamoDB, %s, in %[ms]s",
 219  
                 attrs,
 220  
                 new PrintableConsumedCapacity(
 221  
                     result.getConsumedCapacity()
 222  
                 ).print(),
 223  
                 System.currentTimeMillis() - start
 224  
             );
 225  0
             return result.getAttributes();
 226  0
         } catch (final AmazonClientException ex) {
 227  0
             throw new IOException(
 228  
                 String.format(
 229  
                     "failed to put %s into \"%s\" with %s",
 230  
                     attrs, this.name, this.keys
 231  
                 ),
 232  
                 ex
 233  
             );
 234  
         } finally {
 235  0
             aws.shutdown();
 236  
         }
 237  
     }
 238  
 
 239  
     @Override
 240  
     public Frame frame() {
 241  0
         return this.frm;
 242  
     }
 243  
 
 244  
 }