use of software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient in project openhab-addons by openhab.
the class DynamoDBPersistenceService method store.
@Override
public void store(Item item, @Nullable String alias) {
// Timestamp and capture state immediately as rest of the store is asynchronous (state might change in between)
ZonedDateTime time = ZonedDateTime.now();
logIfManyQueuedTasks();
if (!(item instanceof GenericItem)) {
return;
}
if (item.getState() instanceof UnDefType) {
logger.debug("Undefined item state received. Not storing item {}.", item.getName());
return;
}
if (!isReadyToStore()) {
logger.warn("Not ready to store (config error?), not storing item {}.", item.getName());
return;
}
// Get Item describing the real type of data
// With non-group items this is same as the argument item. With Group items, this is item describing the type of
// state stored in the group.
final Item itemTemplate;
try {
itemTemplate = getEffectiveItem(item);
} catch (IllegalStateException e) {
// Logged already
return;
}
String effectiveName = (alias != null) ? alias : item.getName();
// We do not want to rely item.state since async context below can execute much later.
// We 'copy' the item for local use. copyItem also normalizes the unit with NumberItems.
final GenericItem copiedItem = copyItem(itemTemplate, item, effectiveName, null);
resolveTableSchema().thenAcceptAsync(resolved -> {
if (!resolved) {
logger.warn("Table schema not resolved, not storing item {}.", copiedItem.getName());
return;
}
DynamoDbEnhancedAsyncClient localClient = client;
DynamoDbAsyncClient localLowlevelClient = lowLevelClient;
DynamoDBConfig localConfig = dbConfig;
DynamoDBTableNameResolver localTableNameResolver = tableNameResolver;
if (!isProperlyConfigured || localClient == null || localLowlevelClient == null || localConfig == null || localTableNameResolver == null) {
logger.warn("Not ready to store (config error?), not storing item {}.", item.getName());
return;
}
Integer expireDays = localConfig.getExpireDays();
final DynamoDBItem<?> dto;
switch(localTableNameResolver.getTableSchema()) {
case NEW:
dto = AbstractDynamoDBItem.fromStateNew(copiedItem, time, expireDays);
break;
case LEGACY:
dto = AbstractDynamoDBItem.fromStateLegacy(copiedItem, time);
break;
default:
throw new IllegalStateException("Unexpected. Bug");
}
logger.trace("store() called with item {} {} '{}', which was converted to DTO {}", copiedItem.getClass().getSimpleName(), effectiveName, copiedItem.getState(), dto);
dto.accept(new DynamoDBItemVisitor<TableCreatingPutItem<? extends DynamoDBItem<?>>>() {
@Override
public TableCreatingPutItem<? extends DynamoDBItem<?>> visit(DynamoDBBigDecimalItem dynamoBigDecimalItem) {
return new TableCreatingPutItem<DynamoDBBigDecimalItem>(DynamoDBPersistenceService.this, dynamoBigDecimalItem, getTable(DynamoDBBigDecimalItem.class));
}
@Override
public TableCreatingPutItem<? extends DynamoDBItem<?>> visit(DynamoDBStringItem dynamoStringItem) {
return new TableCreatingPutItem<DynamoDBStringItem>(DynamoDBPersistenceService.this, dynamoStringItem, getTable(DynamoDBStringItem.class));
}
}).putItemAsync();
}, executor).exceptionally(e -> {
logger.error("Unexcepted error", e);
return null;
});
}
use of software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient in project openhab-addons by openhab.
the class DynamoDBPersistenceService method getTable.
private <T extends DynamoDBItem<?>> DynamoDbAsyncTable<T> getTable(Class<T> dtoClass) {
DynamoDbEnhancedAsyncClient localClient = client;
DynamoDBTableNameResolver localTableNameResolver = tableNameResolver;
if (!ensureClient() || localClient == null || localTableNameResolver == null) {
throw new IllegalStateException("Client not ready");
}
ExpectedTableSchema expectedTableSchemaRevision = localTableNameResolver.getTableSchema();
String tableName = localTableNameResolver.fromClass(dtoClass);
final TableSchema<T> schema = getDynamoDBTableSchema(dtoClass, expectedTableSchemaRevision);
// OK since this is the only place tableCache is populated
@SuppressWarnings("unchecked") DynamoDbAsyncTable<T> table = (DynamoDbAsyncTable<T>) tableCache.computeIfAbsent(dtoClass, clz -> {
return localClient.table(tableName, schema);
});
if (table == null) {
// Invariant. To make null checker happy
throw new IllegalStateException();
}
return table;
}
use of software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedAsyncClient in project openhab-addons by openhab.
the class DynamoDBPersistenceService method query.
@Override
public Iterable<HistoricItem> query(FilterCriteria filter) {
logIfManyQueuedTasks();
Instant start = Instant.now();
String filterDescription = filterToString(filter);
logger.trace("Got a query with filter {}", filterDescription);
DynamoDbEnhancedAsyncClient localClient = client;
DynamoDBTableNameResolver localTableNameResolver = tableNameResolver;
if (!isProperlyConfigured) {
logger.debug("Configuration for dynamodb not yet loaded or broken. Returning empty query results.");
return Collections.emptyList();
}
if (!ensureClient() || localClient == null || localTableNameResolver == null) {
logger.warn("DynamoDB not connected. Returning empty query results.");
return Collections.emptyList();
}
//
try {
Boolean resolved = resolveTableSchema().get();
if (!resolved) {
logger.warn("Table schema not resolved, cannot query data.");
return Collections.emptyList();
}
} catch (InterruptedException e) {
logger.warn("Table schema resolution interrupted, cannot query data");
return Collections.emptyList();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
logger.warn("Table schema resolution errored, cannot query data: {} {}", cause == null ? e.getClass().getSimpleName() : cause.getClass().getSimpleName(), cause == null ? e.getMessage() : cause.getMessage());
return Collections.emptyList();
}
try {
//
// Proceed with query
//
String itemName = filter.getItemName();
Item item = getItemFromRegistry(itemName);
if (item == null) {
logger.warn("Could not get item {} from registry! Returning empty query results.", itemName);
return Collections.emptyList();
}
if (item instanceof GroupItem) {
item = ((GroupItem) item).getBaseItem();
logger.debug("Item is instanceof GroupItem '{}'", itemName);
if (item == null) {
logger.debug("BaseItem of GroupItem is null. Ignore and give up!");
return Collections.emptyList();
}
if (item instanceof GroupItem) {
logger.debug("BaseItem of GroupItem is a GroupItem too. Ignore and give up!");
return Collections.emptyList();
}
}
boolean legacy = localTableNameResolver.getTableSchema() == ExpectedTableSchema.LEGACY;
Class<? extends DynamoDBItem<?>> dtoClass = AbstractDynamoDBItem.getDynamoItemClass(item.getClass(), legacy);
String tableName = localTableNameResolver.fromClass(dtoClass);
DynamoDbAsyncTable<? extends DynamoDBItem<?>> table = getTable(dtoClass);
logger.debug("Item {} (of type {}) will be tried to query using DTO class {} from table {}", itemName, item.getClass().getSimpleName(), dtoClass.getSimpleName(), tableName);
QueryEnhancedRequest queryExpression = DynamoDBQueryUtils.createQueryExpression(dtoClass, localTableNameResolver.getTableSchema(), item, filter);
CompletableFuture<List<DynamoDBItem<?>>> itemsFuture = new CompletableFuture<>();
final SdkPublisher<? extends DynamoDBItem<?>> itemPublisher = table.query(queryExpression).items();
Subscriber<DynamoDBItem<?>> pageSubscriber = new PageOfInterestSubscriber<DynamoDBItem<?>>(itemsFuture, filter.getPageNumber(), filter.getPageSize());
itemPublisher.subscribe(pageSubscriber);
// NumberItem.getUnit() is expensive, we avoid calling it in the loop
// by fetching the unit here.
final Item localItem = item;
final Unit<?> itemUnit = localItem instanceof NumberItem ? ((NumberItem) localItem).getUnit() : null;
try {
@SuppressWarnings("null") List<HistoricItem> results = itemsFuture.get().stream().map(dynamoItem -> {
HistoricItem historicItem = dynamoItem.asHistoricItem(localItem, itemUnit);
if (historicItem == null) {
logger.warn("Dynamo item {} serialized state '{}' cannot be converted to item {} {}. Item type changed since persistence. Ignoring", dynamoItem.getClass().getSimpleName(), dynamoItem.getState(), localItem.getClass().getSimpleName(), localItem.getName());
return null;
}
logger.trace("Dynamo item {} converted to historic item: {}", localItem, historicItem);
return historicItem;
}).filter(value -> value != null).collect(Collectors.toList());
logger.debug("Query completed in {} ms. Filter was {}", Duration.between(start, Instant.now()).toMillis(), filterDescription);
return results;
} catch (InterruptedException e) {
logger.warn("Query interrupted. Filter was {}", filterDescription);
return Collections.emptyList();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof ResourceNotFoundException) {
logger.trace("Query failed since the DynamoDB table '{}' does not exist. Filter was {}", tableName, filterDescription);
} else if (logger.isTraceEnabled()) {
logger.trace("Query failed. Filter was {}", filterDescription, e);
} else {
logger.warn("Query failed {} {}. Filter was {}", cause == null ? e.getClass().getSimpleName() : cause.getClass().getSimpleName(), cause == null ? e.getMessage() : cause.getMessage(), filterDescription);
}
return Collections.emptyList();
}
} catch (Exception e) {
logger.error("Unexpected error with query having filter {}: {} {}. Returning empty query results.", filterDescription, e.getClass().getSimpleName(), e.getMessage());
return Collections.emptyList();
}
}
Aggregations