http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java deleted file mode 100644 index 51d3d48..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorPropagatingEnricher.java +++ /dev/null @@ -1,180 +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.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; - -/** - * an enricher policy which just listens for the target sensor(s) on a child entity and passes it up. - * now superseded by syntax such as: - * - * <pre>{@code Enrichers.builder().propagating(XXX).from(source).build()}</pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - * - * @see Propagator if need to sub-class - */ -public class SensorPropagatingEnricher extends AbstractEnricher implements SensorEventListener<Object> { - - public static final Logger log = LoggerFactory.getLogger(SensorPropagatingEnricher.class); - - /** the entity to listen to */ - private final Entity source; - - /** the sensors to listen to */ - private final Set<Sensor<?>> sensors; - - /** the sensors to listen to */ - private final Map<Sensor<?>, Sensor<?>> sensorMappings; - - public static SensorPropagatingEnricher newInstanceListeningToAllSensors(Entity source) { - return newInstanceListeningToAllSensorsBut(source); - } - public static SensorPropagatingEnricher newInstanceListeningToAllSensorsBut(Entity source, Sensor<?>... excludes) { - Set<Sensor<?>> excluded = ImmutableSet.copyOf(excludes); - Set<Sensor<?>> includes = Sets.newLinkedHashSet(); - - for (Sensor<?> it : source.getEntityType().getSensors()) { - if (!excluded.contains(it)) includes.add(it); - } - return new SensorPropagatingEnricher(source, includes); - } - - public static SensorPropagatingEnricher newInstanceListeningTo(Entity source, Sensor<?>... includes) { - return new SensorPropagatingEnricher(source, includes); - } - - /** - * listens to sensors from source, propagates them here renamed according to the map - * - * Instead, consider calling: - * <pre> - * {@code - * addEnricher(Enrichers.builder() - * .propagating(mapOfOldSensorNamesToNewSensorNames) - * .from(source) - * .build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public static SensorPropagatingEnricher newInstanceRenaming(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) { - return new SensorPropagatingEnricher(source, sensors); - } - - /** - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public SensorPropagatingEnricher(Entity source, Sensor<?>... sensors) { - this(source, ImmutableList.copyOf(sensors)); - } - - /** - * Instead, consider calling: - * <pre> - * {@code - * addEnricher(Enrichers.builder() - * .propagating(sensors) - * .from(source) - * .build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers#builder()} - */ - public SensorPropagatingEnricher(Entity source, Collection<Sensor<?>> sensors) { - this.source = source; - this.sensors = ImmutableSet.copyOf(sensors); - this.sensorMappings = ImmutableMap.of(); - } - - public SensorPropagatingEnricher(Entity source, Map<? extends Sensor<?>, ? extends Sensor<?>> sensors) { - this.source = source; - this.sensors = ImmutableSet.copyOf(sensors.keySet()); - this.sensorMappings = ImmutableMap.copyOf(sensors); - } - - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - for (Sensor<?> s: sensors) { - subscribe(source, s, this); - } - } - - @Override - @SuppressWarnings({ "unchecked", "rawtypes" }) - public void onEvent(SensorEvent<Object> event) { - // propagate upwards - Sensor<?> sourceSensor = event.getSensor(); - Sensor<?> destinationSensor = getDestinationSensor(sourceSensor); - - if (log.isTraceEnabled()) log.trace("policy {} got {}, propagating via {}{}", - new Object[] {this, event, entity, (sourceSensor == destinationSensor ? "" : " (as "+destinationSensor+")")}); - - if (event.getSensor() instanceof AttributeSensor) { - entity.setAttribute((AttributeSensor)destinationSensor, event.getValue()); - } else { - entity.emit((Sensor)destinationSensor, event.getValue()); - } - } - - /** useful post-addition to emit current values */ - public void emitAllAttributes() { - emitAllAttributes(false); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void emitAllAttributes(boolean includeNullValues) { - for (Sensor s: sensors) { - if (s instanceof AttributeSensor) { - AttributeSensor destinationSensor = (AttributeSensor<?>) getDestinationSensor(s); - Object v = source.getAttribute((AttributeSensor)s); - if (v != null || includeNullValues) entity.setAttribute(destinationSensor, v); - } - } - } - - /** convenience, to be called by the host */ - public SensorPropagatingEnricher addToEntityAndEmitAll(Entity host) { - host.addEnricher(this); - emitAllAttributes(); - return this; - } - - private Sensor<?> getDestinationSensor(Sensor<?> sourceSensor) { - return sensorMappings.containsKey(sourceSensor) ? sensorMappings.get(sourceSensor): sourceSensor; - } -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java deleted file mode 100644 index 2ad1bdf..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/SensorTransformingEnricher.java +++ /dev/null @@ -1,106 +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.entity.Entity; -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.util.groovy.GroovyJavaMethods; -import org.apache.brooklyn.util.javalang.JavaClassNames; -import org.apache.brooklyn.util.time.Duration; - -import groovy.lang.Closure; - -import com.google.common.base.Function; - -/** - * @deprecated since 0.7.0; use {@link Enrichers.builder()} - * @see Transformer if need to sub-class - */ -public class SensorTransformingEnricher<T,U> extends AbstractTypeTransformingEnricher { - - private Function<? super T, ? extends U> transformation; - - public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Function<? super T, ? extends U> transformation) { - super(producer, source, target); - this.transformation = transformation; - this.uniqueTag = JavaClassNames.simpleClassName(getClass())+":"+source.getName()+"*->"+target.getName();; - } - - public SensorTransformingEnricher(Entity producer, Sensor<T> source, Sensor<U> target, Closure transformation) { - this(producer, source, target, GroovyJavaMethods.functionFromClosure(transformation)); - } - - public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Function<T,U> transformation) { - this(null, source, target, transformation); - } - - public SensorTransformingEnricher(Sensor<T> source, Sensor<U> target, Closure transformation) { - this(null, source, target, GroovyJavaMethods.functionFromClosure(transformation)); - } - - @Override - public void onEvent(SensorEvent event) { - if (accept((T)event.getValue())) { - if (target instanceof AttributeSensor) - entity.setAttribute((AttributeSensor)target, compute((T)event.getValue())); - else - entity.emit(target, compute((T)event.getValue())); - } - } - - protected boolean accept(T value) { - return true; - } - - protected U compute(T value) { - return transformation.apply(value); - } - - /** - * creates an enricher which listens to a source (from the producer), - * transforms it and publishes it under the target - * - * Instead, consider calling: - * <pre> - * {@code - * addEnricher(Enrichers.builder() - * .transforming(source) - * .publishing(target) - * .from(producer) - * .computing(transformation) - * .build()); - * } - * </pre> - * - * @deprecated since 0.7.0; use {@link Enrichers.builder()} - */ - public static <U,V> SensorTransformingEnricher<U,V> newInstanceTransforming(Entity producer, AttributeSensor<U> source, - Function<U,V> transformation, AttributeSensor<V> target) { - return new SensorTransformingEnricher<U,V>(producer, source, target, transformation); - } - - /** as {@link #newInstanceTransforming(Entity, AttributeSensor, Function, AttributeSensor)} - * using the same sensor as the source and the target */ - public static <T> SensorTransformingEnricher<T,T> newInstanceTransforming(Entity producer, AttributeSensor<T> sensor, - Function<T,T> transformation) { - return newInstanceTransforming(producer, sensor, transformation, sensor); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java deleted file mode 100644 index f77bd8c..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/Transformer.java +++ /dev/null @@ -1,103 +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 org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.util.collections.MutableSet; -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.Function; -import com.google.common.reflect.TypeToken; - -//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)") -@SuppressWarnings("serial") -public class Transformer<T,U> extends AbstractTransformer<T,U> { - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(Transformer.class); - - // exactly one of these should be supplied to set a value - public static ConfigKey<?> TARGET_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.targetValue"); - public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_VALUE = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation"); - public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_EVENT = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation.fromevent"); - - public Transformer() { - } - - /** returns a function for transformation, for immediate use only (not for caching, as it may change) */ - @Override - @SuppressWarnings("unchecked") - protected Function<SensorEvent<T>, U> getTransformation() { - MutableSet<Object> suppliers = MutableSet.of(); - suppliers.addIfNotNull(config().getRaw(TARGET_VALUE).orNull()); - suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_EVENT).orNull()); - suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_VALUE).orNull()); - checkArgument(suppliers.size()==1, - "Must set exactly one of: %s, %s, %s", TARGET_VALUE.getName(), TRANSFORMATION_FROM_VALUE.getName(), TRANSFORMATION_FROM_EVENT.getName()); - - Function<?, ?> fromEvent = config().get(TRANSFORMATION_FROM_EVENT); - if (fromEvent != null) { - return (Function<SensorEvent<T>, U>) fromEvent; - } - - final Function<T, U> fromValueFn = (Function<T, U>) config().get(TRANSFORMATION_FROM_VALUE); - if (fromValueFn != null) { - // named class not necessary as result should not be serialized - return new Function<SensorEvent<T>, U>() { - @Override public U apply(SensorEvent<T> input) { - return fromValueFn.apply(input.getValue()); - } - @Override - public String toString() { - return ""+fromValueFn; - } - }; - } - - // from target value - // named class not necessary as result should not be serialized - final Object targetValueRaw = config().getRaw(TARGET_VALUE).orNull(); - return new Function<SensorEvent<T>, U>() { - @Override public U apply(SensorEvent<T> input) { - // evaluate immediately, or return null - // PRETTY_QUICK/200ms seems a reasonable compromise for tasks which require BG evaluation - // but which are non-blocking - // TODO better would be to have a mode in which tasks are not permitted to block on - // external events; they can submit tasks and block on them (or even better, have a callback architecture); - // however that is a non-trivial refactoring - return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType()) - .context(entity) - .description("Computing sensor "+targetSensor+" from "+targetValueRaw) - .timeout(ValueResolver.PRETTY_QUICK_WAIT) - .getMaybe().orNull(); - } - public String toString() { - return ""+targetValueRaw; - } - }; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java deleted file mode 100644 index 6ae48a7..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/UpdatingMap.java +++ /dev/null @@ -1,158 +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.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.Entities; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.core.flags.SetFromFlag; -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.collect.Maps; -import com.google.common.reflect.TypeToken; - -/** - * Enricher which updates an entry in a sensor map ({@link #TARGET_SENSOR}) - * based on the value of another sensor ({@link #SOURCE_SENSOR}. - * <p> - * The key used defaults to the name of the source sensor but can be specified with {@link #KEY_IN_TARGET_SENSOR}. - * The value placed in the map is the result of applying the function in {@link #COMPUTING} to the sensor value, - * with default behaviour being to remove an entry if <code>null</code> is returned - * but this can be overriden by setting {@link #REMOVING_IF_RESULT_IS_NULL} false. - * {@link Entities#REMOVE} and {@link Entities#UNCHANGED} are also respeced as return values for the computation - * (ignoring generics). - * Unlike most other enrichers, this defaults to {@link AbstractEnricher#SUPPRESS_DUPLICATES} being true - * - * @author alex - * - * @param <S> source sensor type - * @param <TKey> key type in target sensor map - * @param <TVal> value type in target sensor map - */ -@SuppressWarnings("serial") -public class UpdatingMap<S,TKey,TVal> extends AbstractEnricher implements SensorEventListener<S> { - - private static final Logger LOG = LoggerFactory.getLogger(UpdatingMap.class); - - @SetFromFlag("fromSensor") - public static final ConfigKey<Sensor<?>> SOURCE_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.sourceSensor"); - @SetFromFlag("targetSensor") - public static final ConfigKey<Sensor<?>> TARGET_SENSOR = ConfigKeys.newConfigKey(new TypeToken<Sensor<?>>() {}, "enricher.targetSensor"); - @SetFromFlag("key") - public static final ConfigKey<?> KEY_IN_TARGET_SENSOR = ConfigKeys.newConfigKey(Object.class, "enricher.updatingMap.keyInTargetSensor", - "Key to update in the target sensor map, defaulting to the name of the source sensor"); - @SetFromFlag("computing") - public static final ConfigKey<Function<?, ?>> COMPUTING = ConfigKeys.newConfigKey(new TypeToken<Function<?,?>>() {}, "enricher.updatingMap.computing"); - @SetFromFlag("removingIfResultIsNull") - public static final ConfigKey<Boolean> REMOVING_IF_RESULT_IS_NULL = ConfigKeys.newBooleanConfigKey("enricher.updatingMap.removingIfResultIsNull", - "Whether the key in the target map is removed if the result if the computation is null"); - - protected AttributeSensor<S> sourceSensor; - protected AttributeSensor<Map<TKey,TVal>> targetSensor; - protected TKey key; - protected Function<S,? extends TVal> computing; - protected Boolean removingIfResultIsNull; - - public UpdatingMap() { - this(Maps.newLinkedHashMap()); - } - - public UpdatingMap(Map<Object, Object> flags) { - super(flags); - // this always suppresses duplicates, but it updates the same map *in place* so the usual suppress duplicates logic should not be applied - // TODO clean up so that we have synchronization guarantees and can inspect the item to see whether it has changed - suppressDuplicates = false; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Override - public void setEntity(EntityLocal entity) { - super.setEntity(entity); - this.sourceSensor = (AttributeSensor<S>) getRequiredConfig(SOURCE_SENSOR); - this.targetSensor = (AttributeSensor<Map<TKey,TVal>>) getRequiredConfig(TARGET_SENSOR); - this.key = (TKey) getConfig(KEY_IN_TARGET_SENSOR); - this.computing = (Function) getRequiredConfig(COMPUTING); - this.removingIfResultIsNull = getConfig(REMOVING_IF_RESULT_IS_NULL); - - subscribe(entity, sourceSensor, this); - onUpdated(); - } - - @Override - public void onEvent(SensorEvent<S> event) { - onUpdated(); - } - - /** - * Called whenever the values for the set of producers changes (e.g. on an event, or on a member added/removed). - */ - @SuppressWarnings("unchecked") - protected void onUpdated() { - try { - Object v = computing.apply(entity.getAttribute(sourceSensor)); - if (v == null && !Boolean.FALSE.equals(removingIfResultIsNull)) { - v = Entities.REMOVE; - } - if (v == Entities.UNCHANGED) { - // nothing - } else { - // TODO check synchronization - TKey key = this.key; - if (key==null) key = (TKey) sourceSensor.getName(); - - Map<TKey, TVal> map = entity.getAttribute(targetSensor); - - boolean created = (map==null); - if (created) map = MutableMap.of(); - - boolean changed; - if (v == Entities.REMOVE) { - changed = map.containsKey(key); - if (changed) - map.remove(key); - } else { - TVal oldV = map.get(key); - if (oldV==null) - changed = (v!=null || !map.containsKey(key)); - else - changed = !oldV.equals(v); - if (changed) - map.put(key, (TVal)v); - } - if (changed || created) - emit(targetSensor, map); - } - } catch (Throwable t) { - LOG.warn("Error calculating map update for enricher "+this, t); - throw Exceptions.propagate(t); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java deleted file mode 100644 index dc65fa8..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlRollingTimeWindowMeanEnricher.java +++ /dev/null @@ -1,178 +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.Iterator; -import java.util.LinkedList; - -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.util.time.Duration; - -import com.google.common.base.Function; - -/** - * Transforms {@link Sensor} data into a rolling average based on a time window. - * - * All values within the window are weighted or discarded based on the timestamps associated with - * them (discards occur when a new value is added or an average is requested) - * <p> - * This will not extrapolate figures - it is assumed a value is valid and correct for the entire - * time period between it and the previous value. Normally, the average attribute is only updated - * when a new value arrives so it can give a fully informed average, but there is a danger of this - * going stale. - * <p> - * When an average is requested, it is likely there will be a segment of the window for which there - * isn't a value. Instead of extrapolating a value and providing different extrapolation techniques, - * the average is reported with a confidence value which reflects the fraction of the time - * window for which the values were valid. - * <p> - * Consumers of the average may ignore the confidence value and just use the last known average. - * They could multiply the returned value by the confidence value to get a decay-type behavior as - * the window empties. A third alternative is to, at a certain confidence threshold, report that - * the average is no longer meaningful. - * <p> - * The default average when no data has been received is 0, with a confidence of 0 - */ -public class YamlRollingTimeWindowMeanEnricher<T extends Number> extends AbstractTransformer<T,Double> { - - public static ConfigKey<Duration> WINDOW_DURATION = ConfigKeys.newConfigKey(Duration.class, "enricher.window.duration", - "Duration for which this window should store data, default one minute", Duration.ONE_MINUTE); - - public static ConfigKey<Double> CONFIDENCE_REQUIRED_TO_PUBLISH = ConfigKeys.newDoubleConfigKey("enricher.window.confidenceRequired", - "Minimum confidence level (ie period covered) required to publish a rolling average", 0.8d); - - public static class ConfidenceQualifiedNumber { - final Double value; - final double confidence; - - public ConfidenceQualifiedNumber(Double value, double confidence) { - this.value = value; - this.confidence = confidence; - } - - @Override - public String toString() { - return ""+value+" ("+(int)(confidence*100)+"%)"; - } - - } - - private final LinkedList<T> values = new LinkedList<T>(); - private final LinkedList<Long> timestamps = new LinkedList<Long>(); - volatile ConfidenceQualifiedNumber lastAverage = new ConfidenceQualifiedNumber(0d,0d); - - @Override - protected Function<SensorEvent<T>, Double> getTransformation() { - return new Function<SensorEvent<T>, Double>() { - @Override - public Double apply(SensorEvent<T> event) { - long eventTime = event.getTimestamp(); - if (event.getValue()==null) { - return null; - } - values.addLast(event.getValue()); - timestamps.addLast(eventTime); - if (eventTime>0) { - ConfidenceQualifiedNumber average = getAverage(eventTime, 0); - - if (average.confidence > getConfig(CONFIDENCE_REQUIRED_TO_PUBLISH)) { - // without confidence, we might publish wildly varying estimates, - // causing spurious resizes, so allow it to be configured, and - // by default require a high value - - // TODO would be nice to include timestamp, etc - return average.value; - } - } - return null; - } - }; - } - - public ConfidenceQualifiedNumber getAverage(long fromTime, long graceAllowed) { - if (timestamps.isEmpty()) { - return lastAverage = new ConfidenceQualifiedNumber(lastAverage.value, 0.0d); - } - - long firstTimestamp = -1; - Iterator<Long> ti = timestamps.iterator(); - while (ti.hasNext()) { - firstTimestamp = ti.next(); - if (firstTimestamp>0) break; - } - if (firstTimestamp<=0) { - // no values with reasonable timestamps - return lastAverage = new ConfidenceQualifiedNumber(values.get(values.size()-1).doubleValue(), 0.0d); - } - - long lastTimestamp = timestamps.get(timestamps.size()-1); - - long now = fromTime; - if (lastTimestamp > fromTime - graceAllowed) { - // without this, if the computation takes place X seconds after the publish, - // we treat X seconds as time for which we have no confidence in the data - now = lastTimestamp; - } - pruneValues(now); - - Duration timePeriod = getConfig(WINDOW_DURATION); - long windowStart = Math.max(now-timePeriod.toMilliseconds(), firstTimestamp); - long windowEnd = Math.max(now-timePeriod.toMilliseconds(), lastTimestamp); - Double confidence = ((double)(windowEnd - windowStart)) / timePeriod.toMilliseconds(); - if (confidence <= 0.0000001d) { - // not enough timestamps in window - double lastValue = values.get(values.size()-1).doubleValue(); - return lastAverage = new ConfidenceQualifiedNumber(lastValue, 0.0d); - } - - long start = windowStart; - long end; - double weightedAverage = 0.0d; - - Iterator<T> valuesIter = values.iterator(); - Iterator<Long> timestampsIter = timestamps.iterator(); - while (valuesIter.hasNext()) { - // Ignores null and out-of-date values (and also values that are received out-of-order, but that shouldn't happen!) - Number val = valuesIter.next(); - Long timestamp = timestampsIter.next(); - if (val!=null && timestamp >= start) { - end = timestamp; - weightedAverage += ((end - start) / (confidence * timePeriod.toMilliseconds())) * val.doubleValue(); - start = timestamp; - } - } - - return lastAverage = new ConfidenceQualifiedNumber(weightedAverage, confidence); - } - - /** - * Discards out-of-date values, but keeps at least one value. - */ - private void pruneValues(long now) { - // keep one value from before the period, so that we can tell the window's start time - Duration timePeriod = getConfig(WINDOW_DURATION); - while(timestamps.size() > 1 && timestamps.get(1) < (now - timePeriod.toMilliseconds())) { - timestamps.removeFirst(); - values.removeFirst(); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java deleted file mode 100644 index c49ac26..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/enricher/YamlTimeWeightedDeltaEnricher.java +++ /dev/null @@ -1,83 +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.SensorEvent; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.sensor.enricher.AbstractTransformer; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.time.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Function; - -/** - * Converts an absolute count sensor into a delta sensor (i.e. the diff between the current and previous value), - * presented as a units/timeUnit based on the event timing. - * <p> - * For example, given a requests.count sensor, this can make a requests.per_sec sensor with {@link #DELTA_PERIOD} set to "1s" (the default). - * <p> - * Suitable for configuration from YAML. - */ -public class YamlTimeWeightedDeltaEnricher<T extends Number> extends AbstractTransformer<T,Double> { - private static final Logger LOG = LoggerFactory.getLogger(YamlTimeWeightedDeltaEnricher.class); - - transient Object lock = new Object(); - Number lastValue; - long lastTime = -1; - - public static ConfigKey<Duration> DELTA_PERIOD = ConfigKeys.newConfigKey(Duration.class, "enricher.delta.period", - "Duration that this delta should compute for, default per second", Duration.ONE_SECOND); - - @Override - protected Function<SensorEvent<T>, Double> getTransformation() { - return new Function<SensorEvent<T>, Double>() { - @Override - public Double apply(SensorEvent<T> event) { - synchronized (lock) { - Double current = TypeCoercions.coerce(event.getValue(), Double.class); - - if (current == null) return null; - - long eventTime = event.getTimestamp(); - long unitMillis = getConfig(DELTA_PERIOD).toMilliseconds(); - Double result = null; - - if (eventTime > 0 && eventTime > lastTime) { - if (lastValue == null || lastTime < 0) { - // cannot calculate time-based delta with a single value - if (LOG.isTraceEnabled()) LOG.trace("{} received event but no last value so will not emit, null -> {} at {}", new Object[] {this, current, eventTime}); - } else { - double duration = eventTime - lastTime; - result = (current - lastValue.doubleValue()) / (duration / unitMillis); - } - } - - lastValue = current; - lastTime = eventTime; - - return result; - } - } - }; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java new file mode 100644 index 0000000..be87f1f --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/core/enricher/BasicEnricherTest.java @@ -0,0 +1,119 @@ +/* + * 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.core.enricher; + +import static org.testng.Assert.assertEquals; + +import java.util.Map; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.sensor.Enricher; +import org.apache.brooklyn.api.sensor.EnricherSpec; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.BasicConfigKey; +import org.apache.brooklyn.core.enricher.AbstractEnricher; +import org.apache.brooklyn.core.entity.BrooklynConfigKeys; +import org.apache.brooklyn.core.entity.factory.ApplicationBuilder; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.core.test.entity.TestApplicationNoEnrichersImpl; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.core.flags.SetFromFlag; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.Iterables; + +/** + * Test that enricher can be created and accessed, by construction and by spec + */ +public class BasicEnricherTest extends BrooklynAppUnitTestSupport { + + // TODO These tests are a copy of BasicPolicyTest, which is a code smell. + // However, the src/main/java code does not contain as much duplication. + + protected void setUpApp() { + EntitySpec<TestApplication> appSpec = EntitySpec.create(TestApplication.class, TestApplicationNoEnrichersImpl.class) + .configure(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION, shouldSkipOnBoxBaseDirResolution()); + app = ApplicationBuilder.newManagedApp(appSpec, mgmt); + } + + public static class MyEnricher extends AbstractEnricher { + @SetFromFlag("intKey") + public static final BasicConfigKey<Integer> INT_KEY = new BasicConfigKey<Integer>(Integer.class, "bkey", "b key"); + + @SetFromFlag("strKey") + public static final ConfigKey<String> STR_KEY = new BasicConfigKey<String>(String.class, "akey", "a key"); + public static final ConfigKey<Integer> INT_KEY_WITH_DEFAULT = new BasicConfigKey<Integer>(Integer.class, "ckey", "c key", 1); + public static final ConfigKey<String> STR_KEY_WITH_DEFAULT = new BasicConfigKey<String>(String.class, "strKey", "str key", "str key default"); + + MyEnricher(Map<?,?> flags) { + super(flags); + } + + public MyEnricher() { + super(); + } + } + + @Test + public void testAddInstance() throws Exception { + MyEnricher enricher = new MyEnricher(); + enricher.setDisplayName("Bob"); + enricher.config().set(MyEnricher.STR_KEY, "aval"); + enricher.config().set(MyEnricher.INT_KEY, 2); + app.addEnricher(enricher); + + assertEquals(enricher.getDisplayName(), "Bob"); + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval"); + assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2); + } + + @Test + public void testAddSpec() throws Exception { + MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class) + .displayName("Bob") + .configure(MyEnricher.STR_KEY, "aval").configure(MyEnricher.INT_KEY, 2)); + + assertEquals(enricher.getDisplayName(), "Bob"); + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval"); + assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2); + } + + @Test + public void testTagsFromSpec() throws Exception { + MyEnricher enricher = app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x")); + + assertEquals(enricher.tags().getTags(), MutableSet.of("x", 99)); + assertEquals(enricher.getUniqueTag(), "x"); + } + + @Test + public void testSameUniqueTagEnricherNotAddedTwice() throws Exception { + app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(99).uniqueTag("x")); + app.addEnricher(EnricherSpec.create(MyEnricher.class).tag(94).uniqueTag("x")); + + assertEquals(app.getEnrichers().size(), 1); + // the more recent one should dominate + Enricher enricher = Iterables.getOnlyElement(app.getEnrichers()); + Assert.assertTrue(enricher.tags().containsTag(94)); + Assert.assertFalse(enricher.tags().containsTag(99)); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java b/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java new file mode 100644 index 0000000..150a09b --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/core/enricher/EnricherConfigTest.java @@ -0,0 +1,147 @@ +/* + * 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.core.enricher; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import org.apache.brooklyn.core.config.BasicConfigKey; +import org.apache.brooklyn.core.enricher.BasicEnricherTest.MyEnricher; +import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; +import org.apache.brooklyn.util.collections.MutableMap; +import org.testng.annotations.Test; + +/** + * Test that configuration properties are usable and inherited correctly. + */ +public class EnricherConfigTest extends BrooklynAppUnitTestSupport { + + // TODO These tests are a copy of PolicyConfigTest, which is a code smell. + // However, the src/main/java code does not contain as much duplication. + + private BasicConfigKey<String> differentKey = new BasicConfigKey<String>(String.class, "differentkey", "diffval"); + + @Test + public void testConfigFlagsPassedInAtConstructionIsAvailable() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put("strKey", "aval") + .put("intKey", 2) + .build()); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval"); + assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2); + // this is set, because key name matches annotation on STR_KEY + assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "aval"); + } + + @Test + public void testUnknownConfigPassedInAtConstructionIsWarnedAndIgnored() throws Exception { + // TODO Also assert it's warned + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(differentKey, "aval") + .build()); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(differentKey), null); + assertEquals(enricher.getEnricherType().getConfigKey(differentKey.getName()), null); + } + + @Test + public void testConfigPassedInAtConstructionIsAvailable() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(MyEnricher.STR_KEY, "aval") + .put(MyEnricher.INT_KEY, 2) + .build()); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval"); + assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2); + // this is not set (contrast with above) + assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), MyEnricher.STR_KEY_WITH_DEFAULT.getDefaultValue()); + } + + @Test + public void testConfigSetToGroovyTruthFalseIsAvailable() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(MyEnricher.INT_KEY_WITH_DEFAULT, 0) + .build()); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.INT_KEY_WITH_DEFAULT), (Integer)0); + } + + @Test + public void testConfigSetToNullIsAvailable() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(MyEnricher.STR_KEY_WITH_DEFAULT, null) + .build()); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), null); + } + + @Test + public void testConfigCanBeSetOnEnricher() throws Exception { + MyEnricher enricher = new MyEnricher(); + enricher.config().set(MyEnricher.STR_KEY, "aval"); + enricher.config().set(MyEnricher.INT_KEY, 2); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "aval"); + assertEquals(enricher.getConfig(MyEnricher.INT_KEY), (Integer)2); + } + + @Test + public void testConfigSetterOverridesConstructorValue() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(MyEnricher.STR_KEY, "aval") + .build()); + enricher.config().set(MyEnricher.STR_KEY, "diffval"); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "diffval"); + } + + @Test + public void testConfigCannotBeSetAfterApplicationIsStarted() throws Exception { + MyEnricher enricher = new MyEnricher(MutableMap.builder() + .put(MyEnricher.STR_KEY, "origval") + .build()); + app.addEnricher(enricher); + + try { + enricher.config().set(MyEnricher.STR_KEY,"newval"); + fail(); + } catch (UnsupportedOperationException e) { + // success + } + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY), "origval"); + } + + @Test + public void testConfigReturnsDefaultValueIfNotSet() throws Exception { + MyEnricher enricher = new MyEnricher(); + app.addEnricher(enricher); + + assertEquals(enricher.getConfig(MyEnricher.STR_KEY_WITH_DEFAULT), "str key default"); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java index d53bc87..1fec2e8 100644 --- a/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/entity/EntitySpecTest.java @@ -30,6 +30,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.BasicConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.location.SimulatedLocation; import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport; @@ -37,7 +38,6 @@ import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; import org.apache.brooklyn.core.test.entity.TestEntityNoEnrichersImpl; import org.apache.brooklyn.entity.group.BasicGroup; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.testng.annotations.BeforeMethod; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java index f751bcb..03a9c79 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/persist/BrooklynMementoPersisterTestFixture.java @@ -46,7 +46,7 @@ import org.apache.brooklyn.core.mgmt.rebind.RecordingRebindExceptionHandler; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.policy.TestPolicy; -import org.apache.brooklyn.sensor.enricher.Enrichers; +import org.apache.brooklyn.enricher.stock.Enrichers; import org.testng.SkipException; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java index c4d295a..e79ba8a 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindEnricherTest.java @@ -34,6 +34,7 @@ import org.apache.brooklyn.api.sensor.Enricher; import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.entity.EntityInternal; import org.apache.brooklyn.core.entity.EntityPredicates; @@ -42,9 +43,8 @@ import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.core.test.entity.TestEntityImpl; +import org.apache.brooklyn.enricher.stock.Enrichers; import org.apache.brooklyn.entity.group.DynamicCluster; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; -import org.apache.brooklyn.sensor.enricher.Enrichers; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.test.EntityTestUtils; import org.apache.brooklyn.util.collections.MutableSet; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java index 26ee74f..e78f062 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindFailuresTest.java @@ -42,6 +42,7 @@ import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.config.ConfigMap; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.entity.EntityFunctions; import org.apache.brooklyn.core.entity.EntityPredicates; import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; @@ -49,7 +50,6 @@ import org.apache.brooklyn.core.mgmt.rebind.RebindEntityTest.MyEntity; import org.apache.brooklyn.core.mgmt.rebind.RebindEntityTest.MyEntityImpl; import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; import org.apache.brooklyn.util.core.flags.SetFromFlag; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.os.Os; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java index 28c9ba8..faff0c9 100644 --- a/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/mgmt/rebind/RebindPolicyTest.java @@ -35,6 +35,7 @@ import org.apache.brooklyn.api.policy.PolicySpec; import org.apache.brooklyn.api.sensor.EnricherSpec; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.core.mgmt.rebind.RebindEnricherTest.MyEnricher; @@ -42,7 +43,6 @@ import org.apache.brooklyn.core.policy.AbstractPolicy; import org.apache.brooklyn.core.test.entity.TestApplication; import org.apache.brooklyn.core.test.entity.TestEntity; import org.apache.brooklyn.entity.group.BasicGroup; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java b/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java index a9f9655..12a6bff 100644 --- a/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java +++ b/core/src/test/java/org/apache/brooklyn/core/policy/basic/EnricherTypeTest.java @@ -22,7 +22,7 @@ import static org.testng.Assert.assertEquals; import org.apache.brooklyn.api.sensor.EnricherType; import org.apache.brooklyn.core.config.BasicConfigKey; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java b/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java index 2340c51..42b52d2 100644 --- a/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java +++ b/core/src/test/java/org/apache/brooklyn/core/test/policy/TestEnricher.java @@ -26,7 +26,7 @@ import org.apache.brooklyn.api.sensor.AttributeSensor; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.BasicConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.sensor.enricher.AbstractEnricher; +import org.apache.brooklyn.core.enricher.AbstractEnricher; import org.apache.brooklyn.util.core.flags.SetFromFlag; import com.google.common.reflect.TypeToken; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/6f15e8a6/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy new file mode 100644 index 0000000..481e233 --- /dev/null +++ b/core/src/test/java/org/apache/brooklyn/enricher/stock/CustomAggregatingEnricherDeprecatedTest.groovy @@ -0,0 +1,368 @@ +/* + * 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.enricher.stock + +import static org.testng.Assert.assertEquals + +import org.apache.brooklyn.api.entity.EntitySpec +import org.apache.brooklyn.api.sensor.AttributeSensor +import org.apache.brooklyn.core.test.entity.TestApplication +import org.apache.brooklyn.core.test.entity.TestEntity +import org.apache.brooklyn.enricher.stock.CustomAggregatingEnricher; +import org.apache.brooklyn.core.entity.Entities +import org.apache.brooklyn.entity.group.BasicGroup +import org.apache.brooklyn.core.location.SimulatedLocation +import org.apache.brooklyn.core.sensor.BasicAttributeSensor +import org.apache.brooklyn.test.TestUtils +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import org.testng.annotations.AfterMethod +import org.testng.annotations.BeforeMethod +import org.testng.annotations.Test + +import com.google.common.base.Function + +class CustomAggregatingEnricherDeprecatedTest { + + public static final Logger log = LoggerFactory.getLogger(CustomAggregatingEnricherDeprecatedTest.class); + + private static final long TIMEOUT_MS = 10*1000 + private static final long SHORT_WAIT_MS = 250 + + TestApplication app + TestEntity producer + + AttributeSensor<Integer> intSensor + AttributeSensor<Integer> target + + @BeforeMethod(alwaysRun=true) + public void setUp() { + app = TestApplication.Factory.newManagedInstanceForTests(); + producer = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + intSensor = new BasicAttributeSensor<Integer>(Integer.class, "int sensor") + target = new BasicAttributeSensor<Integer>(Long.class, "target sensor") + + app.start([new SimulatedLocation()]) + } + + @AfterMethod(alwaysRun=true) + public void tearDown() { + if (app!=null) Entities.destroyAll(app.getManagementContext()); + } + + @Test + public void testEnrichersWithNoProducers() { + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher([:], intSensor, target, 11, 40) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), 40 + } + + @Test + public void testSummingEnricherWhenNoSensorValuesYet() { + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, producers:[producer], 11, 40) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), 11 + } + + @Test + public void testSingleProducerSum() { + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, null, null, producers:[producer]) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), null + cae.onEvent(intSensor.newEvent(producer, 1)) + assertEquals cae.getAggregate(), 1 + } + + @Test + public void testSummingEnricherWhenNoAndNullSensorValue() { + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, null, null, producers:[producer]) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), null + cae.onEvent(intSensor.newEvent(producer, null)) + assertEquals cae.getAggregate(), null + } + + @Test + public void testSummingEnricherWhenNoAndNullSensorValueExplicitValue() { + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, 3 /** if null */, 5 /** if none */, producers:[producer]) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), 3 + cae.onEvent(intSensor.newEvent(producer, null)) + assertEquals cae.getAggregate(), 3 + cae.onEvent(intSensor.newEvent(producer, 1)) + assertEquals cae.getAggregate(), 1 + cae.onEvent(intSensor.newEvent(producer, 7)) + assertEquals cae.getAggregate(), 7 + } + + @Test + public void testMultipleProducersSum() { + List<TestEntity> producers = [ + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)) + ] + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, null, null, producers:producers) + + producer.addEnricher(cae) + assertEquals cae.getAggregate(), null + cae.onEvent(intSensor.newEvent(producers[2], 1)) + assertEquals cae.getAggregate(), 1 + cae.onEvent(intSensor.newEvent(producers[0], 3)) + assertEquals cae.getAggregate(), 4 + cae.onEvent(intSensor.newEvent(producers[1], 3)) + assertEquals cae.getAggregate(), 7 + + } + + @Test + public void testAveragingEnricherWhenNoAndNullSensorValues() { + List<TestEntity> producers = [ + app.createAndManageChild(EntitySpec.create(TestEntity.class)) + ] + CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher( + intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers) + producer.addEnricher(cae) + assertEquals cae.getAggregate(), null + cae.onEvent(intSensor.newEvent(producers[0], null)) + assertEquals cae.getAggregate(), null + } + + @Test + public void testAveragingEnricherWhenNoAndNullSensorValuesExplicit() { + List<TestEntity> producers = [ + app.createAndManageChild(EntitySpec.create(TestEntity.class)) + ] + CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher( + intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */, + producers:producers) + producer.addEnricher(cae) + + assertEquals cae.getAggregate(), 3d + cae.onEvent(intSensor.newEvent(producers[0], null)) + assertEquals cae.getAggregate(), 3d + cae.onEvent(intSensor.newEvent(producers[0], 4)) + assertEquals cae.getAggregate(), 4d + } + + @Test + public void testAveragingEnricherWhenNoSensors() { + List<TestEntity> producers = [ + ] + CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher( + intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 3 /** if null */, 5 /** if none */, + producers:producers) + producer.addEnricher(cae) + + assertEquals cae.getAggregate(), 5d + } + + @Test + public void testMultipleProducersAverage() { + List<TestEntity> producers = [ + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)) + ] + CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher( + intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), null, null, producers:producers) + + producer.addEnricher(cae) + + assertEquals cae.getAggregate(), null + cae.onEvent(intSensor.newEvent(producers[0], 3)) + assertEquals cae.getAggregate(), 3d + + cae.onEvent(intSensor.newEvent(producers[1], 3)) + assertEquals cae.getAggregate(), 3d + + cae.onEvent(intSensor.newEvent(producers[2], 6)) + assertEquals cae.getAggregate(), 4d + + // change p2's value to 7.5, average increase of 0.5. + cae.onEvent(intSensor.newEvent(producers[2], 7.5)) + assertEquals cae.getAggregate(), 4.5d + } + + @Test + public void testMultipleProducersAverageDefaultingZero() { + List<TestEntity> producers = [ + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)), + app.createAndManageChild(EntitySpec.create(TestEntity.class)) + ] + CustomAggregatingEnricher<Double> cae = CustomAggregatingEnricher.<Double>newAveragingEnricher( + intSensor, new BasicAttributeSensor<Double>(Double.class, "target sensor"), 0, 0, producers:producers) + + producer.addEnricher(cae) + + assertEquals cae.getAggregate(), 0d + cae.onEvent(intSensor.newEvent(producers[0], 3)) + assertEquals cae.getAggregate(), 1d + + cae.onEvent(intSensor.newEvent(producers[1], 3)) + assertEquals cae.getAggregate(), 2d + + cae.onEvent(intSensor.newEvent(producers[2], 6)) + assertEquals cae.getAggregate(), 4d + + // change p2's value to 7.5, average increase of 0.5. + cae.onEvent(intSensor.newEvent(producers[2], 7.5)) + assertEquals cae.getAggregate(), 4.5d + } + + @Test + public void testAddingAndRemovingProducers() { + TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher( + intSensor, target, null, null, producers:[p1]) + + producer.addEnricher(cae) + assertEquals cae.getAggregate(), null + + // Event by initial producer + cae.onEvent(intSensor.newEvent(p1, 1)) + assertEquals cae.getAggregate(), 1 + + // Add producer and fire event + cae.addProducer(p2) + cae.onEvent(intSensor.newEvent(p2, 4)) + assertEquals cae.getAggregate(), 5 + + cae.removeProducer(p2) + assertEquals cae.getAggregate(), 1 + } + + @Test + public void testAggregatesNewMembersOfGroup() { + try { + BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class)); + TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)) + TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class)) + log.debug("created $group and the entities it will contain $p1 $p2") + + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, 0, 0, allMembers:true) + group.addEnricher(cae) + + assertEquals cae.getAggregate(), 0 + + group.addMember(p1) + p1.setAttribute(intSensor, 1) + TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) { + assertEquals cae.getAggregate(), 1 + } + + group.addMember(p2) + p2.setAttribute(intSensor, 2) + TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) { + assertEquals cae.getAggregate(), 3 + } + + group.removeMember(p2) + TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) { + assertEquals cae.getAggregate(), 1 + } + } catch (Exception e) { + log.error("testAggregatesNewMembersOfGroup failed (now cleaning up): "+e) + throw e; + } + } + + @Test(groups = "Integration") + public void testAggregatesGroupMembersFiftyTimes() { + for (int i=0; i<50; i++) { + log.debug "testAggregatesNewMembersOfGroup $i" + testAggregatesNewMembersOfGroup(); + } + } + + @Test + public void testAggregatesExistingMembersOfGroup() { + BasicGroup group = app.addChild(EntitySpec.create(BasicGroup.class)); + TestEntity p1 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); + TestEntity p2 = app.getManagementContext().getEntityManager().createEntity(EntitySpec.create(TestEntity.class).parent(group)); + group.addMember(p1) + group.addMember(p2) + p1.setAttribute(intSensor, 1) + Entities.manage(group); + + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true) + group.addEnricher(cae) + + assertEquals cae.getAggregate(), 1 + + p2.setAttribute(intSensor, 2) + TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) { + assertEquals cae.getAggregate(), 3 + } + + group.removeMember(p2) + TestUtils.executeUntilSucceeds(timeout:TIMEOUT_MS) { + assertEquals cae.getAggregate(), 1 + } + } + + @Test + public void testAppliesFilterWhenAggregatingMembersOfGroup() { + BasicGroup group = app.createAndManageChild(EntitySpec.create(BasicGroup.class)); + TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + TestEntity p2 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + TestEntity p3 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + group.addMember(p1) + group.addMember(p2) + p1.setAttribute(intSensor, 1) + p2.setAttribute(intSensor, 2) + p3.setAttribute(intSensor, 4) + + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newSummingEnricher(intSensor, target, null, null, allMembers:true, filter:{it == p1}) + group.addEnricher(cae) + + assertEquals cae.getAggregate(), 1 + + group.addMember(p3) + TestUtils.assertSucceedsContinually(timeout:SHORT_WAIT_MS) { + assertEquals cae.getAggregate(), 1 + } + } + + @Test + public void testCustomAggregatingFunction() { + TestEntity p1 = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + Function<Collection<Integer>,Integer> aggregator = { Collection c -> + int result = 0; c.each { result += it*it }; return result; + } as Function + + CustomAggregatingEnricher<Integer> cae = CustomAggregatingEnricher.<Integer>newEnricher( + intSensor, target, aggregator, 0, producers:[p1]) + + producer.addEnricher(cae) + assertEquals cae.getAggregate(), 0 + + // Event by producer + cae.onEvent(intSensor.newEvent(p1, 2)) + assertEquals cae.getAggregate(), 4 + } +}
