View Javadoc
1   /*
2    * Copyright (c) 2012-2022, 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.simpledb;
31  
32  import com.amazonaws.services.simpledb.model.Attribute;
33  import com.amazonaws.services.simpledb.model.DeleteAttributesRequest;
34  import com.amazonaws.services.simpledb.model.GetAttributesRequest;
35  import com.amazonaws.services.simpledb.model.GetAttributesResult;
36  import com.amazonaws.services.simpledb.model.PutAttributesRequest;
37  import com.amazonaws.services.simpledb.model.ReplaceableAttribute;
38  import com.jcabi.aspects.Immutable;
39  import com.jcabi.aspects.Loggable;
40  import java.util.AbstractMap;
41  import java.util.ArrayList;
42  import java.util.Collection;
43  import java.util.HashSet;
44  import java.util.Map;
45  import java.util.Set;
46  import java.util.concurrent.ConcurrentHashMap;
47  import java.util.concurrent.ConcurrentMap;
48  import lombok.EqualsAndHashCode;
49  
50  /**
51   * Single item/row in a SimpleDB table.
52   *
53   * @since 0.1
54   * @checkstyle ClassDataAbstractionCoupling (500 lines)
55   */
56  @Immutable
57  @Loggable(Loggable.DEBUG)
58  @EqualsAndHashCode(of = { "credentials", "table", "label" })
59  @SuppressWarnings("PMD.TooManyMethods")
60  final class AwsItem implements Item {
61  
62      /**
63       * AWS credentials.
64       */
65      private final transient Credentials credentials;
66  
67      /**
68       * Table name.
69       */
70      private final transient String table;
71  
72      /**
73       * Table name.
74       */
75      private final transient String label;
76  
77      /**
78       * Public ctor.
79       * @param creds Credentials
80       * @param tbl Table name
81       * @param item Item name
82       */
83      AwsItem(final Credentials creds, final String tbl,
84          final String item) {
85          this.credentials = creds;
86          this.table = tbl;
87          this.label = item;
88      }
89  
90      /**
91       * Public ctor.
92       * @param creds Credentials
93       * @param tbl Table name
94       * @param item Item name
95       */
96      AwsItem(final Credentials creds, final String tbl,
97          final com.amazonaws.services.simpledb.model.Item item) {
98          this(creds, tbl, item.getName());
99      }
100 
101     @Override
102     public String toString() {
103         return String.format("%s in %s", this.label, this.table);
104     }
105 
106     @Override
107     public String name() {
108         return this.label;
109     }
110 
111     @Override
112     public int size() {
113         return this.entrySet().size();
114     }
115 
116     @Override
117     public boolean isEmpty() {
118         return this.entrySet().isEmpty();
119     }
120 
121     @Override
122     public boolean containsKey(final Object key) {
123         return this.containsKey(key);
124     }
125 
126     @Override
127     public boolean containsValue(final Object value) {
128         return this.containsValue(value);
129     }
130 
131     @Override
132     public String get(final Object key) {
133         final Set<Map.Entry<String, String>> entries = this.entrySet();
134         String value = null;
135         for (final Map.Entry<String, String> entry : entries) {
136             if (entry.getKey().equals(key)) {
137                 value = entry.getValue();
138             }
139         }
140         return value;
141     }
142 
143     @Override
144     public String put(final String key, final String value) {
145         final String before = this.get(key);
146         final ConcurrentMap<String, String> map =
147             new ConcurrentHashMap<>(0);
148         map.put(key, value);
149         this.putAll(map);
150         return before;
151     }
152 
153     @Override
154     public String remove(final Object key) {
155         final String before = this.get(key);
156         this.credentials.aws().deleteAttributes(
157             new DeleteAttributesRequest()
158                 .withDomainName(this.table)
159                 .withItemName(this.label)
160                 .withAttributes(new Attribute().withName(key.toString()))
161         );
162         return before;
163     }
164 
165     @Override
166     @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
167     public void putAll(final Map<? extends String, ? extends String> map) {
168         final Collection<ReplaceableAttribute> attrs =
169             new ArrayList<>(map.size());
170         for (final Map.Entry<?, ?> entry : map.entrySet()) {
171             attrs.add(
172                 new ReplaceableAttribute()
173                     .withName(entry.getKey().toString())
174                     .withValue(entry.getValue().toString())
175                     .withReplace(true)
176             );
177         }
178         this.credentials.aws().putAttributes(
179             new PutAttributesRequest()
180                 .withDomainName(this.table)
181                 .withItemName(this.label)
182                 .withAttributes(attrs)
183         );
184     }
185 
186     @Override
187     public void clear() {
188         this.credentials.aws().deleteAttributes(
189             new DeleteAttributesRequest()
190                 .withDomainName(this.table)
191                 .withItemName(this.label)
192         );
193     }
194 
195     @Override
196     public Set<String> keySet() {
197         final Set<Map.Entry<String, String>> entries = this.entrySet();
198         final Set<String> keys = new HashSet<>(entries.size());
199         for (final Map.Entry<String, String> entry : entries) {
200             keys.add(entry.getValue());
201         }
202         return keys;
203     }
204 
205     @Override
206     public Collection<String> values() {
207         final Set<Map.Entry<String, String>> entries = this.entrySet();
208         final Collection<String> values = new ArrayList<>(entries.size());
209         for (final Map.Entry<String, String> entry : entries) {
210             values.add(entry.getValue());
211         }
212         return values;
213     }
214 
215     @Override
216     @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
217     public Set<Map.Entry<String, String>> entrySet() {
218         final GetAttributesResult result = this.credentials.aws().getAttributes(
219             new GetAttributesRequest()
220                 .withConsistentRead(true)
221                 .withDomainName(this.table)
222                 .withItemName(this.label)
223         );
224         final Set<Map.Entry<String, String>> entries =
225             new HashSet<>(0);
226         for (final Attribute attr : result.getAttributes()) {
227             entries.add(
228                 new AbstractMap.SimpleImmutableEntry<>(
229                     attr.getName(), attr.getValue()
230                 )
231             );
232         }
233         return entries;
234     }
235 
236 }