@Override public void deleteAllAttributes(String itemName) { if (!initialised) { throw new IllegalStateException("The optimistic persister has not been initialised"); } logger.log("About to delete all attributes from simpledb item: " + itemName); DeleteAttributesRequest deleteAttributesRequest = new DeleteAttributesRequest( simpleDbDomainName, itemName); AmazonSimpleDB client = getSimpleDBClient(); client.deleteAttributes(deleteAttributesRequest); logger.log("Deleted all attributes from simpledb item."); }
/** * Creates a domain, based on the Domain Policy; The default is UPDATE(if it does not exist create it) * * @return true if the domain was successfuly managed, false if the domain has been managed before */ public synchronized boolean manageDomain(final String domainName, final DomainManagementPolicy policy, final AmazonSimpleDB sdb) { Assert.notNull(sdb); if(! managedDomains.contains(domainName)) { try { if(policy == DomainManagementPolicy.UPDATE || policy == null) { createDomain(domainName, sdb); } else if(policy == DomainManagementPolicy.DROP_CREATE) { dropDomain(domainName, sdb); createDomain(domainName, sdb); } managedDomains.add(domainName); return true; } catch(AmazonClientException e) { throw SimpleDbExceptionTranslator.getTranslatorInstance().translateAmazonClientException(e); } } else { LOGGER.debug("Domain has been managed before: {}", domainName); } return false; }
protected void createDomain(final String domainName, final AmazonSimpleDB sdb) { try { LOGGER.debug("Creating domain: {}", domainName); CreateDomainRequest request = new CreateDomainRequest(domainName); sdb.createDomain(request); LOGGER.debug("Created domain: {}", domainName); } catch(AmazonClientException amazonException) { throw SimpleDbExceptionTranslator.getTranslatorInstance().translateAmazonClientException(amazonException); } }
@Test public void manageDomains_should_create_domains_referred_by_repository() { AmazonSimpleDB sdb = operations.getDB(); final String domainPrefix = operations.getSimpleDb().getDomainPrefix(); ListDomainsResult listDomainsResult = sdb.listDomains(new ListDomainsRequest()); List<String> domainNames = listDomainsResult.getDomainNames(); String nextToken = listDomainsResult.getNextToken(); while (nextToken != null && !nextToken.isEmpty()) { listDomainsResult = sdb.listDomains(new ListDomainsRequest().withNextToken(nextToken)); domainNames.addAll(listDomainsResult.getDomainNames()); nextToken = listDomainsResult.getNextToken(); } assertThat(domainNames.contains(domainPrefix + ".simpleDbReferences"), is(true)); assertThat(domainNames.contains(domainPrefix + ".firstNestedEntity"), is(true)); assertThat(domainNames.contains(domainPrefix + ".secondNestedEntity"), is(true)); Assert.assertNotNull(operations); }
@Override public ImmutablePair<Optional<Integer>, Set<Attribute>> get(String itemName) { if (!initialised) { throw new IllegalStateException("The optimistic persister has not been initialised"); } logger.log("About to get all active attributes from simpledb item: " + itemName); AmazonSimpleDB client = getSimpleDBClient(); // Do a consistent read - to ensure we get correct version number GetAttributesRequest simpleDBRequest = new GetAttributesRequest(simpleDbDomainName, itemName); logger.log("Using simpleDB domain: " + simpleDbDomainName); simpleDBRequest.setConsistentRead(true); GetAttributesResult result = client.getAttributes(simpleDBRequest); List<Attribute> attributes = result.getAttributes(); // Get the version number and other attributes. Optional<Integer> version = Optional.empty(); Set<Attribute> nonVersionAttributes = new HashSet<>(); if (attributes.size() > 0) { // If we have any attributes, we'll always have a version number Attribute versionNumberAttribute = attributes.stream() .filter(attribute -> attribute.getName().equals(versionAttributeName)).findFirst().get(); version = Optional.of(Integer.parseInt(versionNumberAttribute.getValue())); logger.log("Retrieved version number: " + versionNumberAttribute.getValue()); attributes.remove(versionNumberAttribute); // Add all active attributes (i.e. those not pending deletion) nonVersionAttributes.addAll(attributes.stream() .filter(attribute -> !attribute.getValue().startsWith("Inactive")) .collect(Collectors.toSet())); } logger.log("Got all attributes from simpledb"); return new ImmutablePair<>(version, nonVersionAttributes); }
/** * Returns a SimpleDB database client. */ protected AmazonSimpleDB getSimpleDBClient() { // Use a getter here so unit tests can substitute a mock client AmazonSimpleDB client = AmazonSimpleDBClientBuilder.standard().withRegion(region.getName()) .build(); return client; }
@Before public void beforeTest() { optimisticPersister = new TestOptimisticPersister(); // Set up the mocks mockLogger = mockery.mock(LambdaLogger.class); mockery.checking(new Expectations() { { ignoring(mockLogger); } }); mockSimpleDBClient = mockery.mock(AmazonSimpleDB.class); optimisticPersister.setSimpleDBClient(mockSimpleDBClient); // Set up some typical test attributes allAttributes = new HashSet<>(); nonVersionAttributes = new HashSet<>(); activeNonVersionAttributes = new HashSet<>(); Attribute versionAttribute = new Attribute(); versionAttribute.setName(versionAttributeName); versionAttribute.setValue(Integer.toString(testVersionNumber)); Attribute activeAttribute = new Attribute(); activeAttribute.setName("ActiveAttribute"); activeAttribute.setValue("Active"); Attribute inactiveAttribute = new Attribute(); inactiveAttribute.setName("InactiveAttribute"); inactiveAttribute.setValue("Inactive"); allAttributes.add(versionAttribute); allAttributes.add(activeAttribute); allAttributes.add(inactiveAttribute); nonVersionAttributes.add(activeAttribute); nonVersionAttributes.add(inactiveAttribute); activeNonVersionAttributes.add(activeAttribute); }
/** * AwsItem can load an item. * @throws Exception If some problem inside */ @Test public void loadsItemFromSimpleDb() throws Exception { final AmazonSimpleDB aws = Mockito.mock(AmazonSimpleDB.class); Mockito.doReturn( new GetAttributesResult().withAttributes( new Attribute().withName("attr-1").withValue("value-1") ) ).when(aws).getAttributes(Mockito.any(GetAttributesRequest.class)); final Credentials credentials = Mockito.mock(Credentials.class); Mockito.doReturn(aws).when(credentials).aws(); final String name = "item-name"; final String table = "table-name"; final Item item = new AwsItem(credentials, table, name); item.get("hello"); Mockito.verify(aws).getAttributes( GetAttributesRequest.class.cast( Mockito.argThat( Matchers.allOf( Matchers.hasProperty( "domainName", Matchers.equalTo(table) ), Matchers.hasProperty( "itemName", Matchers.equalTo(name) ) ) ) ) ); }
/** * Running the delete-domain command over & over again on the same domain, or if the domain does NOT exist will NOT * result in a Amazon Exception * * @param domainName */ protected void dropDomain(final String domainName, final AmazonSimpleDB sdb) { try { LOGGER.debug("Dropping domain: {}", domainName); DeleteDomainRequest request = new DeleteDomainRequest(domainName); sdb.deleteDomain(request); LOGGER.debug("Dropped domain: {}", domainName); } catch(AmazonClientException amazonException) { throw SimpleDbExceptionTranslator.getTranslatorInstance().translateAmazonClientException(amazonException); } }
protected boolean exists(final String domainName, final AmazonSimpleDB sdb) { try { ListDomainsResult listDomainsResult = sdb.listDomains(new ListDomainsRequest()); List<String> domainNames = listDomainsResult.getDomainNames(); String nextToken = listDomainsResult.getNextToken(); while (nextToken != null && !nextToken.isEmpty()) { listDomainsResult = sdb.listDomains(new ListDomainsRequest().withNextToken(nextToken)); domainNames.addAll(listDomainsResult.getDomainNames()); nextToken = listDomainsResult.getNextToken(); } return domainNames.contains(domainName); } catch(AmazonClientException amazonException) { throw SimpleDbExceptionTranslator.getTranslatorInstance().translateAmazonClientException(amazonException); } }
@Override public List<ImmutablePair<String, List<Attribute>>> getAllItems() { if (!initialised) { throw new IllegalStateException("The optimistic persister has not been initialised"); } // Query database to get items List<ImmutablePair<String, List<Attribute>>> items = new ArrayList<>(); AmazonSimpleDB client = getSimpleDBClient(); SelectRequest selectRequest = new SelectRequest(); // N.B. Think if results are paged, second and subsequent pages will always // be eventually-consistent only. This is currently used only to back up the // database - so being eventually-consistent is good enough - after all - // even if we were fully consistent, someone could still add a new booking // right after our call anyway. selectRequest.setConsistentRead(true); // Query all items in the domain selectRequest.setSelectExpression("select * from `" + simpleDbDomainName + "`"); String nextToken = null; do { SelectResult selectResult = client.select(selectRequest); selectResult.getItems().forEach( item -> { List<Attribute> attributes = new ArrayList<>(); item.getAttributes() .stream() // Do not return the version attribute or inactive attributes .filter( attribute -> (!attribute.getName().equals(versionAttributeName) && !attribute .getValue().startsWith("Inactive"))).forEach(attribute -> { attributes.add(attribute); }); items.add(new ImmutablePair<>(item.getName(), attributes)); }); nextToken = selectResult.getNextToken(); selectRequest.setNextToken(nextToken); } while (nextToken != null); return items; }
@Override public void delete(String itemName, Attribute attribute) throws Exception { if (!initialised) { throw new IllegalStateException("The optimistic persister has not been initialised"); } logger.log("About to delete attribute from simpledb item: " + itemName); AmazonSimpleDB client = getSimpleDBClient(); // We retry the delete if necessary if we get a // ConditionalCheckFailed exception, i.e. if someone else modifies the // database between us reading and writing it. RetryHelper .DoWithRetries(() -> { try { // Get existing attributes (and version number), via consistent // read: ImmutablePair<Optional<Integer>, Set<Attribute>> versionedAttributes = get(itemName); if (!versionedAttributes.left.isPresent()) { logger .log("A version number attribute did not exist - this means no attributes exist, so we have nothing to delete."); return null; } if (!versionedAttributes.right.contains(attribute)) { logger.log("The attribute did not exist - so we have nothing to delete."); return null; } // Since it seems impossible to update the version number while // deleting an attribute, we first mark the attribute as inactive, // and then delete it. ReplaceableAttribute inactiveAttribute = new ReplaceableAttribute(); inactiveAttribute.setName(attribute.getName()); inactiveAttribute.setValue("Inactive" + attribute.getValue()); inactiveAttribute.setReplace(true); put(itemName, versionedAttributes.left, inactiveAttribute); // Now we can safely delete the attribute, as other readers will now // ignore it. UpdateCondition updateCondition = new UpdateCondition(); updateCondition.setName(inactiveAttribute.getName()); updateCondition.setValue(inactiveAttribute.getValue()); // Update will proceed unless the attribute no longer exists updateCondition.setExists(true); Attribute attributeToDelete = new Attribute(); attributeToDelete.setName(inactiveAttribute.getName()); attributeToDelete.setValue(inactiveAttribute.getValue()); List<Attribute> attributesToDelete = new ArrayList<>(); attributesToDelete.add(attributeToDelete); DeleteAttributesRequest simpleDBDeleteRequest = new DeleteAttributesRequest( simpleDbDomainName, itemName, attributesToDelete, updateCondition); client.deleteAttributes(simpleDBDeleteRequest); logger.log("Deleted attribute from simpledb"); return null; } catch (AmazonServiceException ase) { if (ase.getErrorCode().contains("AttributeDoesNotExist")) { // Case of trying to delete an attribute that no longer exists - // that's ok - it probably just means more than one person was // trying to delete the attribute at once. So swallow this // exception logger .log("Caught AmazonServiceException for AttributeDoesNotExist whilst deleting attribute so" + " swallowing and continuing"); return null; } else { throw ase; } } }, Exception.class, Optional.of("Database put failed - conditional check failed"), logger); }
public void setSimpleDBClient(AmazonSimpleDB simpleDBClient) { this.simpleDBClient = simpleDBClient; }
@Override public AmazonSimpleDB getSimpleDBClient() { return simpleDBClient; }
public AmazonSimpleDB getSdbClient() { return sdbClient; }
public DeleteDomainCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public DeleteAttributesCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public ListDomainsCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public AbstractSdbCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { this.sdbClient = sdbClient; this.configuration = configuration; this.exchange = exchange; }
public DomainMetadataCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public AmazonSimpleDB getAmazonSDBClient() { return amazonSDBClient; }
/** * To use the AmazonSimpleDB as the client */ public void setAmazonSDBClient(AmazonSimpleDB amazonSDBClient) { this.amazonSDBClient = amazonSDBClient; }
public BatchPutAttributesCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public GetAttributesCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public PutAttributesCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public SelectCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
public BatchDeleteAttributesCommand(AmazonSimpleDB sdbClient, SdbConfiguration configuration, Exchange exchange) { super(sdbClient, configuration, exchange); }
/** * Collect data for SimpleDB. * * @param stats * current statistics object. * @param account * currently used credentials object. * @param region * currently used aws region. */ public static void scanSimpleDB(AwsStats stats, AwsAccount account, Regions region) { if (region == Regions.EU_CENTRAL_1) return; LOG.debug("Scan for SimpleDB in region " + region.getName() + " in account " + account.getAccountId()); /* * Amazon SimpleDB * * The AWS SimpleDB client allows you to query and manage your data * stored in SimpleDB domains (similar to tables in a relational DB). * * In this sample, we use a SimpleDB client to iterate over all the * domains owned by the current user, and add up the number of items * (similar to rows of data in a relational DB) in each domain. */ try { AmazonSimpleDB simpleDB = new AmazonSimpleDBClient(account.getCredentials()); simpleDB.setRegion(Region.getRegion(region)); ListDomainsRequest sdbRequest = new ListDomainsRequest().withMaxNumberOfDomains(100); ListDomainsResult sdbResult = simpleDB.listDomains(sdbRequest); int totalItems = 0; for (String domainName : sdbResult.getDomainNames()) { DomainMetadataRequest metadataRequest = new DomainMetadataRequest().withDomainName(domainName); DomainMetadataResult domainMetadata = simpleDB.domainMetadata(metadataRequest); int items = domainMetadata.getItemCount(); totalItems += items; AwsResource res = new AwsResource(domainName, account.getAccountId(), AwsResourceType.SimpleDB, region); res.addInfo(AwsTag.Items, items); stats.add(res); } LOG.info(sdbResult.getDomainNames().size() + " SimpleDB domains containing a total of " + totalItems + " items in region " + region.getName() + " in account " + account.getAccountId()); } catch (AmazonServiceException ase) { LOG.error("Exception of SimpleDB: " + ase.getMessage()); } catch (Exception ex) { LOG.error("Exception of SimpleDB: " + ex.getMessage()); } }
@Override @NotNull(message = "AWS client is never NULL") public AmazonSimpleDB aws() { return this.credentials.aws(); }
public AmazonSimpleDB getSimpleDbClient() { return simpleDbClient; }
@Override public final AmazonSimpleDB getDB() { return simpleDb.getSimpleDbClient(); }
/** * * @param db */ public AmazonSimpleDatabase(AmazonSimpleDB db) { this.db = db; }
/** * Build AWS client. * * <p>Don't forget to shut it down after use, * using {@link AmazonSimpleDB#shutdown()}. * * @return Amazon Dynamo DB client */ @NotNull AmazonSimpleDB aws();
/** * Get SimpleDB client. * @return The client */ @NotNull(message = "AWS SimpleDB client is never NULL") AmazonSimpleDB aws();
/** * @return Amazon SimpleDb client instance */ AmazonSimpleDB getDB();