001package com.nimbusds.infinispan.persistence.dynamodb.config;
002
003
004import java.util.Properties;
005import java.util.Set;
006
007import com.amazonaws.regions.Regions;
008import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
009import com.codahale.metrics.MetricRegistry;
010import net.jcip.annotations.Immutable;
011import org.infinispan.commons.configuration.BuiltBy;
012import org.infinispan.commons.configuration.ConfigurationFor;
013import org.infinispan.commons.configuration.attributes.Attribute;
014import org.infinispan.commons.configuration.attributes.AttributeDefinition;
015import org.infinispan.commons.configuration.attributes.AttributeSet;
016import org.infinispan.commons.util.StringPropertyReplacer;
017import org.infinispan.configuration.cache.AbstractStoreConfiguration;
018import org.infinispan.configuration.cache.AsyncStoreConfiguration;
019import org.infinispan.configuration.cache.SingletonStoreConfiguration;
020
021import com.nimbusds.common.config.LoggableConfiguration;
022import com.nimbusds.infinispan.persistence.dynamodb.DynamoDBItemTransformer;
023import com.nimbusds.infinispan.persistence.dynamodb.DynamoDBStore;
024import com.nimbusds.infinispan.persistence.dynamodb.logging.Loggers;
025
026
027/**
028 * DynamoDB store configuration.
029 */
030@Immutable
031@BuiltBy(DynamoDBStoreConfigurationBuilder.class)
032@ConfigurationFor(DynamoDBStore.class)
033public class DynamoDBStoreConfiguration extends AbstractStoreConfiguration implements LoggableConfiguration {
034        
035        
036        /**
037         * The attribute definition for the DynamoDB endpoint.
038         */
039        static final AttributeDefinition<String> ENDPOINT = AttributeDefinition.builder("endpoint", null, String.class).build();
040        
041        
042        /**
043         * The attribute definition for the AWS region.
044         */
045        static final AttributeDefinition<Regions> REGION = AttributeDefinition.builder("region", Regions.DEFAULT_REGION, Regions.class).build();
046        
047        
048        /**
049         * The attribute definition for the item transformer class.
050         */
051        static final AttributeDefinition<Class> ITEM_TRANSFORMER = AttributeDefinition.builder("recordTransformer", null, Class.class).build();
052        
053        
054        /**
055         * The attribute definition for the query executor class.
056         */
057        static final AttributeDefinition<Class> QUERY_EXECUTOR = AttributeDefinition.builder("queryExecutor", null, Class.class).build();
058        
059        
060        /**
061         * The attribute definition for the indexed DynamoDB table attributes.
062         */
063        static final AttributeDefinition<Set> INDEXED_ATTRIBUTES = AttributeDefinition.builder("indexedAttributes", null, Set.class).build();
064        
065        
066        /**
067         * The attribute definition for making consistent reads.
068         */
069        static final AttributeDefinition<Boolean> CONSISTENT_READS = AttributeDefinition.builder("consistentReads", false, Boolean.class).build();
070        
071        
072        /**
073         * The attribute definition for the read capacity to provision when
074         * creating a new DynamoDB table and indices.
075         */
076        static final AttributeDefinition<Long> READ_CAPACITY = AttributeDefinition.builder("readCapacity", 1L, Long.class).build();
077        
078        
079        /**
080         * The attribute definition for the write capacity to provision when
081         * creating a new DynamoDB table and indices.
082         */
083        static final AttributeDefinition<Long> WRITE_CAPACITY = AttributeDefinition.builder("writeCapacity", 1L, Long.class).build();
084        
085        
086        /**
087         * The attribute definition for creating the DynamoDB table with
088         * encryption at rest.
089         */
090        static final AttributeDefinition<Boolean> ENCRYPTION_AT_REST = AttributeDefinition.builder("encryptionAtRest", false, Boolean.class).build();
091        
092        
093        /**
094         * The attribute definition for the optional DynamoDB table prefix.
095         */
096        static final AttributeDefinition<String> TABLE_PREFIX = AttributeDefinition.builder("tablePrefix", "", String.class).build();
097
098        
099        /**
100         * The attribute definition for an explicit metric registry to use
101         * (other than {@link com.nimbusds.common.monitor.MonitorRegistries}
102         * singleton).
103         */
104        static final AttributeDefinition<MetricRegistry> METRIC_REGISTRY = AttributeDefinition.builder("metricRegistry", null, MetricRegistry.class).build();
105
106        
107        /**
108         * The attribute definition for the optional range key to apply to all
109         * DynamoDB operations.
110         */
111        static final AttributeDefinition<String> APPLY_RANGE_KEY = AttributeDefinition.builder("applyRangeKey", null, String.class).build();
112        
113        
114        /**
115         * The attribute definition for the value of the optional range key.
116         */
117        static final AttributeDefinition<String> RANGE_KEY_VALUE = AttributeDefinition.builder("rangeKeyValue", null, String.class).build();
118        
119        
120        /**
121         * The attribute definition for the enable stream flag.
122         */
123        static final AttributeDefinition<Boolean> ENABLE_STREAM = AttributeDefinition.builder("enableStream", false, Boolean.class).build();
124        
125        
126        /**
127         * The attribute definition for the continuous backups flag.
128         */
129        static final AttributeDefinition<Boolean> ENABLE_CONTINUOUS_BACKUPS = AttributeDefinition.builder("enableContinuousBackups", false, Boolean.class).build();
130        
131        
132        /**
133         * The attribute definition for the enable TTL flag.
134         */
135        static final AttributeDefinition<Boolean> ENABLE_TTL = AttributeDefinition.builder("enableTTL", false, Boolean.class).build();
136        
137        
138        /**
139         * The attribute definition for the expired entries purge limit.
140         */
141        static final AttributeDefinition<Integer> PURGE_LIMIT = AttributeDefinition.builder("purgeLimit", -1, Integer.class).build();
142        
143        
144        /**
145         * The attribute definition for the HTTP proxy host.
146         */
147        static final AttributeDefinition<String> HTTP_PROXY_HOST = AttributeDefinition.builder("httpProxyHost", null, String.class).build();
148        
149        
150        /**
151         * The attribute definition for the HTTP proxy port.
152         */
153        static final AttributeDefinition<Integer> HTTP_PROXY_PORT = AttributeDefinition.builder("httpProxyPort", -1, Integer.class).build();
154        
155        
156        /**
157         * The attribute definition for the HMAC SHA-256 key.
158         */
159        static final AttributeDefinition<String> HMAC_SHA_256_KEY = AttributeDefinition.builder("hmacSHA256Key", null, String.class).build();
160        
161        
162        /**
163         * Returns the attribute definitions for the DynamoDB store configuration.
164         *
165         * @return The attribute definitions.
166         */
167        public static AttributeSet attributeDefinitionSet() {
168                return new AttributeSet(DynamoDBStoreConfiguration.class,
169                        AbstractStoreConfiguration.attributeDefinitionSet(),
170                        ENDPOINT,
171                        REGION,
172                        ITEM_TRANSFORMER,
173                        QUERY_EXECUTOR,
174                        INDEXED_ATTRIBUTES,
175                        CONSISTENT_READS,
176                        READ_CAPACITY,
177                        WRITE_CAPACITY,
178                        ENCRYPTION_AT_REST,
179                        TABLE_PREFIX,
180                        APPLY_RANGE_KEY,
181                        RANGE_KEY_VALUE,
182                        ENABLE_STREAM,
183                        METRIC_REGISTRY,
184                        ENABLE_CONTINUOUS_BACKUPS,
185                        ENABLE_TTL,
186                        PURGE_LIMIT,
187                        HTTP_PROXY_HOST,
188                        HTTP_PROXY_PORT,
189                        HMAC_SHA_256_KEY);
190        }
191        
192        
193        /**
194         * The DynamoDB endpoint. If set region is overridden (ignored).
195         */
196        private final Attribute<String> endpoint;
197        
198        
199        /**
200         * The AWS region.
201         */
202        private final Attribute<Regions> region;
203        
204        
205        /**
206         * The class for transforming between Infinispan entries (key / value
207         * pair and optional metadata) and a corresponding DynamoDB item.
208         *
209         * <p>See {@link DynamoDBItemTransformer}.
210         */
211        private final Attribute<Class> itemTransformerClass;
212        
213        
214        /**
215         * Optional class for executing direct DynamoDB queries against
216         * DynamoDB.
217         *
218         * <p>See {@link com.nimbusds.infinispan.persistence.common.query.QueryExecutor}
219         */
220        private final Attribute<Class> queryExecutorClass;
221        
222        
223        /**
224         * Optional set of the indexed DynamoDB attributes.
225         */
226        private final Attribute<Set> indexedAttributes;
227        
228        
229        /**
230         * The consistent read flag.
231         */
232        private final Attribute<Boolean> consistentRead;
233        
234        
235        /**
236         * The optional DynamoDB table prefix.
237         */
238        private final Attribute<String> tablePrefix;
239        
240        
241        /**
242         * The read capacity to provision when creating a new DynamoDB table
243         * and indices.
244         */
245        private final Attribute<Long> readCapacity;
246        
247        
248        /**
249         * The write capacity to provision when creating a new DynamoDB table
250         * and indices.
251         */
252        private final Attribute<Long> writeCapacity;
253        
254        
255        /**
256         * To create the DynamoDB table with encryption at rest.
257         */
258        private final Attribute<Boolean> encryptionAtRest;
259        
260        
261        /**
262         * The optional range key to apply to all DynamoDB operations.
263         */
264        private final Attribute<String> applyRangeKey;
265        
266        
267        /**
268         * The value of the optional range key.
269         */
270        private final Attribute<String> rangeKeyValue;
271        
272        
273        /**
274         * The stream enable flag.
275         */
276        private final Attribute<Boolean> enableStream;
277        
278        
279        /**
280         * The explicit metric registry to use.
281         */
282        private final Attribute<MetricRegistry> metricRegistry;
283        
284        
285        /**
286         * The continuous backups / point in time recovery flag.
287         */
288        private final Attribute<Boolean> enableContinuousBackups;
289        
290        
291        /**
292         * The enable TTL flag.
293         */
294        private final Attribute<Boolean> enableTTL;
295        
296        
297        /**
298         * The expired entries purge limit.
299         */
300        private final Attribute<Integer> purgeLimit;
301        
302        
303        /**
304         * The HTTP proxy host.
305         */
306        private final Attribute<String> httpProxyHost;
307        
308        
309        /**
310         * The HTTP proxy port.
311         */
312        private final Attribute<Integer> httpProxyPort;
313        
314        
315        /**
316         * The HMAC SHA-256 key (BASE 64 encoded).
317         */
318        private final Attribute<String> hmacSHA256Key;
319
320
321        /**
322         * Creates a new DynamoDB store configuration.
323         *
324         * @param attributes           The configuration attributes. Must not
325         *                             be {@code null}.
326         * @param asyncConfig          Configuration for the async cache
327         *                             loader.
328         * @param singletonStoreConfig Configuration for a singleton store.
329         */
330        public DynamoDBStoreConfiguration(final AttributeSet attributes,
331                                          final AsyncStoreConfiguration asyncConfig,
332                                          final SingletonStoreConfiguration singletonStoreConfig) {
333
334                super(attributes, asyncConfig, singletonStoreConfig);
335                
336                endpoint = attributes.attribute(ENDPOINT);
337                assert endpoint != null;
338                
339                region = attributes.attribute(REGION);
340                assert region != null;
341                
342                itemTransformerClass = attributes.attribute(ITEM_TRANSFORMER);
343                assert itemTransformerClass != null;
344                
345                queryExecutorClass = attributes.attribute(QUERY_EXECUTOR);
346                
347                indexedAttributes = attributes.attribute(INDEXED_ATTRIBUTES);
348                
349                consistentRead = attributes.attribute(CONSISTENT_READS);
350                
351                readCapacity = attributes.attribute(READ_CAPACITY);
352                assert readCapacity != null;
353                
354                writeCapacity = attributes.attribute(WRITE_CAPACITY);
355                assert writeCapacity != null;
356                
357                encryptionAtRest = attributes.attribute(ENCRYPTION_AT_REST);
358                
359                tablePrefix = attributes.attribute(TABLE_PREFIX);
360                assert tablePrefix != null;
361                
362                applyRangeKey = attributes.attribute(APPLY_RANGE_KEY);
363                assert applyRangeKey != null;
364                
365                rangeKeyValue = attributes.attribute(RANGE_KEY_VALUE);
366                assert rangeKeyValue != null;
367                
368                enableStream = attributes.attribute(ENABLE_STREAM);
369                assert enableStream != null;
370                
371                enableContinuousBackups = attributes.attribute(ENABLE_CONTINUOUS_BACKUPS);
372                assert enableContinuousBackups != null;
373                
374                enableTTL = attributes.attribute(ENABLE_TTL);
375                assert enableTTL != null;
376                
377                purgeLimit = attributes.attribute(PURGE_LIMIT);
378                
379                httpProxyHost = attributes.attribute(HTTP_PROXY_HOST);
380                
381                httpProxyPort = attributes.attribute(HTTP_PROXY_PORT);
382                
383                hmacSHA256Key = attributes.attribute(HMAC_SHA_256_KEY);
384
385                metricRegistry = attributes.attribute(METRIC_REGISTRY);
386        }
387        
388        
389        /**
390         * Returns the DynamoDB endpoint.
391         *
392         * @return The DynamoDB endpoint, {@code null} if not set.
393         */
394        public String getEndpoint() {
395                
396                return endpoint.get();
397        }
398        
399        
400        /**
401         * Returns the AWS region.
402         *
403         * @return The AWS region.
404         */
405        public Regions getRegion() {
406                
407                return region.get();
408        }
409        
410        
411        /**
412         * Returns the class for transforming between Infinispan entries (key /
413         * value pairs and optional metadata) and a corresponding DynamoDB
414         * item.
415         *
416         * <p>See {@link DynamoDBItemTransformer}.
417         *
418         * @return The item transformer class.
419         */
420        public Class getItemTransformerClass() {
421                
422                return itemTransformerClass.get();
423        }
424        
425        
426        /**
427         * Returns the optional class for executing direct queries against
428         * DynamoDB.
429         *
430         * <p>See {@link com.nimbusds.infinispan.persistence.common.query.QueryExecutor}
431         *
432         * @return The query executor class, {@code null} if not specified.
433         */
434        public Class getQueryExecutorClass() {
435                
436                return queryExecutorClass.get();
437        }
438        
439        
440        /**
441         * Returns the optional indexed DynamoDB attributes.
442         *
443         * <p>See {@link #getQueryExecutorClass}
444         *
445         * @return The indexed attributes, {@code null} if no specified.
446         */
447        @SuppressWarnings("unchecked")
448        public Set<String> getIndexedAttributes() {
449                
450                return (Set<String>) indexedAttributes.get();
451        }
452        
453        
454        /**
455         * Returns the consistent reads flag.
456         *
457         * @return {@code true} for strong consistent reads, {@code false} for
458         *         eventually consistent.
459         */
460        public boolean isConsistentReads() {
461                
462                return consistentRead.get();
463        }
464        
465        
466        /**
467         * Returns the read and write capacity to provision when creating a new
468         * DynamoDB table.
469         *
470         * @return The read and write capacity.
471         */
472        public ProvisionedThroughput getProvisionedThroughput() {
473                
474                return new ProvisionedThroughput(readCapacity.get(), writeCapacity.get());
475        }
476        
477        
478        /**
479         * Returns the setting for creating the DynamoDB table with encryption
480         * at rest.
481         *
482         * @return {@code true} to create the table with encryption at rest,
483         *         {@code false} with no encryption.
484         */
485        public boolean isTableWithEncryptionAtRest() {
486                
487                return encryptionAtRest.get();
488        }
489        
490        
491        /**
492         * Returns the optional DynamoDB table prefix.
493         *
494         * @return The DynamoDB table prefix, empty string if not set.
495         */
496        public String getTablePrefix() {
497                
498                return tablePrefix.get();
499        }
500        
501        
502        /**
503         * Returns the name of the optional range key to apply to all DynamoDB
504         * operations.
505         *
506         * @return The range key name, {@code null} if not specified.
507         */
508        public String getApplyRangeKey() {
509                
510                return applyRangeKey.get();
511        }
512        
513        
514        /**
515         * Returns the value of the optional range key.
516         *
517         * @return The range key value, {@code null} if not specified.
518         */
519        public String getRangeKeyValue() {
520                
521                return rangeKeyValue.get();
522        }
523        
524        
525        /**
526         * Returns the value of the enable stream flag.
527         *
528         * @return The enable stream flag.
529         */
530        public boolean isEnableStream() {
531                
532                return enableStream.get();
533        }
534        
535        
536        /**
537         * Returns the value of the enable continuous backups / point in time
538         * recovery flag.
539         *
540         * @return The continuous backups flag.
541         */
542        public boolean isEnableContinuousBackups() {
543                
544                return enableContinuousBackups.get();
545        }
546        
547        
548        /**
549         * Returns the values of the enable TTL flag.
550         *
551         * @return The enable TTL flag.
552         */
553        public boolean isEnableTTL() {
554                
555                return enableTTL.get();
556        }
557        
558        
559        /**
560         * Returns the expired items purge limit.
561         *
562         * @return The expired items purge limit, -1 for no limit.
563         */
564        public int getPurgeLimit() {
565                
566                return purgeLimit.get();
567        }
568        
569        
570        /**
571         * Returns the HTTP proxy host.
572         *
573         * @return The host, {@code null} if none.
574         */
575        public String getHTTPProxyHost() {
576                
577                return httpProxyHost.get();
578        }
579        
580        
581        /**
582         * Returns the HTTP proxy port.
583         *
584         * @return The port, -1 if not specified.
585         */
586        public int getHTTPProxyPort() {
587                
588                return httpProxyPort.get();
589        }
590        
591        
592        /**
593         * Returns the HMAC SHA-256 key.
594         *
595         * @return The HMAC SHA-256 key (BASE 64 encoded), {@code null} if not
596         *         specified.
597         */
598        public String getHMACSHA256Key() {
599        
600                return hmacSHA256Key.get();
601        }
602        
603        
604        /**
605         * Returns the explicit metric registry to use.
606         *
607         * @return The metric registry instance.
608         */
609        public MetricRegistry getMetricRegistry() {
610                
611                return metricRegistry.get();
612        }
613        
614        
615        @Override
616        public Properties properties() {
617                
618                // Interpolate with system properties where ${sysPropName} is found
619                
620                Properties interpolatedProps = new Properties();
621                
622                for (String name : super.properties().stringPropertyNames()) {
623                        interpolatedProps.setProperty(name, StringPropertyReplacer.replaceProperties(super.properties().getProperty(name)));
624                }
625                
626                return interpolatedProps;
627        }
628        
629        
630        @Override
631        public void log() {
632                
633                Loggers.MAIN_LOG.info("[DS0000] Infinispan DynamoDB store: Endpoint (overrides region): {}", getEndpoint() != null ? getEndpoint() : "not set");
634                Loggers.MAIN_LOG.info("[DS0001] Infinispan DynamoDB store: Region: {}", getRegion());
635                Loggers.MAIN_LOG.info("[DS0002] Infinispan DynamoDB store: Item transformer class: {}", getItemTransformerClass().getCanonicalName());
636                Loggers.MAIN_LOG.info("[DS0009] Infinispan DynamoDB store: Query executor class: {}", getQueryExecutorClass() != null ? getQueryExecutorClass().getCanonicalName() : "none");
637                Loggers.MAIN_LOG.info("[DS0010] Infinispan DynamoDB store: Indexed attributes: {}", getIndexedAttributes() != null ? getIndexedAttributes() : "none");
638                Loggers.MAIN_LOG.info("[DS0015] Infinispan DynamoDB store: Consistent reads: {}", isConsistentReads());
639                Loggers.MAIN_LOG.info("[DS0004] Infinispan DynamoDB store: AWS secret access key: [hidden]");
640                Loggers.MAIN_LOG.info("[DS0005] Infinispan DynamoDB store: Capacity to provision: read={} write={}", getProvisionedThroughput().getReadCapacityUnits(), getProvisionedThroughput().getWriteCapacityUnits());
641                Loggers.MAIN_LOG.info("[DS0011] Infinispan DynamoDB store: Table encryption at rest: {}", isTableWithEncryptionAtRest());
642                Loggers.MAIN_LOG.info("[DS0006] Infinispan DynamoDB store: Table prefix: {}", getTablePrefix().isEmpty() ? "none" : getTablePrefix());
643                Loggers.MAIN_LOG.info("[DS0007] Infinispan DynamoDB store: Apply range key: {}", getApplyRangeKey() != null ? getApplyRangeKey() : "none");
644                Loggers.MAIN_LOG.info("[DS0008] Infinispan DynamoDB store: Range key value: {}", getRangeKeyValue() != null ? getRangeKeyValue() : "none");
645                Loggers.MAIN_LOG.info("[DS0003] Infinispan DynamoDB store: Enable stream: {}", isEnableStream());
646                Loggers.MAIN_LOG.info("[DS0012] Infinispan DynamoDB store: Enable continuous backups: {}", isEnableContinuousBackups());
647                Loggers.MAIN_LOG.info("[DS0014] Infinispan DynamoDB store: Enable TTL: {}", isEnableTTL());
648                Loggers.MAIN_LOG.info("[DS0016] Infinispan DynamoDB store: Expired entries purge limit: {}", this::getPurgeLimit);
649                Loggers.MAIN_LOG.info("[DS0017] Infinispan DynamoDB store: HTTP proxy host: {}", getHTTPProxyHost() != null ? getHTTPProxyHost() : "none");
650                Loggers.MAIN_LOG.info("[DS0018] Infinispan DynamoDB store: HTTP proxy port: {}", getHTTPProxyPort());
651                Loggers.MAIN_LOG.info("[DS0019] Infinispan DynamoDB store: HMAC SHA-256 key: {}", getHMACSHA256Key() != null ? "configured" : "none");
652                Loggers.MAIN_LOG.info("[DS0013] Infinispan DynamoDB store: Explicit metric registry: {}", getMetricRegistry() != null);
653        }
654}