com.nimbusds.infinispan.persistence.dynamodb.RequestFactory Maven / Gradle / Ivy
package com.nimbusds.infinispan.persistence.dynamodb;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Set;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.ItemCollection;
import com.amazonaws.services.dynamodbv2.document.RangeKeyCondition;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.document.spec.DeleteItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.GetItemSpec;
import com.amazonaws.services.dynamodbv2.document.spec.QuerySpec;
import com.amazonaws.services.dynamodbv2.document.spec.ScanSpec;
import com.amazonaws.services.dynamodbv2.model.*;
import com.nimbusds.infinispan.persistence.common.InfinispanEntry;
import org.apache.commons.lang3.StringUtils;
import org.infinispan.persistence.spi.PersistenceException;
/**
* DynamoDB request factory. This class is thread-safe.
*/
class RequestFactory {
/**
* The DynamoDB table name.
*/
private final String tableName;
/**
* The DynamoDB item transformer.
*/
private final DynamoDBItemTransformer itemTransformer;
/**
* The indexed (GSI) DynamoDB table attributes.
*/
private final Set indexAttributes;
/**
* The DynamoDB provisioned read and write capacity.
*/
private final ProvisionedThroughput rwCapacity;
/**
* The name of the optional range key to apply to all DynamoDB
* operations.
*/
private final String rangeKeyName;
/**
* The value of the optional range key.
*/
private final String rangeKeyValue;
/**
* Determines if the optional range key must be applied to all DynamoDB
* operations.
*/
private final boolean applyRangeKey;
/**
* Creates a new DynamoDB request factory.
*
* @param itemTransformer The DynamoDB item transformer.
* @param indexAttributes The indexed DynamoDB attributes, {@code null}
* if not specified.
* @param rwCapacity The provisioned read and write capacity.
* @param tablePrefix The optional DynamoDB table prefix to use,
* empty string if none.
* @param rangeKeyName The name of the optional range key to apply to
* all DynamoDB operations, {@code null} if not
* specified.
* @param rangeKeyValue The value of the optional range key, {@code
* null} if not specified.
*/
RequestFactory(final DynamoDBItemTransformer itemTransformer,
final Set indexAttributes,
final ProvisionedThroughput rwCapacity,
final String tablePrefix,
final String rangeKeyName,
final String rangeKeyValue) {
assert itemTransformer != null;
this.itemTransformer = itemTransformer;
this.indexAttributes = indexAttributes;
assert tablePrefix != null;
this.tableName = tablePrefix + itemTransformer.getTableName();
assert rwCapacity != null;
this.rwCapacity = rwCapacity;
this.rangeKeyName = rangeKeyName;
this.rangeKeyValue = rangeKeyValue;
applyRangeKey = StringUtils.isNotBlank(rangeKeyName);
}
/**
* Returns {@code true} if a range key is configured to be applied to
* all DynamoDB operations.
*
* @return {@code true} if a range key is configured, else {@code
* false}.
*/
boolean appliesRangeKey() {
return applyRangeKey;
}
/**
* Returns the configured DynamoDB item transformer.
*
* @return The DynamoDB item transformer.
*/
DynamoDBItemTransformer getItemTransformer() {
return itemTransformer;
}
/**
* Returns the final table name.
*
* @return The table name.
*/
String getTableName() {
return tableName;
}
/**
* Returns the name of the global secondary index (GSI) for the optional
* range key if configured.
*
* @return The range key GSI name, {@code null} if a range key is not
* configured.
*/
String getRangeKeyGSIName() {
return applyRangeKey ? tableName + "-" + rangeKeyName + "-gsi" : null;
}
/**
* Returns the name of the global secondary index (GSI) for the
* specified attribute.
*
* @param attr The attribute name.
*
* @return The GSI name.
*/
String getGSIName(final String attr) {
return tableName + "-" + attr + "-gsi";
}
/**
* Returns a create table request.
*
* @return The create table request.
*/
CreateTableRequest resolveCreateTableRequest() {
Collection keyAttrs = new LinkedList<>();
keyAttrs.add(new KeySchemaElement(itemTransformer.getHashKeyAttributeName(), KeyType.HASH));
Collection attrs = new LinkedList<>();
attrs.add(new AttributeDefinition(itemTransformer.getHashKeyAttributeName(), ScalarAttributeType.S));
Collection gsIndices = new LinkedList<>();
if (applyRangeKey) {
keyAttrs.add(new KeySchemaElement(rangeKeyName, KeyType.RANGE));
attrs.add(new AttributeDefinition(rangeKeyName, ScalarAttributeType.S));
gsIndices.add(new GlobalSecondaryIndex()
.withIndexName(getRangeKeyGSIName())
.withKeySchema(new KeySchemaElement(rangeKeyName, KeyType.HASH))
.withProjection(new Projection().withProjectionType(ProjectionType.ALL))
.withProvisionedThroughput(rwCapacity));
}
if (indexAttributes != null) {
// indexed attributes
for (String a : indexAttributes) {
attrs.add(new AttributeDefinition(a, ScalarAttributeType.S));
gsIndices.add(new GlobalSecondaryIndex()
.withIndexName(getGSIName(a))
.withKeySchema(new KeySchemaElement(a, KeyType.HASH))
.withProjection(new Projection().withProjectionType(ProjectionType.ALL))
.withProvisionedThroughput(rwCapacity)
);
}
}
CreateTableRequest createTableRequest = new CreateTableRequest()
.withTableName(tableName)
.withProvisionedThroughput(rwCapacity)
.withKeySchema(keyAttrs)
.withAttributeDefinitions(attrs);
if (!gsIndices.isEmpty()) {
createTableRequest.withGlobalSecondaryIndexes(gsIndices);
}
return createTableRequest;
}
/**
* Resolves the DynamoDB hash key.
*
* @param key The Infinispan entry key.
*
* @return The DynamoDB hash key.
*/
@SuppressWarnings("unchecked")
private String resolveHashKey(final Object key) {
if (key instanceof byte[]) {
throw new PersistenceException("Cannot resolve " + itemTransformer.getTableName() + " key from byte[], enable compatibility mode");
}
return itemTransformer.resolveHashKey((K) key);
}
/**
* Returns the DynamoDB get item spec for the specified key.
*
* @param key The key.
*
* @return The get item spec.
*/
GetItemSpec resolveGetItemSpec(final Object key) {
if (applyRangeKey) {
return new GetItemSpec().withPrimaryKey(
itemTransformer.getHashKeyAttributeName(),
resolveHashKey(key),
rangeKeyName,
rangeKeyValue);
}
return new GetItemSpec().withPrimaryKey(
itemTransformer.getHashKeyAttributeName(),
resolveHashKey(key));
}
/**
* Returns the DynamoDB item for the specified Infinispan entry.
*
* @param infinispanEntry The Infinispan entry.
*
* @return The DynamoDB item.
*/
Item resolveItem(final InfinispanEntry infinispanEntry) {
Item item = itemTransformer.toItem(infinispanEntry);
item = applyOptionalRangeKey(item);
return item;
}
/**
* Returns the DynamoDB delete item spec for the specified key.
*
* @param key The key.
*
* @return The delete item spec.
*/
DeleteItemSpec resolveDeleteItemSpec(final Object key) {
DeleteItemSpec spec = new DeleteItemSpec();
if (applyRangeKey) {
spec.withPrimaryKey(
itemTransformer.getHashKeyAttributeName(),
resolveHashKey(key),
rangeKeyName,
rangeKeyValue);
} else {
spec.withPrimaryKey(
itemTransformer.getHashKeyAttributeName(),
resolveHashKey(key));
}
return spec.withReturnValues(ReturnValue.ALL_OLD); // to confirm deletion
}
/**
* Returns the result of a request to get all items from the specified
* DynamoDB table.
*
* @param table The DynamoDB table.
*
* @return The iterable item collection.
*/
ItemCollection> getAllItems(final Table table) {
if (applyRangeKey) {
RangeKeyCondition c = new RangeKeyCondition(rangeKeyName).eq(rangeKeyValue);
return table.getIndex(getRangeKeyGSIName()).query(new QuerySpec().withRangeKeyCondition(c));
}
return table.scan(new ScanSpec());
}
/**
* Applies the optional range key to the specified DynamoDB item (for
* writing).
*
* @param item The DynamoDB item.
*
* @return The resulting DynamoDB item.
*/
Item applyOptionalRangeKey(final Item item) {
if (!applyRangeKey) {
return item;
}
Object hashKeyValue = item.get(itemTransformer.getHashKeyAttributeName());
if (hashKeyValue == null) {
throw new PersistenceException("Missing hash key in transformed DynamoDB item: " + itemTransformer.getHashKeyAttributeName());
}
return item.withPrimaryKey(
itemTransformer.getHashKeyAttributeName(),
hashKeyValue,
rangeKeyName,
rangeKeyValue
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy