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}