http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java deleted file mode 100644 index 823b8b7..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Combiner.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import static com.google.common.base.Preconditions.checkState; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.sensor.BasicSensorEvent; -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; -import com.google.common.reflect.TypeToken; - -@SuppressWarnings("serial") -//@Catalog(name="Combiner", description="Combines attributes; see Enrichers.builder().combining(...)") -public class Combiner<T,U> extends AbstractEnricher implements SensorEventListener<T> { - - private static final Logger LOG = LoggerFactory.getLogger(Combiner.class); - - public static ConfigKey<Function<?, ?>> TRANSFORMATION = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation"); - - public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer"); - - public static ConfigKey<Set<Sensor<?>>> SOURCE_SENSORS = ConfigKeys.newConfigKey(new TypeToken<Set<Sensor<?>>>() {}, "enricher.sourceSensors"); - - public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor"); - - public static final ConfigKey<Predicate<?>> VALUE_FILTER = ConfigKeys.newConfigKey(new TypeToken<Predicate<?>>() {}, "enricher.aggregating.valueFilter"); - - protected Function<? super Collection<T>, ? extends U> transformation; - protected Entity producer; - protected Set<Sensor<T>> sourceSensors; - protected Sensor<U> targetSensor; - protected Predicate<? super T> valueFilter; - - /** - * Users of values should either on it synchronize when iterating over its entries or use - * copyOfValues to obtain an immutable copy of the map. - */ - // We use a synchronizedMap over a ConcurrentHashMap for entities that store null values. - protected final Map<Sensor<T>, T> values = Collections.synchronizedMap(new LinkedHashMap<Sensor<T>, T>()); - - public Combiner() { - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - this.transformation = (Function<? super Collection<T>, ? extends U>) getRequiredConfig(TRANSFORMATION); - this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER); - this.sourceSensors = (Set) getRequiredConfig(SOURCE_SENSORS); - this.targetSensor = (Sensor<U>) getRequiredConfig(TARGET_SENSOR); - this.valueFilter = (Predicate<? super T>) (getConfig(VALUE_FILTER) == null ? Predicates.alwaysTrue() : getConfig(VALUE_FILTER)); - - checkState(sourceSensors.size() > 0, "must specify at least one sourceSensor"); - - for (Sensor<T> sourceSensor : sourceSensors) { - subscribe(producer, sourceSensor, this); - } - - for (Sensor<T> sourceSensor : sourceSensors) { - if (sourceSensor instanceof AttributeSensor) { - Object value = producer.getAttribute((AttributeSensor<?>)sourceSensor); - // TODO Aled didn't you write a convenience to "subscribeAndRunIfSet" ? (-Alex) - // Unfortunately not yet! - if (value != null) { - onEvent(new BasicSensorEvent(sourceSensor, producer, value, -1)); - } - } - } - } - - @Override - public void onEvent(SensorEvent<T> event) { - synchronized (values) { - values.put(event.getSensor(), event.getValue()); - } - onUpdated(); - } - - /** - * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed). - */ - protected void onUpdated() { - try { - emit(targetSensor, compute()); - } catch (Throwable t) { - LOG.warn("Error calculating and setting combination for enricher "+this, t); - throw Exceptions.propagate(t); - } - } - - protected Object compute() { - synchronized (values) { - // TODO Could avoid copying when filter not needed - List<T> vs = MutableList.copyOf(Iterables.filter(values.values(), valueFilter)); - return transformation.apply(vs); - } - } -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java deleted file mode 100644 index c11b83a..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/CustomAggregatingEnricher.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import groovy.lang.Closure; - -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.groovy.GroovyJavaMethods; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; -import com.google.common.base.Throwables; -import com.google.common.reflect.TypeToken; - -/** - * Subscribes to events from producers with a sensor of type T, aggregates them with the - * provided closure and emits the result on the target sensor V. - * @param <T> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ -public class CustomAggregatingEnricher<S,T> extends AbstractAggregatingEnricher<S,T> implements SensorEventListener<S> { - - private static final Logger LOG = LoggerFactory.getLogger(CustomAggregatingEnricher.class); - - protected final Function<Collection<S>, T> aggregator; - - /** - * The valid keys for the flags are: - * - producers: a collection of entities to be aggregated - * - allMembers: indicates that should track members of the entity that the aggregator is associated with, - * to aggregate across all those members. - * - filter: a Predicate or Closure, indicating which entities to include - * - * @param flags - * @param source - * @param target - * @param aggregator Aggregates a collection of values, to return a single value for the target sensor - * @param defaultIniitalValueForUnreportedSensors Default value to populate the collection given to aggregator, - * where sensors are null or not present initially, defaults to null (note however that subsequent null reports will put an explicit null) - */ - public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, - Function<Collection<S>, T> aggregator, S defaultIniitalValueForUnreportedSensors) { - super(flags, source, target, defaultIniitalValueForUnreportedSensors); - this.aggregator = aggregator; - } - - public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, - Function<Collection<S>, T> aggregator) { - this(flags, source, target, aggregator, null); - } - - public CustomAggregatingEnricher(AttributeSensor<? extends S> source, AttributeSensor<T> target, - Function<Collection<S>, T> aggregator, S defaultValue) { - this(Collections.<String,Object>emptyMap(), source, target, aggregator, defaultValue); - } - - public CustomAggregatingEnricher(AttributeSensor<? extends S> source, AttributeSensor<T> target, - Function<Collection<S>, T> aggregator) { - this(Collections.<String,Object>emptyMap(), source, target, aggregator, null); - } - - /** - * @param flags - * @param source - * @param target - * @param aggregator Should take a collection of values and return a single, aggregate value - * @param defaultValueForUnreportedSensors - * - * @see #CustomAggregatingEnricher(Map, AttributeSensor, AttributeSensor, Function, Object) - */ - @SuppressWarnings("unchecked") - public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, - Closure<?> aggregator, S defaultValueForUnreportedSensors) { - this(flags, source, target, GroovyJavaMethods.<Collection<S>, T>functionFromClosure((Closure<T>)aggregator), defaultValueForUnreportedSensors); - } - - public CustomAggregatingEnricher(Map<String,?> flags, AttributeSensor<? extends S> source, AttributeSensor<T> target, Closure<?> aggregator) { - this(flags, source, target, aggregator, null); - } - - public CustomAggregatingEnricher(AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator, S defaultValueForUnreportedSensors) { - this(Collections.<String,Object>emptyMap(), source, target, aggregator, defaultValueForUnreportedSensors); - } - - public CustomAggregatingEnricher(AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator) { - this(Collections.<String,Object>emptyMap(), source, target, aggregator, null); - } - - @Override - public void onUpdated() { - try { - entity.setAttribute(target, getAggregate()); - } catch (Throwable t) { - LOG.warn("Error calculating and setting aggregate for enricher "+this, t); - throw Throwables.propagate(t); - } - } - - public T getAggregate() { - synchronized (values) { - return (T) aggregator.apply(values.values()); - } - } - - /** - * Instead, consider calling: - * <pre> - * {@code - * Enrichers.Builder builder = Enrichers.builder() - * .aggregating(source) - * .publishing(target) - * .computing(GroovyJavaMethods.<Collection<S>, T>functionFromClosure((Closure<T>)aggregator)) - * .defaultValueForUnreportedSensors(defaultValueForUnreportedSensors); - * - * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers(); - * if (filter != null) builder.entityFilter(filter); - * if (hardCodedProducers != null) builder.fromHardcodedProducers(hardCodedProducers); - * - * addEnricher(builder.build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator, S defaultVal) { - return new CustomAggregatingEnricher<S,T>(flags, source, target, aggregator, defaultVal); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator) { - return newEnricher(flags, source, target, aggregator, null); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator, S defaultVal) { - return newEnricher(Collections.<String,Object>emptyMap(), source, target, aggregator, defaultVal); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - AttributeSensor<S> source, AttributeSensor<T> target, Closure<?> aggregator) { - return newEnricher(Collections.<String,Object>emptyMap(), source, target, aggregator, null); - } - - /** - * Instead, consider calling: - * <pre> - * {@code - * Enrichers.Builder builder = Enrichers.builder() - * .aggregating(source) - * .publishing(target) - * .computing(aggregator) - * .defaultValueForUnreportedSensors(defaultVal); - * - * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers(); - * if (filter != null) builder.entityFilter(filter); - * if (hardCodedProducers != null) builder.fromHardcodedProducers(hardCodedProducers); - * - * addEnricher(builder.build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> target, Function<Collection<S>, T> aggregator, S defaultVal) { - return new CustomAggregatingEnricher<S,T>(flags, source, target, aggregator, defaultVal); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - Map<String,?> flags, AttributeSensor<S> source, AttributeSensor<T> target, Function<Collection<S>, T> aggregator) { - return newEnricher(flags, source, target, aggregator, null); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - AttributeSensor<S> source, AttributeSensor<T> target, Function<Collection<S>, T> aggregator, S defaultVal) { - return newEnricher(Collections.<String,Object>emptyMap(), source, target, aggregator, defaultVal); - } - public static <S,T> CustomAggregatingEnricher<S,T> newEnricher( - AttributeSensor<S> source, AttributeSensor<T> target, Function<Collection<S>, T> aggregator) { - return newEnricher(Collections.<String,Object>emptyMap(), source, target, aggregator, null); - } - - /** - * creates an enricher which sums over all children/members, - * defaulting to excluding sensors which have not published anything (or published null), and null if there are no sensors; - * this behaviour can be customised, both default value for sensors, and what to report if no sensors - * - * Instead, consider calling: - * <pre> - * {@code - * Enrichers.Builder builder = Enrichers.builder() - * .aggregating(source) - * .publishing(target) - * .computingSum() - * .defaultValueForUnreportedSensors(defaultValueForUnreportedSensors) - * .valueToReportIfNoSensors(valueToReportIfNoSensors); - * - * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers(); - * if (filter != null) builder.entityFilter(filter); - * if (hardCodedProducers != null) builder.fromHardcodedProducers(hardCodedProducers); - * - * addEnricher(builder.build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public static <N extends Number, T extends Number> CustomAggregatingEnricher<N,T> newSummingEnricher( - Map<String,?> flags, AttributeSensor<N> source, final AttributeSensor<T> target, - final N defaultValueForUnreportedSensors, final T valueToReportIfNoSensors) { - - Function<Collection<N>, T> aggregator = new Function<Collection<N>, T>() { - @Override public T apply(Collection<N> vals) { - return sum(vals, defaultValueForUnreportedSensors, valueToReportIfNoSensors, target.getTypeToken()); - } - }; - return new CustomAggregatingEnricher<N,T>(flags, source, target, aggregator, defaultValueForUnreportedSensors); - } - - /** @see {@link #newSummingEnricher(Map, AttributeSensor, AttributeSensor, Number, Number)} */ - public static <N extends Number> CustomAggregatingEnricher<N,N> newSummingEnricher( - AttributeSensor<N> source, AttributeSensor<N> target) { - return newSummingEnricher(Collections.<String,Object>emptyMap(), source, target, null, null); - } - - /** creates an enricher which averages over all children/members, - * defaulting to excluding sensors which have not published anything (or published null), and null if there are no sensors; - * this behaviour can be customised, both default value for sensors, and what to report if no sensors - * - * Instead, consider calling: - * <pre> - * {@code - * Enrichers.Builder builder = Enrichers.builder() - * .aggregating(source) - * .publishing(target) - * .computingAverage() - * .defaultValueForUnreportedSensors(defaultValueForUnreportedSensors) - * .valueToReportIfNoSensors(valueToReportIfNoSensors); - * - * if (Boolean.TRUE.equals(allMembers)) builder.fromMembers(); - * if (filter != null) builder.entityFilter(filter); - * if (hardCodedProducers != null) builder.fromHardcodedProducers(hardCodedProducers); - * - * addEnricher(builder.build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public static <N extends Number> CustomAggregatingEnricher<N,Double> newAveragingEnricher( - Map<String,?> flags, AttributeSensor<? extends N> source, final AttributeSensor<Double> target, - final N defaultValueForUnreportedSensors, final Double valueToReportIfNoSensors) { - Function<Collection<N>, Double> aggregator = new Function<Collection<N>, Double>() { - @Override public Double apply(Collection<N> vals) { - int count = count(vals, defaultValueForUnreportedSensors!=null); - return (count==0) ? valueToReportIfNoSensors : - (Double) ((sum(vals, defaultValueForUnreportedSensors, 0, TypeToken.of(Double.class)) / count)); - } - }; - return new CustomAggregatingEnricher<N,Double>(flags, source, target, aggregator, defaultValueForUnreportedSensors); - } - - /** @see #newAveragingEnricher(Map, AttributeSensor, AttributeSensor, Number, Double) */ - public static <N extends Number> CustomAggregatingEnricher<N,Double> newAveragingEnricher( - AttributeSensor<N> source, AttributeSensor<Double> target) { - return newAveragingEnricher(Collections.<String,Object>emptyMap(), source, target, null, null); - } - - @SuppressWarnings("unchecked") - private static <N extends Number> N cast(Number n, TypeToken<? extends N> numberType) { - return (N) TypeCoercions.castPrimitive(n, numberType.getRawType()); - } - - private static <N extends Number> N sum(Iterable<? extends Number> vals, Number valueIfNull, Number valueIfNone, TypeToken<N> type) { - double result = 0d; - int count = 0; - if (vals!=null) { - for (Number val : vals) { - if (val!=null) { - result += val.doubleValue(); - count++; - } else if (valueIfNull!=null) { - result += valueIfNull.doubleValue(); - count++; - } - } - } - if (count==0) return cast(valueIfNone, type); - return cast(result, type); - } - - private static int count(Iterable<? extends Object> vals, boolean includeNullValues) { - int result = 0; - if (vals!=null) - for (Object val : vals) - if (val!=null || includeNullValues) result++; - return result; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java deleted file mode 100644 index 1363617..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherDynamicType.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.api.sensor.EnricherType; -import org.apache.brooklyn.core.objs.BrooklynDynamicType; - -public class EnricherDynamicType extends BrooklynDynamicType<Enricher, AbstractEnricher> { - - public EnricherDynamicType(Class<? extends Enricher> type) { - super(type); - } - - public EnricherDynamicType(AbstractEnricher enricher) { - super(enricher); - } - - public EnricherType getSnapshot() { - return (EnricherType) super.getSnapshot(); - } - - @Override - protected EnricherTypeSnapshot newSnapshot() { - return new EnricherTypeSnapshot(name, value(configKeys)); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java deleted file mode 100644 index ed06de3..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/EnricherTypeSnapshot.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import java.util.Map; - -import org.apache.brooklyn.api.sensor.EnricherType; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.objs.BrooklynTypeSnapshot; - -public class EnricherTypeSnapshot extends BrooklynTypeSnapshot implements EnricherType { - private static final long serialVersionUID = 4670930188951106009L; - - EnricherTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) { - super(name, configKeys); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - return (obj instanceof EnricherTypeSnapshot) && super.equals(obj); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java deleted file mode 100644 index 84e541d..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Enrichers.java +++ /dev/null @@ -1,824 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Enricher; -import org.apache.brooklyn.api.sensor.EnricherSpec; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.collections.MutableSet; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.text.StringPredicates; -import org.apache.brooklyn.util.text.Strings; - -import com.google.common.annotations.Beta; -import com.google.common.base.Function; -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; -import com.google.common.reflect.TypeToken; - -public class Enrichers { - - private Enrichers() {} - - public static InitialBuilder builder() { - return new InitialBuilder(); - } - - public abstract static class Builder<B extends Builder<B>> { - @SuppressWarnings("unchecked") - protected B self() { - return (B) this; - } - } - - public abstract static class AbstractEnricherBuilder<B extends AbstractEnricherBuilder<B>> extends Builder<B> { - final Class<? extends Enricher> enricherType; - Boolean suppressDuplicates; - String uniqueTag; - Set<Object> tags = MutableSet.of(); - - public AbstractEnricherBuilder(Class<? extends Enricher> enricherType) { - this.enricherType = enricherType; - } - - public B uniqueTag(String tag) { - uniqueTag = Preconditions.checkNotNull(tag); - return self(); - } - public B addTag(Object tag) { - tags.add(Preconditions.checkNotNull(tag)); - return self(); - } - public B suppressDuplicates(Boolean suppressDuplicates) { - this.suppressDuplicates = suppressDuplicates; - return self(); - } - - protected abstract String getDefaultUniqueTag(); - - protected EnricherSpec<? extends Enricher> build() { - EnricherSpec<? extends Enricher> spec = EnricherSpec.create(enricherType); - - String uniqueTag2 = uniqueTag; - if (uniqueTag2==null) - uniqueTag2 = getDefaultUniqueTag(); - if (uniqueTag2!=null) - spec.uniqueTag(uniqueTag2); - - if (!tags.isEmpty()) spec.tags(tags); - if (suppressDuplicates!=null) - spec.configure(AbstractEnricher.SUPPRESS_DUPLICATES, suppressDuplicates); - - return spec; - } - } - - protected abstract static class AbstractInitialBuilder<B extends AbstractInitialBuilder<B>> extends Builder<B> { - public PropagatorBuilder propagating(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) { - return new PropagatorBuilder(vals); - } - public PropagatorBuilder propagating(Iterable<? extends Sensor<?>> vals) { - return new PropagatorBuilder(vals); - } - public PropagatorBuilder propagating(Sensor<?>... vals) { - return new PropagatorBuilder(vals); - } - public PropagatorBuilder propagatingAll() { - return new PropagatorBuilder(true, null); - } - public PropagatorBuilder propagatingAllButUsualAnd(Sensor<?>... vals) { - return new PropagatorBuilder(true, ImmutableSet.<Sensor<?>>builder().addAll(Propagator.SENSORS_NOT_USUALLY_PROPAGATED).add(vals).build()); - } - public PropagatorBuilder propagatingAllBut(Sensor<?>... vals) { - return new PropagatorBuilder(true, ImmutableSet.copyOf(vals)); - } - public PropagatorBuilder propagatingAllBut(Iterable<? extends Sensor<?>> vals) { - return new PropagatorBuilder(true, vals); - } - - /** - * Builds an enricher which transforms a given sensor: - * <li> applying a (required) function ({@link TransformerBuilder#computing(Function)}, or - * {@link AbstractAggregatorBuilder#computingAverage()}/ - * {@link AbstractAggregatorBuilder#computingSum()}, mandatory); - * <li> and publishing it on the entity where the enricher is attached; - * <li> optionally taking the sensor from a different source entity ({@link TransformerBuilder#from(Entity)}); - * <li> and optionally publishing it as a different sensor ({@link TransformerBuilder#publishing(AttributeSensor)}); - * <p> You must supply at least one of the optional values, of course, otherwise the enricher may loop endlessly! - */ - public <S> TransformerBuilder<S, Object> transforming(AttributeSensor<S> val) { - return new TransformerBuilder<S, Object>(val); - } - /** as {@link #transforming(AttributeSensor)} but accepting multiple sensors, with the function acting on the set of values */ - public <S> CombinerBuilder<S, Object> combining(Collection<AttributeSensor<? extends S>> vals) { - return new CombinerBuilder<S, Object>(vals); - } - /** as {@link #combining(Collection)} */ - @SafeVarargs - public final <S> CombinerBuilder<S, Object> combining(AttributeSensor<? extends S>... vals) { - return new CombinerBuilder<S, Object>(vals); - } - /** as {@link #combining(Collection)} but the collection of values comes from the given sensor on multiple entities */ - public <S> AggregatorBuilder<S, Object> aggregating(AttributeSensor<S> val) { - return new AggregatorBuilder<S,Object>(val); - } - /** creates an {@link UpdatingMap} enricher: - * {@link UpdatingMapBuilder#from(AttributeSensor)} and {@link UpdatingMapBuilder#computing(Function)} are required - **/ - public <S,TKey,TVal> UpdatingMapBuilder<S, TKey, TVal> updatingMap(AttributeSensor<Map<TKey,TVal>> target) { - return new UpdatingMapBuilder<S, TKey, TVal>(target); - } - /** creates a {@link org.apache.brooklyn.sensor.enricher.Joiner} enricher builder - * which joins entries in a list to produce a String - **/ - public JoinerBuilder joining(AttributeSensor<?> source) { - return new JoinerBuilder(source); - } - } - - - protected abstract static class AbstractAggregatorBuilder<S, T, B extends AbstractAggregatorBuilder<S, T, B>> extends AbstractEnricherBuilder<B> { - protected final AttributeSensor<S> aggregating; - protected AttributeSensor<T> publishing; - protected Entity fromEntity; - /** @deprecated since 0.7.0, kept for backwards compatibility for rebind, but not used otherwise */ - @Deprecated protected Function<? super Collection<S>, ? extends T> computing; - // use supplier so latest values of other fields can be used - protected Supplier<Function<? super Collection<S>, ? extends T>> computingSupplier; - protected Boolean fromMembers; - protected Boolean fromChildren; - protected Boolean excludingBlank; - protected ImmutableSet<Entity> fromHardcodedProducers; - protected Predicate<? super Entity> entityFilter; - protected Predicate<Object> valueFilter; - protected Object defaultValueForUnreportedSensors; - protected Object valueToReportIfNoSensors; - - public AbstractAggregatorBuilder(AttributeSensor<S> aggregating) { - super(Aggregator.class); - this.aggregating = aggregating; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <T2 extends T> AggregatorBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) { - this.publishing = (AttributeSensor) checkNotNull(val); - return (AggregatorBuilder) self(); - } - public B from(Entity val) { - this.fromEntity = checkNotNull(val); - return self(); - } - public B fromMembers() { - this.fromMembers = true; - return self(); - } - public B fromChildren() { - this.fromChildren = true; - return self(); - } - public B fromHardcodedProducers(Iterable<? extends Entity> val) { - this.fromHardcodedProducers = ImmutableSet.copyOf(val); - return self(); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public B computing(Function<? super Collection<S>, ? extends T> val) { - this.computingSupplier = (Supplier)Suppliers.ofInstance(checkNotNull(val)); - return self(); - } - @SuppressWarnings({ "unchecked", "rawtypes", "unused" }) - private B computingSumLegacy() { - // since 0.7.0, kept in case we need to rebind to this - Function<Collection<S>, Number> function = new Function<Collection<S>, Number>() { - @Override public Number apply(Collection<S> input) { - return sum((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, (TypeToken) publishing.getTypeToken()); - }}; - this.computing((Function)function); - return self(); - } - @SuppressWarnings({ "unchecked", "rawtypes", "unused" }) - private B computingAverageLegacy() { - // since 0.7.0, kept in case we need to rebind to this - Function<Collection<S>, Number> function = new Function<Collection<S>, Number>() { - @Override public Number apply(Collection<S> input) { - return average((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, (TypeToken) publishing.getTypeToken()); - }}; - this.computing((Function)function); - return self(); - } - public B computingSum() { - this.computingSupplier = new Supplier<Function<? super Collection<S>, ? extends T>>() { - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Function<? super Collection<S>, ? extends T> get() { - // relies on TypeCoercion of result from Number to T, and type erasure for us to get away with it! - return (Function)new ComputingSum((Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, publishing.getTypeToken()); - } - }; - return self(); - } - - public B computingAverage() { - this.computingSupplier = new Supplier<Function<? super Collection<S>, ? extends T>>() { - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Function<? super Collection<S>, ? extends T> get() { - // relies on TypeCoercion of result from Number to T, and type erasure for us to get away with it! - return (Function)new ComputingAverage((Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, publishing.getTypeToken()); - } - }; - return self(); - } - public B defaultValueForUnreportedSensors(S val) { - this.defaultValueForUnreportedSensors = val; - return self(); - } - public B valueToReportIfNoSensors(Object val) { - this.valueToReportIfNoSensors = val; - return self(); - } - public B entityFilter(Predicate<? super Entity> val) { - this.entityFilter = val; - return self(); - } - public B excludingBlank() { - this.excludingBlank = true; - return self(); - } - @Override - protected String getDefaultUniqueTag() { - if (publishing==null) return null; - return "aggregator:"+publishing.getName(); - } - public EnricherSpec<?> build() { - Predicate<Object> valueFilter; - if (Boolean.TRUE.equals(excludingBlank)) { - valueFilter = new Predicate<Object>() { - @Override public boolean apply(Object input) { - return (input != null) && - ((input instanceof CharSequence) ? Strings.isNonBlank((CharSequence)input) : true); - } - }; - // above kept for deserialization; not sure necessary - valueFilter = StringPredicates.isNonBlank(); - } else { - valueFilter = null; - } - // FIXME excludingBlank; use valueFilter? exclude means ignored entirely or substituted for defaultMemberValue? - return super.build().configure(MutableMap.builder() - .putIfNotNull(Aggregator.PRODUCER, fromEntity) - .put(Aggregator.TARGET_SENSOR, publishing) - .put(Aggregator.SOURCE_SENSOR, aggregating) - .putIfNotNull(Aggregator.FROM_CHILDREN, fromChildren) - .putIfNotNull(Aggregator.FROM_MEMBERS, fromMembers) - .putIfNotNull(Aggregator.TRANSFORMATION, computingSupplier.get()) - .putIfNotNull(Aggregator.FROM_HARDCODED_PRODUCERS, fromHardcodedProducers) - .putIfNotNull(Aggregator.ENTITY_FILTER, entityFilter) - .putIfNotNull(Aggregator.VALUE_FILTER, valueFilter) - .putIfNotNull(Aggregator.DEFAULT_MEMBER_VALUE, defaultValueForUnreportedSensors) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("aggregating", aggregating) - .add("publishing", publishing) - .add("fromEntity", fromEntity) - .add("computing", computingSupplier) - .add("fromMembers", fromMembers) - .add("fromChildren", fromChildren) - .add("excludingBlank", excludingBlank) - .add("fromHardcodedProducers", fromHardcodedProducers) - .add("entityFilter", entityFilter) - .add("valueFilter", valueFilter) - .add("defaultValueForUnreportedSensors", defaultValueForUnreportedSensors) - .add("valueToReportIfNoSensors", valueToReportIfNoSensors) - .toString(); - } - } - - protected abstract static class AbstractCombinerBuilder<S, T, B extends AbstractCombinerBuilder<S, T, B>> extends AbstractEnricherBuilder<B> { - protected final List<AttributeSensor<? extends S>> combining; - protected AttributeSensor<T> publishing; - protected Entity fromEntity; - protected Function<? super Collection<S>, ? extends T> computing; - protected Boolean excludingBlank; - protected Object valueToReportIfNoSensors; - protected Predicate<Object> valueFilter; - - // For summing/averaging - protected Object defaultValueForUnreportedSensors; - - @SafeVarargs - public AbstractCombinerBuilder(AttributeSensor<? extends S>... vals) { - this(ImmutableList.copyOf(vals)); - } - public AbstractCombinerBuilder(Collection<AttributeSensor<? extends S>> vals) { - super(Combiner.class); - checkArgument(checkNotNull(vals).size() > 0, "combining-sensors must be non-empty"); - this.combining = ImmutableList.<AttributeSensor<? extends S>>copyOf(vals); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <T2 extends T> CombinerBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) { - this.publishing = (AttributeSensor) checkNotNull(val); - return (CombinerBuilder) this; - } - public B from(Entity val) { - this.fromEntity = checkNotNull(val); - return self(); - } - public B computing(Function<? super Collection<S>, ? extends T> val) { - this.computing = checkNotNull(val); - return self(); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public B computingSum() { - Function<Collection<S>, Number> function = new Function<Collection<S>, Number>() { - @Override public Number apply(Collection<S> input) { - return sum((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, (TypeToken) publishing.getTypeToken()); - }}; - this.computing((Function)function); - return self(); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public B computingAverage() { - Function<Collection<S>, Number> function = new Function<Collection<S>, Number>() { - @Override public Number apply(Collection<S> input) { - return average((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, (TypeToken) publishing.getTypeToken()); - }}; - this.computing((Function)function); - return self(); - } - public B defaultValueForUnreportedSensors(Object val) { - this.defaultValueForUnreportedSensors = val; - return self(); - } - public B valueToReportIfNoSensors(Object val) { - this.valueToReportIfNoSensors = val; - return self(); - } - public B excludingBlank() { - this.excludingBlank = true; - return self(); - } - @Override - protected String getDefaultUniqueTag() { - if (publishing==null) return null; - return "combiner:"+publishing.getName(); - } - public EnricherSpec<?> build() { - return super.build().configure(MutableMap.builder() - .putIfNotNull(Combiner.PRODUCER, fromEntity) - .put(Combiner.TARGET_SENSOR, publishing) - .put(Combiner.SOURCE_SENSORS, combining) - .putIfNotNull(Combiner.TRANSFORMATION, computing) - .putIfNotNull(Combiner.VALUE_FILTER, valueFilter) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("combining", combining) - .add("publishing", publishing) - .add("fromEntity", fromEntity) - .add("computing", computing) - .add("excludingBlank", excludingBlank) - .add("valueToReportIfNoSensors", valueToReportIfNoSensors) - .add("valueFilter", valueFilter) - .toString(); - } - } - - protected abstract static class AbstractTransformerBuilder<S, T, B extends AbstractTransformerBuilder<S, T, B>> extends AbstractEnricherBuilder<B> { - protected final AttributeSensor<S> transforming; - protected AttributeSensor<T> publishing; - protected Entity fromEntity; - protected Function<? super S, ?> computing; - protected Function<? super SensorEvent<S>, ?> computingFromEvent; - - public AbstractTransformerBuilder(AttributeSensor<S> val) { - super(Transformer.class); - this.transforming = checkNotNull(val); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <T2 extends T> TransformerBuilder<S,T2> publishing(AttributeSensor<? extends T2> val) { - this.publishing = (AttributeSensor) checkNotNull(val); - return (TransformerBuilder) this; - } - public B from(Entity val) { - this.fromEntity = checkNotNull(val); - return self(); - } - public B computing(Function<? super S, ? extends T> val) { - this.computing = checkNotNull(val); - return self(); - } - public B computingFromEvent(Function<? super SensorEvent<S>, ? extends T> val) { - this.computingFromEvent = checkNotNull(val); - return self(); - } - @Override - protected String getDefaultUniqueTag() { - if (publishing==null) return null; - return "transformer:"+publishing.getName(); - } - public EnricherSpec<?> build() { - return super.build().configure(MutableMap.builder() - .putIfNotNull(Transformer.PRODUCER, fromEntity) - .put(Transformer.TARGET_SENSOR, publishing) - .put(Transformer.SOURCE_SENSOR, transforming) - .putIfNotNull(Transformer.TRANSFORMATION_FROM_VALUE, computing) - .putIfNotNull(Transformer.TRANSFORMATION_FROM_EVENT, computingFromEvent) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("publishing", publishing) - .add("transforming", transforming) - .add("fromEntity", fromEntity) - .add("computing", computing) - .toString(); - } - } - - protected abstract static class AbstractPropagatorBuilder<B extends AbstractPropagatorBuilder<B>> extends AbstractEnricherBuilder<B> { - protected final Map<? extends Sensor<?>, ? extends Sensor<?>> propagating; - protected final Boolean propagatingAll; - protected final Iterable<? extends Sensor<?>> propagatingAllBut; - protected Entity fromEntity; - - public AbstractPropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) { - super(Propagator.class); - checkArgument(checkNotNull(vals).size() > 0, "propagating-sensors must be non-empty"); - this.propagating = vals; - this.propagatingAll = null; - this.propagatingAllBut = null; - } - public AbstractPropagatorBuilder(Iterable<? extends Sensor<?>> vals) { - this(newIdentityMap(ImmutableSet.copyOf(vals))); - } - public AbstractPropagatorBuilder(Sensor<?>... vals) { - this(newIdentityMap(ImmutableSet.copyOf(vals))); - } - AbstractPropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) { - super(Propagator.class); - // Ugly constructor! Taking boolean to differentiate it from others; could use a static builder - // but feels like overkill having a builder for a builder, being called by a builder! - checkArgument(propagatingAll, "Not propagating all; use PropagatingAll(vals)"); - this.propagating = null; - this.propagatingAll = true; - this.propagatingAllBut = (butVals == null || Iterables.isEmpty(butVals)) ? null: butVals; - } - public B from(Entity val) { - this.fromEntity = checkNotNull(val); - return self(); - } - @Override - protected String getDefaultUniqueTag() { - List<String> summary = MutableList.of(); - if (propagating!=null) { - for (Map.Entry<? extends Sensor<?>, ? extends Sensor<?>> entry: propagating.entrySet()) { - if (entry.getKey().getName().equals(entry.getValue().getName())) - summary.add(entry.getKey().getName()); - else - summary.add(entry.getKey().getName()+"->"+entry.getValue().getName()); - } - } - if (Boolean.TRUE.equals(propagatingAll)) - summary.add("ALL"); - if (propagatingAllBut!=null && !Iterables.isEmpty(propagatingAllBut)) { - List<String> allBut = MutableList.of(); - for (Sensor<?> s: propagatingAllBut) allBut.add(s.getName()); - summary.add("ALL_BUT:"+com.google.common.base.Joiner.on(",").join(allBut)); - } - - return "propagating["+fromEntity.getId()+":"+com.google.common.base.Joiner.on(",").join(summary)+"]"; - } - public EnricherSpec<? extends Enricher> build() { - return super.build().configure(MutableMap.builder() - .putIfNotNull(Propagator.PRODUCER, fromEntity) - .putIfNotNull(Propagator.SENSOR_MAPPING, propagating) - .putIfNotNull(Propagator.PROPAGATING_ALL, propagatingAll) - .putIfNotNull(Propagator.PROPAGATING_ALL_BUT, propagatingAllBut) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("fromEntity", fromEntity) - .add("propagating", propagating) - .add("propagatingAll", propagatingAll) - .add("propagatingAllBut", propagatingAllBut) - .toString(); - } - } - - public abstract static class AbstractUpdatingMapBuilder<S, TKey, TVal, B extends AbstractUpdatingMapBuilder<S, TKey, TVal, B>> extends AbstractEnricherBuilder<B> { - protected AttributeSensor<Map<TKey,TVal>> targetSensor; - protected AttributeSensor<? extends S> fromSensor; - protected TKey key; - protected Function<S, ? extends TVal> computing; - protected Boolean removingIfResultIsNull; - - public AbstractUpdatingMapBuilder(AttributeSensor<Map<TKey,TVal>> target) { - super(UpdatingMap.class); - this.targetSensor = target; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <S2 extends S> UpdatingMapBuilder<S2,TKey,TVal> from(AttributeSensor<S2> fromSensor) { - this.fromSensor = checkNotNull(fromSensor); - return (UpdatingMapBuilder) this; - } - public B computing(Function<S,? extends TVal> val) { - this.computing = checkNotNull(val); - return self(); - } - /** sets an explicit key to use; defaults to using the name of the source sensor specified in {@link #from(AttributeSensor)} */ - public B key(TKey key) { - this.key = key; - return self(); - } - /** sets explicit behaviour for treating <code>null</code> return values; - * default is to remove */ - public B removingIfResultIsNull(boolean val) { - this.removingIfResultIsNull = val; - return self(); - } - @Override - protected String getDefaultUniqueTag() { - if (targetSensor==null || fromSensor==null) return null; - return "updating:"+targetSensor.getName()+"<-"+fromSensor.getName(); - } - public EnricherSpec<?> build() { - return super.build().configure(MutableMap.builder() - .put(UpdatingMap.TARGET_SENSOR, targetSensor) - .put(UpdatingMap.SOURCE_SENSOR, fromSensor) - .putIfNotNull(UpdatingMap.KEY_IN_TARGET_SENSOR, key) - .put(UpdatingMap.COMPUTING, computing) - .putIfNotNull(UpdatingMap.REMOVING_IF_RESULT_IS_NULL, removingIfResultIsNull) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("publishing", targetSensor) - .add("fromSensor", fromSensor) - .add("key", key) - .add("computing", computing) - .add("removingIfResultIsNull", removingIfResultIsNull) - .toString(); - } - } - - protected abstract static class AbstractJoinerBuilder<B extends AbstractJoinerBuilder<B>> extends AbstractEnricherBuilder<B> { - protected final AttributeSensor<?> transforming; - protected AttributeSensor<String> publishing; - protected Entity fromEntity; - protected String separator; - protected Boolean quote; - protected Integer minimum; - protected Integer maximum; - - public AbstractJoinerBuilder(AttributeSensor<?> source) { - super(Joiner.class); - this.transforming = checkNotNull(source); - } - public B publishing(AttributeSensor<String> target) { - this.publishing = checkNotNull(target); - return self(); - } - public B separator(String separator) { - this.separator = separator; - return self(); - } - public B quote(Boolean quote) { - this.quote = quote; - return self(); - } - public B minimum(Integer minimum) { - this.minimum = minimum; - return self(); - } - public B maximum(Integer maximum) { - this.maximum = maximum; - return self(); - } - @Override - protected String getDefaultUniqueTag() { - if (transforming==null || publishing==null) return null; - return "joiner:"+transforming.getName()+"->"+publishing.getName(); - } - public EnricherSpec<?> build() { - return super.build().configure(MutableMap.builder() - .putIfNotNull(Joiner.PRODUCER, fromEntity) - .put(Joiner.TARGET_SENSOR, publishing) - .put(Joiner.SOURCE_SENSOR, transforming) - .putIfNotNull(Joiner.SEPARATOR, separator) - .putIfNotNull(Joiner.QUOTE, quote) - .putIfNotNull(Joiner.MINIMUM, minimum) - .putIfNotNull(Joiner.MAXIMUM, maximum) - .build()); - } - - @Override - public String toString() { - return Objects.toStringHelper(this) - .omitNullValues() - .add("publishing", publishing) - .add("transforming", transforming) - .add("separator", separator) - .toString(); - } - } - - public static class InitialBuilder extends AbstractInitialBuilder<InitialBuilder> { - } - - public static class AggregatorBuilder<S, T> extends AbstractAggregatorBuilder<S, T, AggregatorBuilder<S, T>> { - public AggregatorBuilder(AttributeSensor<S> aggregating) { - super(aggregating); - } - } - - public static class PropagatorBuilder extends AbstractPropagatorBuilder<PropagatorBuilder> { - public PropagatorBuilder(Map<? extends Sensor<?>, ? extends Sensor<?>> vals) { - super(vals); - } - public PropagatorBuilder(Iterable<? extends Sensor<?>> vals) { - super(vals); - } - public PropagatorBuilder(Sensor<?>... vals) { - super(vals); - } - PropagatorBuilder(boolean propagatingAll, Iterable<? extends Sensor<?>> butVals) { - super(propagatingAll, butVals); - } - } - - public static class CombinerBuilder<S, T> extends AbstractCombinerBuilder<S, T, CombinerBuilder<S, T>> { - @SafeVarargs - public CombinerBuilder(AttributeSensor<? extends S>... vals) { - super(vals); - } - public CombinerBuilder(Collection<AttributeSensor<? extends S>> vals) { - super(vals); - } - } - - public static class TransformerBuilder<S, T> extends AbstractTransformerBuilder<S, T, TransformerBuilder<S, T>> { - public TransformerBuilder(AttributeSensor<S> val) { - super(val); - } - } - - public static class UpdatingMapBuilder<S, TKey, TVal> extends AbstractUpdatingMapBuilder<S, TKey, TVal, UpdatingMapBuilder<S, TKey, TVal>> { - public UpdatingMapBuilder(AttributeSensor<Map<TKey,TVal>> val) { - super(val); - } - } - - public static class JoinerBuilder extends AbstractJoinerBuilder<JoinerBuilder> { - public JoinerBuilder(AttributeSensor<?> source) { - super(source); - } - } - - @Beta - private abstract static class ComputingNumber<T extends Number> implements Function<Collection<T>, T> { - protected final Number defaultValueForUnreportedSensors; - protected final Number valueToReportIfNoSensors; - protected final TypeToken<T> typeToken; - @SuppressWarnings({ "rawtypes", "unchecked" }) - public ComputingNumber(Number defaultValueForUnreportedSensors, Number valueToReportIfNoSensors, TypeToken<T> typeToken) { - this.defaultValueForUnreportedSensors = defaultValueForUnreportedSensors; - this.valueToReportIfNoSensors = valueToReportIfNoSensors; - if (typeToken!=null && TypeToken.of(Number.class).isAssignableFrom(typeToken.getType())) { - this.typeToken = typeToken; - } else if (typeToken==null || typeToken.isAssignableFrom(Number.class)) { - // use double if e.g. Object is supplied - this.typeToken = (TypeToken)TypeToken.of(Double.class); - } else { - throw new IllegalArgumentException("Type "+typeToken+" is not valid for "+this); - } - } - @Override public abstract T apply(Collection<T> input); - } - - @Beta - public static class ComputingSum<T extends Number> extends ComputingNumber<T> { - public ComputingSum(Number defaultValueForUnreportedSensors, Number valueToReportIfNoSensors, TypeToken<T> typeToken) { - super(defaultValueForUnreportedSensors, valueToReportIfNoSensors, typeToken); - } - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override public T apply(Collection<T> input) { - return (T) sum((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, typeToken); - } - } - - @Beta - public static class ComputingAverage<T extends Number> extends ComputingNumber<T> { - public ComputingAverage(Number defaultValueForUnreportedSensors, Number valueToReportIfNoSensors, TypeToken<T> typeToken) { - super(defaultValueForUnreportedSensors, valueToReportIfNoSensors, typeToken); - } - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override public T apply(Collection<T> input) { - return (T) average((Collection)input, (Number)defaultValueForUnreportedSensors, (Number)valueToReportIfNoSensors, typeToken); - } - } - - protected static <T extends Number> T average(Collection<T> vals, Number defaultValueForUnreportedSensors, Number valueToReportIfNoSensors, TypeToken<T> type) { - Double doubleValueToReportIfNoSensors = (valueToReportIfNoSensors == null) ? null : valueToReportIfNoSensors.doubleValue(); - int count = count(vals, defaultValueForUnreportedSensors!=null); - Double result = (count==0) ? doubleValueToReportIfNoSensors : - (Double) ((sum(vals, defaultValueForUnreportedSensors, 0, TypeToken.of(Double.class)) / count)); - - return cast(result, type); - } - - @SuppressWarnings("unchecked") - protected static <N extends Number> N cast(Number n, TypeToken<? extends N> numberType) { - return (N) TypeCoercions.castPrimitive(n, numberType.getRawType()); - } - - @Beta //may be moved - public static <N extends Number> N sum(Iterable<? extends Number> vals, Number valueIfNull, Number valueIfNone, TypeToken<N> type) { - double result = 0d; - int count = 0; - if (vals!=null) { - for (Number val : vals) { - if (val!=null) { - result += val.doubleValue(); - count++; - } else if (valueIfNull!=null) { - result += valueIfNull.doubleValue(); - count++; - } - } - } - if (count==0) return cast(valueIfNone, type); - return cast(result, type); - } - - protected static int count(Iterable<? extends Object> vals, boolean includeNullValues) { - int result = 0; - if (vals != null) - for (Object val : vals) - if (val!=null || includeNullValues) result++; - return result; - } - - private static <T> Map<T,T> newIdentityMap(Set<T> keys) { - Map<T,T> result = Maps.newLinkedHashMap(); - for (T key : keys) { - result.put(key, key); - } - return result; - } - - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java deleted file mode 100644 index c6d9329..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Joiner.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.sensor.BasicSensorEvent; -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.core.flags.SetFromFlag; -import org.apache.brooklyn.util.text.StringEscapes; -import org.apache.brooklyn.util.text.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.reflect.TypeToken; - -//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)") -@SuppressWarnings("serial") -public class Joiner<T> extends AbstractEnricher implements SensorEventListener<T> { - - private static final Logger LOG = LoggerFactory.getLogger(Joiner.class); - - public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer"); - public static ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor"); - public static ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor"); - @SetFromFlag("separator") - public static ConfigKey<String> SEPARATOR = ConfigKeys.newStringConfigKey("enricher.joiner.separator", "Separator string to insert between each argument", ","); - @SetFromFlag("quote") - public static ConfigKey<Boolean> QUOTE = ConfigKeys.newBooleanConfigKey("enricher.joiner.quote", "Whether to bash-escape each parameter and wrap in double-quotes, defaulting to true", true); - @SetFromFlag("minimum") - public static ConfigKey<Integer> MINIMUM = ConfigKeys.newIntegerConfigKey("enricher.joiner.minimum", "Minimum number of elements to join; if fewer than this, sets null; default 0 (no minimum)"); - @SetFromFlag("maximum") - public static ConfigKey<Integer> MAXIMUM = ConfigKeys.newIntegerConfigKey("enricher.joiner.maximum", "Maximum number of elements to join; default null means all elements always taken"); - - protected Entity producer; - protected AttributeSensor<T> sourceSensor; - protected Sensor<String> targetSensor; - - public Joiner() { - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - - this.producer = getConfig(PRODUCER) == null ? entity: getConfig(PRODUCER); - this.sourceSensor = (AttributeSensor<T>) getRequiredConfig(SOURCE_SENSOR); - this.targetSensor = (Sensor<String>) getRequiredConfig(TARGET_SENSOR); - - subscribe(producer, sourceSensor, this); - - Object value = producer.getAttribute((AttributeSensor<?>)sourceSensor); - // TODO would be useful to have a convenience to "subscribeAndThenIfItIsAlreadySetRunItOnce" - if (value!=null) { - onEvent(new BasicSensorEvent(sourceSensor, producer, value, -1)); - } - } - - @Override - public void onEvent(SensorEvent<T> event) { - emit(targetSensor, compute(event)); - } - - protected Object compute(SensorEvent<T> event) { - Object v = event.getValue(); - Object result = null; - if (v!=null) { - if (v instanceof Map) { - v = ((Map<?,?>)v).values(); - } - if (!(v instanceof Iterable)) { - LOG.warn("Enricher "+this+" received a non-iterable value "+v.getClass()+" "+v+"; refusing to join"); - } else { - MutableList<Object> c1 = MutableList.of(); - Integer maximum = getConfig(MAXIMUM); - for (Object ci: (Iterable<?>)v) { - if (maximum!=null && maximum>=0) { - if (c1.size()>=maximum) break; - } - c1.appendIfNotNull(Strings.toString(ci)); - } - Integer minimum = getConfig(MINIMUM); - if (minimum!=null && c1.size() < minimum) { - // use default null return value - } else { - if (getConfig(QUOTE)) { - MutableList<Object> c2 = MutableList.of(); - for (Object ci: c1) { - c2.add(StringEscapes.BashStringEscapes.wrapBash((String)ci)); - } - c1 = c2; - } - result = Strings.join(c1, getConfig(SEPARATOR)); - } - } - } - if (LOG.isTraceEnabled()) - LOG.trace("Enricher "+this+" computed "+result+" from "+event); - return result; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java deleted file mode 100644 index 2d74848..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Propagator.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.brooklyn.sensor.enricher; - -import java.util.Collection; -import java.util.Map; -import java.util.Set; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.entity.Attributes; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.core.flags.SetFromFlag; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.core.task.ValueResolver; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Preconditions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.reflect.TypeToken; - -@SuppressWarnings("serial") -//@Catalog(name="Propagator", description="Propagates attributes from one entity to another; see Enrichers.builder().propagating(...)") -public class Propagator extends AbstractEnricher implements SensorEventListener<Object> { - - private static final Logger LOG = LoggerFactory.getLogger(Propagator.class); - - public static final Set<Sensor<?>> SENSORS_NOT_USUALLY_PROPAGATED = ImmutableSet.<Sensor<?>>of( - Attributes.SERVICE_UP, Attributes.SERVICE_NOT_UP_INDICATORS, - Attributes.SERVICE_STATE_ACTUAL, Attributes.SERVICE_STATE_EXPECTED, Attributes.SERVICE_PROBLEMS); - - @SetFromFlag("producer") - public static ConfigKey<Entity> PRODUCER = ConfigKeys.newConfigKey(Entity.class, "enricher.producer"); - - @SetFromFlag("propagatingAllBut") - public static ConfigKey<Collection<Sensor<?>>> PROPAGATING_ALL_BUT = ConfigKeys.newConfigKey(new TypeToken<Collection<Sensor<?>>>() {}, "enricher.propagating.propagatingAllBut"); - - @SetFromFlag("propagatingAll") - public static ConfigKey<Boolean> PROPAGATING_ALL = ConfigKeys.newBooleanConfigKey("enricher.propagating.propagatingAll"); - - @SetFromFlag("propagating") - public static ConfigKey<Collection<? extends Sensor<?>>> PROPAGATING = ConfigKeys.newConfigKey(new TypeToken<Collection<? extends Sensor<?>>>() {}, "enricher.propagating.inclusions"); - - @SetFromFlag("sensorMapping") - public static ConfigKey<Map<? extends Sensor<?>, ? extends Sensor<?>>> SENSOR_MAPPING = ConfigKeys.newConfigKey(new TypeToken<Map<? extends Sensor<?>, ? extends Sensor<?>>>() {}, "enricher.propagating.sensorMapping"); - - protected Entity producer; - protected Map<? extends Sensor<?>, ? extends Sensor<?>> sensorMapping; - protected boolean propagatingAll; - protected Collection<Sensor<?>> propagatingAllBut; - protected Predicate<Sensor<?>> sensorFilter; - - public Propagator() { - } - - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - - this.producer = getConfig(PRODUCER) == null ? entity : getConfig(PRODUCER); - boolean sensorMappingSet = getConfig(SENSOR_MAPPING)!=null; - MutableMap<Sensor<?>,Sensor<?>> sensorMappingTemp = MutableMap.copyOf(getConfig(SENSOR_MAPPING)); - this.propagatingAll = Boolean.TRUE.equals(getConfig(PROPAGATING_ALL)) || getConfig(PROPAGATING_ALL_BUT)!=null; - - if (getConfig(PROPAGATING) != null) { - if (propagatingAll) { - throw new IllegalStateException("Propagator enricher "+this+" must not have 'propagating' set at same time as either 'propagatingAll' or 'propagatingAllBut'"); - } - - for (Object sensorO : getConfig(PROPAGATING)) { - Sensor<?> sensor = Tasks.resolving(sensorO).as(Sensor.class).timeout(ValueResolver.REAL_QUICK_WAIT).context(producer).get(); - if (!sensorMappingTemp.containsKey(sensor)) { - sensorMappingTemp.put(sensor, sensor); - } - } - this.sensorMapping = ImmutableMap.copyOf(sensorMappingTemp); - this.sensorFilter = new Predicate<Sensor<?>>() { - @Override public boolean apply(Sensor<?> input) { - // TODO kept for deserialization of inner classes, but shouldn't be necessary, as with other inner classes (qv); - // NB: previously this did this check: -// return input != null && sensorMapping.keySet().contains(input); - // but those clauses seems wrong (when would input be null?) and unnecessary (we are doing an explicit subscribe in this code path) - return true; - } - }; - } else if (sensorMappingSet) { - if (propagatingAll) { - throw new IllegalStateException("Propagator enricher "+this+" must not have 'sensorMapping' set at same time as either 'propagatingAll' or 'propagatingAllBut'"); - } - this.sensorMapping = ImmutableMap.copyOf(sensorMappingTemp); - this.sensorFilter = Predicates.alwaysTrue(); - } else { - this.sensorMapping = ImmutableMap.<Sensor<?>, Sensor<?>>of(); - if (!propagatingAll) { - // default if nothing specified is to do all but the ones not usually propagated - propagatingAll = true; - // user specified nothing, so *set* the all_but to the default set - // if desired, we could allow this to be dynamically reconfigurable, remove this field and always look up; - // slight performance hit (always looking up), and might need to recompute subscriptions, so not supported currently - // TODO this default is @Beta behaviour! -- maybe better to throw? - propagatingAllBut = SENSORS_NOT_USUALLY_PROPAGATED; - } else { - propagatingAllBut = getConfig(PROPAGATING_ALL_BUT); - } - this.sensorFilter = new Predicate<Sensor<?>>() { - @Override public boolean apply(Sensor<?> input) { - Collection<Sensor<?>> exclusions = propagatingAllBut; - // TODO this anonymous inner class and getConfig check kept should be removed / confirmed for rebind compatibility. - // we *should* be regenerating these fields on each rebind (calling to this method), - // so serialization of this class shouldn't be needed (and should be skipped), but that needs to be checked. - if (propagatingAllBut==null) exclusions = getConfig(PROPAGATING_ALL_BUT); - return input != null && (exclusions==null || !exclusions.contains(input)); - } - }; - } - - Preconditions.checkState(propagatingAll ^ sensorMapping.size() > 0, - "Nothing to propagate; detected: propagatingAll (%s, excluding %s), sensorMapping (%s)", propagatingAll, getConfig(PROPAGATING_ALL_BUT), sensorMapping); - - if (propagatingAll) { - subscribe(producer, null, this); - } else { - for (Sensor<?> sensor : sensorMapping.keySet()) { - subscribe(producer, sensor, this); - } - } - - emitAllAttributes(); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public void onEvent(SensorEvent<Object> event) { - // propagate upwards - Sensor<?> sourceSensor = event.getSensor(); - Sensor<?> destinationSensor = getDestinationSensor(sourceSensor); - - if (!sensorFilter.apply(sourceSensor)) { - return; // ignoring excluded sensor - } - - if (LOG.isTraceEnabled()) LOG.trace("enricher {} got {}, propagating via {}{}", - new Object[] {this, event, entity, (sourceSensor == destinationSensor ? "" : " (as "+destinationSensor+")")}); - - emit((Sensor)destinationSensor, event.getValue()); - } - - /** useful once sensors are added to emit all values */ - public void emitAllAttributes() { - emitAllAttributes(false); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void emitAllAttributes(boolean includeNullValues) { - Iterable<? extends Sensor<?>> sensorsToPopulate = propagatingAll - ? Iterables.filter(producer.getEntityType().getSensors(), sensorFilter) - : sensorMapping.keySet(); - - for (Sensor<?> s : sensorsToPopulate) { - if (s instanceof AttributeSensor) { - AttributeSensor destinationSensor = (AttributeSensor<?>) getDestinationSensor(s); - Object v = producer.getAttribute((AttributeSensor<?>)s); - // TODO we should keep a timestamp for the source sensor and echo it - // (this pretends timestamps are current, which probably isn't the case when we are propagating) - if (v != null || includeNullValues) entity.setAttribute(destinationSensor, v); - } - } - } - - private Sensor<?> getDestinationSensor(Sensor<?> sourceSensor) { - return sensorMapping.containsKey(sourceSensor) ? sensorMapping.get(sourceSensor): sourceSensor; - } -}
