Coverage Report - co.stateful.core.DyLocks
 
Classes in this File Line Coverage Branch Coverage Complexity
DyLocks
0%
0/34
0%
0/14
2.167
DyLocks$1
0%
0/6
N/A
2.167
DyLocks$AjcClosure1
0%
0/1
N/A
2.167
DyLocks$AjcClosure3
0%
0/1
N/A
2.167
DyLocks$AjcClosure5
0%
0/1
N/A
2.167
DyLocks$AjcClosure7
0%
0/1
N/A
2.167
 
 1  0
 /**
 2  
  * Copyright (c) 2014, stateful.co
 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 stateful.co 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 co.stateful.core;
 31  
 
 32  
 import co.stateful.spi.Locks;
 33  
 import com.amazonaws.AmazonClientException;
 34  
 import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
 35  
 import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
 36  
 import com.amazonaws.services.dynamodbv2.model.ExpectedAttributeValue;
 37  
 import com.amazonaws.services.dynamodbv2.model.PutItemRequest;
 38  
 import com.google.common.base.Predicate;
 39  
 import com.google.common.base.Predicates;
 40  
 import com.google.common.collect.ImmutableMap;
 41  
 import com.google.common.collect.Iterables;
 42  
 import com.jcabi.aspects.Immutable;
 43  
 import com.jcabi.aspects.Loggable;
 44  
 import com.jcabi.dynamo.Attributes;
 45  
 import com.jcabi.dynamo.Conditions;
 46  
 import com.jcabi.dynamo.Item;
 47  
 import com.jcabi.dynamo.QueryValve;
 48  
 import com.jcabi.dynamo.Table;
 49  
 import com.jcabi.urn.URN;
 50  
 import java.io.IOException;
 51  
 import java.util.Iterator;
 52  
 import java.util.Map;
 53  
 import lombok.EqualsAndHashCode;
 54  
 import lombok.ToString;
 55  
 
 56  
 /**
 57  
  * Locks in DynamoDB.
 58  
  *
 59  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 60  
  * @version $Id$
 61  
  * @since 1.1
 62  
  */
 63  
 @Immutable
 64  0
 @ToString
 65  0
 @EqualsAndHashCode(of = "owner")
 66  
 @Loggable(Loggable.DEBUG)
 67  
 final class DyLocks implements Locks {
 68  
 
 69  
     /**
 70  
      * Table name.
 71  
      */
 72  
     public static final String TBL = "locks";
 73  
 
 74  
     /**
 75  
      * Hash.
 76  
      */
 77  
     public static final String HASH = "urn";
 78  
 
 79  
     /**
 80  
      * Range.
 81  
      */
 82  
     public static final String RANGE = "name";
 83  
 
 84  
     /**
 85  
      * Label.
 86  
      */
 87  
     public static final String ATTR_LABEL = "label";
 88  
 
 89  
     /**
 90  
      * Dynamo table.
 91  
      */
 92  
     private final transient Table table;
 93  
 
 94  
     /**
 95  
      * Name of the user.
 96  
      */
 97  
     private final transient URN owner;
 98  
 
 99  
     /**
 100  
      * Ctor.
 101  
      * @param tbl Dynamo table
 102  
      * @param urn Owner of them
 103  
      */
 104  0
     DyLocks(final Table tbl, final URN urn) {
 105  0
         this.table = tbl;
 106  0
         this.owner = urn;
 107  0
     }
 108  
 
 109  
     @Override
 110  
     public Map<String, String> names() {
 111  0
         final ImmutableMap.Builder<String, String> map =
 112  
             new ImmutableMap.Builder<String, String>();
 113  0
         Iterables.all(
 114  
             this.table.frame().through(
 115  
                 new QueryValve().withAttributesToGet(
 116  
                     DyLocks.ATTR_LABEL
 117  
                 )
 118  
             ).where(DyLocks.HASH, Conditions.equalTo(this.owner)),
 119  0
             new Predicate<Item>() {
 120  
                 @Override
 121  
                 public boolean apply(final Item item) {
 122  
                     try {
 123  0
                         map.put(
 124  
                             item.get(DyLocks.RANGE).getS(),
 125  
                             item.get(DyLocks.ATTR_LABEL).getS()
 126  
                         );
 127  0
                     } catch (final IOException ex) {
 128  0
                         throw new IllegalStateException(ex);
 129  0
                     }
 130  0
                     return true;
 131  
                 }
 132  
             }
 133  
         );
 134  0
         return map.build();
 135  
     }
 136  
 
 137  
     @Override
 138  
     public String lock(final String name, final String label)
 139  
         throws IOException {
 140  0
         final AmazonDynamoDB aws = this.table.region().aws();
 141  0
         String msg = "";
 142  
         try {
 143  0
             final PutItemRequest request = new PutItemRequest();
 144  0
             request.setTableName(this.table.name());
 145  0
             request.setItem(
 146  
                 new Attributes()
 147  
                     .with(DyLocks.HASH, this.owner)
 148  
                     .with(DyLocks.RANGE, name)
 149  
                     .with(DyLocks.ATTR_LABEL, label)
 150  
             );
 151  0
             request.setExpected(
 152  
                 new ImmutableMap.Builder<String, ExpectedAttributeValue>().put(
 153  
                     DyLocks.ATTR_LABEL,
 154  
                     new ExpectedAttributeValue().withExists(false)
 155  
                 ).build()
 156  
             );
 157  0
             aws.putItem(request);
 158  0
         } catch (final ConditionalCheckFailedException ex) {
 159  0
             msg = ex.getLocalizedMessage();
 160  0
         } catch (final AmazonClientException ex) {
 161  0
             throw new IOException(ex);
 162  
         } finally {
 163  0
             aws.shutdown();
 164  0
         }
 165  0
         return msg;
 166  
     }
 167  
 
 168  
     @Override
 169  
     public void unlock(final String name) {
 170  0
         Iterables.removeIf(
 171  
             this.table.frame()
 172  
                 .through(new QueryValve())
 173  
                 .where(DyLocks.HASH, this.owner.toString())
 174  
                 .where(DyLocks.RANGE, name),
 175  
             Predicates.alwaysTrue()
 176  
         );
 177  0
     }
 178  
 
 179  
     @Override
 180  
     public String unlock(final String name, final String label)
 181  
         throws IOException {
 182  0
         final Iterator<Item> items = this.table.frame()
 183  
             .through(new QueryValve())
 184  
             .where(DyLocks.HASH, this.owner.toString())
 185  
             .where(DyLocks.RANGE, name)
 186  
             .iterator();
 187  0
         String msg = "";
 188  0
         if (items.hasNext()) {
 189  0
             final String required = items.next().get(DyLocks.ATTR_LABEL).getS();
 190  0
             if (required.equals(label)) {
 191  0
                 this.unlock(name);
 192  
             } else {
 193  0
                 msg = required;
 194  
             }
 195  
         }
 196  0
         return msg;
 197  
     }
 198  
 }