@Override
  public void onManagementBecomingMaster() {
    // Enricher attribute setup.  A way of automatically discovering these (but avoiding
    // averaging things like HTTP port and response codes) would be neat.
    List<? extends List<? extends AttributeSensor<? extends Number>>> summingEnricherSetup =
        ImmutableList.of(
            ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT),
            ImmutableList.of(ERROR_COUNT, ERROR_COUNT),
            ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST),
            ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW),
            ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME));

    List<? extends List<? extends AttributeSensor<? extends Number>>> averagingEnricherSetup =
        ImmutableList.of(
            ImmutableList.of(REQUEST_COUNT, REQUEST_COUNT_PER_NODE),
            ImmutableList.of(ERROR_COUNT, ERROR_COUNT_PER_NODE),
            ImmutableList.of(REQUESTS_PER_SECOND_LAST, REQUESTS_PER_SECOND_LAST_PER_NODE),
            ImmutableList.of(REQUESTS_PER_SECOND_IN_WINDOW, REQUESTS_PER_SECOND_IN_WINDOW_PER_NODE),
            ImmutableList.of(TOTAL_PROCESSING_TIME, TOTAL_PROCESSING_TIME_PER_NODE));

    for (List<? extends AttributeSensor<? extends Number>> es : summingEnricherSetup) {
      AttributeSensor<? extends Number> t = es.get(0);
      AttributeSensor<? extends Number> total = es.get(1);
      enrichers()
          .add(
              Enrichers.builder()
                  .aggregating(t)
                  .publishing(total)
                  .fromMembers()
                  .computingSum()
                  .build());
    }

    for (List<? extends AttributeSensor<? extends Number>> es : averagingEnricherSetup) {
      @SuppressWarnings("unchecked")
      AttributeSensor<Number> t = (AttributeSensor<Number>) es.get(0);
      @SuppressWarnings("unchecked")
      AttributeSensor<Double> average = (AttributeSensor<Double>) es.get(1);

      // TODO This needs to respond to changes in FABRIC_SIZE as well, to recalculate
      enrichers()
          .add(
              Enrichers.builder()
                  .transforming(t)
                  .publishing(average)
                  .computing(
                      new Function<Number, Double>() {
                        @Override
                        public Double apply(@Nullable Number input) {
                          Integer size = getAttribute(DynamicWebAppFabric.FABRIC_SIZE);
                          return (size != null && input != null)
                              ? (input.doubleValue() / size)
                              : null;
                        }
                      })
                  .build());
    }
  }
  @Test
  public void testAggregatingMembersEnricher() throws Exception {
    origApp.start(ImmutableList.of(origLoc));
    origCluster.resize(2);

    origApp.addEnricher(
        Enrichers.builder()
            .aggregating(METRIC1)
            .from(origCluster)
            .fromMembers()
            .computing(StringFunctions.joiner(","))
            .publishing(METRIC2)
            .build());

    TestApplication newApp = rebind();
    DynamicCluster newCluster =
        (DynamicCluster)
            Iterables.find(newApp.getChildren(), Predicates.instanceOf(DynamicCluster.class));

    int i = 1;
    for (Entity member : newCluster.getMembers()) {
      ((EntityInternal) member).setAttribute(METRIC1, "myval" + (i++));
    }
    EntityTestUtils.assertAttributeEventually(
        newApp,
        METRIC2,
        Predicates.or(Predicates.equalTo("myval1,myval2"), Predicates.equalTo("myval2,myval1")));
  }
  @Test
  public void testPropagatingEnricher() throws Exception {
    origApp.addEnricher(Enrichers.builder().propagating(METRIC1).from(origEntity).build());

    TestApplication newApp = rebind();
    TestEntity newEntity =
        (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));

    newEntity.setAttribute(METRIC1, "myval");
    EntityTestUtils.assertAttributeEqualsEventually(newApp, METRIC1, "myval");
  }
  @Override
  public void init() {
    super.init();

    ConfigToAttributes.apply(this, MESOS_SLAVE_ID);

    EnricherSpec<?> serviceUp =
        Enrichers.builder()
            .propagating(ImmutableMap.of(SLAVE_ACTIVE, SERVICE_UP))
            .from(this)
            .build();
    enrichers().add(serviceUp);
  }
  @SuppressWarnings("unchecked")
  @Test
  public void testCombiningEnricher() throws Exception {
    origApp.addEnricher(
        Enrichers.builder()
            .combining(METRIC1, METRIC2)
            .from(origEntity)
            .computing(StringFunctions.joiner(","))
            .publishing(METRIC2)
            .build());

    TestApplication newApp = rebind();
    TestEntity newEntity =
        (TestEntity) Iterables.find(newApp.getChildren(), Predicates.instanceOf(TestEntity.class));

    newEntity.setAttribute(METRIC1, "myval");
    newEntity.setAttribute(METRIC2, "myval2");
    EntityTestUtils.assertAttributeEventually(
        newApp,
        METRIC2,
        Predicates.or(Predicates.equalTo("myval,myval2"), Predicates.equalTo("myval2,myval")));
  }