Skip to content

Commit

Permalink
Merge f462dc2 into 1eb036c
Browse files Browse the repository at this point in the history
  • Loading branch information
faisalferoz committed Nov 19, 2018
2 parents 1eb036c + f462dc2 commit ea49843
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public interface CreateTable {

boolean isTable(String tableName);

CreateTableResult createTable(String tableName, String hashKeyName);
CreateTableResult createTable(Class<?> type);

boolean waitTableExists(String tableName, long secondsBetweenPolls, long timeoutSeconds);
void waitTableActive(String tableName, int timeoutSeconds, int interval);

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,111 +16,70 @@

package com.github.wonwoo.dynamodb.autoconfigure;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.amazonaws.AmazonClientException;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.model.*;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;
import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex;
import com.amazonaws.services.dynamodbv2.model.ListTablesResult;
import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazonaws.services.dynamodbv2.util.TableUtils;

/**
* @author wonwoo
*/
public class DynamoDbCreateTable implements CreateTable {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

private Long readCapacityUnits = 10L;
private Long writeCapacityUnits = 10L;

private final AmazonDynamoDB amazonDynamoDB;

public DynamoDbCreateTable(AmazonDynamoDB amazonDynamoDB) {
this.amazonDynamoDB = amazonDynamoDB;
}
private final DynamoDBMapper dynamoDBMapper;

@Override
public boolean isTable(String tableName) {
ListTablesResult tables = amazonDynamoDB.listTables();
List<String> tableNames = tables.getTableNames();
return tableNames.size() != 0 && tableNames.stream().anyMatch(s -> s.equals(tableName));
public DynamoDbCreateTable(final AmazonDynamoDB amazonDynamoDB) {
this.amazonDynamoDB = amazonDynamoDB;
this.dynamoDBMapper = new DynamoDBMapper(amazonDynamoDB);
}

@Override
public CreateTableResult createTable(String tableName, String hashKeyName) {
List<AttributeDefinition> attributeDefinitions = new ArrayList<>();
attributeDefinitions.add(new AttributeDefinition(hashKeyName, ScalarAttributeType.S));
List<KeySchemaElement> ks = new ArrayList<>();
ks.add(new KeySchemaElement(hashKeyName, KeyType.HASH));
ProvisionedThroughput provisionedthroughput =
new ProvisionedThroughput(this.readCapacityUnits, this.writeCapacityUnits);
CreateTableRequest request =
new CreateTableRequest()
.withTableName(tableName)
.withAttributeDefinitions(attributeDefinitions)
.withKeySchema(ks)
.withProvisionedThroughput(provisionedthroughput);

return amazonDynamoDB.createTable(request);
}

private TableStatus tableStatus(String tableName) {
DescribeTableRequest request = new DescribeTableRequest();
request.setTableName(tableName);
try {
DescribeTableResult result = amazonDynamoDB.describeTable(request);
TableStatus tableStatus = TableStatus.fromValue(result.getTable().getTableStatus());
logger.debug("table status {} ", tableStatus);
return tableStatus;
} catch (ResourceNotFoundException e) {
logger.debug("ResourceNotFound is TableName {}", tableName);
return null;
} catch (AmazonClientException e) {
logger.error("Unknown error ", e);
throw new IllegalStateException("Unknown Exception", e);
}
public boolean isTable(final String tableName) {
final ListTablesResult tables = amazonDynamoDB.listTables();
final List<String> tableNames = tables.getTableNames();
return tableNames.stream().anyMatch(s -> s.equals(tableName));
}

@Override
public boolean waitTableExists(String tableName, long secondsPolls, long timeout) {
long sleepTime = TimeUnit.SECONDS.toMillis(timeout);

while (!leaseTableExists(tableName)) {
if (sleepTime <= 0) {
return false;
public CreateTableResult createTable(final Class<?> type) {
final ProvisionedThroughput provisionedthroughput =
new ProvisionedThroughput(this.readCapacityUnits, this.writeCapacityUnits);
final CreateTableRequest request = dynamoDBMapper.generateCreateTableRequest(type).withProvisionedThroughput(provisionedthroughput);
if (request.getGlobalSecondaryIndexes() != null) {
// have to set provisioned throughput of gsi as well
for (final GlobalSecondaryIndex gsi : request.getGlobalSecondaryIndexes()) {
gsi.setProvisionedThroughput(provisionedthroughput);
}
long timeToSleepMillis = Math.min(TimeUnit.SECONDS.toMillis(secondsPolls), sleepTime);
sleepTime -= sleep(timeToSleepMillis);
}

return true;
}

private boolean leaseTableExists(String tableName) {
return TableStatus.ACTIVE == tableStatus(tableName);
return amazonDynamoDB.createTable(request);
}

private long sleep(long timeToSleepMillis) {
long startTime = System.currentTimeMillis();

@Override
public void waitTableActive(final String tableName, final int timeout, final int interval) {
try {
Thread.sleep(timeToSleepMillis);
} catch (InterruptedException e) {
logger.info("Interrupted while sleeping");
TableUtils.waitUntilActive(amazonDynamoDB, tableName, timeout, interval);
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}

return System.currentTimeMillis() - startTime;
}

public void setReadCapacityUnits(Long readCapacityUnits) {
public void setReadCapacityUnits(final Long readCapacityUnits) {
this.readCapacityUnits = readCapacityUnits;
}

public void setWriteCapacityUnits(Long writeCapacityUnits) {
public void setWriteCapacityUnits(final Long writeCapacityUnits) {
this.writeCapacityUnits = writeCapacityUnits;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
import org.socialsignin.spring.data.dynamodb.mapping.DynamoDBPersistentProperty;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import com.amazonaws.services.dynamodbv2.model.CreateTableResult;

Expand All @@ -42,14 +40,13 @@ public class DynamoDbMapping {
private final CreateTable createTable;
private final DynamoDBMappingContext context;

private static final String ACTIVE = "ACTIVE";
private static final long DEFAULT_SECONDS_BETWEEN_POLLS = 5L;
private static final long DEFAULT_TIMEOUT_SECONDS = 30L;
private static final int DEFAULT_SECONDS_BETWEEN_POLLS = 5;
private static final int DEFAULT_TIMEOUT_SECONDS = 30;

private long secondsBetweenPolls = DEFAULT_SECONDS_BETWEEN_POLLS;
private long timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;
private int secondsBetweenPolls = DEFAULT_SECONDS_BETWEEN_POLLS;
private int timeoutSeconds = DEFAULT_TIMEOUT_SECONDS;

public DynamoDbMapping(CreateTable createTable, DynamoDBMappingContext context) {
public DynamoDbMapping(final CreateTable createTable, final DynamoDBMappingContext context) {
this.createTable = createTable;
this.context = context;
}
Expand All @@ -58,61 +55,48 @@ public Collection<DynamoDBPersistentEntityImpl<?>> getPersistentEntities() {
return context.getPersistentEntities();
}

public DynamoDBPersistentEntityImpl<?> getPersistentEntity(Class<?> type) {
DynamoDBPersistentEntityImpl<?> persistentEntity = context.getPersistentEntity(type);
public DynamoDBPersistentEntityImpl<?> getPersistentEntity(final Class<?> type) {
final DynamoDBPersistentEntityImpl<?> persistentEntity = context.getPersistentEntity(type);
if(persistentEntity == null) {
throw new NullPointerException("persistentEntity is null");
}
return persistentEntity;
}

public DynamoDBPersistentProperty getIdProperty(Class<?> type) {
public DynamoDBPersistentProperty getIdProperty(final Class<?> type) {
return getPersistentEntity(type).getIdProperty();
}

public TypeInformation<?> getTypeInformation(Class<?> type) {
public TypeInformation<?> getTypeInformation(final Class<?> type) {
return getPersistentEntity(type).getTypeInformation();
}


public List<CreateTableResult> createTable() {
List<CreateTableResult> results = new ArrayList<>();
for (DynamoDBPersistentEntity<?> entity : context.getPersistentEntities()) {
DynamoDBPersistentProperty idProperty = entity.getIdProperty();
final List<CreateTableResult> results = new ArrayList<>();
for (final DynamoDBPersistentEntity<?> entity : context.getPersistentEntities()) {
final DynamoDBPersistentProperty idProperty = entity.getIdProperty();
if(idProperty == null) {
throw new NullPointerException("entity property Id is null");
}
DynamoDBTable table = findMergedAnnotation(entity.getTypeInformation().getType(), DynamoDBTable.class);
final DynamoDBTable table = findMergedAnnotation(entity.getTypeInformation().getType(), DynamoDBTable.class);
if (!createTable.isTable(table.tableName())) {
CreateTableResult createTableTable = createTable.createTable(table.tableName(), getIdProperty(idProperty));
if(!ACTIVE.equals(createTableTable.getTableDescription().getTableStatus())) {
createTable.waitTableExists(table.tableName(), this.secondsBetweenPolls, this.timeoutSeconds);
}
final CreateTableResult createTableTable = createTable.createTable(entity.getTypeInformation().getType());
createTable.waitTableActive(table.tableName(), this.timeoutSeconds, this.secondsBetweenPolls);
results.add(createTableTable);
}
}
return results;
}

private String getIdProperty(DynamoDBPersistentProperty idProperty) {
DynamoDBHashKey dynamoDBHashKey = idProperty.findAnnotation(DynamoDBHashKey.class);
String attributeName = dynamoDBHashKey.attributeName();
if(StringUtils.hasText(attributeName)) {
return attributeName;
}
return idProperty.getName();
}


private <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
private <A extends Annotation> A findMergedAnnotation(final AnnotatedElement element, final Class<A> annotationType) {
return AnnotatedElementUtils.findMergedAnnotation(element, annotationType);
}

public void setSecondsBetweenPolls(long secondsBetweenPolls) {
public void setSecondsBetweenPolls(final int secondsBetweenPolls) {
this.secondsBetweenPolls = secondsBetweenPolls;
}

public void setTimeoutSeconds(long timeoutSeconds) {
public void setTimeoutSeconds(final int timeoutSeconds) {
this.timeoutSeconds = timeoutSeconds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;

Expand Down Expand Up @@ -138,14 +139,14 @@ public void createTable() {
listTablesResult.setTableNames(Arrays.asList("foo", "bar"));

given(createTable.isTable(any())).willReturn(false);
given(createTable.createTable(any(), any())).willReturn(value);
given(createTable.waitTableExists(any(), anyLong(), anyLong())).willReturn(true);
given(createTable.createTable(any())).willReturn(value);
//given(createTable.waitTableActive(anyString(), anyLong(), anyLong())).willReturn(true);
List<CreateTableResult> table = this.dynamoDbMapping.createTable();
assertThat(table).hasSize(2);
assertThat(table.iterator().next().getTableDescription()).isEqualTo(tableDescription);
assertThat(table.iterator().next().getTableDescription()).isEqualTo(tableDescription);
verify(createTable).waitTableExists("persons", 10, 30);
verify(createTable).waitTableExists("foo", 10, 30);
verify(createTable).waitTableActive("persons", 30, 10);
verify(createTable).waitTableActive("foo", 30, 10);
}

@DynamoDBTable(tableName = "foo")
Expand Down Expand Up @@ -176,4 +177,4 @@ public void setId(String id) {
}
}

}
}
Loading

0 comments on commit ea49843

Please sign in to comment.