@Override
 public void update(
     final OwnerFullName ownerFullName,
     final String instanceId,
     final Callback<AutoScalingInstance> instanceUpdateCallback)
     throws AutoScalingMetadataException {
   persistenceSupport.updateByExample(
       persistenceSupport.exampleWithName(ownerFullName, instanceId),
       ownerFullName,
       instanceId,
       instanceUpdateCallback);
 }
 @Override
 public <T> T lookup(
     final OwnerFullName ownerFullName,
     final String instanceId,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   return persistenceSupport.lookupByExample(
       persistenceSupport.exampleWithName(ownerFullName, instanceId),
       ownerFullName,
       instanceId,
       Predicates.alwaysTrue(),
       transform);
 }
 @Override
 public AutoScalingGroup update(
     final OwnerFullName ownerFullName,
     final String autoScalingGroupName,
     final Callback<AutoScalingGroup> groupUpdateCallback)
     throws AutoScalingMetadataException {
   return persistenceSupport.update(ownerFullName, autoScalingGroupName, groupUpdateCallback);
 }
 @Override
 public <T> List<T> list(
     final OwnerFullName ownerFullName,
     final Predicate<? super AutoScalingInstance> filter,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   return persistenceSupport.list(ownerFullName, filter, transform);
 }
 @Override
 public <T> List<T> listByGroup(
     final AutoScalingGroupMetadata group,
     final Predicate<? super AutoScalingInstance> filter,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   final AutoScalingInstance example = exampleForGroup(group);
   return persistenceSupport.listByExample(example, filter, transform);
 }
 @Override
 public <T> List<T> listUnhealthyByGroup(
     final AutoScalingGroupMetadata group,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   final AutoScalingInstance example = exampleForGroup(group);
   example.setHealthStatus(HealthStatus.Unhealthy);
   return persistenceSupport.listByExample(example, Predicates.alwaysTrue(), transform);
 }
 @Override
 public <T> List<T> listByGroup(
     final OwnerFullName ownerFullName,
     final String groupName,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   final AutoScalingInstance example = AutoScalingInstance.withOwner(ownerFullName);
   example.setAutoScalingGroupName(groupName);
   return persistenceSupport.listByExample(example, Predicates.alwaysTrue(), transform);
 }
 @Override
 public <T> List<T> listByState(
     final LifecycleState lifecycleState,
     final ConfigurationState configurationState,
     final Function<? super AutoScalingInstance, T> transform)
     throws AutoScalingMetadataException {
   final AutoScalingInstance example =
       AutoScalingInstance.withStates(lifecycleState, configurationState);
   return persistenceSupport.listByExample(
       example, Predicates.and(lifecycleState, configurationState), transform);
 }
  @Override
  public void markExpiredPendingUnhealthy(
      final AutoScalingGroupMetadata group, final Collection<String> instanceIds, final long maxAge)
      throws AutoScalingMetadataException {
    final AutoScalingInstance example = exampleForGroup(group);
    example.setHealthStatus(HealthStatus.Healthy);

    final List<AutoScalingInstance> instancesToMark =
        instanceIds.isEmpty()
            ? Collections.<AutoScalingInstance>emptyList()
            : persistenceSupport.listByExample(
                example,
                LifecycleState.Pending,
                Property.forName("displayName").in(instanceIds),
                Collections.<String, String>emptyMap(),
                Functions.<AutoScalingInstance>identity());

    for (final AutoScalingInstance instance : instancesToMark) {
      try {
        persistenceSupport.updateByExample(
            AutoScalingInstance.withUuid(instance.getNaturalId()),
            group.getOwner(),
            instance.getInstanceId(),
            new Callback<AutoScalingInstance>() {
              @Override
              public void fire(final AutoScalingInstance instance) {
                if (instance.getCreationTimestamp().getTime() < maxAge) {
                  logger.info("Marking pending instance unhealthy: " + instance.getInstanceId());
                  instance.setHealthStatus(HealthStatus.Unhealthy);
                } else {
                  logger.debug(
                      "Not marking pending instance unhealthy (within timeout): "
                          + instance.getInstanceId());
                }
              }
            });
      } catch (final AutoScalingMetadataNotFoundException e) {
        // removed, no need to mark unhealthy
      }
    }
  }
  @Override
  public void markMissingInstancesUnhealthy(
      final AutoScalingGroupMetadata group, final Collection<String> instanceIds)
      throws AutoScalingMetadataException {
    final AutoScalingInstance example = exampleForGroup(group);
    example.setHealthStatus(HealthStatus.Healthy);

    final List<AutoScalingInstance> instancesToMark =
        persistenceSupport.listByExample(
            example,
            LifecycleState.InService,
            instanceIds.isEmpty()
                ? Restrictions.conjunction()
                : Restrictions.not(Property.forName("displayName").in(instanceIds)),
            Collections.<String, String>emptyMap(),
            Functions.<AutoScalingInstance>identity());

    for (final AutoScalingInstance instance : instancesToMark) {
      try {
        persistenceSupport.updateByExample(
            AutoScalingInstance.withUuid(instance.getNaturalId()),
            group.getOwner(),
            instance.getInstanceId(),
            new Callback<AutoScalingInstance>() {
              @Override
              public void fire(final AutoScalingInstance instance) {
                if (instance.healthStatusGracePeriodExpired()) {
                  logger.info("Marking instance unhealthy: " + instance.getInstanceId());
                  instance.setHealthStatus(HealthStatus.Unhealthy);
                } else {
                  logger.debug(
                      "Instance not healthy but within grace period: " + instance.getInstanceId());
                }
              }
            });
      } catch (final AutoScalingMetadataNotFoundException e) {
        // removed, no need to mark unhealthy
      }
    }
  }
  @Override
  public Set<String> verifyInstanceIds(
      final String accountNumber, final Collection<String> instanceIds)
      throws AutoScalingMetadataException {
    final Set<String> verifiedInstanceIds = Sets.newHashSet();

    if (!instanceIds.isEmpty()) {
      final AutoScalingInstance example = AutoScalingInstance.withOwner(accountNumber);
      final Criterion idCriterion = Property.forName("displayName").in(instanceIds);

      Iterables.addAll(
          verifiedInstanceIds,
          persistenceSupport.listByExample(
              example,
              Predicates.alwaysTrue(),
              idCriterion,
              Collections.<String, String>emptyMap(),
              AutoScalingInstances.instanceId()));
    }

    return verifiedInstanceIds;
  }
  private void updateInstances(
      final AutoScalingInstance fromExample,
      final Predicate<? super AutoScalingInstance> fromPredicate,
      final Predicate<? super AutoScalingInstance> updatePredicate,
      final Collection<String> instanceIds)
      throws AutoScalingMetadataException {
    final AbstractOwnedPersistents.WorkCallback<Void> updateCallback =
        new AbstractOwnedPersistents.WorkCallback<Void>() {
          @Override
          public Void doWork() throws AutoScalingMetadataException {
            final List<AutoScalingInstance> instances =
                persistenceSupport.listByExample(
                    fromExample,
                    fromPredicate,
                    Property.forName("displayName").in(instanceIds),
                    Collections.<String, String>emptyMap(),
                    Functions.<AutoScalingInstance>identity());
            CollectionUtils.each(instances, updatePredicate);
            return null;
          }
        };

    persistenceSupport.transactionWithRetry(AutoScalingInstance.class, updateCallback);
  }
 @Override
 public List<AutoScalingGroup> list(final OwnerFullName ownerFullName)
     throws AutoScalingMetadataException {
   return persistenceSupport.list(ownerFullName);
 }
 @Override
 public AutoScalingGroup lookup(
     final OwnerFullName ownerFullName, final String autoScalingGroupName)
     throws AutoScalingMetadataException {
   return persistenceSupport.lookup(ownerFullName, autoScalingGroupName);
 }
 @Override
 public AutoScalingGroup save(final AutoScalingGroup autoScalingGroup)
     throws AutoScalingMetadataException {
   return persistenceSupport.save(autoScalingGroup);
 }
 @Override
 public List<AutoScalingGroup> list(
     final OwnerFullName ownerFullName, final Predicate<? super AutoScalingGroup> filter)
     throws AutoScalingMetadataException {
   return persistenceSupport.list(ownerFullName, filter);
 }
 @Override
 public boolean delete(final AutoScalingInstanceMetadata autoScalingInstance)
     throws AutoScalingMetadataException {
   return persistenceSupport.delete(autoScalingInstance);
 }
 @Override
 public AutoScalingInstance save(final AutoScalingInstance autoScalingInstance)
     throws AutoScalingMetadataException {
   return persistenceSupport.save(autoScalingInstance);
 }
 @Override
 public boolean deleteByGroup(final AutoScalingGroupMetadata group)
     throws AutoScalingMetadataException {
   final AutoScalingInstance example = exampleForGroup(group);
   return !persistenceSupport.deleteByExample(example).isEmpty();
 }